From aab9be7f2088d494b9f289b68aa18257295ad21a Mon Sep 17 00:00:00 2001 From: Tim Steiner <tsteiner2@unl.edu> Date: Thu, 8 Nov 2012 12:05:34 -0600 Subject: [PATCH] [gh-518] Upgrade Drupal Core to 7.17 --- CHANGELOG.txt | 77 +++- INSTALL.txt | 4 +- MAINTAINERS.txt | 216 +++++----- README.md | 35 ++ includes/ajax.inc | 2 +- includes/authorize.inc | 2 +- includes/bootstrap.inc | 146 +++---- includes/common.inc | 177 ++++++--- includes/database/database.inc | 4 +- includes/database/log.inc | 10 +- includes/database/pgsql/database.inc | 11 + includes/entity.inc | 19 +- includes/errors.inc | 15 - includes/file.inc | 8 +- includes/filetransfer/filetransfer.inc | 2 +- includes/form.inc | 166 +++++--- includes/image.inc | 19 +- includes/install.core.inc | 91 +++-- includes/install.inc | 63 +-- includes/iso.inc | 2 +- includes/language.inc | 17 +- includes/mail.inc | 28 +- includes/menu.inc | 159 ++++---- includes/module.inc | 43 +- includes/session.inc | 20 +- includes/stream_wrappers.inc | 6 +- includes/theme.inc | 14 +- includes/unicode.inc | 4 +- includes/update.inc | 33 +- misc/collapse.js | 2 +- misc/states.js | 4 +- modules/aggregator/aggregator.admin.inc | 2 +- modules/aggregator/aggregator.api.php | 33 +- modules/aggregator/aggregator.info | 6 +- modules/aggregator/aggregator.install | 54 ++- modules/aggregator/aggregator.module | 7 +- modules/aggregator/aggregator.processor.inc | 3 +- modules/aggregator/aggregator.test | 158 +++++--- modules/aggregator/tests/aggregator_test.info | 6 +- .../tests/aggregator_test_rss091.xml | 11 + modules/block/block.api.php | 1 + modules/block/block.info | 6 +- modules/block/block.test | 130 +++--- modules/block/tests/block_test.info | 6 +- .../block_test_theme/block_test_theme.info | 6 +- modules/blog/blog.info | 6 +- modules/book/book.admin.inc | 2 +- modules/book/book.info | 6 +- modules/book/book.js | 6 + modules/color/color.info | 6 +- modules/comment/comment-wrapper.tpl.php | 3 +- modules/comment/comment.info | 6 +- modules/comment/comment.module | 15 +- modules/comment/comment.test | 372 +++++++++--------- modules/comment/comment.tpl.php | 2 + modules/contact/contact.info | 6 +- modules/contextual/contextual.info | 6 +- modules/dashboard/dashboard.info | 6 +- modules/dblog/dblog.info | 6 +- modules/dblog/dblog.module | 2 +- modules/dblog/dblog.test | 2 +- modules/field/field.api.php | 20 +- modules/field/field.form.inc | 35 +- modules/field/field.info | 6 +- modules/field/field.info.inc | 9 +- modules/field/field.install | 10 +- modules/field/field.module | 2 +- .../field_sql_storage/field_sql_storage.info | 6 +- .../field_sql_storage.install | 2 +- modules/field/modules/list/list.info | 6 +- .../field/modules/list/tests/list_test.info | 6 +- modules/field/modules/number/number.info | 6 +- modules/field/modules/options/options.info | 6 +- modules/field/modules/text/text.info | 6 +- modules/field/tests/field.test | 5 +- modules/field/tests/field_test.entity.inc | 14 +- modules/field/tests/field_test.info | 6 +- modules/field/theme/field.tpl.php | 2 + modules/field_ui/field_ui.info | 6 +- modules/file/file.api.php | 6 - modules/file/file.info | 6 +- modules/file/file.js | 9 +- modules/file/tests/file_module_test.info | 6 +- modules/filter/filter.info | 6 +- modules/forum/forum.info | 6 +- modules/forum/forum.module | 12 +- modules/forum/forum.test | 8 + modules/help/help.info | 6 +- modules/image/image.field.inc | 13 +- modules/image/image.info | 6 +- modules/image/image.module | 6 +- modules/image/image.test | 106 ++++- modules/image/tests/image_module_test.info | 6 +- modules/image/tests/image_module_test.module | 11 +- modules/locale/locale.info | 6 +- modules/locale/locale.install | 15 +- modules/locale/locale.module | 2 +- modules/locale/locale.test | 12 +- modules/locale/tests/locale_test.info | 6 +- modules/menu/menu.admin.inc | 10 +- modules/menu/menu.info | 6 +- modules/node/node.api.php | 67 ++-- modules/node/node.info | 6 +- modules/node/node.install | 2 +- modules/node/node.module | 64 +-- modules/node/node.test | 91 ++++- modules/node/node.tpl.php | 20 +- modules/node/tests/node_access_test.info | 6 +- modules/node/tests/node_test.info | 6 +- modules/node/tests/node_test.module | 10 + modules/node/tests/node_test_exception.info | 6 +- modules/openid/openid.inc | 2 +- modules/openid/openid.info | 6 +- modules/openid/openid.module | 6 +- modules/openid/openid.pages.inc | 1 + modules/openid/openid.test | 192 ++++----- modules/openid/tests/openid_test.info | 6 +- modules/overlay/overlay-child-rtl.css | 5 + modules/overlay/overlay-child.css | 5 + modules/overlay/overlay-child.js | 4 + modules/overlay/overlay-parent.css | 5 + modules/overlay/overlay-parent.js | 20 +- modules/overlay/overlay.info | 6 +- modules/overlay/overlay.install | 4 +- modules/overlay/overlay.module | 53 ++- modules/overlay/overlay.tpl.php | 2 + modules/path/path.info | 6 +- modules/path/path.module | 2 - modules/php/php.info | 6 +- modules/poll/poll-results.tpl.php | 2 + modules/poll/poll-vote.tpl.php | 2 + modules/poll/poll.info | 6 +- modules/poll/poll.module | 2 +- modules/poll/poll.test | 110 +++--- modules/profile/profile-wrapper.tpl.php | 2 +- modules/profile/profile.info | 6 +- modules/profile/profile.module | 2 +- modules/rdf/rdf.info | 6 +- modules/rdf/rdf.test | 2 +- modules/rdf/tests/rdf_test.info | 6 +- modules/search/search-result.tpl.php | 2 + modules/search/search-results.tpl.php | 2 + modules/search/search.info | 6 +- modules/search/search.pages.inc | 1 - .../search/tests/search_embedded_form.info | 6 +- modules/search/tests/search_extra_type.info | 6 +- modules/shortcut/shortcut.admin.inc | 11 +- modules/shortcut/shortcut.admin.js | 2 +- modules/shortcut/shortcut.info | 6 +- modules/shortcut/shortcut.module | 28 +- modules/shortcut/shortcut.test | 4 +- modules/simpletest/drupal_web_test_case.php | 31 +- modules/simpletest/simpletest.api.php | 2 +- modules/simpletest/simpletest.info | 13 +- .../simpletest/tests/actions_loop_test.info | 6 +- modules/simpletest/tests/ajax_forms_test.info | 6 +- .../simpletest/tests/ajax_forms_test.module | 4 - modules/simpletest/tests/ajax_test.info | 6 +- modules/simpletest/tests/batch_test.info | 6 +- modules/simpletest/tests/common.test | 49 ++- modules/simpletest/tests/common_test.info | 6 +- .../tests/common_test_cron_helper.info | 6 +- modules/simpletest/tests/database_test.info | 6 +- modules/simpletest/tests/database_test.test | 19 +- ...drupal_system_listing_compatible_test.info | 6 +- ...upal_system_listing_incompatible_test.info | 6 +- .../simpletest/tests/entity_cache_test.info | 6 +- .../tests/entity_cache_test_dependency.info | 6 +- .../tests/entity_crud_hook_test.info | 6 +- .../tests/entity_crud_hook_test.module | 23 +- .../tests/entity_crud_hook_test.test | 22 +- .../tests/entity_query_access_test.info | 6 +- modules/simpletest/tests/error_test.info | 6 +- modules/simpletest/tests/file_test.info | 6 +- modules/simpletest/tests/filter_test.info | 6 +- modules/simpletest/tests/form.test | 138 +++++++ modules/simpletest/tests/form_test.info | 6 +- modules/simpletest/tests/form_test.module | 104 +++++ modules/simpletest/tests/https.php | 4 +- modules/simpletest/tests/image.test | 8 +- modules/simpletest/tests/image_test.info | 6 +- modules/simpletest/tests/mail.test | 4 +- modules/simpletest/tests/menu.test | 2 +- modules/simpletest/tests/menu_test.info | 6 +- modules/simpletest/tests/module.test | 10 +- modules/simpletest/tests/module_test.info | 6 +- modules/simpletest/tests/path_test.info | 6 +- .../simpletest/tests/requirements1_test.info | 6 +- .../tests/requirements1_test.install | 2 +- .../simpletest/tests/requirements2_test.info | 6 +- modules/simpletest/tests/session.test | 8 +- modules/simpletest/tests/session_test.info | 6 +- .../tests/system_dependencies_test.info | 6 +- ...atible_core_version_dependencies_test.info | 6 +- ...system_incompatible_core_version_test.info | 6 +- ...ible_module_version_dependencies_test.info | 6 +- ...stem_incompatible_module_version_test.info | 6 +- modules/simpletest/tests/system_test.info | 6 +- modules/simpletest/tests/taxonomy_test.info | 6 +- modules/simpletest/tests/taxonomy_test.module | 30 ++ modules/simpletest/tests/theme.test | 13 +- modules/simpletest/tests/theme_test.info | 6 +- .../themes/test_basetheme/test_basetheme.info | 6 +- .../themes/test_subtheme/test_subtheme.info | 6 +- .../tests/themes/test_theme/test_theme.info | 6 +- .../simpletest/tests/update_script_test.info | 6 +- modules/simpletest/tests/update_test_1.info | 6 +- modules/simpletest/tests/update_test_2.info | 6 +- modules/simpletest/tests/update_test_3.info | 6 +- .../tests/upgrade/drupal-6.forum.database.php | 14 + .../tests/upgrade/drupal-6.menu.database.php | 27 ++ .../upgrade/drupal-6.upload.database.php | 31 ++ .../upgrade/drupal-7.aggregator.database.php | 149 +++++++ ...upal-7.filled.standard_all.database.php.gz | Bin 97562 -> 97603 bytes .../tests/upgrade/update.aggregator.test | 47 +++ .../tests/upgrade/upgrade.forum.test | 6 +- modules/simpletest/tests/url_alter_test.info | 6 +- modules/simpletest/tests/xmlrpc_test.info | 6 +- modules/statistics/statistics.info | 6 +- modules/statistics/statistics.test | 101 ++--- modules/syslog/syslog.info | 6 +- modules/syslog/syslog.module | 3 +- modules/syslog/syslog.test | 2 +- modules/system/html.tpl.php | 2 + modules/system/maintenance-page.tpl.php | 2 + modules/system/page.tpl.php | 2 + modules/system/region.tpl.php | 2 + modules/system/system.admin.inc | 17 +- modules/system/system.api.php | 167 +++++++- modules/system/system.base.css | 4 + modules/system/system.info | 6 +- modules/system/system.install | 100 ++++- modules/system/system.module | 43 +- modules/system/theme.api.php | 4 +- modules/taxonomy/taxonomy-term.tpl.php | 4 +- modules/taxonomy/taxonomy.api.php | 24 ++ modules/taxonomy/taxonomy.info | 6 +- modules/taxonomy/taxonomy.install | 2 +- modules/taxonomy/taxonomy.module | 157 ++++++-- modules/taxonomy/taxonomy.pages.inc | 19 +- modules/taxonomy/taxonomy.test | 25 +- modules/toolbar/toolbar.info | 6 +- modules/toolbar/toolbar.tpl.php | 2 + modules/tracker/tracker.info | 6 +- .../translation/tests/translation_test.info | 6 +- modules/translation/translation.info | 6 +- modules/trigger/tests/trigger_test.info | 6 +- modules/trigger/trigger.info | 6 +- modules/update/tests/aaa_update_test.info | 6 +- modules/update/tests/bbb_update_test.info | 6 +- modules/update/tests/ccc_update_test.info | 6 +- .../update_test_basetheme.info | 6 +- .../update_test_subtheme.info | 6 +- modules/update/tests/update_test.info | 6 +- modules/update/update.compare.inc | 5 +- modules/update/update.fetch.inc | 14 +- modules/update/update.info | 6 +- modules/update/update.test | 5 +- modules/user/tests/user_form_test.info | 6 +- modules/user/user-picture.tpl.php | 2 + modules/user/user-profile.tpl.php | 2 + modules/user/user.api.php | 16 + modules/user/user.info | 6 +- modules/user/user.install | 2 +- modules/user/user.module | 17 +- modules/user/user.test | 36 +- profiles/minimal/minimal.info | 6 +- profiles/minimal/minimal.install | 2 +- profiles/standard/standard.info | 6 +- profiles/standard/standard.install | 2 +- ...drupal_system_listing_compatible_test.info | 6 +- ...upal_system_listing_incompatible_test.info | 6 +- profiles/testing/testing.info | 6 +- scripts/drupal.sh | 2 +- scripts/generate-d7-content.sh | 3 +- scripts/run-tests.sh | 4 +- sites/README.txt | 19 + sites/all/README.txt | 7 - sites/all/modules/README.txt | 18 +- sites/all/themes/README.txt | 16 +- sites/default/default.settings.php | 101 +++-- sites/example.sites.php | 70 ++-- themes/bartik/bartik.info | 6 +- .../bartik/templates/comment-wrapper.tpl.php | 1 - themes/bartik/templates/node.tpl.php | 18 +- themes/garland/garland.info | 6 +- themes/seven/page.tpl.php | 2 +- themes/seven/seven.info | 6 +- themes/stark/stark.info | 6 +- 289 files changed, 3836 insertions(+), 1916 deletions(-) create mode 100644 modules/simpletest/tests/upgrade/drupal-7.aggregator.database.php create mode 100644 modules/simpletest/tests/upgrade/update.aggregator.test create mode 100644 sites/README.txt delete mode 100644 sites/all/README.txt diff --git a/CHANGELOG.txt b/CHANGELOG.txt index b4beae31e..94522f5aa 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,4 +1,67 @@ +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 @@ -315,8 +378,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 @@ -543,7 +606,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. @@ -661,7 +724,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 @@ -716,7 +779,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. @@ -895,7 +958,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 @@ -955,7 +1018,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: diff --git a/INSTALL.txt b/INSTALL.txt index 7b526e33c..c3a26adfe 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -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/ diff --git a/MAINTAINERS.txt b/MAINTAINERS.txt index aa1421533..61715668e 100644 --- a/MAINTAINERS.txt +++ b/MAINTAINERS.txt @@ -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 diff --git a/README.md b/README.md index 3d7980a24..ec2a8dbc1 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,7 @@ CONTENTS OF THIS FILE * About Drupal * Configuration and features + * Installation profiles * Appearance * Developing for Drupal @@ -162,6 +163,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 ---------- diff --git a/includes/ajax.inc b/includes/ajax.inc index fb07477d6..4107029fe 100644 --- a/includes/ajax.inc +++ b/includes/ajax.inc @@ -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' diff --git a/includes/authorize.inc b/includes/authorize.inc index da6918ca7..8360e132c 100644 --- a/includes/authorize.inc +++ b/includes/authorize.inc @@ -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 diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index a27697bae..cd41f0bbf 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -8,7 +8,7 @@ /** * The current system version. */ -define('VERSION', '7.16'); +define('VERSION', '7.17'); /** * 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__, ''); @@ -749,7 +722,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(); @@ -776,7 +749,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']; @@ -802,7 +775,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(). @@ -1758,7 +1731,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 @@ -1824,18 +1798,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()) { @@ -2141,14 +2126,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). @@ -2547,7 +2544,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; @@ -2640,6 +2637,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 @@ -2650,6 +2650,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())); diff --git a/includes/common.inc b/includes/common.inc index dfa9153a2..8994b3f4a 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -92,14 +92,20 @@ define('JS_THEME', 100); define('HTTP_REQUEST_TIMEOUT', -1); /** - * Constants defining cache granularity for blocks and renderable arrays. - * - * 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 + * @defgroup block_caching Block Caching + * @{ + * Constants that define each block's caching state. + * + * 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; @@ -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() { @@ -798,10 +813,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 +867,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 +911,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 +1081,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". */ @@ -1701,7 +1766,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 +2144,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 @@ -2312,21 +2377,22 @@ 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 + * @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 @@ -2342,8 +2408,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; @@ -3930,7 +3998,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 @@ -5117,6 +5186,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 @@ -5179,7 +5249,7 @@ function drupal_cron_run() { } // Restore the user. $GLOBALS['user'] = $original_user; - drupal_save_session(TRUE); + drupal_save_session($original_session_saving); return $return; } @@ -5211,7 +5281,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 @@ -7452,12 +7522,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; @@ -7545,12 +7615,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); @@ -7583,13 +7654,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(); @@ -7619,11 +7689,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 @@ -7641,6 +7706,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) { @@ -7660,7 +7730,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. @@ -7697,7 +7767,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'. @@ -7706,6 +7775,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)) { @@ -7732,16 +7803,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); @@ -7836,7 +7907,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 @@ -7849,7 +7920,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 diff --git a/includes/database/database.inc b/includes/database/database.inc index 5bcae67a3..cae50fb87 100644 --- a/includes/database/database.inc +++ b/includes/database/database.inc @@ -167,7 +167,7 @@ * } * @endcode * - * @link http://drupal.org/developing/api/database + * @link http://drupal.org/developing/api/database @endlink */ @@ -2769,7 +2769,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. */ diff --git a/includes/database/log.inc b/includes/database/log.inc index ec27ef8e6..27eae62cd 100644 --- a/includes/database/log.inc +++ b/includes/database/log.inc @@ -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'], diff --git a/includes/database/pgsql/database.inc b/includes/database/pgsql/database.inc index 79c16b212..00ed7990e 100644 --- a/includes/database/pgsql/database.inc +++ b/includes/database/pgsql/database.inc @@ -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(); diff --git a/includes/entity.inc b/includes/entity.inc index 832abe2fd..2fefd5904 100644 --- a/includes/entity.inc +++ b/includes/entity.inc @@ -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 { } diff --git a/includes/errors.inc b/includes/errors.inc index 9d0df0544..7fd2de2fb 100644 --- a/includes/errors.inc +++ b/includes/errors.inc @@ -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. * diff --git a/includes/file.inc b/includes/file.inc index c5e5cf07d..1e256c634 100644 --- a/includes/file.inc +++ b/includes/file.inc @@ -398,8 +398,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 { @@ -2236,7 +2236,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. @@ -2489,7 +2489,7 @@ function file_get_content_headers($file) { } return array( - 'Content-Type' => $type . '; name="' . $name . '"', + 'Content-Type' => $type, 'Content-Length' => $file->filesize, 'Content-Disposition' => $disposition . '; filename="' . $name . '"', 'Cache-Control' => 'private', diff --git a/includes/filetransfer/filetransfer.inc b/includes/filetransfer/filetransfer.inc index bd2057cdd..023b866e3 100644 --- a/includes/filetransfer/filetransfer.inc +++ b/includes/filetransfer/filetransfer.inc @@ -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. */ diff --git a/includes/form.inc b/includes/form.inc index d7350b3e2..aa90eca69 100644 --- a/includes/form.inc +++ b/includes/form.inc @@ -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. + * + * 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. * - * For example, to redirect to 'node': + * 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())); } } @@ -3251,21 +3255,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 +3262,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 */ @@ -3645,6 +3662,35 @@ function form_pre_render_fieldset($element) { /** * Creates a group formatted as vertical tabs. * + * Note that autocomplete callbacks should include special handling as the + * user's input may contain forward slashes. If the user-submitted string has a + * '/' in the text that is sent in the autocomplete request, the menu system + * will split the text and pass it to the callback as multiple arguments. + * + * Suppose your autocomplete path in the menu system is 'mymodule_autocomplete.' + * In your form you have: + * @code + * '#autocomplete_path' => 'mymodule_autocomplete/' . $some_key . '/' . $some_id, + * @endcode + * The user types in "keywords" so the full path called is: + * 'mymodule_autocomplete/$some_key/$some_id/keywords' + * + * You should include code similar to the following to handle slashes in the + * input: + * @code + * function mymodule_autocomplete_callback($arg1, $arg2, $keywords) { + * $args = func_get_args(); + * // We need to remove $arg1 and $arg2 from the beginning of the array so we + * // are left with the keywords. + * array_shift($args); + * array_shift($args); + * // We store the user's original input in $keywords, including any slashes. + * $keywords = implode('/', $args); + * + * // Your code here. + * } + * @endcode + * * @param $element * An associative array containing the properties and children of the * fieldset. @@ -4153,7 +4199,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) { $element['#attributes']['class'][] = 'error'; } } @@ -4363,7 +4409,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(), diff --git a/includes/image.inc b/includes/image.inc index f6ae7f19b..ee5a086de 100644 --- a/includes/image.inc +++ b/includes/image.inc @@ -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 @@ -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 diff --git a/includes/install.core.inc b/includes/install.core.inc index 7bcd026ae..9805e1c88 100644 --- a/includes/install.core.inc +++ b/includes/install.core.inc @@ -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. @@ -524,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'), @@ -708,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. @@ -776,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(); @@ -785,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 @@ -829,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 @@ -841,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; @@ -912,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']; @@ -969,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; @@ -1000,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 @@ -1040,8 +1041,7 @@ 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 from a list or from a $_POST submission. */ function _install_select_profile($profiles) { if (sizeof($profiles) == 0) { @@ -1064,12 +1064,14 @@ function _install_select_profile($profiles) { } /** - * 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(); @@ -1246,7 +1248,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'; @@ -1296,7 +1300,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 @@ -1315,7 +1319,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. @@ -1325,7 +1329,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. @@ -1378,7 +1382,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. @@ -1412,15 +1416,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')); @@ -1443,7 +1446,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 @@ -1486,7 +1489,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. @@ -1502,13 +1505,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') @@ -1673,7 +1676,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'; @@ -1786,7 +1797,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'])) { @@ -1801,7 +1814,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; diff --git a/includes/install.inc b/includes/install.inc index 6411f8f19..0372483b6 100644 --- a/includes/install.inc +++ b/includes/install.inc @@ -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,13 +1230,14 @@ 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: diff --git a/includes/iso.inc b/includes/iso.inc index a88de57e9..6c66c569f 100644 --- a/includes/iso.inc +++ b/includes/iso.inc @@ -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"), diff --git a/includes/language.inc b/includes/language.inc index 20909f5a6..d0ea83113 100644 --- a/includes/language.inc +++ b/includes/language.inc @@ -190,6 +190,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 +204,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); @@ -408,7 +419,7 @@ 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. @@ -440,10 +451,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. diff --git a/includes/mail.inc b/includes/mail.inc index 13a6f4643..8479d8e9b 100644 --- a/includes/mail.inc +++ b/includes/mail.inc @@ -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 @@ -191,7 +191,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(). @@ -328,7 +328,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 +340,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 +374,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 +553,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 +565,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 +592,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. diff --git a/includes/menu.inc b/includes/menu.inc index b25a374ac..0cb9d23b8 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -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 @@ -638,7 +639,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 +747,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 +797,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 +821,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 +845,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 +942,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 +1082,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 +1150,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 +1175,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 +1189,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 +1323,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 +1338,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 +1356,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 +1452,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 +1475,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 +1502,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 +1525,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 +1557,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 +1592,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 +1786,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 +1798,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 +1820,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 +2112,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 +2145,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 +2239,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 +2260,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 +2288,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 +2312,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 +2336,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 +2426,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 +2546,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 +2597,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 +2610,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 +2661,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 +2684,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 +2733,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 +2757,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 +2769,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 +2806,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 +2906,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 +2997,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 +3216,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 +3230,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 +3296,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 +3318,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 +3326,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 +3368,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 +3408,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 +3440,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 +3489,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 +3513,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 +3531,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 +3758,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. diff --git a/includes/module.inc b/includes/module.inc index 28bca2350..d932f07b9 100644 --- a/includes/module.inc +++ b/includes/module.inc @@ -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,7 +892,7 @@ 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 diff --git a/includes/session.inc b/includes/session.inc index 95364f848..0a95b8548 100644 --- a/includes/session.inc +++ b/includes/session.inc @@ -353,6 +353,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])) { @@ -422,6 +427,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) @@ -469,6 +479,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(); @@ -511,7 +526,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; } diff --git a/includes/stream_wrappers.inc b/includes/stream_wrappers.inc index 2af8c9e91..fa401c6b7 100644 --- a/includes/stream_wrappers.inc +++ b/includes/stream_wrappers.inc @@ -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. diff --git a/includes/theme.inc b/includes/theme.inc index c4b712271..777922f05 100644 --- a/includes/theme.inc +++ b/includes/theme.inc @@ -2069,10 +2069,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 +2095,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 +2114,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 +2130,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))); } @@ -2177,7 +2179,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) { diff --git a/includes/unicode.inc b/includes/unicode.inc index cd9cd9bf0..81a0a4dfe 100644 --- a/includes/unicode.inc +++ b/includes/unicode.inc @@ -96,7 +96,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 @@ -128,7 +128,7 @@ function _unicode_check() { * Return 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( diff --git a/includes/update.inc b/includes/update.inc index d8fec64df..559a0a711 100644 --- a/includes/update.inc +++ b/includes/update.inc @@ -787,12 +787,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(); @@ -830,10 +830,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) @@ -842,7 +842,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(); } } @@ -897,7 +898,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); } @@ -1476,17 +1477,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". - */ diff --git a/misc/collapse.js b/misc/collapse.js index 1a98dc0e0..bd51ce532 100644 --- a/misc/collapse.js +++ b/misc/collapse.js @@ -58,7 +58,7 @@ 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) { $fieldset.removeClass('collapsed'); diff --git a/misc/states.js b/misc/states.js index 594f8187b..4b4f1d518 100644 --- a/misc/states.js +++ b/misc/states.js @@ -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 diff --git a/modules/aggregator/aggregator.admin.inc b/modules/aggregator/aggregator.admin.inc index 9f92a6705..8b817c0fa 100644 --- a/modules/aggregator/aggregator.admin.inc +++ b/modules/aggregator/aggregator.admin.inc @@ -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, ); diff --git a/modules/aggregator/aggregator.api.php b/modules/aggregator/aggregator.api.php index 0f708eb85..cd5e47b14 100644 --- a/modules/aggregator/aggregator.api.php +++ b/modules/aggregator/aggregator.api.php @@ -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 diff --git a/modules/aggregator/aggregator.info b/modules/aggregator/aggregator.info index 65e402b3e..2f1d05357 100644 --- a/modules/aggregator/aggregator.info +++ b/modules/aggregator/aggregator.info @@ -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-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/aggregator/aggregator.install b/modules/aggregator/aggregator.install index f19d7de9b..b84556a9d 100644 --- a/modules/aggregator/aggregator.install +++ b/modules/aggregator/aggregator.install @@ -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" + */ diff --git a/modules/aggregator/aggregator.module b/modules/aggregator/aggregator.module index 686f4248a..93457c68d 100644 --- a/modules/aggregator/aggregator.module +++ b/modules/aggregator/aggregator.module @@ -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(); } diff --git a/modules/aggregator/aggregator.processor.inc b/modules/aggregator/aggregator.processor.inc index 7fa86a9ad..3f1319c8c 100644 --- a/modules/aggregator/aggregator.processor.inc +++ b/modules/aggregator/aggregator.processor.inc @@ -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'])); } } diff --git a/modules/aggregator/aggregator.test b/modules/aggregator/aggregator.test index 77b60cb93..eff31020f 100644 --- a/modules/aggregator/aggregator.test +++ b/modules/aggregator/aggregator.test @@ -25,10 +25,10 @@ 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; } @@ -40,7 +40,7 @@ class AggregatorTestCase extends DrupalWebTestCase { */ 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.'); } /** @@ -90,7 +90,7 @@ class AggregatorTestCase extends DrupalWebTestCase { 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,7 +108,7 @@ 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))); } /** @@ -119,7 +119,7 @@ class AggregatorTestCase extends DrupalWebTestCase { */ 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.'); } /** @@ -167,12 +167,12 @@ class AggregatorTestCase extends DrupalWebTestCase { /** - * Check if the feed name and url is unique. + * Check if the feed name and URL is 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. */ @@ -316,7 +316,7 @@ 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))); } } } @@ -337,19 +337,48 @@ class AddFeedTestCase extends AggregatorTestCase { $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); + } } class CategorizeFeedTestCase extends AggregatorTestCase { @@ -369,11 +398,11 @@ class CategorizeFeedTestCase extends AggregatorTestCase { // 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,7 +420,7 @@ 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'); } } @@ -419,16 +448,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. @@ -457,11 +486,11 @@ 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'); } } @@ -497,10 +526,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 +550,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))); } } @@ -554,9 +583,9 @@ 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); } @@ -582,14 +611,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 +629,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 +640,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'); } } @@ -644,11 +673,11 @@ 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.'); } /** @@ -659,7 +688,7 @@ class ImportOPMLTestCase extends AggregatorTestCase { $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,14 +696,14 @@ 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.'); } /** @@ -685,14 +714,14 @@ class ImportOPMLTestCase extends AggregatorTestCase { $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 +745,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,10 +760,10 @@ 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.'); } function testOPMLImport() { @@ -834,20 +863,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. @@ -876,7 +905,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); @@ -910,10 +939,19 @@ class FeedParserTestCase extends AggregatorTestCase { $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'); } /** @@ -923,7 +961,7 @@ class FeedParserTestCase extends AggregatorTestCase { $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.'); diff --git a/modules/aggregator/tests/aggregator_test.info b/modules/aggregator/tests/aggregator_test.info index fe8ccd107..204d2edf2 100644 --- a/modules/aggregator/tests/aggregator_test.info +++ b/modules/aggregator/tests/aggregator_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/aggregator/tests/aggregator_test_rss091.xml b/modules/aggregator/tests/aggregator_test_rss091.xml index f39a2732c..29440227f 100644 --- a/modules/aggregator/tests/aggregator_test_rss091.xml +++ b/modules/aggregator/tests/aggregator_test_rss091.xml @@ -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> diff --git a/modules/block/block.api.php b/modules/block/block.api.php index 3cd52f8b7..312eb11f2 100644 --- a/modules/block/block.api.php +++ b/modules/block/block.api.php @@ -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: diff --git a/modules/block/block.info b/modules/block/block.info index ef2f99927..cd9bf089c 100644 --- a/modules/block/block.info +++ b/modules/block/block.info @@ -6,8 +6,8 @@ core = 7.x files[] = block.test configure = admin/structure/block -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/block/block.test b/modules/block/block.test index 8e6e47042..11d070993 100644 --- a/modules/block/block.test +++ b/modules/block/block.test @@ -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.'); } } diff --git a/modules/block/tests/block_test.info b/modules/block/tests/block_test.info index 542949043..077515208 100644 --- a/modules/block/tests/block_test.info +++ b/modules/block/tests/block_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/block/tests/themes/block_test_theme/block_test_theme.info b/modules/block/tests/themes/block_test_theme/block_test_theme.info index bc74f0fba..4b585c5c9 100644 --- a/modules/block/tests/themes/block_test_theme/block_test_theme.info +++ b/modules/block/tests/themes/block_test_theme/block_test_theme.info @@ -13,8 +13,8 @@ regions[footer] = Footer regions[highlighted] = Highlighted regions[help] = Help -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/blog/blog.info b/modules/blog/blog.info index 9dd7d37a8..bdfc3c03d 100644 --- a/modules/blog/blog.info +++ b/modules/blog/blog.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = blog.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/book/book.admin.inc b/modules/book/book.admin.inc index 2f60610c8..62c6e841a 100644 --- a/modules/book/book.admin.inc +++ b/modules/book/book.admin.inc @@ -278,5 +278,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.'))); } diff --git a/modules/book/book.info b/modules/book/book.info index f92a1744e..d3e42dd44 100644 --- a/modules/book/book.info +++ b/modules/book/book.info @@ -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-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/book/book.js b/modules/book/book.js index 075f33b93..0853e8ecb 100644 --- a/modules/book/book.js +++ b/modules/book/book.js @@ -1,3 +1,9 @@ +/** + * @file + * Javascript behaviors for the Book module. + */ + + (function ($) { Drupal.behaviors.bookFieldsetSummaries = { diff --git a/modules/color/color.info b/modules/color/color.info index 3bf42fe5c..a12fcdd54 100644 --- a/modules/color/color.info +++ b/modules/color/color.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = color.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/comment/comment-wrapper.tpl.php b/modules/comment/comment-wrapper.tpl.php index 3293e88ae..c69145929 100644 --- a/modules/comment/comment-wrapper.tpl.php +++ b/modules/comment/comment-wrapper.tpl.php @@ -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; ?>> diff --git a/modules/comment/comment.info b/modules/comment/comment.info index 89be17cc5..c42f7afba 100644 --- a/modules/comment/comment.info +++ b/modules/comment/comment.info @@ -9,8 +9,8 @@ files[] = comment.test configure = admin/content/comment stylesheets[all][] = comment.css -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/comment/comment.module b/modules/comment/comment.module index 429c3b01b..4241538a0 100644 --- a/modules/comment/comment.module +++ b/modules/comment/comment.module @@ -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); } /** @@ -2375,7 +2387,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. diff --git a/modules/comment/comment.test b/modules/comment/comment.test index e787d25d1..30bff7140 100644 --- a/modules/comment/comment.test +++ b/modules/comment/comment.test @@ -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')); diff --git a/modules/comment/comment.tpl.php b/modules/comment/comment.tpl.php index a483813d2..829847357 100644 --- a/modules/comment/comment.tpl.php +++ b/modules/comment/comment.tpl.php @@ -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; ?>> diff --git a/modules/contact/contact.info b/modules/contact/contact.info index c4fe6a06c..42c369994 100644 --- a/modules/contact/contact.info +++ b/modules/contact/contact.info @@ -6,8 +6,8 @@ core = 7.x files[] = contact.test configure = admin/structure/contact -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/contextual/contextual.info b/modules/contextual/contextual.info index 69777c6c5..b88194467 100644 --- a/modules/contextual/contextual.info +++ b/modules/contextual/contextual.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = contextual.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/dashboard/dashboard.info b/modules/dashboard/dashboard.info index 6fc1b3478..30091ddce 100644 --- a/modules/dashboard/dashboard.info +++ b/modules/dashboard/dashboard.info @@ -7,8 +7,8 @@ files[] = dashboard.test dependencies[] = block configure = admin/dashboard/customize -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/dblog/dblog.info b/modules/dblog/dblog.info index 18a4ba268..3935ee9a4 100644 --- a/modules/dblog/dblog.info +++ b/modules/dblog/dblog.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = dblog.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/dblog/dblog.module b/modules/dblog/dblog.module index 9420c538d..d831548c9 100644 --- a/modules/dblog/dblog.module +++ b/modules/dblog/dblog.module @@ -96,7 +96,7 @@ function dblog_init() { /** * Implements hook_cron(). * - * Remove expired log messages and flood control events. + * Remove expired log messages. */ function dblog_cron() { // Cleanup the watchdog table. diff --git a/modules/dblog/dblog.test b/modules/dblog/dblog.test index a91356c85..ad01e97f5 100644 --- a/modules/dblog/dblog.test +++ b/modules/dblog/dblog.test @@ -256,7 +256,7 @@ class DBLogTestCase extends DrupalWebTestCase { // View dblog 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]')); } diff --git a/modules/field/field.api.php b/modules/field/field.api.php index 0d01c59fa..5f641173e 100644 --- a/modules/field/field.api.php +++ b/modules/field/field.api.php @@ -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, ), ); } @@ -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. diff --git a/modules/field/field.form.inc b/modules/field/field.form.inc index 6c27c4329..280f778ff 100644 --- a/modules/field/field.form.inc +++ b/modules/field/field.form.inc @@ -6,7 +6,38 @@ */ /** - * Create a separate form element for each field. + * Creates a form element for a field and can populate it with a default value. + * + * If the form element is not associated with an entity (i.e., $entity is NULL) + * field_get_default_value will be called to supply the default value for the + * field. Also allows other modules to alter the form element by implementing + * their own hooks. + * + * @param $entity_type + * The type of entity (for example 'node' or 'user') that the field belongs + * to. + * @param $entity + * The entity object that the field belongs to. This may be NULL if creating a + * form element with a default value. + * @param $field + * An array representing the field whose editing element is being created. + * @param $instance + * An array representing the structure for $field in its current context. + * @param $langcode + * The language associated with the field. + * @param $items + * An array of the field values. When creating a new entity this may be NULL + * or an empty array to use default values. + * @param $form + * An array representing the form that the editing element will be attached + * to. + * @param $form_state + * An array containing the current state of the form. + * @param $get_delta + * Used to get only a specific delta value of a multiple value field. + * + * @return + * The form element array created for this field. */ function field_default_form($entity_type, $entity, $field, $instance, $langcode, $items, &$form, &$form_state, $get_delta = NULL) { // This could be called with no entity, as when a UI module creates a @@ -278,7 +309,7 @@ function theme_field_multiple_value_form($variables) { $header = array( array( - 'data' => '<label>' . t('!title: !required', array('!title' => $element['#title'], '!required' => $required)) . "</label>", + 'data' => '<label>' . t('!title !required', array('!title' => $element['#title'], '!required' => $required)) . "</label>", 'colspan' => 2, 'class' => array('field-label'), ), diff --git a/modules/field/field.info b/modules/field/field.info index 6443781c0..88d4088bd 100644 --- a/modules/field/field.info +++ b/modules/field/field.info @@ -10,8 +10,8 @@ dependencies[] = field_sql_storage required = TRUE stylesheets[all][] = theme/field.css -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/field/field.info.inc b/modules/field/field.info.inc index eb5cc5ca7..9e7ab938d 100644 --- a/modules/field/field.info.inc +++ b/modules/field/field.info.inc @@ -54,8 +54,8 @@ function field_info_cache_clear() { * the field type. * - 'widget types': Array of hook_field_widget_info() results, keyed by * widget_type. Each element has the following components: label, field - * types, settings, and behaviors from hook_field_widget_info(), as well - * as module, giving the module that exposes the widget type. + * types, settings, weight, and behaviors from hook_field_widget_info(), + * as well as module, giving the module that exposes the widget type. * - 'formatter types': Array of hook_field_formatter_info() results, keyed by * formatter_type. Each element has the following components: label, field * types, and behaviors from hook_field_formatter_info(), as well as @@ -124,6 +124,7 @@ function _field_info_collate_types($reset = FALSE) { } } drupal_alter('field_widget_info', $info['widget types']); + uasort($info['widget types'], 'drupal_sort_weight'); // Populate formatter types. foreach (module_implements('field_formatter_info') as $module) { @@ -702,6 +703,10 @@ function field_info_instances($entity_type = NULL, $bundle_name = NULL) { * The field name for the instance. * @param $bundle_name * The bundle name for the instance. + * + * @return + * An associative array of instance data for the specific field and bundle; + * NULL if the instance does not exist. */ function field_info_instance($entity_type, $field_name, $bundle_name) { $info = _field_info_collate_fields(); diff --git a/modules/field/field.install b/modules/field/field.install index 5934a264c..34d28073d 100644 --- a/modules/field/field.install +++ b/modules/field/field.install @@ -172,7 +172,7 @@ function field_schema() { * This function can be used for databases whose schema is at field module * version 7000 or higher. * - * @ingroup update-api-6.x-to-7.x + * @ingroup update_api */ function _update_7000_field_create_field(&$field) { // Merge in default values.` @@ -253,7 +253,7 @@ function _update_7000_field_create_field(&$field) { * @param $field_name * The field name to delete. * - * @ingroup update-api-6.x-to-7.x + * @ingroup update_api */ function _update_7000_field_delete_field($field_name) { $table_name = 'field_data_' . $field_name; @@ -284,7 +284,7 @@ function _update_7000_field_delete_field($field_name) { * * This function is valid for a database schema version 7000. * - * @ingroup update-api-6.x-to-7.x + * @ingroup update_api */ function _update_7000_field_delete_instance($field_name, $entity_type, $bundle) { // Delete field instance configuration data. @@ -322,6 +322,8 @@ function _update_7000_field_delete_instance($field_name, $entity_type, $bundle) * @return * An array of fields matching $conditions, keyed by the property specified * by the $key parameter. + * + * @ingroup update_api */ function _update_7000_field_read_fields(array $conditions = array(), $key = 'id') { $fields = array(); @@ -356,7 +358,7 @@ function _update_7000_field_read_fields(array $conditions = array(), $key = 'id' * This function can be used for databases whose schema is at field module * version 7000 or higher. * - * @ingroup update-api-6.x-to-7.x + * @ingroup update_api */ function _update_7000_field_create_instance($field, &$instance) { // Merge in defaults. diff --git a/modules/field/field.module b/modules/field/field.module index 6fc97a2bf..b6cf05c9b 100644 --- a/modules/field/field.module +++ b/modules/field/field.module @@ -376,7 +376,7 @@ function field_system_info_alter(&$info, $file, $type) { } if ($non_deleted) { if (module_exists('field_ui')) { - $explanation = t('Field type(s) in use - see !link', array('!link' => l(t('Field list'), 'admin/reports/fields'))); + $explanation = t('Field type(s) in use - see <a href="@fields-page">Field list</a>', array('@fields-page' => url('admin/reports/fields'))); } else { $explanation = t('Fields type(s) in use'); diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.info b/modules/field/modules/field_sql_storage/field_sql_storage.info index e00119580..d7d5e8e56 100644 --- a/modules/field/modules/field_sql_storage/field_sql_storage.info +++ b/modules/field/modules/field_sql_storage/field_sql_storage.info @@ -7,8 +7,8 @@ dependencies[] = field files[] = field_sql_storage.test required = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.install b/modules/field/modules/field_sql_storage/field_sql_storage.install index 78c520fcf..24973ab45 100644 --- a/modules/field/modules/field_sql_storage/field_sql_storage.install +++ b/modules/field/modules/field_sql_storage/field_sql_storage.install @@ -30,7 +30,7 @@ function field_sql_storage_schema() { * This function can be used for databases whose schema is at field module * version 7000 or higher. * - * @ingroup update-api-6.x-to-7.x + * @ingroup update_api */ function _update_7000_field_sql_storage_write($entity_type, $bundle, $entity_id, $revision_id, $field_name, $data) { $table_name = "field_data_{$field_name}"; diff --git a/modules/field/modules/list/list.info b/modules/field/modules/list/list.info index bdfe6e4ae..515b31095 100644 --- a/modules/field/modules/list/list.info +++ b/modules/field/modules/list/list.info @@ -7,8 +7,8 @@ dependencies[] = field dependencies[] = options files[] = tests/list.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/field/modules/list/tests/list_test.info b/modules/field/modules/list/tests/list_test.info index cb046ed13..107e3f98a 100644 --- a/modules/field/modules/list/tests/list_test.info +++ b/modules/field/modules/list/tests/list_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/field/modules/number/number.info b/modules/field/modules/number/number.info index 8acefcd3e..478f2301c 100644 --- a/modules/field/modules/number/number.info +++ b/modules/field/modules/number/number.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = field files[] = number.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/field/modules/options/options.info b/modules/field/modules/options/options.info index 443dee1fa..abe3ac44c 100644 --- a/modules/field/modules/options/options.info +++ b/modules/field/modules/options/options.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = field files[] = options.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/field/modules/text/text.info b/modules/field/modules/text/text.info index e784f8f1b..811d6417c 100644 --- a/modules/field/modules/text/text.info +++ b/modules/field/modules/text/text.info @@ -7,8 +7,8 @@ dependencies[] = field files[] = text.test required = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/field/tests/field.test b/modules/field/tests/field.test index 739ddbe99..8004178eb 100644 --- a/modules/field/tests/field.test +++ b/modules/field/tests/field.test @@ -1119,8 +1119,11 @@ class FieldInfoTestCase extends FieldTestCase { 'test_setting' => 999))); field_create_instance($instance); + $info = entity_get_info('test_entity'); $instances = field_info_instances('test_entity', $instance['bundle']); - $this->assertEqual(count($instances), 1, t('One instance shows up in info when attached to a bundle.')); + $this->assertEqual(count($instances), 1, format_string('One instance shows up in info when attached to a bundle on a @label.', array( + '@label' => $info['label'] + ))); $this->assertTrue($instance < $instances[$instance['field_name']], t('Instance appears in info correctly')); // Test a valid entity type but an invalid bundle. diff --git a/modules/field/tests/field_test.entity.inc b/modules/field/tests/field_test.entity.inc index 52ed3fcd0..95af3eeba 100644 --- a/modules/field/tests/field_test.entity.inc +++ b/modules/field/tests/field_test.entity.inc @@ -23,7 +23,7 @@ function field_test_entity_info() { return array( 'test_entity' => array( - 'name' => t('Test Entity'), + 'label' => t('Test Entity'), 'fieldable' => TRUE, 'field cache' => FALSE, 'base table' => 'test_entity', @@ -38,7 +38,7 @@ function field_test_entity_info() { ), // This entity type doesn't get form handling for now... 'test_cacheable_entity' => array( - 'name' => t('Test Entity, cacheable'), + 'label' => t('Test Entity, cacheable'), 'fieldable' => TRUE, 'field cache' => TRUE, 'entity keys' => array( @@ -50,7 +50,7 @@ function field_test_entity_info() { 'view modes' => $test_entity_modes, ), 'test_entity_bundle_key' => array( - 'name' => t('Test Entity with a bundle key.'), + 'label' => t('Test Entity with a bundle key.'), 'base table' => 'test_entity_bundle_key', 'fieldable' => TRUE, 'field cache' => FALSE, @@ -63,7 +63,7 @@ function field_test_entity_info() { ), // In this case, the bundle key is not stored in the database. 'test_entity_bundle' => array( - 'name' => t('Test Entity with a specified bundle.'), + 'label' => t('Test Entity with a specified bundle.'), 'base table' => 'test_entity_bundle', 'fieldable' => TRUE, 'controller class' => 'TestEntityBundleController', @@ -77,7 +77,7 @@ function field_test_entity_info() { ), // @see EntityPropertiesTestCase::testEntityLabel() 'test_entity_no_label' => array( - 'name' => t('Test entity without label'), + 'label' => t('Test entity without label'), 'fieldable' => TRUE, 'field cache' => FALSE, 'base table' => 'test_entity', @@ -90,7 +90,7 @@ function field_test_entity_info() { 'view modes' => $test_entity_modes, ), 'test_entity_label' => array( - 'name' => t('Test entity label'), + 'label' => t('Test entity label'), 'fieldable' => TRUE, 'field cache' => FALSE, 'base table' => 'test_entity', @@ -104,7 +104,7 @@ function field_test_entity_info() { 'view modes' => $test_entity_modes, ), 'test_entity_label_callback' => array( - 'name' => t('Test entity label callback'), + 'label' => t('Test entity label callback'), 'fieldable' => TRUE, 'field cache' => FALSE, 'base table' => 'test_entity', diff --git a/modules/field/tests/field_test.info b/modules/field/tests/field_test.info index 4ad0c9922..2b7673928 100644 --- a/modules/field/tests/field_test.info +++ b/modules/field/tests/field_test.info @@ -6,8 +6,8 @@ files[] = field_test.entity.inc version = VERSION hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/field/theme/field.tpl.php b/modules/field/theme/field.tpl.php index a6d7a9659..f0f9d583f 100644 --- a/modules/field/theme/field.tpl.php +++ b/modules/field/theme/field.tpl.php @@ -40,6 +40,8 @@ * * @see template_preprocess_field() * @see theme_field() + * + * @ingroup themeable */ ?> <!-- diff --git a/modules/field_ui/field_ui.info b/modules/field_ui/field_ui.info index 37fe22273..b68a951b2 100644 --- a/modules/field_ui/field_ui.info +++ b/modules/field_ui/field_ui.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = field files[] = field_ui.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/file/file.api.php b/modules/file/file.api.php index 72aae40c9..df178c6f6 100644 --- a/modules/file/file.api.php +++ b/modules/file/file.api.php @@ -51,12 +51,6 @@ function hook_file_download_access($file_item, $entity_type, $entity) { * The type of $entity; for example, 'node' or 'user'. * @param $entity * The $entity to which $file is referenced. - * - * @return - * An array of grants, keyed by module name, each with a Boolean grant value. - * Return an empty array to assert FALSE. You may choose to return your own - * module's value in addition to other grants or to overwrite the values set - * by other modules. */ function hook_file_download_access_alter(&$grants, $file_item, $entity_type, $entity) { // For our example module, we always enforce the rules set by node module. diff --git a/modules/file/file.info b/modules/file/file.info index e6e73ca9a..16b58dd4b 100644 --- a/modules/file/file.info +++ b/modules/file/file.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = field files[] = tests/file.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/file/file.js b/modules/file/file.js index 577480bbc..0135a3b27 100644 --- a/modules/file/file.js +++ b/modules/file/file.js @@ -73,7 +73,14 @@ Drupal.file = Drupal.file || { var acceptableMatch = new RegExp('\\.(' + extensionPattern + ')$', 'gi'); if (!acceptableMatch.test(this.value)) { var error = Drupal.t("The selected file %filename cannot be uploaded. Only files with the following extensions are allowed: %extensions.", { - '%filename': this.value, + // According to the specifications of HTML5, a file upload control + // should not reveal the real local path to the file that a user + // has selected. Some web browsers implement this restriction by + // replacing the local path with "C:\fakepath\", which can cause + // confusion by leaving the user thinking perhaps Drupal could not + // find the file because it messed up the file path. To avoid this + // confusion, therefore, we strip out the bogus fakepath string. + '%filename': this.value.replace('C:\\fakepath\\', ''), '%extensions': extensionPattern.replace(/\|/g, ', ') }); $(this).closest('div.form-managed-file').prepend('<div class="messages error file-upload-js-error">' + error + '</div>'); diff --git a/modules/file/tests/file_module_test.info b/modules/file/tests/file_module_test.info index 393104e2d..a0725de9b 100644 --- a/modules/file/tests/file_module_test.info +++ b/modules/file/tests/file_module_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/filter/filter.info b/modules/filter/filter.info index bf1ad2ae7..8de2adfca 100644 --- a/modules/filter/filter.info +++ b/modules/filter/filter.info @@ -7,8 +7,8 @@ files[] = filter.test required = TRUE configure = admin/config/content/formats -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/forum/forum.info b/modules/forum/forum.info index 97cb5021b..5f46897db 100644 --- a/modules/forum/forum.info +++ b/modules/forum/forum.info @@ -9,8 +9,8 @@ files[] = forum.test configure = admin/structure/forum stylesheets[all][] = forum.css -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/forum/forum.module b/modules/forum/forum.module index 7e8d81bde..fe0ef7920 100644 --- a/modules/forum/forum.module +++ b/modules/forum/forum.module @@ -330,10 +330,12 @@ function forum_node_presave($node) { $langcode = key($node->taxonomy_forums); if (!empty($node->taxonomy_forums[$langcode])) { $node->forum_tid = $node->taxonomy_forums[$langcode][0]['tid']; - $old_tid = db_query_range("SELECT f.tid FROM {forum} f INNER JOIN {node} n ON f.vid = n.vid WHERE n.nid = :nid ORDER BY f.vid DESC", 0, 1, array(':nid' => $node->nid))->fetchField(); - if ($old_tid && isset($node->forum_tid) && ($node->forum_tid != $old_tid) && !empty($node->shadow)) { - // A shadow copy needs to be created. Retain new term and add old term. - $node->taxonomy_forums[$langcode][] = array('tid' => $old_tid); + if (isset($node->nid)) { + $old_tid = db_query_range("SELECT f.tid FROM {forum} f INNER JOIN {node} n ON f.vid = n.vid WHERE n.nid = :nid ORDER BY f.vid DESC", 0, 1, array(':nid' => $node->nid))->fetchField(); + if ($old_tid && isset($node->forum_tid) && ($node->forum_tid != $old_tid) && !empty($node->shadow)) { + // A shadow copy needs to be created. Retain new term and add old term. + $node->taxonomy_forums[$langcode][] = array('tid' => $old_tid); + } } } } @@ -1328,7 +1330,7 @@ function _forum_get_topic_order($sortby) { * The ID of the node to update. */ function _forum_update_forum_index($nid) { - $count = db_query('SELECT COUNT(cid) FROM {comment} WHERE nid = :nid AND status = :status', array( + $count = db_query('SELECT COUNT(cid) FROM {comment} c INNER JOIN {forum_index} i ON c.nid = i.nid WHERE c.nid = :nid AND c.status = :status', array( ':nid' => $nid, ':status' => COMMENT_PUBLISHED, ))->fetchField(); diff --git a/modules/forum/forum.test b/modules/forum/forum.test index d78d962de..6937c623d 100644 --- a/modules/forum/forum.test +++ b/modules/forum/forum.test @@ -197,6 +197,14 @@ class ForumTestCase extends DrupalWebTestCase { $this->drupalGet('forum/' . $this->forum['tid']); $this->drupalPost("node/$node->nid/edit", array(), t('Save')); $this->assertResponse(200); + + // Make sure constructing a forum node programmatically produces no notices. + $node = new stdClass; + $node->type = 'forum'; + $node->title = 'Test forum notices'; + $node->uid = 1; + $node->taxonomy_forums[LANGUAGE_NONE][0]['tid'] = $this->root_forum['tid']; + node_save($node); } /** diff --git a/modules/help/help.info b/modules/help/help.info index acf9cacb3..23645a23e 100644 --- a/modules/help/help.info +++ b/modules/help/help.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = help.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/image/image.field.inc b/modules/image/image.field.inc index 5e80d88a7..e2a0249ed 100644 --- a/modules/image/image.field.inc +++ b/modules/image/image.field.inc @@ -600,9 +600,12 @@ function theme_image_formatter($variables) { $item = $variables['item']; $image = array( 'path' => $item['uri'], - 'alt' => $item['alt'], ); + if (array_key_exists('alt', $item)) { + $image['alt'] = $item['alt']; + } + if (isset($item['attributes'])) { $image['attributes'] = $item['attributes']; } @@ -613,7 +616,7 @@ function theme_image_formatter($variables) { } // Do not output an empty 'title' attribute. - if (drupal_strlen($item['title']) > 0) { + if (isset($item['title']) && drupal_strlen($item['title']) > 0) { $image['title'] = $item['title']; } @@ -631,9 +634,11 @@ function theme_image_formatter($variables) { $output = theme('image', $image); } - if (!empty($variables['path']['path'])) { + // The link path and link options are both optional, but for the options to be + // processed, the link path must at least be an empty string. + if (isset($variables['path']['path'])) { $path = $variables['path']['path']; - $options = $variables['path']['options']; + $options = isset($variables['path']['options']) ? $variables['path']['options'] : array(); // When displaying an image inside a link, the html option must be TRUE. $options['html'] = TRUE; $output = l($output, $path, $options); diff --git a/modules/image/image.info b/modules/image/image.info index 577994329..df2551816 100644 --- a/modules/image/image.info +++ b/modules/image/image.info @@ -7,8 +7,8 @@ dependencies[] = file files[] = image.test configure = admin/config/media/image-styles -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/image/image.module b/modules/image/image.module index a9c4d027c..ff50452d5 100644 --- a/modules/image/image.module +++ b/modules/image/image.module @@ -34,7 +34,7 @@ define('IMAGE_STORAGE_MODULE', IMAGE_STORAGE_OVERRIDE | IMAGE_STORAGE_DEFAULT); require_once DRUPAL_ROOT . '/modules/image/image.field.inc'; /** - * Implement of hook_help(). + * Implements hook_help(). */ function image_help($path, $arg) { switch ($path) { @@ -1054,7 +1054,7 @@ function image_effect_definitions() { $effects = &drupal_static(__FUNCTION__); if (!isset($effects)) { - if ($cache = cache_get("image_effects:$langcode") && !empty($cache->data)) { + if ($cache = cache_get("image_effects:$langcode")) { $effects = $cache->data; } else { @@ -1262,7 +1262,7 @@ function theme_image_style($variables) { $variables['width'] = $dimensions['width']; $variables['height'] = $dimensions['height']; - // Determine the url for the styled image. + // Determine the URL for the styled image. $variables['path'] = image_style_url($variables['style_name'], $variables['path']); return theme('image', $variables); } diff --git a/modules/image/image.test b/modules/image/image.test index e4b6d373a..1ca846506 100644 --- a/modules/image/image.test +++ b/modules/image/image.test @@ -183,7 +183,7 @@ class ImageStylesPathAndUrlTestCase extends DrupalWebTestCase { // Create a working copy of the file. $files = $this->drupalGetTestFiles('image'); - $file = reset($files); + $file = array_shift($files); $image_info = image_get_info($file->uri); $original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME); // Let the image_module_test module know about this file, so it can claim @@ -212,18 +212,30 @@ class ImageStylesPathAndUrlTestCase extends DrupalWebTestCase { $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', t('Expires header was sent.')); $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'no-cache, must-revalidate, post-check=0, pre-check=0', t('Cache-Control header was set to prevent caching.')); $this->assertEqual($this->drupalGetHeader('X-Image-Owned-By'), 'image_module_test', t('Expected custom header has been added.')); - // Verify access is denied to private image styles. - $this->drupalLogout(); + + // Make sure that a second request to the already existing derivate works + // too. $this->drupalGet($generate_url); + $this->assertResponse(200, t('Image was generated at the URL.')); + + // Repeat this with a different file that we do not have access to and + // make sure that access is denied. + $file_noaccess = array_shift($files); + $original_uri_noaccess = file_unmanaged_copy($file_noaccess->uri, $scheme . '://', FILE_EXISTS_RENAME); + $generated_uri_noaccess = $scheme . '://styles/' . $this->style_name . '/' . $scheme . '/'. drupal_basename($original_uri_noaccess); + $this->assertFalse(file_exists($generated_uri_noaccess), t('Generated file does not exist.')); + $generate_url_noaccess = image_style_url($this->style_name, $original_uri_noaccess); + + $this->drupalGet($generate_url_noaccess); $this->assertResponse(403, t('Confirmed that access is denied for the private image style.') ); // Verify that images are not appended to the response. Currently this test only uses PNG images. if (strpos($generate_url, '.png') === FALSE ) { - $this->fail( t('Confirming that private image styles are not appended require PNG file.') ); + $this->fail('Confirming that private image styles are not appended require PNG file.'); } else { // Check for PNG-Signature (cf. http://www.libpng.org/pub/png/book/chapter08.html#png.ch08.div.2) in the // response body. - $this->assertNoRaw( chr(137) . chr(80) . chr(78) . chr(71) . chr(13) . chr(10) . chr(26) . chr(10), t('No PNG signature found in the response body.') ); + $this->assertNoRaw( chr(137) . chr(80) . chr(78) . chr(71) . chr(13) . chr(10) . chr(26) . chr(10), 'No PNG signature found in the response body.'); } } } @@ -243,7 +255,7 @@ class ImageEffectsUnitTest extends ImageToolkitTestCase { } function setUp() { - parent::setUp('image_test'); + parent::setUp('image_module_test'); module_load_include('inc', 'image', 'image.effects'); } @@ -330,6 +342,25 @@ class ImageEffectsUnitTest extends ImageToolkitTestCase { $this->assertEqual($calls['rotate'][0][1], 90, t('Degrees were passed correctly')); $this->assertEqual($calls['rotate'][0][2], 0xffffff, t('Background color was passed correctly')); } + + /** + * Test image effect caching. + */ + function testImageEffectsCaching() { + $image_effect_definitions_called = &drupal_static('image_module_test_image_effect_info_alter'); + + // First call should grab a fresh copy of the data. + $effects = image_effect_definitions(); + $this->assertTrue($image_effect_definitions_called === 1, 'image_effect_definitions() generated data.'); + + // Second call should come from cache. + drupal_static_reset('image_effect_definitions'); + drupal_static_reset('image_module_test_image_effect_info_alter'); + $cached_effects = image_effect_definitions(); + $this->assertTrue(is_null($image_effect_definitions_called), 'image_effect_definitions() returned data from cache.'); + + $this->assertTrue($effects == $cached_effects, 'Cached effects are the same as generated effects.'); + } } /** @@ -717,7 +748,7 @@ class ImageFieldDisplayTestCase extends ImageFieldTestCase { if ($scheme == 'private') { // Only verify HTTP headers when using private scheme and the headers are // sent by Drupal. - $this->assertEqual($this->drupalGetHeader('Content-Type'), 'image/png; name="' . $test_image->filename . '"', t('Content-Type header was sent.')); + $this->assertEqual($this->drupalGetHeader('Content-Type'), 'image/png', t('Content-Type header was sent.')); $this->assertEqual($this->drupalGetHeader('Content-Disposition'), 'inline; filename="' . $test_image->filename . '"', t('Content-Disposition header was sent.')); $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'private', t('Cache-Control header was sent.')); @@ -1566,3 +1597,64 @@ class ImageFieldDefaultImagesTestCase extends ImageFieldTestCase { } } + +/** + * Tests image theme functions. + */ +class ImageThemeFunctionWebTestCase extends DrupalWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'Image theme functions', + 'description' => 'Test that the image theme functions work correctly.', + 'group' => 'Image', + ); + } + + function setUp() { + parent::setUp(array('image')); + } + + /** + * Tests usage of the image field formatters. + */ + function testImageFormatterTheme() { + // Create an image. + $files = $this->drupalGetTestFiles('image'); + $file = reset($files); + $original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME); + + // Create a style. + image_style_save(array('name' => 'test')); + $url = image_style_url('test', $original_uri); + + // Test using theme_image_formatter() without an image title, alt text, or + // link options. + $path = $this->randomName(); + $element = array( + '#theme' => 'image_formatter', + '#image_style' => 'test', + '#item' => array( + 'uri' => $original_uri, + ), + '#path' => array( + 'path' => $path, + ), + ); + $rendered_element = render($element); + $expected_result = '<a href="' . url($path) . '"><img typeof="foaf:Image" src="' . $url . '" alt="" /></a>'; + $this->assertEqual($expected_result, $rendered_element, 'theme_image_formatter() correctly renders without title, alt, or path options.'); + + // Link the image to a fragment on the page, and not a full URL. + $fragment = $this->randomName(); + $element['#path']['path'] = ''; + $element['#path']['options'] = array( + 'external' => TRUE, + 'fragment' => $fragment, + ); + $rendered_element = render($element); + $expected_result = '<a href="#' . $fragment . '"><img typeof="foaf:Image" src="' . $url . '" alt="" /></a>'; + $this->assertEqual($expected_result, $rendered_element, 'theme_image_formatter() correctly renders a link fragment.'); + } + +} diff --git a/modules/image/tests/image_module_test.info b/modules/image/tests/image_module_test.info index 1c107f7d1..9e3832236 100644 --- a/modules/image/tests/image_module_test.info +++ b/modules/image/tests/image_module_test.info @@ -6,8 +6,8 @@ core = 7.x files[] = image_module_test.module hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/image/tests/image_module_test.module b/modules/image/tests/image_module_test.module index 766a9d957..8a322fb97 100644 --- a/modules/image/tests/image_module_test.module +++ b/modules/image/tests/image_module_test.module @@ -9,7 +9,6 @@ function image_module_test_file_download($uri) { if (variable_get('image_module_test_file_download', FALSE) == $uri) { return array('X-Image-Owned-By' => 'image_module_test'); } - return -1; } /** @@ -39,3 +38,13 @@ function image_module_test_image_effect_info() { function image_module_test_null_effect(array &$image, array $data) { return TRUE; } + +/** + * Implements hook_image_effect_info_alter(). + * + * Used to keep a count of cache misses in image_effect_definitions(). + */ +function image_module_test_image_effect_info_alter(&$effects) { + $image_effects_definition_called = &drupal_static(__FUNCTION__, 0); + $image_effects_definition_called++; +} diff --git a/modules/locale/locale.info b/modules/locale/locale.info index 34db19a62..0861a48eb 100644 --- a/modules/locale/locale.info +++ b/modules/locale/locale.info @@ -6,8 +6,8 @@ core = 7.x files[] = locale.test configure = admin/config/regional/language -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/locale/locale.install b/modules/locale/locale.install index 2d94c7170..b4db757f1 100644 --- a/modules/locale/locale.install +++ b/modules/locale/locale.install @@ -201,6 +201,19 @@ function locale_update_7004() { } } +/** + * Increase {locales_languages}.formula column's length. + */ +function locale_update_7005() { + db_change_field('languages', 'formula', 'formula', array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + 'description' => 'Plural formula in PHP code to evaluate to get plural indexes.', + )); +} + /** * @} End of "addtogroup updates-7.x-extra". */ @@ -303,7 +316,7 @@ function locale_schema() { ), 'formula' => array( 'type' => 'varchar', - 'length' => 128, + 'length' => 255, 'not null' => TRUE, 'default' => '', 'description' => 'Plural formula in PHP code to evaluate to get plural indexes.', diff --git a/modules/locale/locale.module b/modules/locale/locale.module index a20f3d5d7..94e7cd151 100644 --- a/modules/locale/locale.module +++ b/modules/locale/locale.module @@ -1033,7 +1033,7 @@ function locale_url_outbound_alter(&$path, &$options, $original_path) { include_once DRUPAL_ROOT . '/includes/language.inc'; foreach (language_types_configurable() as $type) { - // Get url rewriter callbacks only from enabled language providers. + // Get URL rewriter callbacks only from enabled language providers. $negotiation = variable_get("language_negotiation_$type", array()); foreach ($negotiation as $id => $provider) { diff --git a/modules/locale/locale.test b/modules/locale/locale.test index 6f3135b08..632506e13 100644 --- a/modules/locale/locale.test +++ b/modules/locale/locale.test @@ -1958,7 +1958,7 @@ class LocalePathFunctionalTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'Path language settings', - 'description' => 'Checks you can configure a language for individual url aliases.', + 'description' => 'Checks you can configure a language for individual URL aliases.', 'group' => 'Locale', ); } @@ -2268,7 +2268,7 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase { public static function getInfo() { return array( 'name' => 'UI language negotiation', - 'description' => 'Test UI language switching by url path prefix and domain.', + 'description' => 'Test UI language switching by URL path prefix and domain.', 'group' => 'Locale', ); } @@ -2396,7 +2396,7 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase { $this->assertResponse(404, "Unknown language path prefix should return 404"); // Setup for domain negotiation, first configure the language to have domain - // URL. We use https and a port to make sure that only the domain name is used. + // URL. We use HTTPS and a port to make sure that only the domain name is used. $edit = array('prefix' => '', 'domain' => "https://$language_domain:99"); $this->drupalPost("admin/config/regional/language/edit/$language", $edit, t('Save language')); // Set the site to use domain language negotiation. @@ -2513,7 +2513,7 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase { $languages = language_list(); foreach (array('it', 'fr') as $langcode) { - // Build the link we're going to test based on the clean url setting. + // Build the link we're going to test based on the clean URL setting. $link = (!empty($GLOBALS['conf']['clean_url'])) ? $langcode . '.example.com/admin' : $langcode . '.example.com/?q=admin'; // Test URL in another language. @@ -2524,14 +2524,14 @@ class LocaleUILanguageNegotiationTest extends DrupalWebTestCase { $correct_link = $url_scheme . $link; $this->assertTrue($url == $correct_link, t('The url() function returns the right url (@url) in accordance with the chosen language', array('@url' => $url . " == " . $correct_link))); - // Test https via options. + // Test HTTPS via options. variable_set('https', TRUE); $url = url('admin', array('https' => TRUE, 'language' => $languages[$langcode])); $correct_link = 'https://' . $link; $this->assertTrue($url == $correct_link, t('The url() function returns the right https url (via options) (@url) in accordance with the chosen language', array('@url' => $url . " == " . $correct_link))); variable_set('https', FALSE); - // Test https via current url scheme. + // Test HTTPS via current URL scheme. $temp_https = $is_https; $is_https = TRUE; $url = url('admin', array('language' => $languages[$langcode])); diff --git a/modules/locale/tests/locale_test.info b/modules/locale/tests/locale_test.info index 11a7f48fa..ffd5175fe 100644 --- a/modules/locale/tests/locale_test.info +++ b/modules/locale/tests/locale_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/menu/menu.admin.inc b/modules/menu/menu.admin.inc index 226c3b005..5ac755e58 100644 --- a/modules/menu/menu.admin.inc +++ b/modules/menu/menu.admin.inc @@ -99,7 +99,14 @@ function _menu_overview_tree_form($tree) { $mlid = 'mlid:' . $item['mlid']; $form[$mlid]['#item'] = $item; $form[$mlid]['#attributes'] = $item['hidden'] ? array('class' => array('menu-disabled')) : array('class' => array('menu-enabled')); - $form[$mlid]['title']['#markup'] = l($item['title'], $item['href'], $item['localized_options']) . ($item['hidden'] ? ' (' . t('disabled') . ')' : ''); + $form[$mlid]['title']['#markup'] = l($item['title'], $item['href'], $item['localized_options']); + if ($item['hidden']) { + $form[$mlid]['title']['#markup'] .= ' (' . t('disabled') . ')'; + } + elseif ($item['link_path'] == 'user' && $item['module'] == 'system') { + $form[$mlid]['title']['#markup'] .= ' (' . t('logged in users only') . ')'; + } + $form[$mlid]['hidden'] = array( '#type' => 'checkbox', '#title' => t('Enable @title menu link', array('@title' => $item['title'])), @@ -463,7 +470,6 @@ function menu_edit_menu($form, &$form_state, $type, $menu = array()) { '#machine_name' => array( 'exists' => 'menu_edit_menu_name_exists', 'source' => array('title'), - 'label' => t('URL path'), 'replace_pattern' => '[^a-z0-9-]+', 'replace' => '-', ), diff --git a/modules/menu/menu.info b/modules/menu/menu.info index f2fa31a37..18a57a735 100644 --- a/modules/menu/menu.info +++ b/modules/menu/menu.info @@ -6,8 +6,8 @@ core = 7.x files[] = menu.test configure = admin/structure/menu -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/node/node.api.php b/modules/node/node.api.php index 6d14a0737..052effc9b 100644 --- a/modules/node/node.api.php +++ b/modules/node/node.api.php @@ -498,9 +498,18 @@ function hook_node_revision_delete($node) { /** * Respond to creation of a new node. * - * This hook is invoked from node_save() after the node is inserted into the - * node table in the database, after the type-specific hook_insert() is invoked, - * and after field_attach_insert() is called. + * This hook is invoked from node_save() after the database query that will + * insert the node into the node table is scheduled for execution, after the + * type-specific hook_insert() is invoked, and after field_attach_insert() is + * called. + * + * Note that when this hook is invoked, the changes have not yet been written to + * the database, because a database transaction is still in progress. The + * transaction is not finalized until the save operation is entirely completed + * and node_save() goes out of scope. You should not rely on data in the + * database at this time as it is not updated yet. You should also note that any + * write/update database queries executed from this hook are also not committed + * immediately. Check node_save() and db_transaction() for more info. * * @param $node * The node that is being created. @@ -517,40 +526,43 @@ function hook_node_insert($node) { } /** - * Act on nodes being loaded from the database. + * Act on arbitrary nodes being loaded from the database. + * + * This hook should be used to add information that is not in the node or + * node revisions table, not to replace information that is in these tables + * (which could interfere with the entity cache). For performance reasons, + * information for all available nodes should be loaded in a single query where + * possible. * * This hook is invoked during node loading, which is handled by entity_load(), * via classes NodeController and DrupalDefaultEntityController. After the node * information is read from the database or the entity cache, hook_load() is - * invoked on the node's content type module, then field_attach_node_revision() + * invoked on the node's content type module, then field_attach_load_revision() * or field_attach_load() is called, then hook_entity_load() is invoked on all * implementing modules, and finally hook_node_load() is invoked on all * implementing modules. * - * This hook should only be used to add information that is not in the node or - * node revisions table, not to replace information that is in these tables - * (which could interfere with the entity cache). For performance reasons, - * information for all available nodes should be loaded in a single query where - * possible. - * - * The $types parameter allows for your module to have an early return (for - * efficiency) if your module only supports certain node types. However, if your - * module defines a content type, you can use hook_load() to respond to loading - * of just that content type. - * * @param $nodes * An array of the nodes being loaded, keyed by nid. * @param $types - * An array containing the types of the nodes. + * An array containing the node types present in $nodes. Allows for an early + * return for modules that only support certain node types. However, if your + * module defines a content type, you can use hook_load() to respond to + * loading of just that content type. * * For a detailed usage example, see nodeapi_example.module. * * @ingroup node_api_hooks */ function hook_node_load($nodes, $types) { - $result = db_query('SELECT nid, foo FROM {mytable} WHERE nid IN(:nids)', array(':nids' => array_keys($nodes))); - foreach ($result as $record) { - $nodes[$record->nid]->foo = $record->foo; + // Decide whether any of $types are relevant to our purposes. + if (count(array_intersect($types_we_want_to_process, $types))) { + // Gather our extra data for each of these nodes. + $result = db_query('SELECT nid, foo FROM {mytable} WHERE nid IN(:nids)', array(':nids' => array_keys($nodes))); + // Add our extra data to the node objects. + foreach ($result as $record) { + $nodes[$record->nid]->foo = $record->foo; + } } } @@ -684,9 +696,18 @@ function hook_node_presave($node) { /** * Respond to updates to a node. * - * This hook is invoked from node_save() after the node is updated in the node - * table in the database, after the type-specific hook_update() is invoked, and - * after field_attach_update() is called. + * This hook is invoked from node_save() after the database query that will + * update node in the node table is scheduled for execution, after the + * type-specific hook_update() is invoked, and after field_attach_update() is + * called. + * + * Note that when this hook is invoked, the changes have not yet been written to + * the database, because a database transaction is still in progress. The + * transaction is not finalized until the save operation is entirely completed + * and node_save() goes out of scope. You should not rely on data in the + * database at this time as it is not updated yet. You should also note that any + * write/update database queries executed from this hook are also not committed + * immediately. Check node_save() and db_transaction() for more info. * * @param $node * The node that is being updated. diff --git a/modules/node/node.info b/modules/node/node.info index d684c5685..d2fd883ae 100644 --- a/modules/node/node.info +++ b/modules/node/node.info @@ -9,8 +9,8 @@ required = TRUE configure = admin/structure/types stylesheets[all][] = node.css -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/node/node.install b/modules/node/node.install index 434410c8d..16d3dbaa0 100644 --- a/modules/node/node.install +++ b/modules/node/node.install @@ -474,7 +474,7 @@ function node_update_dependencies() { * * This function is valid for a database schema version 7000. * - * @ingroup update-api-6.x-to-7.x + * @ingroup update_api */ function _update_7000_node_get_types() { $node_types = db_query('SELECT * FROM {node_type}')->fetchAllAssoc('type', PDO::FETCH_OBJ); diff --git a/modules/node/node.module b/modules/node/node.module index 264816c00..d86c74d2d 100644 --- a/modules/node/node.module +++ b/modules/node/node.module @@ -243,7 +243,7 @@ function node_field_display_node_alter(&$display, $context) { } /** - * Entity uri callback. + * Entity URI callback. */ function node_uri($node) { return array( @@ -1345,6 +1345,14 @@ function node_build_content($node, $view_mode = 'full', $langcode = NULL) { // Remove previously built content, if exists. $node->content = array(); + // Allow modules to change the view mode. + $context = array( + 'entity_type' => 'node', + 'entity' => $node, + 'langcode' => $langcode, + ); + drupal_alter('entity_view_mode', $view_mode, $context); + // The 'view' hook can be implemented to overwrite the default function // to display nodes. if (node_hook($node, 'view')) { @@ -1385,6 +1393,10 @@ function node_build_content($node, $view_mode = 'full', $langcode = NULL) { // Allow modules to make their own additions to the node. module_invoke_all('node_view', $node, $view_mode, $langcode); module_invoke_all('entity_view', $node, 'node', $view_mode, $langcode); + + // Make sure the current view mode is stored if no module has already + // populated the related key. + $node->content += array('#view_mode' => $view_mode); } /** @@ -1984,6 +1996,9 @@ function node_menu() { 'page callback' => 'node_feed', 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, + // Pass a FALSE and array argument to ensure that additional path components + // are not passed to node_feed(). + 'page arguments' => array(FALSE, array()), ); // @todo Remove this loop when we have a 'description callback' property. // Reset internal static cache of _node_types_build(), forces to rebuild the @@ -2578,10 +2593,10 @@ function node_view_multiple($nodes, $view_mode = 'teaser', $weight = 0, $langcod function node_page_default() { $select = db_select('node', 'n') ->fields('n', array('nid', 'sticky', 'created')) - ->condition('promote', 1) - ->condition('status', 1) - ->orderBy('sticky', 'DESC') - ->orderBy('created', 'DESC') + ->condition('n.promote', 1) + ->condition('n.status', 1) + ->orderBy('n.sticky', 'DESC') + ->orderBy('n.created', 'DESC') ->extend('PagerDefault') ->limit(variable_get('default_nodes_main', 10)) ->addTag('node_access'); @@ -2764,7 +2779,7 @@ function node_search_validate($form, &$form_state) { // Insert extra restrictions into the search keywords string. if (isset($form_state['values']['type']) && is_array($form_state['values']['type'])) { - // Retrieve selected types - Forms API sets the value of unselected + // Retrieve selected types - Form API sets the value of unselected // checkboxes to 0. $form_state['values']['type'] = array_filter($form_state['values']['type']); if (count($form_state['values']['type'])) { @@ -3891,24 +3906,25 @@ function node_unpublish_by_keyword_action($node, $context) { */ function node_requirements($phase) { $requirements = array(); - // Ensure translations don't break at install time - $t = get_t(); - // Only show rebuild button if there are either 0, or 2 or more, rows - // in the {node_access} table, or if there are modules that - // implement hook_node_grants(). - $grant_count = db_query('SELECT COUNT(*) FROM {node_access}')->fetchField(); - if ($grant_count != 1 || count(module_implements('node_grants')) > 0) { - $value = format_plural($grant_count, 'One permission in use', '@count permissions in use', array('@count' => $grant_count)); - } else { - $value = $t('Disabled'); - } - $description = $t('If the site is experiencing problems with permissions to content, you may have to rebuild the permissions cache. Rebuilding will remove all privileges to content and replace them with permissions based on the current modules and settings. Rebuilding may take some time if there is a lot of content or complex permission settings. After rebuilding has completed, content will automatically use the new permissions.'); - - $requirements['node_access'] = array( - 'title' => $t('Node Access Permissions'), - 'value' => $value, - 'description' => $description . ' ' . l(t('Rebuild permissions'), 'admin/reports/status/rebuild'), - ); + if ($phase === 'runtime') { + // Only show rebuild button if there are either 0, or 2 or more, rows + // in the {node_access} table, or if there are modules that + // implement hook_node_grants(). + $grant_count = db_query('SELECT COUNT(*) FROM {node_access}')->fetchField(); + if ($grant_count != 1 || count(module_implements('node_grants')) > 0) { + $value = format_plural($grant_count, 'One permission in use', '@count permissions in use', array('@count' => $grant_count)); + } + else { + $value = t('Disabled'); + } + $description = t('If the site is experiencing problems with permissions to content, you may have to rebuild the permissions cache. Rebuilding will remove all privileges to content and replace them with permissions based on the current modules and settings. Rebuilding may take some time if there is a lot of content or complex permission settings. After rebuilding has completed, content will automatically use the new permissions.'); + + $requirements['node_access'] = array( + 'title' => t('Node Access Permissions'), + 'value' => $value, + 'description' => $description . ' ' . l(t('Rebuild permissions'), 'admin/reports/status/rebuild'), + ); + } return $requirements; } diff --git a/modules/node/node.test b/modules/node/node.test index 37d05e529..d789d3c0e 100644 --- a/modules/node/node.test +++ b/modules/node/node.test @@ -695,7 +695,7 @@ class NodeBlockTestCase extends DrupalWebTestCase { $this->drupalLogin($admin_user); } - function testSearchFormBlock() { + function testSyndicateBlock() { // Set block title to confirm that the interface is available. $this->drupalPost('admin/structure/block/manage/node/syndicate/configure', array('title' => $this->randomName(8)), t('Save block')); $this->assertText(t('The block configuration has been saved.'), t('Block configuration set.')); @@ -832,7 +832,11 @@ class NodeRSSContentTestCase extends DrupalWebTestCase { // viewing node. $this->drupalGet("node/$node->nid"); $this->assertNoText($rss_only_content, t('Node content designed for RSS doesn\'t appear when viewing node.')); - + + // Check that the node feed page does not try to interpret additional path + // components as arguments for node_feed() and returns default content. + $this->drupalGet('rss.xml/' . $this->randomName() . '/' . $this->randomName()); + $this->assertText($rss_only_content, t('Ignore page arguments when delivering rss.xml.')); } } @@ -2030,9 +2034,9 @@ class NodeQueryAlter extends DrupalWebTestCase { // Create user with simple node access permission. The 'node test view' // permission is implemented and granted by the node_access_test module. - $this->accessUser = $this->drupalCreateUser(array('access content', 'node test view')); - $this->noAccessUser = $this->drupalCreateUser(array('access content')); - $this->noAccessUser2 = $this->drupalCreateUser(array('access content')); + $this->accessUser = $this->drupalCreateUser(array('access content overview', 'access content', 'node test view')); + $this->noAccessUser = $this->drupalCreateUser(array('access content overview', 'access content')); + $this->noAccessUser2 = $this->drupalCreateUser(array('access content overview', 'access content')); } /** @@ -2045,11 +2049,19 @@ class NodeQueryAlter extends DrupalWebTestCase { $this->assertText('Yes, 4 nodes', "4 nodes were found for access user"); $this->assertNoText('Exception', "No database exception"); + // Test the content overview page. + $this->drupalGet('admin/content'); + $table_rows = $this->xpath('//tbody/tr'); + $this->assertEqual(4, count($table_rows), "4 nodes were found for access user"); + // Verify that a user with no access permission cannot see nodes. $this->drupalLogin($this->noAccessUser); $this->drupalGet('node_access_test_page'); $this->assertText('No nodes', "No nodes were found for no access user"); $this->assertNoText('Exception', "No database exception"); + + $this->drupalGet('admin/content'); + $this->assertText(t('No content available.')); } /** @@ -2474,24 +2486,24 @@ class NodeAccessPagerTestCase extends DrupalWebTestCase { // View the node page. With the default 50 comments per page there should // be two pages (0, 1) but no third (2) page. $this->drupalGet('node/' . $node->nid); - $this->assertText($node->title, t('Node title found.')); - $this->assertText(t('Comments'), t('Has a comments section.')); - $this->assertRaw('page=1', t('Secound page exists.')); - $this->assertNoRaw('page=2', t('No third page exists.')); + $this->assertText($node->title); + $this->assertText(t('Comments')); + $this->assertRaw('page=1'); + $this->assertNoRaw('page=2'); } /** * Tests the forum node pager for nodes with multiple grants per realm. */ public function testForumPager() { - // Lookup the forums vocabulary vid. + // Look up the forums vocabulary ID. $vid = variable_get('forum_nav_vocabulary', 0); - $this->assertTrue($vid, t('Forum navigation vocabulary found.')); + $this->assertTrue($vid, 'Forum navigation vocabulary ID is set.'); - // Lookup the general discussion term. + // Look up the general discussion term. $tree = taxonomy_get_tree($vid, 0, 1); $tid = reset($tree)->tid; - $this->assertTrue($tid, t('General discussion term found.')); + $this->assertTrue($tid, 'General discussion term is found in the forum vocabulary.'); // Create 30 nodes. for ($i = 0; $i < 30; $i++) { @@ -2510,8 +2522,8 @@ class NodeAccessPagerTestCase extends DrupalWebTestCase { // page there should be two pages for 30 nodes, no more. $this->drupalLogin($this->web_user); $this->drupalGet('forum/' . $tid); - $this->assertRaw('page=1', t('Secound page exists.')); - $this->assertNoRaw('page=2', t('No third page exists.')); + $this->assertRaw('page=1'); + $this->assertNoRaw('page=2'); } } @@ -2589,3 +2601,52 @@ class NodeAccessFieldTestCase extends NodeWebTestCase { $this->assertRaw($default, 'The updated default value is displayed when creating a new node.'); } } + +/** + * Tests changing view modes for nodes. + */ +class NodeEntityViewModeAlterTest extends NodeWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'Node entity view mode', + 'description' => 'Test changing view mode.', + 'group' => 'Node' + ); + } + + function setUp() { + parent::setUp(array('node_test')); + } + + /** + * Create a "Basic page" node and verify its consistency in the database. + */ + function testNodeViewModeChange() { + $web_user = $this->drupalCreateUser(array('create page content', 'edit own page content')); + $this->drupalLogin($web_user); + + // Create a node. + $edit = array(); + $langcode = LANGUAGE_NONE; + $edit["title"] = $this->randomName(8); + $edit["body[$langcode][0][value]"] = t('Data that should appear only in the body for the node.'); + $edit["body[$langcode][0][summary]"] = t('Extra data that should appear only in the teaser for the node.'); + $this->drupalPost('node/add/page', $edit, t('Save')); + + $node = $this->drupalGetNodeByTitle($edit["title"]); + + // Set the flag to alter the view mode and view the node. + variable_set('node_test_change_view_mode', 'teaser'); + $this->drupalGet('node/' . $node->nid); + + // Check that teaser mode is viewed. + $this->assertText('Extra data that should appear only in the teaser for the node.', 'Teaser text present'); + // Make sure body text is not present. + $this->assertNoText('Data that should appear only in the body for the node.', 'Body text not present'); + + // Test that the correct build mode has been set. + $build = node_view($node); + $this->assertEqual($build['#view_mode'], 'teaser', 'The view mode has correctly been set to teaser.'); + } +} diff --git a/modules/node/node.tpl.php b/modules/node/node.tpl.php index 6d0f489d7..4c358a16d 100644 --- a/modules/node/node.tpl.php +++ b/modules/node/node.tpl.php @@ -14,7 +14,7 @@ * - $date: Formatted creation date. Preprocess functions can reformat it by * calling format_date() with the desired parameters on the $created variable. * - $name: Themed username of node author output from theme_username(). - * - $node_url: Direct url of the current node. + * - $node_url: Direct URL of the current node. * - $display_submitted: Whether submission information should be displayed. * - $submitted: Submission information created from $name and $date during * template_preprocess_node(). @@ -22,7 +22,7 @@ * CSS. It can be manipulated through the variable $classes_array from * preprocess functions. The default values can be one or more of the * following: - * - node: The current template type, i.e., "theming hook". + * - node: The current template type; for example, "theming hook". * - node-[type]: The current node type. For example, if the node is a * "Blog entry" it would result in "node-blog". Note that the machine * name will often be in a short form of the human readable label. @@ -42,7 +42,7 @@ * * Other variables: * - $node: Full node object. Contains data that may not be safe. - * - $type: Node type, i.e. story, page, blog, etc. + * - $type: Node type; for example, story, page, blog, etc. * - $comment_count: Number of comments attached to the node. * - $uid: User ID of the node author. * - $created: Time the node was published formatted in Unix timestamp. @@ -53,7 +53,7 @@ * - $id: Position of the node. Increments each time it's output. * * Node status variables: - * - $view_mode: View mode, e.g. 'full', 'teaser'... + * - $view_mode: View mode; for example, "full", "teaser". * - $teaser: Flag for the teaser state (shortcut for $view_mode == 'teaser'). * - $page: Flag for the full page state. * - $promote: Flag for front page promotion state. @@ -67,15 +67,17 @@ * - $is_admin: Flags true when the current user is an administrator. * * Field variables: for each field instance attached to the node a corresponding - * variable is defined, e.g. $node->body becomes $body. When needing to access - * a field's raw values, developers/themers are strongly encouraged to use these - * variables. Otherwise they will have to explicitly specify the desired field - * language, e.g. $node->body['en'], thus overriding any language negotiation - * rule that was previously applied. + * variable is defined; for example, $node->body becomes $body. When needing to + * access a field's raw values, developers/themers are strongly encouraged to + * use these variables. Otherwise they will have to explicitly specify the + * desired field language; for example, $node->body['en'], thus overriding any + * language negotiation rule that was previously applied. * * @see template_preprocess() * @see template_preprocess_node() * @see template_process() + * + * @ingroup themeable */ ?> <div id="node-<?php print $node->nid; ?>" class="<?php print $classes; ?> clearfix"<?php print $attributes; ?>> diff --git a/modules/node/tests/node_access_test.info b/modules/node/tests/node_access_test.info index 372384811..7312d2fa9 100644 --- a/modules/node/tests/node_access_test.info +++ b/modules/node/tests/node_access_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/node/tests/node_test.info b/modules/node/tests/node_test.info index c5bb88f05..702d44a4e 100644 --- a/modules/node/tests/node_test.info +++ b/modules/node/tests/node_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/node/tests/node_test.module b/modules/node/tests/node_test.module index b0ebc149a..a52c1fad0 100644 --- a/modules/node/tests/node_test.module +++ b/modules/node/tests/node_test.module @@ -149,3 +149,13 @@ function node_test_node_update($node) { } } } + +/** + * Implements hook_entity_view_mode_alter(). + */ +function node_test_entity_view_mode_alter(&$view_mode, $context) { + // Only alter the view mode if we are on the test callback. + if ($change_view_mode = variable_get('node_test_change_view_mode', '')) { + $view_mode = $change_view_mode; + } +} diff --git a/modules/node/tests/node_test_exception.info b/modules/node/tests/node_test_exception.info index d9c8b6c42..795f53667 100644 --- a/modules/node/tests/node_test_exception.info +++ b/modules/node/tests/node_test_exception.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/openid/openid.inc b/modules/openid/openid.inc index 3c8281540..74a08d576 100644 --- a/modules/openid/openid.inc +++ b/modules/openid/openid.inc @@ -858,7 +858,7 @@ function _openid_invalid_openid_transition($identity, $response) { $fallback_account = user_external_load($fallback_identity); } - // Try to replace https with http. OpenID providers often redirect + // Try to replace HTTPS with HTTP. OpenID providers often redirect // from http to https, but Drupal didn't follow the redirect. if (!$fallback_account && strpos($fallback_identity, 'https://') !== FALSE) { $fallback_identity = str_replace('https://', 'http://', $fallback_identity); diff --git a/modules/openid/openid.info b/modules/openid/openid.info index 4f65facc4..5faa5f533 100644 --- a/modules/openid/openid.info +++ b/modules/openid/openid.info @@ -5,8 +5,8 @@ package = Core core = 7.x files[] = openid.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/openid/openid.module b/modules/openid/openid.module index 6cfdad95a..a3f4fc8e0 100644 --- a/modules/openid/openid.module +++ b/modules/openid/openid.module @@ -428,7 +428,7 @@ function openid_discovery($claimed_id) { } /** - * Implementation of hook_openid_discovery_method_info(). + * Implements hook_openid_discovery_method_info(). * * Define standard discovery methods. */ @@ -566,7 +566,7 @@ function _openid_xrds_discovery($claimed_id) { } /** - * Implementation of hook_openid_normalization_method_info(). + * Implements hook_openid_normalization_method_info(). * * Define standard normalization methods. */ @@ -1010,7 +1010,7 @@ function openid_verify_assertion_return_url($service, $response) { /** * Remove expired nonces from the database. * - * Implementation of hook_cron(). + * Implements hook_cron(). */ function openid_cron() { db_delete('openid_nonce') diff --git a/modules/openid/openid.pages.inc b/modules/openid/openid.pages.inc index 6e3f096e4..8a52f2040 100644 --- a/modules/openid/openid.pages.inc +++ b/modules/openid/openid.pages.inc @@ -56,6 +56,7 @@ function openid_user_identities($account) { '#theme' => 'table', '#header' => $header, '#rows' => $rows, + '#empty' => t('No OpenID identities available for this account.'), ); $build['openid_user_add'] = drupal_get_form('openid_user_add'); return $build; diff --git a/modules/openid/openid.test b/modules/openid/openid.test index 1f03c135d..292c5317c 100644 --- a/modules/openid/openid.test +++ b/modules/openid/openid.test @@ -19,7 +19,7 @@ abstract class OpenIDWebTestCase extends DrupalWebTestCase { $this->drupalPost('', $edit, t('Log in')); // Check we are on the OpenID redirect form. - $this->assertTitle(t('OpenID redirect'), t('OpenID redirect page was displayed.')); + $this->assertTitle(t('OpenID redirect'), 'OpenID redirect page was displayed.'); // Submit form to the OpenID Provider Endpoint. $this->drupalPost(NULL, array(), t('Send')); @@ -78,13 +78,13 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase { // the URL of the OpenID Provider Endpoint. // Identifier is the URL of an XRDS document. - // The URL scheme is stripped in order to test that the supplied identifier - // is normalized in openid_begin(). + // On HTTP test environments, the URL scheme is stripped in order to test + // that the supplied identifier is normalized in openid_begin(). $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE)); - $this->addIdentity(preg_replace('@^https?://@', '', $identity), 2, 'http://example.com/xrds', $identity); + $this->addIdentity(preg_replace('@^http://@', '', $identity), 2, 'http://example.com/xrds', $identity); $identity = url('openid-test/yadis/xrds/delegate', array('absolute' => TRUE)); - $this->addIdentity(preg_replace('@^https?://@', '', $identity), 2, 'http://example.com/xrds-delegate', $identity); + $this->addIdentity(preg_replace('@^http://@', '', $identity), 2, 'http://example.com/xrds-delegate', $identity); // Identifier is the URL of an XRDS document containing an OP Identifier // Element. The Relying Party sends the special value @@ -92,8 +92,8 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase { // Identifier. The OpenID Provider responds with the actual identifier // including the fragment. $identity = url('openid-test/yadis/xrds/dummy-user', array('absolute' => TRUE, 'fragment' => $this->randomName())); - // Tell openid_test.module to respond with this identifier. We test if - // openid_complete() processes it right. + // Tell openid_test.module to respond with this identifier. If the fragment + // part is present in the identifier, it should be retained. variable_set('openid_test_response', array('openid.claimed_id' => $identity)); $this->addIdentity(url('openid-test/yadis/xrds/server', array('absolute' => TRUE)), 2, 'http://specs.openid.net/auth/2.0/identifier_select', $identity); variable_set('openid_test_response', array()); @@ -162,7 +162,7 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase { // Test logging in via the login block on the front page. $this->submitLoginForm($identity); - $this->assertLink(t('Log out'), 0, t('User was logged in.')); + $this->assertLink(t('Log out'), 0, 'User was logged in.'); $this->drupalLogout(); @@ -171,12 +171,12 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase { $this->drupalPost('user/login', $edit, t('Log in')); // Check we are on the OpenID redirect form. - $this->assertTitle(t('OpenID redirect'), t('OpenID redirect page was displayed.')); + $this->assertTitle(t('OpenID redirect'), 'OpenID redirect page was displayed.'); // Submit form to the OpenID Provider Endpoint. $this->drupalPost(NULL, array(), t('Send')); - $this->assertLink(t('Log out'), 0, t('User was logged in.')); + $this->assertLink(t('Log out'), 0, 'User was logged in.'); // Verify user was redirected away from user/login to an accessible page. $this->assertResponse(200); @@ -211,12 +211,12 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase { $this->drupalPost('user/login', $edit, t('Log in')); // Check we are on the OpenID redirect form. - $this->assertTitle(t('OpenID redirect'), t('OpenID redirect page was displayed.')); + $this->assertTitle(t('OpenID redirect'), 'OpenID redirect page was displayed.'); // Submit form to the OpenID Provider Endpoint. $this->drupalPost(NULL, array(), t('Send')); - $this->assertLink(t('Log out'), 0, t('User was logged in.')); + $this->assertLink(t('Log out'), 0, 'User was logged in.'); // Verify user was redirected away from user/login to an accessible page. $this->assertText(t('Operating in maintenance mode.')); @@ -232,14 +232,14 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase { // Add identity to user's profile. $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE)); $this->addIdentity($identity); - $this->assertText($identity, t('Identity appears in list.')); + $this->assertText($identity, 'Identity appears in list.'); // Delete the newly added identity. $this->clickLink(t('Delete')); $this->drupalPost(NULL, array(), t('Confirm')); - $this->assertText(t('OpenID deleted.'), t('Identity deleted')); - $this->assertNoText($identity, t('Identity no longer appears in list.')); + $this->assertText(t('OpenID deleted.'), 'Identity deleted'); + $this->assertNoText($identity, 'Identity no longer appears in list.'); } /** @@ -263,11 +263,11 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase { 'accounts[' . $this->web_user->uid . ']' => TRUE, ); $this->drupalPost('admin/people', $edit, t('Update')); - $this->assertRaw('The update has been performed.', t('Account was blocked.')); + $this->assertRaw('The update has been performed.', 'Account was blocked.'); $this->drupalLogout(); $this->submitLoginForm($identity); - $this->assertRaw(t('The username %name has not been activated or is blocked.', array('%name' => $this->web_user->name)), t('User login was blocked.')); + $this->assertRaw(t('The username %name has not been activated or is blocked.', array('%name' => $this->web_user->name)), 'User login was blocked.'); } /** @@ -291,14 +291,14 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase { $this->drupalPost('user/' . $this->web_user->uid . '/openid', $edit, t('Add an OpenID')); if ($claimed_id === FALSE) { - $this->assertRaw(t('Sorry, that is not a valid OpenID. Ensure you have spelled your ID correctly.'), t('Invalid identity was rejected.')); + $this->assertRaw(t('Sorry, that is not a valid OpenID. Ensure you have spelled your ID correctly.'), 'Invalid identity was rejected.'); return; } // OpenID 1 used a HTTP redirect, OpenID 2 uses a HTML form that is submitted automatically using JavaScript. if ($version == 2) { // Check we are on the OpenID redirect form. - $this->assertTitle(t('OpenID redirect'), t('OpenID redirect page was displayed.')); + $this->assertTitle(t('OpenID redirect'), 'OpenID redirect page was displayed.'); // Submit form to the OpenID Provider Endpoint. $this->drupalPost(NULL, array(), t('Send')); @@ -307,7 +307,7 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase { if (!isset($claimed_id)) { $claimed_id = $identity; } - $this->assertRaw(t('Successfully added %identity', array('%identity' => $claimed_id)), t('Identity %identity was added.', array('%identity' => $identity))); + $this->assertRaw(t('Successfully added %identity', array('%identity' => $claimed_id)), format_string('Identity %identity was added.', array('%identity' => $identity))); } /** @@ -380,8 +380,8 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase { variable_set('openid_test_response', $response); $this->submitLoginForm($identity); $this->assertNoRaw('OpenID login failed.'); - $this->assertFieldByName('name', '', t('No username was supplied by provider.')); - $this->assertFieldByName('mail', '', t('No e-mail address was supplied by provider.')); + $this->assertFieldByName('name', '', 'No username was supplied by provider.'); + $this->assertFieldByName('mail', '', 'No e-mail address was supplied by provider.'); // Check that unsigned SREG fields are ignored. $response = array( @@ -392,8 +392,8 @@ class OpenIDFunctionalTestCase extends OpenIDWebTestCase { variable_set('openid_test_response', $response); $this->submitLoginForm($identity); $this->assertNoRaw('OpenID login failed.'); - $this->assertFieldByName('name', 'john', t('Username was supplied by provider.')); - $this->assertFieldByName('mail', '', t('E-mail address supplied by provider was ignored.')); + $this->assertFieldByName('name', 'john', 'Username was supplied by provider.'); + $this->assertFieldByName('mail', '', 'E-mail address supplied by provider was ignored.'); } } @@ -426,14 +426,14 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase { // Use a User-supplied Identity that is the URL of an XRDS document. $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE)); $this->submitLoginForm($identity); - $this->assertRaw(t('Once you have verified your e-mail address, you may log in via OpenID.'), t('User was asked to verify e-mail address.')); - $this->assertRaw(t('A welcome message with further instructions has been sent to your e-mail address.'), t('A welcome message was sent to the user.')); + $this->assertRaw(t('Once you have verified your e-mail address, you may log in via OpenID.'), 'User was asked to verify e-mail address.'); + $this->assertRaw(t('A welcome message with further instructions has been sent to your e-mail address.'), 'A welcome message was sent to the user.'); $reset_url = $this->getPasswordResetURLFromMail(); $user = user_load_by_name('john'); - $this->assertTrue($user, t('User was registered with right username.')); - $this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.')); - $this->assertFalse($user->data, t('No additional user info was saved.')); + $this->assertTrue($user, 'User was registered with right username.'); + $this->assertEqual($user->mail, 'john@example.com', 'User was registered with right email address.'); + $this->assertFalse($user->data, 'No additional user info was saved.'); $this->submitLoginForm($identity); $this->assertRaw(t('You must validate your email address for this account before logging in via OpenID.')); @@ -446,7 +446,7 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase { // Verify that the account was activated. $this->submitLoginForm($identity); - $this->assertLink(t('Log out'), 0, t('User was logged in.')); + $this->assertLink(t('Log out'), 0, 'User was logged in.'); } /** @@ -461,17 +461,17 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase { // Use a User-supplied Identity that is the URL of an XRDS document. $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE)); $this->submitLoginForm($identity); - $this->assertLink(t('Log out'), 0, t('User was logged in.')); + $this->assertLink(t('Log out'), 0, 'User was logged in.'); $user = user_load_by_name('john'); - $this->assertTrue($user, t('User was registered with right username.')); - $this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.')); - $this->assertFalse($user->data, t('No additional user info was saved.')); + $this->assertTrue($user, 'User was registered with right username.'); + $this->assertEqual($user->mail, 'john@example.com', 'User was registered with right email address.'); + $this->assertFalse($user->data, 'No additional user info was saved.'); $this->drupalLogout(); $this->submitLoginForm($identity); - $this->assertLink(t('Log out'), 0, t('User was logged in.')); + $this->assertLink(t('Log out'), 0, 'User was logged in.'); } /** @@ -487,29 +487,29 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase { $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE)); $this->submitLoginForm($identity); - $this->assertRaw(t('Account registration using the information provided by your OpenID provider failed due to the reasons listed below. Complete the registration by filling out the form below. If you already have an account, you can <a href="@login">log in</a> now and add your OpenID under "My account".', array('@login' => url('user/login'))), t('User was asked to complete the registration process manually.')); - $this->assertRaw(t('The name %name is already taken.', array('%name' => $web_user->name)), t('Form validation error for username was displayed.')); - $this->assertRaw(t('The e-mail address %mail is not valid.', array('%mail' => 'mail@invalid#')), t('Form validation error for e-mail address was displayed.')); + $this->assertRaw(t('Account registration using the information provided by your OpenID provider failed due to the reasons listed below. Complete the registration by filling out the form below. If you already have an account, you can <a href="@login">log in</a> now and add your OpenID under "My account".', array('@login' => url('user/login'))), 'User was asked to complete the registration process manually.'); + $this->assertRaw(t('The name %name is already taken.', array('%name' => $web_user->name)), 'Form validation error for username was displayed.'); + $this->assertRaw(t('The e-mail address %mail is not valid.', array('%mail' => 'mail@invalid#')), 'Form validation error for e-mail address was displayed.'); // Enter username and e-mail address manually. $edit = array('name' => 'john', 'mail' => 'john@example.com'); $this->drupalPost(NULL, $edit, t('Create new account')); - $this->assertRaw(t('Once you have verified your e-mail address, you may log in via OpenID.'), t('User was asked to verify e-mail address.')); + $this->assertRaw(t('Once you have verified your e-mail address, you may log in via OpenID.'), 'User was asked to verify e-mail address.'); $reset_url = $this->getPasswordResetURLFromMail(); $user = user_load_by_name('john'); - $this->assertTrue($user, t('User was registered with right username.')); - $this->assertFalse($user->data, t('No additional user info was saved.')); + $this->assertTrue($user, 'User was registered with right username.'); + $this->assertFalse($user->data, 'No additional user info was saved.'); // Follow the one-time login that was sent in the welcome e-mail. $this->drupalGet($reset_url); $this->drupalPost(NULL, array(), t('Log in')); // The user is taken to user/%uid/edit. - $this->assertFieldByName('mail', 'john@example.com', t('User was registered with right e-mail address.')); + $this->assertFieldByName('mail', 'john@example.com', 'User was registered with right e-mail address.'); $this->clickLink(t('OpenID identities')); - $this->assertRaw($identity, t('OpenID identity was registered.')); + $this->assertRaw($identity, 'OpenID identity was registered.'); } /** @@ -523,29 +523,29 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase { // Use a User-supplied Identity that is the URL of an XRDS document. $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE)); $this->submitLoginForm($identity); - $this->assertRaw(t('Complete the registration by filling out the form below. If you already have an account, you can <a href="@login">log in</a> now and add your OpenID under "My account".', array('@login' => url('user/login'))), t('User was asked to complete the registration process manually.')); - $this->assertNoRaw(t('You must enter a username.'), t('Form validation error for username was not displayed.')); - $this->assertNoRaw(t('You must enter an e-mail address.'), t('Form validation error for e-mail address was not displayed.')); + $this->assertRaw(t('Complete the registration by filling out the form below. If you already have an account, you can <a href="@login">log in</a> now and add your OpenID under "My account".', array('@login' => url('user/login'))), 'User was asked to complete the registration process manually.'); + $this->assertNoRaw(t('You must enter a username.'), 'Form validation error for username was not displayed.'); + $this->assertNoRaw(t('You must enter an e-mail address.'), 'Form validation error for e-mail address was not displayed.'); // Enter username and e-mail address manually. $edit = array('name' => 'john', 'mail' => 'john@example.com'); $this->drupalPost(NULL, $edit, t('Create new account')); - $this->assertRaw(t('Once you have verified your e-mail address, you may log in via OpenID.'), t('User was asked to verify e-mail address.')); + $this->assertRaw(t('Once you have verified your e-mail address, you may log in via OpenID.'), 'User was asked to verify e-mail address.'); $reset_url = $this->getPasswordResetURLFromMail(); $user = user_load_by_name('john'); - $this->assertTrue($user, t('User was registered with right username.')); - $this->assertFalse($user->data, t('No additional user info was saved.')); + $this->assertTrue($user, 'User was registered with right username.'); + $this->assertFalse($user->data, 'No additional user info was saved.'); // Follow the one-time login that was sent in the welcome e-mail. $this->drupalGet($reset_url); $this->drupalPost(NULL, array(), t('Log in')); // The user is taken to user/%uid/edit. - $this->assertFieldByName('mail', 'john@example.com', t('User was registered with right e-mail address.')); + $this->assertFieldByName('mail', 'john@example.com', 'User was registered with right e-mail address.'); $this->clickLink(t('OpenID identities')); - $this->assertRaw($identity, t('OpenID identity was registered.')); + $this->assertRaw($identity, 'OpenID identity was registered.'); } /** @@ -568,11 +568,11 @@ class OpenIDRegistrationTestCase extends OpenIDWebTestCase { // Use a User-supplied Identity that is the URL of an XRDS document. $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE)); $this->submitLoginForm($identity); - $this->assertLink(t('Log out'), 0, t('User was logged in.')); + $this->assertLink(t('Log out'), 0, 'User was logged in.'); $user = user_load_by_name('john'); - $this->assertTrue($user, t('User was registered with right username.')); - $this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.')); + $this->assertTrue($user, 'User was registered with right username.'); + $this->assertEqual($user->mail, 'john@example.com', 'User was registered with right email address.'); } } @@ -624,7 +624,7 @@ class OpenIDInvalidIdentifierTransitionTestCase extends OpenIDFunctionalTestCase $this->assertResponse(200); // Verify the message. - $this->assertRaw(t('There is already an existing account associated with the OpenID identifier that you have provided.'), t('Message that OpenID identifier must be updated manually was displayed.')); + $this->assertRaw(t('There is already an existing account associated with the OpenID identifier that you have provided.'), 'Message that OpenID identifier must be updated manually was displayed.'); } /** @@ -655,7 +655,7 @@ class OpenIDInvalidIdentifierTransitionTestCase extends OpenIDFunctionalTestCase $this->assertResponse(200); // Verify the message. - $this->assertRaw(t('New OpenID identifier %identity was added as a replacement for invalid identifier %invalid_identity.', array('%invalid_identity' => $identity_stripped, '%identity' => $identity)), t('Message that OpenID identifier was added automatically was displayed.')); + $this->assertRaw(t('New OpenID identifier %identity was added as a replacement for invalid identifier %invalid_identity.', array('%invalid_identity' => $identity_stripped, '%identity' => $identity)), 'Message that OpenID identifier was added automatically was displayed.'); } } @@ -680,25 +680,25 @@ class OpenIDTestCase extends DrupalWebTestCase { * Test _openid_dh_XXX_to_XXX() functions. */ function testConversion() { - $this->assertEqual(_openid_dh_long_to_base64('12345678901234567890123456789012345678901234567890'), 'CHJ/Y2mq+DyhUCZ0evjH8ZbOPwrS', t('_openid_dh_long_to_base64() returned expected result.')); - $this->assertEqual(_openid_dh_base64_to_long('BsH/g8Nrpn2dtBSdu/sr1y8hxwyx'), '09876543210987654321098765432109876543210987654321', t('_openid_dh_base64_to_long() returned expected result.')); + $this->assertEqual(_openid_dh_long_to_base64('12345678901234567890123456789012345678901234567890'), 'CHJ/Y2mq+DyhUCZ0evjH8ZbOPwrS', '_openid_dh_long_to_base64() returned expected result.'); + $this->assertEqual(_openid_dh_base64_to_long('BsH/g8Nrpn2dtBSdu/sr1y8hxwyx'), '09876543210987654321098765432109876543210987654321', '_openid_dh_base64_to_long() returned expected result.'); - $this->assertEqual(_openid_dh_long_to_binary('12345678901234567890123456789012345678901234567890'), "\x08r\x7fci\xaa\xf8<\xa1P&tz\xf8\xc7\xf1\x96\xce?\x0a\xd2", t('_openid_dh_long_to_binary() returned expected result.')); - $this->assertEqual(_openid_dh_binary_to_long("\x06\xc1\xff\x83\xc3k\xa6}\x9d\xb4\x14\x9d\xbb\xfb+\xd7/!\xc7\x0c\xb1"), '09876543210987654321098765432109876543210987654321', t('_openid_dh_binary_to_long() returned expected result.')); + $this->assertEqual(_openid_dh_long_to_binary('12345678901234567890123456789012345678901234567890'), "\x08r\x7fci\xaa\xf8<\xa1P&tz\xf8\xc7\xf1\x96\xce?\x0a\xd2", '_openid_dh_long_to_binary() returned expected result.'); + $this->assertEqual(_openid_dh_binary_to_long("\x06\xc1\xff\x83\xc3k\xa6}\x9d\xb4\x14\x9d\xbb\xfb+\xd7/!\xc7\x0c\xb1"), '09876543210987654321098765432109876543210987654321', '_openid_dh_binary_to_long() returned expected result.'); } /** * Test _openid_dh_xorsecret(). */ function testOpenidDhXorsecret() { - $this->assertEqual(_openid_dh_xorsecret('123456790123456790123456790', "abc123ABC\x00\xFF"), "\xa4'\x06\xbe\xf1.\x00y\xff\xc2\xc1", t('_openid_dh_xorsecret() returned expected result.')); + $this->assertEqual(_openid_dh_xorsecret('123456790123456790123456790', "abc123ABC\x00\xFF"), "\xa4'\x06\xbe\xf1.\x00y\xff\xc2\xc1", '_openid_dh_xorsecret() returned expected result.'); } /** * Test _openid_get_bytes(). */ function testOpenidGetBytes() { - $this->assertEqual(strlen(_openid_get_bytes(20)), 20, t('_openid_get_bytes() returned expected result.')); + $this->assertEqual(strlen(_openid_get_bytes(20)), 20, '_openid_get_bytes() returned expected result.'); } /** @@ -718,7 +718,7 @@ class OpenIDTestCase extends DrupalWebTestCase { ); $association = new stdClass(); $association->mac_key = "1234567890abcdefghij\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9"; - $this->assertEqual(_openid_signature($association, $response, array('foo', 'bar')), 'QnKZQzSFstT+GNiJDFOptdcZjrc=', t('Expected signature calculated.')); + $this->assertEqual(_openid_signature($association, $response, array('foo', 'bar')), 'QnKZQzSFstT+GNiJDFOptdcZjrc=', 'Expected signature calculated.'); } /** @@ -729,26 +729,26 @@ class OpenIDTestCase extends DrupalWebTestCase { // section 7.2. If the user-supplied string starts with xri:// it should be // stripped and the resulting string should be treated as an XRI when it // starts with "=", "@", "+", "$", "!" or "(". - $this->assertTrue(_openid_is_xri('xri://=foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme.')); - $this->assertTrue(_openid_is_xri('xri://@foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme.')); - $this->assertTrue(_openid_is_xri('xri://+foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme.')); - $this->assertTrue(_openid_is_xri('xri://$foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme.')); - $this->assertTrue(_openid_is_xri('xri://!foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme..')); - $this->assertTrue(_openid_is_xri('xri://(foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme..')); - - $this->assertTrue(_openid_is_xri('=foo'), t('_openid_is_xri() returned expected result for an xri identifier.')); - $this->assertTrue(_openid_is_xri('@foo'), t('_openid_is_xri() returned expected result for an xri identifier.')); - $this->assertTrue(_openid_is_xri('+foo'), t('_openid_is_xri() returned expected result for an xri identifier.')); - $this->assertTrue(_openid_is_xri('$foo'), t('_openid_is_xri() returned expected result for an xri identifier.')); - $this->assertTrue(_openid_is_xri('!foo'), t('_openid_is_xri() returned expected result for an xri identifier.')); - $this->assertTrue(_openid_is_xri('(foo'), t('_openid_is_xri() returned expected result for an xri identifier.')); - - $this->assertFalse(_openid_is_xri('foo'), t('_openid_is_xri() returned expected result for an http URL.')); - $this->assertFalse(_openid_is_xri('xri://foo'), t('_openid_is_xri() returned expected result for an http URL.')); - $this->assertFalse(_openid_is_xri('http://foo/'), t('_openid_is_xri() returned expected result for an http URL.')); - $this->assertFalse(_openid_is_xri('http://example.com/'), t('_openid_is_xri() returned expected result for an http URL.')); - $this->assertFalse(_openid_is_xri('user@example.com/'), t('_openid_is_xri() returned expected result for an http URL.')); - $this->assertFalse(_openid_is_xri('http://user@example.com/'), t('_openid_is_xri() returned expected result for an http URL.')); + $this->assertTrue(_openid_is_xri('xri://=foo'), '_openid_is_xri() returned expected result for an xri identifier with xri scheme.'); + $this->assertTrue(_openid_is_xri('xri://@foo'), '_openid_is_xri() returned expected result for an xri identifier with xri scheme.'); + $this->assertTrue(_openid_is_xri('xri://+foo'), '_openid_is_xri() returned expected result for an xri identifier with xri scheme.'); + $this->assertTrue(_openid_is_xri('xri://$foo'), '_openid_is_xri() returned expected result for an xri identifier with xri scheme.'); + $this->assertTrue(_openid_is_xri('xri://!foo'), '_openid_is_xri() returned expected result for an xri identifier with xri scheme..'); + $this->assertTrue(_openid_is_xri('xri://(foo'), '_openid_is_xri() returned expected result for an xri identifier with xri scheme..'); + + $this->assertTrue(_openid_is_xri('=foo'), '_openid_is_xri() returned expected result for an xri identifier.'); + $this->assertTrue(_openid_is_xri('@foo'), '_openid_is_xri() returned expected result for an xri identifier.'); + $this->assertTrue(_openid_is_xri('+foo'), '_openid_is_xri() returned expected result for an xri identifier.'); + $this->assertTrue(_openid_is_xri('$foo'), '_openid_is_xri() returned expected result for an xri identifier.'); + $this->assertTrue(_openid_is_xri('!foo'), '_openid_is_xri() returned expected result for an xri identifier.'); + $this->assertTrue(_openid_is_xri('(foo'), '_openid_is_xri() returned expected result for an xri identifier.'); + + $this->assertFalse(_openid_is_xri('foo'), '_openid_is_xri() returned expected result for an http URL.'); + $this->assertFalse(_openid_is_xri('xri://foo'), '_openid_is_xri() returned expected result for an http URL.'); + $this->assertFalse(_openid_is_xri('http://foo/'), '_openid_is_xri() returned expected result for an http URL.'); + $this->assertFalse(_openid_is_xri('http://example.com/'), '_openid_is_xri() returned expected result for an http URL.'); + $this->assertFalse(_openid_is_xri('user@example.com/'), '_openid_is_xri() returned expected result for an http URL.'); + $this->assertFalse(_openid_is_xri('http://user@example.com/'), '_openid_is_xri() returned expected result for an http URL.'); } /** @@ -758,16 +758,16 @@ class OpenIDTestCase extends DrupalWebTestCase { // Test that the normalization is according to OpenID Authentication 2.0, // section 7.2 and 11.5.2. - $this->assertEqual(openid_normalize('$foo'), '$foo', t('openid_normalize() correctly normalized an XRI.')); - $this->assertEqual(openid_normalize('xri://$foo'), '$foo', t('openid_normalize() correctly normalized an XRI with an xri:// scheme.')); + $this->assertEqual(openid_normalize('$foo'), '$foo', 'openid_normalize() correctly normalized an XRI.'); + $this->assertEqual(openid_normalize('xri://$foo'), '$foo', 'openid_normalize() correctly normalized an XRI with an xri:// scheme.'); - $this->assertEqual(openid_normalize('example.com/'), 'http://example.com/', t('openid_normalize() correctly normalized a URL with a missing scheme.')); - $this->assertEqual(openid_normalize('example.com'), 'http://example.com/', t('openid_normalize() correctly normalized a URL with a missing scheme and empty path.')); - $this->assertEqual(openid_normalize('http://example.com'), 'http://example.com/', t('openid_normalize() correctly normalized a URL with an empty path.')); + $this->assertEqual(openid_normalize('example.com/'), 'http://example.com/', 'openid_normalize() correctly normalized a URL with a missing scheme.'); + $this->assertEqual(openid_normalize('example.com'), 'http://example.com/', 'openid_normalize() correctly normalized a URL with a missing scheme and empty path.'); + $this->assertEqual(openid_normalize('http://example.com'), 'http://example.com/', 'openid_normalize() correctly normalized a URL with an empty path.'); - $this->assertEqual(openid_normalize('http://example.com/path'), 'http://example.com/path', t('openid_normalize() correctly normalized a URL with a path.')); + $this->assertEqual(openid_normalize('http://example.com/path'), 'http://example.com/path', 'openid_normalize() correctly normalized a URL with a path.'); - $this->assertEqual(openid_normalize('http://example.com/path#fragment'), 'http://example.com/path', t('openid_normalize() correctly normalized a URL with a fragment.')); + $this->assertEqual(openid_normalize('http://example.com/path#fragment'), 'http://example.com/path', 'openid_normalize() correctly normalized a URL with a fragment.'); } /** @@ -786,24 +786,24 @@ class OpenIDTestCase extends DrupalWebTestCase { ); $values = openid_extract_namespace($response, 'http://example.com/ns/dummy', NULL, FALSE); - $this->assertEqual($values, array(), t('Nothing found for unused namespace.')); + $this->assertEqual($values, array(), 'Nothing found for unused namespace.'); $values = openid_extract_namespace($response, 'http://example.com/ns/dummy', 'sreg', FALSE); - $this->assertEqual($values, array('nickname' => 'john'), t('Value found for fallback prefix.')); + $this->assertEqual($values, array('nickname' => 'john'), 'Value found for fallback prefix.'); $values = openid_extract_namespace($response, OPENID_NS_SREG, 'sreg', FALSE); - $this->assertEqual($values, array('nickname' => 'george', 'email' => 'george@example.com'), t('Namespace takes precedence over fallback prefix.')); + $this->assertEqual($values, array('nickname' => 'george', 'email' => 'george@example.com'), 'Namespace takes precedence over fallback prefix.'); // ext1.email is signed, but ext1.nickname is not. $values = openid_extract_namespace($response, OPENID_NS_SREG, 'sreg', TRUE); - $this->assertEqual($values, array('email' => 'george@example.com'), t('Unsigned namespaced fields ignored.')); + $this->assertEqual($values, array('email' => 'george@example.com'), 'Unsigned namespaced fields ignored.'); $values = openid_extract_namespace($response, 'http://example.com/ns/ext2', 'sreg', FALSE); - $this->assertEqual($values, array('foo' => '123', 'bar' => '456'), t('Unsigned fields found.')); + $this->assertEqual($values, array('foo' => '123', 'bar' => '456'), 'Unsigned fields found.'); // ext2.foo and ext2.bar are ignored, because ns.ext2 is not signed. The // fallback prefix is not used, because the namespace is specified. $values = openid_extract_namespace($response, 'http://example.com/ns/ext2', 'sreg', TRUE); - $this->assertEqual($values, array(), t('Unsigned fields ignored.')); + $this->assertEqual($values, array(), 'Unsigned fields ignored.'); } } diff --git a/modules/openid/tests/openid_test.info b/modules/openid/tests/openid_test.info index 5fd142eec..dccc075ce 100644 --- a/modules/openid/tests/openid_test.info +++ b/modules/openid/tests/openid_test.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = openid hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/overlay/overlay-child-rtl.css b/modules/overlay/overlay-child-rtl.css index 7fd39f440..2e5a267c4 100644 --- a/modules/overlay/overlay-child-rtl.css +++ b/modules/overlay/overlay-child-rtl.css @@ -1,4 +1,9 @@ +/** + * @file + * RTL styling for Overlay child pages. + */ + html { direction: rtl; } diff --git a/modules/overlay/overlay-child.css b/modules/overlay/overlay-child.css index a2b23b462..959ebddbd 100644 --- a/modules/overlay/overlay-child.css +++ b/modules/overlay/overlay-child.css @@ -1,4 +1,9 @@ +/** + * @file + * Basic styling for the Overlay child pages. + */ + html.js { background: transparent !important; overflow-y: scroll; diff --git a/modules/overlay/overlay-child.js b/modules/overlay/overlay-child.js index e78e3831c..4ff6cf0c8 100644 --- a/modules/overlay/overlay-child.js +++ b/modules/overlay/overlay-child.js @@ -1,3 +1,7 @@ +/** + * @file + * Attaches the behaviors for the Overlay child pages. + */ (function ($) { diff --git a/modules/overlay/overlay-parent.css b/modules/overlay/overlay-parent.css index dad6d5575..9459a7af3 100644 --- a/modules/overlay/overlay-parent.css +++ b/modules/overlay/overlay-parent.css @@ -1,4 +1,9 @@ +/** + * @file + * Basic styling for the Overlay module. + */ + html.overlay-open, html.overlay-open body { height: 100%; diff --git a/modules/overlay/overlay-parent.js b/modules/overlay/overlay-parent.js index ace7deff7..413475977 100644 --- a/modules/overlay/overlay-parent.js +++ b/modules/overlay/overlay-parent.js @@ -1,3 +1,8 @@ +/** + * @file + * Attaches the behaviors for the Overlay parent pages. + */ + (function ($) { /** @@ -339,7 +344,7 @@ Drupal.overlay.setFocusBefore = function ($element, document) { * Check if the given link is in the administrative section of the site. * * @param url - * The url to be tested. + * The URL to be tested. * * @return boolean * TRUE if the URL represents an administrative link, FALSE otherwise. @@ -374,7 +379,7 @@ Drupal.overlay.isAdminLink = function (url) { * Determine whether a link is external to the site. * * @param url - * The url to be tested. + * The URL to be tested. * * @return boolean * TRUE if the URL is external to the site, FALSE otherwise. @@ -560,7 +565,7 @@ Drupal.overlay.eventhandlerOverrideLink = function (event) { var target = $target[0]; var href = target.href; - // Only handle links that have an href attribute and use the http(s) protocol. + // Only handle links that have an href attribute and use the HTTP(S) protocol. if (href != undefined && href != '' && target.protocol.match(/^https?\:/)) { var anchor = href.replace(target.ownerDocument.location.href, ''); // Skip anchor links. @@ -607,7 +612,14 @@ Drupal.overlay.eventhandlerOverrideLink = function (event) { else { // Add the overlay-context state to the link, so "overlay-restore" links // can restore the context. - $target.attr('href', $.param.fragment(href, { 'overlay-context': this.getPath(window.location) + window.location.search })); + if ($target[0].hash) { + // Leave links with an existing fragment alone. Adding an extra + // parameter to a link like "node/1#section-1" breaks the link. + } + else { + // For links with no existing fragment, add the overlay context. + $target.attr('href', $.param.fragment(href, { 'overlay-context': this.getPath(window.location) + window.location.search })); + } // When the link has a destination query parameter and that destination // is an admin link we need to fragmentize it. This will make it reopen diff --git a/modules/overlay/overlay.info b/modules/overlay/overlay.info index 7f5669b18..f6dd0277e 100644 --- a/modules/overlay/overlay.info +++ b/modules/overlay/overlay.info @@ -4,8 +4,8 @@ package = Core version = VERSION core = 7.x -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/overlay/overlay.install b/modules/overlay/overlay.install index 2fa7c84bc..2df860b5e 100644 --- a/modules/overlay/overlay.install +++ b/modules/overlay/overlay.install @@ -2,14 +2,14 @@ /** * @file - * Install, update and uninstall functions for the overlay module. + * Install, update, and uninstall functions for the Overlay module. */ /** * Implements hook_enable(). * * If the module is being enabled through the admin UI, and not from an - * install profile, reopen the modules page in an overlay. + * installation profile, reopen the modules page in an overlay. */ function overlay_enable() { if (strpos(current_path(), 'admin/modules') === 0) { diff --git a/modules/overlay/overlay.module b/modules/overlay/overlay.module index 6acc2603d..c07cc6cfa 100644 --- a/modules/overlay/overlay.module +++ b/modules/overlay/overlay.module @@ -302,7 +302,10 @@ function overlay_page_alter(&$page) { } /** - * Menu callback; dismisses the overlay accessibility message for this user. + * Page callback: Dismisses the overlay accessibility message for this user. + * + * @return + * A render array for a page containing a list of content. */ function overlay_user_dismiss_message() { global $user; @@ -327,10 +330,12 @@ function overlay_user_dismiss_message() { * If the current user can access the overlay and has not previously indicated * that this message should be dismissed, this function returns a message * containing a link to disable the overlay. Nothing is returned for anonymous - * users, because the links control per-user settings. Therefore, because some - * screen readers are unable to properly read overlay contents, site builders - * are discouraged from granting the "access overlay" permission to the - * anonymous role. See http://drupal.org/node/890284. + * users, because the links control per-user settings. Because some screen + * readers are unable to properly read overlay contents, site builders are + * discouraged from granting the "access overlay" permission to the anonymous + * role. + * + * @see http://drupal.org/node/890284 */ function overlay_disable_message() { global $user; @@ -385,7 +390,13 @@ function overlay_disable_message() { /** * Returns the HTML for the message about how to disable the overlay. * - * @see overlay_disable_message() + * @param $variables + * An associative array with an 'element' element, which itself is an + * associative array containing: + * - profile_link: The link to this user's account. + * - dismiss_message_link: The link to dismiss the overlay. + * + * @ingroup themeable */ function theme_overlay_disable_message($variables) { $element = $variables['element']; @@ -473,8 +484,12 @@ function overlay_preprocess_maintenance_page(&$variables) { } /** - * Preprocesses template variables for overlay.tpl.php + * Implements template_preprocess_HOOK() for overlay.tpl.php * + * If the current page request is inside the overlay, add appropriate classes + * to the <body> element, and simplify the page title. + * + * @see template_process_overlay() * @see overlay.tpl.php */ function template_preprocess_overlay(&$variables) { @@ -485,20 +500,21 @@ function template_preprocess_overlay(&$variables) { } /** - * Processes variables for overlay.tpl.php + * Implements template_process_HOOK() for overlay.tpl.php + * + * Places the rendered HTML for the page body into a top level variable. * * @see template_preprocess_overlay() * @see overlay.tpl.php */ function template_process_overlay(&$variables) { - // Place the rendered HTML for the page body into a top level variable. $variables['page'] = $variables['page']['#children']; } /** * Implements hook_preprocess_page(). * - * Hide tabs inside the overlay. + * If the current page request is inside the overlay, hide the tabs. * * @see overlay_get_mode() */ @@ -509,7 +525,7 @@ function overlay_preprocess_page(&$variables) { } /** - * Callback to request that the overlay display an empty page. + * Stores and returns whether an empty page override is needed. * * This is used to prevent a page request which closes the overlay (for * example, a form submission) from being fully re-rendered before the overlay @@ -550,7 +566,7 @@ function overlay_page_delivery_callback_alter(&$callback) { } /** - * Delivery callback to display an empty page. + * Prints an empty page. * * This function is used to print out a bare minimum empty page which still has * the scripts and styles necessary in order to trigger the overlay to close. @@ -562,7 +578,7 @@ function overlay_deliver_empty_page() { } /** - * Get the current overlay mode. + * Gets the current overlay mode. * * @see overlay_set_mode() */ @@ -688,12 +704,13 @@ function overlay_overlay_child_initialize() { } /** - * Callback to request that the overlay close as soon as the page is displayed. + * Requests that the overlay overlay closes when the page is displayed. * * @param $redirect * (optional) The path that should open in the parent window after the * overlay closes. If not set, no redirect will be performed on the parent * window. + * * @param $redirect_options * (optional) An associative array of options to use when generating the * redirect URL. @@ -757,7 +774,7 @@ function overlay_supplemental_regions() { } /** - * Helper function for returning a list of page regions related to the overlay. + * Returns a list of page regions related to the overlay. * * @param $type * The type of regions to return. This can either be 'overlay_regions' or @@ -923,7 +940,7 @@ function overlay_store_rendered_content($id = NULL, $content = NULL) { } /** - * Request that the parent window refresh a particular page region. + * Requests that the parent window refreshes a particular page region. * * @param $region * The name of the page region to refresh. The parent window will trigger a @@ -938,7 +955,7 @@ function overlay_request_refresh($region) { } /** - * Request that the entire parent window be reloaded when the overlay closes. + * Requests that the entire parent window is reloaded when the overlay closes. * * @see overlay_trigger_refresh() */ @@ -947,7 +964,7 @@ function overlay_request_page_refresh() { } /** - * Check if the parent window needs to be refreshed on this page load. + * Checks if the parent window needs to be refreshed on this page load. * * If the previous page load requested that any page regions be refreshed, or * if it requested that the entire page be refreshed when the overlay closes, diff --git a/modules/overlay/overlay.tpl.php b/modules/overlay/overlay.tpl.php index 54b10af1f..df8633752 100644 --- a/modules/overlay/overlay.tpl.php +++ b/modules/overlay/overlay.tpl.php @@ -17,6 +17,8 @@ * @see template_preprocess() * @see template_preprocess_overlay() * @see template_process() + * + * @ingroup themeable */ ?> diff --git a/modules/path/path.info b/modules/path/path.info index 64c037442..8e79a1e72 100644 --- a/modules/path/path.info +++ b/modules/path/path.info @@ -6,8 +6,8 @@ core = 7.x files[] = path.test configure = admin/config/search/path -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/path/path.module b/modules/path/path.module index 1bb06f42b..81c7bb2c5 100644 --- a/modules/path/path.module +++ b/modules/path/path.module @@ -137,8 +137,6 @@ function path_form_node_form_alter(&$form, $form_state) { '#title' => t('URL alias'), '#default_value' => $path['alias'], '#maxlength' => 255, - '#collapsible' => TRUE, - '#collapsed' => TRUE, '#description' => t('Optionally specify an alternative URL by which this content can be accessed. For example, type "about" when writing an about page. Use a relative path and don\'t add a trailing slash or the URL alias won\'t work.'), ); $form['path']['pid'] = array('#type' => 'value', '#value' => $path['pid']); diff --git a/modules/php/php.info b/modules/php/php.info index ce6cde508..5409ab108 100644 --- a/modules/php/php.info +++ b/modules/php/php.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = php.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/poll/poll-results.tpl.php b/modules/poll/poll-results.tpl.php index 5e14dec21..678bc2b12 100644 --- a/modules/poll/poll-results.tpl.php +++ b/modules/poll/poll-results.tpl.php @@ -15,6 +15,8 @@ * - $vote: The choice number of the current user's vote. * * @see template_preprocess_poll_results() + * + * @ingroup themeable */ ?> <div class="poll"> diff --git a/modules/poll/poll-vote.tpl.php b/modules/poll/poll-vote.tpl.php index 068ff7c05..699a26d42 100644 --- a/modules/poll/poll-vote.tpl.php +++ b/modules/poll/poll-vote.tpl.php @@ -12,6 +12,8 @@ * form_alter hooks. * * @see template_preprocess_poll_vote() + * + * @ingroup themeable */ ?> <div class="poll"> diff --git a/modules/poll/poll.info b/modules/poll/poll.info index 908327fa9..2c1536ce7 100644 --- a/modules/poll/poll.info +++ b/modules/poll/poll.info @@ -6,8 +6,8 @@ core = 7.x files[] = poll.test stylesheets[all][] = poll.css -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/poll/poll.module b/modules/poll/poll.module index 6cea88648..70eb65dce 100644 --- a/modules/poll/poll.module +++ b/modules/poll/poll.module @@ -817,7 +817,7 @@ function poll_view_results($node, $view_mode, $block = FALSE) { // Make sure that choices are ordered by their weight. uasort($node->choice, 'drupal_sort_weight'); - // Count the votes and find the maximum + // Count the votes and find the maximum. $total_votes = 0; $max_votes = 0; foreach ($node->choice as $choice) { diff --git a/modules/poll/poll.test b/modules/poll/poll.test index 9982222c8..35eea2237 100644 --- a/modules/poll/poll.test +++ b/modules/poll/poll.test @@ -64,7 +64,7 @@ class PollTestCase extends DrupalWebTestCase { $this->drupalPost(NULL, $edit, t('Save')); $node = $this->drupalGetNodeByTitle($title); $this->assertText(t('@type @title has been created.', array('@type' => node_type_get_name('poll'), '@title' => $title)), 'Poll has been created.'); - $this->assertTrue($node->nid, t('Poll has been found in the database.')); + $this->assertTrue($node->nid, 'Poll has been found in the database.'); return isset($node->nid) ? $node->nid : FALSE; } @@ -137,7 +137,7 @@ class PollTestCase extends DrupalWebTestCase { // The expected weight of each choice is higher than the previous one. $weight++; // Directly assert the weight form element value for this choice. - $this->assertFieldByName('choice[chid:' . $id . '][weight]', $weight, t('Found choice @id with weight @weight.', array( + $this->assertFieldByName('choice[chid:' . $id . '][weight]', $weight, format_string('Found choice @id with weight @weight.', array( '@id' => $id, '@weight' => $weight, ))); @@ -167,7 +167,7 @@ class PollTestCase extends DrupalWebTestCase { $expected_order = $expected; foreach ($elements as $element) { $next_label = array_shift($expected_order); - $this->assertEqual((string) $element, $next_label, t('Found choice @label in preview.', array( + $this->assertEqual((string) $element, $next_label, format_string('Found choice @label in preview.', array( '@label' => $next_label, ))); } @@ -232,7 +232,7 @@ class PollCreateTestCase extends PollTestCase { $this->assertEqual(end($option), $new_option, 'Last item is equal to new option.'); $votes = $this->xpath('//div[@id="node-1"]//div[@class="poll"]//div[@class="percent"]'); - $this->assertTrue(strpos(end($votes), $vote_count) > 0, t("Votes saved.")); + $this->assertTrue(strpos(end($votes), $vote_count) > 0, "Votes saved."); } function testPollClose() { @@ -254,7 +254,7 @@ class PollCreateTestCase extends PollTestCase { // Verify 'Vote' button no longer appears. $this->drupalGet('node/' . $poll_nid); $elements = $this->xpath('//input[@id="edit-vote"]'); - $this->assertTrue(empty($elements), t("Vote button doesn't appear.")); + $this->assertTrue(empty($elements), "Vote button doesn't appear."); // Verify status on 'poll' page is 'closed'. $this->drupalGet('poll'); @@ -272,7 +272,7 @@ class PollCreateTestCase extends PollTestCase { $this->drupalPost('node/' . $poll_nid, $vote_edit, t('Vote')); $this->assertText('Your vote was recorded.', 'Your vote was recorded.'); $elements = $this->xpath('//input[@value="Cancel your vote"]'); - $this->assertTrue(isset($elements[0]), t("'Cancel your vote' button appears.")); + $this->assertTrue(isset($elements[0]), "'Cancel your vote' button appears."); // Edit the poll node and close the poll. $this->drupalLogout(); @@ -283,7 +283,7 @@ class PollCreateTestCase extends PollTestCase { // Verify 'Cancel your vote' button no longer appears. $this->drupalGet('node/' . $poll_nid); $elements = $this->xpath('//input[@value="Cancel your vote"]'); - $this->assertTrue(empty($elements), t("'Cancel your vote' button no longer appears.")); + $this->assertTrue(empty($elements), "'Cancel your vote' button no longer appears."); } } @@ -323,7 +323,7 @@ class PollVoteTestCase extends PollTestCase { $this->assertText('Your vote was recorded.', 'Your vote was recorded.'); $this->assertText('Total votes: 1', 'Vote count updated correctly.'); $elements = $this->xpath('//input[@value="Cancel your vote"]'); - $this->assertTrue(isset($elements[0]), t("'Cancel your vote' button appears.")); + $this->assertTrue(isset($elements[0]), "'Cancel your vote' button appears."); $this->drupalGet("node/$poll_nid/votes"); $this->assertText(t('This table lists all the recorded votes for this poll. If anonymous users are allowed to vote, they will be identified by the IP address of the computer they used when they voted.'), 'Vote table text.'); @@ -359,7 +359,7 @@ class PollVoteTestCase extends PollTestCase { $this->assertText('Your vote was recorded.', 'Your vote was recorded.'); $this->assertText('Total votes: 1', 'Vote count updated correctly.'); $elements = $this->xpath('//input[@value="Cancel your vote"]'); - $this->assertTrue(empty($elements), t("'Cancel your vote' button does not appear.")); + $this->assertTrue(empty($elements), "'Cancel your vote' button does not appear."); } } @@ -383,13 +383,13 @@ class PollBlockTestCase extends PollTestCase { function testRecentBlock() { // Set block title to confirm that the interface is available. $this->drupalPost('admin/structure/block/manage/poll/recent/configure', array('title' => $this->randomName(8)), 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[poll_recent][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.'); // Create a poll which should appear in recent polls block. $title = $this->randomName(); @@ -465,9 +465,9 @@ class PollJSAddChoice extends DrupalWebTestCase { $commands = $this->drupalPostAJAX(NULL, $edit, array('op' => t('More choices'))); $this->content = $commands[1]['data']; - $this->assertFieldByName('choice[chid:0][chtext]', $edit['choice[new:0][chtext]'], t('Field !i found', array('!i' => 0))); - $this->assertFieldByName('choice[chid:1][chtext]', $edit['choice[new:1][chtext]'], t('Field !i found', array('!i' => 1))); - $this->assertFieldByName('choice[new:0][chtext]', '', t('Field !i found', array('!i' => 2))); + $this->assertFieldByName('choice[chid:0][chtext]', $edit['choice[new:0][chtext]'], format_string('Field !i found', array('!i' => 0))); + $this->assertFieldByName('choice[chid:1][chtext]', $edit['choice[new:1][chtext]'], format_string('Field !i found', array('!i' => 1))); + $this->assertFieldByName('choice[new:0][chtext]', '', format_string('Field !i found', array('!i' => 2))); } } @@ -524,49 +524,49 @@ class PollVoteCheckHostname extends PollTestCase { // User1 vote on Poll. $this->drupalPost('node/' . $this->poll_nid, $edit, t('Vote')); - $this->assertText(t('Your vote was recorded.'), t('%user vote was recorded.', array('%user' => $this->web_user1->name))); - $this->assertText(t('Total votes: @votes', array('@votes' => 1)), t('Vote count updated correctly.')); + $this->assertText(t('Your vote was recorded.'), format_string('%user vote was recorded.', array('%user' => $this->web_user1->name))); + $this->assertText(t('Total votes: @votes', array('@votes' => 1)), 'Vote count updated correctly.'); // Check to make sure User1 cannot vote again. $this->drupalGet('node/' . $this->poll_nid); $elements = $this->xpath('//input[@value="Vote"]'); - $this->assertTrue(empty($elements), t("%user is not able to vote again.", array('%user' => $this->web_user1->name))); + $this->assertTrue(empty($elements), format_string("%user is not able to vote again.", array('%user' => $this->web_user1->name))); $elements = $this->xpath('//input[@value="Cancel your vote"]'); - $this->assertTrue(!empty($elements), t("'Cancel your vote' button appears.")); + $this->assertTrue(!empty($elements), "'Cancel your vote' button appears."); // Logout User1. $this->drupalLogout(); // Fill the page cache by requesting the poll. $this->drupalGet('node/' . $this->poll_nid); - $this->assertEqual($this->drupalGetHeader('x-drupal-cache'), 'MISS', t('Page was cacheable but was not in the cache.')); + $this->assertEqual($this->drupalGetHeader('x-drupal-cache'), 'MISS', 'Page was cacheable but was not in the cache.'); $this->drupalGet('node/' . $this->poll_nid); - $this->assertEqual($this->drupalGetHeader('x-drupal-cache'), 'HIT', t('Page was cached.')); + $this->assertEqual($this->drupalGetHeader('x-drupal-cache'), 'HIT', 'Page was cached.'); // Anonymous user vote on Poll. $this->drupalPost(NULL, $edit, t('Vote')); - $this->assertText(t('Your vote was recorded.'), t('Anonymous vote was recorded.')); - $this->assertText(t('Total votes: @votes', array('@votes' => 2)), t('Vote count updated correctly.')); + $this->assertText(t('Your vote was recorded.'), 'Anonymous vote was recorded.'); + $this->assertText(t('Total votes: @votes', array('@votes' => 2)), 'Vote count updated correctly.'); $elements = $this->xpath('//input[@value="Cancel your vote"]'); - $this->assertTrue(!empty($elements), t("'Cancel your vote' button appears.")); + $this->assertTrue(!empty($elements), "'Cancel your vote' button appears."); // Check to make sure Anonymous user cannot vote again. $this->drupalGet('node/' . $this->poll_nid); - $this->assertFalse($this->drupalGetHeader('x-drupal-cache'), t('Page was not cacheable.')); + $this->assertFalse($this->drupalGetHeader('x-drupal-cache'), 'Page was not cacheable.'); $elements = $this->xpath('//input[@value="Vote"]'); - $this->assertTrue(empty($elements), t("Anonymous is not able to vote again.")); + $this->assertTrue(empty($elements), "Anonymous is not able to vote again."); $elements = $this->xpath('//input[@value="Cancel your vote"]'); - $this->assertTrue(!empty($elements), t("'Cancel your vote' button appears.")); + $this->assertTrue(!empty($elements), "'Cancel your vote' button appears."); // Login User2. $this->drupalLogin($this->web_user2); // User2 vote on poll. $this->drupalPost('node/' . $this->poll_nid, $edit, t('Vote')); - $this->assertText(t('Your vote was recorded.'), t('%user vote was recorded.', array('%user' => $this->web_user2->name))); + $this->assertText(t('Your vote was recorded.'), format_string('%user vote was recorded.', array('%user' => $this->web_user2->name))); $this->assertText(t('Total votes: @votes', array('@votes' => 3)), 'Vote count updated correctly.'); $elements = $this->xpath('//input[@value="Cancel your vote"]'); - $this->assertTrue(empty($elements), t("'Cancel your vote' button does not appear.")); + $this->assertTrue(empty($elements), "'Cancel your vote' button does not appear."); // Logout User2. $this->drupalLogout(); @@ -582,22 +582,22 @@ class PollVoteCheckHostname extends PollTestCase { // Check to make sure Anonymous user can vote again with a new session after // a hostname change. $this->drupalGet('node/' . $this->poll_nid); - $this->assertEqual($this->drupalGetHeader('x-drupal-cache'), 'MISS', t('Page was cacheable but was not in the cache.')); + $this->assertEqual($this->drupalGetHeader('x-drupal-cache'), 'MISS', 'Page was cacheable but was not in the cache.'); $this->drupalPost(NULL, $edit, t('Vote')); - $this->assertText(t('Your vote was recorded.'), t('%user vote was recorded.', array('%user' => $this->web_user2->name))); + $this->assertText(t('Your vote was recorded.'), format_string('%user vote was recorded.', array('%user' => $this->web_user2->name))); $this->assertText(t('Total votes: @votes', array('@votes' => 4)), 'Vote count updated correctly.'); $elements = $this->xpath('//input[@value="Cancel your vote"]'); - $this->assertTrue(!empty($elements), t("'Cancel your vote' button appears.")); + $this->assertTrue(!empty($elements), "'Cancel your vote' button appears."); // Check to make sure Anonymous user cannot vote again with a new session, // and that the vote from the previous session cannot be cancelledd. $this->curlClose(); $this->drupalGet('node/' . $this->poll_nid); - $this->assertEqual($this->drupalGetHeader('x-drupal-cache'), 'MISS', t('Page was cacheable but was not in the cache.')); + $this->assertEqual($this->drupalGetHeader('x-drupal-cache'), 'MISS', 'Page was cacheable but was not in the cache.'); $elements = $this->xpath('//input[@value="Vote"]'); - $this->assertTrue(empty($elements), t('Anonymous is not able to vote again.')); + $this->assertTrue(empty($elements), 'Anonymous is not able to vote again.'); $elements = $this->xpath('//input[@value="Cancel your vote"]'); - $this->assertTrue(empty($elements), t("'Cancel your vote' button does not appear.")); + $this->assertTrue(empty($elements), "'Cancel your vote' button does not appear."); // Login User1. $this->drupalLogin($this->web_user1); @@ -605,9 +605,9 @@ class PollVoteCheckHostname extends PollTestCase { // Check to make sure User1 still cannot vote even after hostname changed. $this->drupalGet('node/' . $this->poll_nid); $elements = $this->xpath('//input[@value="Vote"]'); - $this->assertTrue(empty($elements), t("%user is not able to vote again.", array('%user' => $this->web_user1->name))); + $this->assertTrue(empty($elements), format_string("%user is not able to vote again.", array('%user' => $this->web_user1->name))); $elements = $this->xpath('//input[@value="Cancel your vote"]'); - $this->assertTrue(!empty($elements), t("'Cancel your vote' button appears.")); + $this->assertTrue(!empty($elements), "'Cancel your vote' button appears."); } } @@ -683,11 +683,11 @@ class PollTokenReplaceTestCase extends PollTestCase { $tests['[node:poll-duration]'] = format_interval($poll->runtime, 1, $language->language); // 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('node' => $poll), array('language' => $language)); - $this->assertEqual($output, $expected, t('Sanitized poll token %token replaced.', array('%token' => $input))); + $this->assertEqual($output, $expected, format_string('Sanitized poll token %token replaced.', array('%token' => $input))); } // Generate and test unsanitized tokens. @@ -695,7 +695,7 @@ class PollTokenReplaceTestCase extends PollTestCase { foreach ($tests as $input => $expected) { $output = token_replace($input, array('node' => $poll), array('language' => $language, 'sanitize' => FALSE)); - $this->assertEqual($output, $expected, t('Unsanitized poll token %token replaced.', array('%token' => $input))); + $this->assertEqual($output, $expected, format_string('Unsanitized poll token %token replaced.', array('%token' => $input))); } } } @@ -718,33 +718,33 @@ class PollExpirationTestCase extends PollTestCase { $title = $this->randomName(); $choices = $this->_generateChoices(2); $poll_nid = $this->pollCreate($title, $choices, FALSE); - $this->assertTrue($poll_nid, t('Poll for auto-expire test created.')); + $this->assertTrue($poll_nid, 'Poll for auto-expire test created.'); // Visit the poll edit page and verify that by default, expiration // is set to unlimited. $this->drupalGet("node/$poll_nid/edit"); - $this->assertField('runtime', t('Poll expiration setting found.')); + $this->assertField('runtime', 'Poll expiration setting found.'); $elements = $this->xpath('//select[@id="edit-runtime"]/option[@selected="selected"]'); - $this->assertTrue(isset($elements[0]['value']) && $elements[0]['value'] == 0, t('Poll expiration set to unlimited.')); + $this->assertTrue(isset($elements[0]['value']) && $elements[0]['value'] == 0, 'Poll expiration set to unlimited.'); // Set the expiration to one week. $edit = array(); $poll_expiration = 604800; // One week. $edit['runtime'] = $poll_expiration; $this->drupalPost(NULL, $edit, t('Save')); - $this->assertRaw(t('Poll %title has been updated.', array('%title' => $title)), t('Poll expiration settings saved.')); + $this->assertRaw(t('Poll %title has been updated.', array('%title' => $title)), 'Poll expiration settings saved.'); // Make sure that the changed expiration settings is kept. $this->drupalGet("node/$poll_nid/edit"); $elements = $this->xpath('//select[@id="edit-runtime"]/option[@selected="selected"]'); - $this->assertTrue(isset($elements[0]['value']) && $elements[0]['value'] == $poll_expiration, t('Poll expiration set to unlimited.')); + $this->assertTrue(isset($elements[0]['value']) && $elements[0]['value'] == $poll_expiration, 'Poll expiration set to unlimited.'); // Force a cron run. Since the expiration date has not yet been reached, // the poll should remain active. drupal_cron_run(); $this->drupalGet("node/$poll_nid/edit"); $elements = $this->xpath('//input[@id="edit-active-1"]'); - $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), t('Poll is still active.')); + $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), 'Poll is still active.'); // Test expiration. Since REQUEST_TIME is a constant and we don't // want to keep SimpleTest waiting until the moment of expiration arrives, @@ -759,7 +759,7 @@ class PollExpirationTestCase extends PollTestCase { drupal_cron_run(); $this->drupalGet("node/$poll_nid/edit"); $elements = $this->xpath('//input[@id="edit-active-0"]'); - $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), t('Poll has expired.')); + $this->assertTrue(isset($elements[0]) && !empty($elements[0]['checked']), 'Poll has expired.'); } } @@ -781,7 +781,7 @@ class PollDeleteChoiceTestCase extends PollTestCase { $title = $this->randomName(); $choices = array('First choice', 'Second choice', 'Third choice'); $poll_nid = $this->pollCreate($title, $choices, FALSE); - $this->assertTrue($poll_nid, t('Poll for choice deletion logic test created.')); + $this->assertTrue($poll_nid, 'Poll for choice deletion logic test created.'); // Edit the poll, and try to delete first poll choice. $this->drupalGet("node/$poll_nid/edit"); @@ -793,9 +793,9 @@ class PollDeleteChoiceTestCase extends PollTestCase { $this->clickLink($title); // Check the first poll choice is deleted, while the others remain. - $this->assertNoText('First choice', t('First choice removed.')); - $this->assertText('Second choice', t('Second choice remains.')); - $this->assertText('Third choice', t('Third choice remains.')); + $this->assertNoText('First choice', 'First choice removed.'); + $this->assertText('Second choice', 'Second choice remains.'); + $this->assertText('Third choice', 'Third choice remains.'); } } @@ -828,7 +828,7 @@ class PollTranslateTestCase extends PollTestCase { $title = $this->randomName(); $choices = array($this->randomName(), $this->randomName()); $poll_nid = $this->pollCreate($title, $choices, FALSE); - $this->assertTrue($poll_nid, t('Poll for translation logic test created.')); + $this->assertTrue($poll_nid, 'Poll for translation logic test created.'); $this->drupalLogout(); $this->drupalLogin($admin_user); @@ -838,14 +838,14 @@ class PollTranslateTestCase extends PollTestCase { $edit = array(); $edit['langcode'] = 'nl'; $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language')); - $this->assertRaw(t('The language %language has been created and can now be used.', array('%language' => 'Dutch')), t('Language Dutch has been created.')); + $this->assertRaw(t('The language %language has been created and can now be used.', array('%language' => 'Dutch')), 'Language Dutch has been created.'); // Set "Poll" content type to use multilingual support with translation. $this->drupalGet('admin/structure/types/manage/poll'); $edit = array(); $edit['language_content_type'] = 2; $this->drupalPost('admin/structure/types/manage/poll', $edit, t('Save content type')); - $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Poll')), t('Poll content type has been updated.')); + $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Poll')), 'Poll content type has been updated.'); // Edit poll. $this->drupalGet("node/$poll_nid/edit"); @@ -866,7 +866,7 @@ class PollTranslateTestCase extends PollTestCase { $this->assertFieldByName('choice[chid:1][chvotes]', '0', ('Found choice with vote count 0')); $this->assertFieldByName('choice[chid:2][chvotes]', '0', ('Found choice with vote count 0')); // Check that the choice names got copied from the Dutch poll. - $this->assertFieldByName('choice[chid:1][chtext]', $dutch_poll->choice[1]['chtext'], t('Found choice with text @text', array('@text' => $dutch_poll->choice[1]['chtext']))); - $this->assertFieldByName('choice[chid:2][chtext]', $dutch_poll->choice[2]['chtext'], t('Found choice with text @text', array('@text' => $dutch_poll->choice[2]['chtext']))); + $this->assertFieldByName('choice[chid:1][chtext]', $dutch_poll->choice[1]['chtext'], format_string('Found choice with text @text', array('@text' => $dutch_poll->choice[1]['chtext']))); + $this->assertFieldByName('choice[chid:2][chtext]', $dutch_poll->choice[2]['chtext'], format_string('Found choice with text @text', array('@text' => $dutch_poll->choice[2]['chtext']))); } } diff --git a/modules/profile/profile-wrapper.tpl.php b/modules/profile/profile-wrapper.tpl.php index 997ab9860..3940ba02e 100644 --- a/modules/profile/profile-wrapper.tpl.php +++ b/modules/profile/profile-wrapper.tpl.php @@ -6,7 +6,7 @@ * profiles. * * This template is used when viewing a list of users. It can be a general - * list for viewing all users with the url of "example.com/profile" or when + * list for viewing all users with the URL of "example.com/profile" or when * viewing a set of users who share a specific value for a profile such * as "example.com/profile/country/belgium". * diff --git a/modules/profile/profile.info b/modules/profile/profile.info index 552eac6ec..051ad84be 100644 --- a/modules/profile/profile.info +++ b/modules/profile/profile.info @@ -11,8 +11,8 @@ configure = admin/config/people/profile ; See user_system_info_alter(). hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/profile/profile.module b/modules/profile/profile.module index 6b00d4296..d76d08ac6 100644 --- a/modules/profile/profile.module +++ b/modules/profile/profile.module @@ -229,7 +229,7 @@ function profile_user_insert(&$edit, $account, $category) { /** * Implements hook_user_cancel(). */ -function profile_user_cancel(&$edit, $account, $method) { +function profile_user_cancel($edit, $account, $method) { switch ($method) { case 'user_cancel_reassign': db_delete('profile_value') diff --git a/modules/rdf/rdf.info b/modules/rdf/rdf.info index 81e2a176b..6b0e523dd 100644 --- a/modules/rdf/rdf.info +++ b/modules/rdf/rdf.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = rdf.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/rdf/rdf.test b/modules/rdf/rdf.test index 9f786ab5b..b8aeb90a1 100644 --- a/modules/rdf/rdf.test +++ b/modules/rdf/rdf.test @@ -159,7 +159,7 @@ class RdfRdfaMarkupTestCase extends DrupalWebTestCase { $image = current($this->drupalGetTestFiles('image')); // Create an array for drupalPost with the field names as the keys and - // the uris for the test files as the values. + // the URIs for the test files as the values. $edit = array("files[" . $field_name . "_" . $langcode . "_0]" => drupal_realpath($file->uri), "files[" . $image_field . "_" . $langcode . "_0]" => drupal_realpath($image->uri)); diff --git a/modules/rdf/tests/rdf_test.info b/modules/rdf/tests/rdf_test.info index dbe56097a..0dbbce8bf 100644 --- a/modules/rdf/tests/rdf_test.info +++ b/modules/rdf/tests/rdf_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/search/search-result.tpl.php b/modules/search/search-result.tpl.php index 949452ac3..47e89ef8e 100644 --- a/modules/search/search-result.tpl.php +++ b/modules/search/search-result.tpl.php @@ -60,6 +60,8 @@ * @see template_preprocess() * @see template_preprocess_search_result() * @see template_process() + * + * @ingroup themeable */ ?> <li class="<?php print $classes; ?>"<?php print $attributes; ?>> diff --git a/modules/search/search-results.tpl.php b/modules/search/search-results.tpl.php index e35be1edc..aa9bf8d4d 100644 --- a/modules/search/search-results.tpl.php +++ b/modules/search/search-results.tpl.php @@ -19,6 +19,8 @@ * * * @see template_preprocess_search_results() + * + * @ingroup themeable */ ?> <?php if ($search_results): ?> diff --git a/modules/search/search.info b/modules/search/search.info index e8cd028dc..25271b996 100644 --- a/modules/search/search.info +++ b/modules/search/search.info @@ -8,8 +8,8 @@ files[] = search.test configure = admin/config/search/settings stylesheets[all][] = search.css -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/search/search.pages.inc b/modules/search/search.pages.inc index 833ea8bcc..b74847303 100644 --- a/modules/search/search.pages.inc +++ b/modules/search/search.pages.inc @@ -156,5 +156,4 @@ function search_form_submit($form, &$form_state) { } $form_state['redirect'] = $form_state['action'] . '/' . $keys; - return; } diff --git a/modules/search/tests/search_embedded_form.info b/modules/search/tests/search_embedded_form.info index 489d941a8..2c48e471e 100644 --- a/modules/search/tests/search_embedded_form.info +++ b/modules/search/tests/search_embedded_form.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/search/tests/search_extra_type.info b/modules/search/tests/search_extra_type.info index 60b415680..208fb6d31 100644 --- a/modules/search/tests/search_extra_type.info +++ b/modules/search/tests/search_extra_type.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/shortcut/shortcut.admin.inc b/modules/shortcut/shortcut.admin.inc index 91ce7c837..c592a3185 100644 --- a/modules/shortcut/shortcut.admin.inc +++ b/modules/shortcut/shortcut.admin.inc @@ -471,7 +471,7 @@ function _shortcut_link_form_elements($shortcut_link = NULL) { ); } else { - $shortcut_link['link_path'] = drupal_get_path_alias($shortcut_link['link_path']); + $shortcut_link['link_path'] = ($shortcut_link['link_path'] == '<front>') ? '' : drupal_get_path_alias($shortcut_link['link_path']); } $form['shortcut_link']['#tree'] = TRUE; @@ -520,7 +520,11 @@ function shortcut_link_edit_validate($form, &$form_state) { */ function shortcut_link_edit_submit($form, &$form_state) { // Normalize the path in case it is an alias. - $form_state['values']['shortcut_link']['link_path'] = drupal_get_normal_path($form_state['values']['shortcut_link']['link_path']); + $shortcut_path = drupal_get_normal_path($form_state['values']['shortcut_link']['link_path']); + if (empty($shortcut_path)) { + $shortcut_path = '<front>'; + } + $form_state['values']['shortcut_link']['link_path'] = $shortcut_path; $shortcut_link = array_merge($form_state['values']['original_shortcut_link'], $form_state['values']['shortcut_link']); @@ -577,6 +581,9 @@ function shortcut_admin_add_link($shortcut_link, &$shortcut_set, $limit = NULL) // Normalize the path in case it is an alias. $shortcut_link['link_path'] = drupal_get_normal_path($shortcut_link['link_path']); + if (empty($shortcut_link['link_path'])) { + $shortcut_link['link_path'] = '<front>'; + } // Add the link to the end of the list. $shortcut_set->links[] = $shortcut_link; diff --git a/modules/shortcut/shortcut.admin.js b/modules/shortcut/shortcut.admin.js index 5554e5a7c..422cc4ce3 100644 --- a/modules/shortcut/shortcut.admin.js +++ b/modules/shortcut/shortcut.admin.js @@ -50,7 +50,7 @@ Drupal.behaviors.shortcutDrag = { // the tableDrag system. However, the row that swapped with it // has moved to the "disabled" section, so we need to force its // status to be disabled and mark it also as changed. - var changedRowObject = new tableDrag.row(changedRow, 'mouse', self.indentEnabled, self.maxDepth, true); + var changedRowObject = new tableDrag.row(changedRow, 'mouse', false, 0, true); changedRowObject.markChanged(); tableDrag.rowStatusChange(changedRowObject); } diff --git a/modules/shortcut/shortcut.info b/modules/shortcut/shortcut.info index 15526702d..cc741e188 100644 --- a/modules/shortcut/shortcut.info +++ b/modules/shortcut/shortcut.info @@ -6,8 +6,8 @@ core = 7.x files[] = shortcut.test configure = admin/config/user-interface/shortcut -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/shortcut/shortcut.module b/modules/shortcut/shortcut.module index 4c67a1416..2f6db0ad3 100644 --- a/modules/shortcut/shortcut.module +++ b/modules/shortcut/shortcut.module @@ -86,7 +86,7 @@ function shortcut_menu() { 'title' => 'Edit shortcuts', 'page callback' => 'drupal_get_form', 'page arguments' => array('shortcut_set_customize', 4), - 'title callback' => 'shortcut_set_title', + 'title callback' => 'shortcut_set_title_callback', 'title arguments' => array(4), 'access callback' => 'shortcut_set_edit_access', 'access arguments' => array(4), @@ -617,8 +617,8 @@ function shortcut_valid_link($path) { if ($path != $normal_path) { $path = $normal_path; } - // Only accept links that correspond to valid paths on the site itself. - return !url_is_external($path) && menu_get_item($path); + // An empty path is valid too and will be converted to <front>. + return (!url_is_external($path) && menu_get_item($path)) || empty($path) || $path == '<front>'; } /** @@ -735,9 +735,15 @@ function shortcut_toolbar_pre_render($toolbar) { } /** - * Returns the title of a shortcut set. + * Returns the sanitized title of a shortcut set. * - * Title callback for the editing pages for shortcut sets. + * Deprecated. This function was previously used as a menu item title callback + * but has been replaced by shortcut_set_title_callback() (which does not + * sanitize the title, since the menu system does that automatically). In + * Drupal 7, use that function for title callbacks, and call check_plain() + * directly if you need a sanitized title. In Drupal 8, this function will be + * restored as a title callback and therefore will no longer sanitize its + * output. * * @param $shortcut_set * An object representing the shortcut set, as returned by @@ -747,3 +753,15 @@ function shortcut_set_title($shortcut_set) { return check_plain($shortcut_set->title); } +/** + * Returns the title of a shortcut set. + * + * Title callback for the editing pages for shortcut sets. + * + * @param $shortcut_set + * An object representing the shortcut set, as returned by + * shortcut_set_load(). + */ +function shortcut_set_title_callback($shortcut_set) { + return $shortcut_set->title; +} diff --git a/modules/shortcut/shortcut.test b/modules/shortcut/shortcut.test index 322c63f11..801d58550 100644 --- a/modules/shortcut/shortcut.test +++ b/modules/shortcut/shortcut.test @@ -124,6 +124,7 @@ class ShortcutLinksTestCase extends ShortcutTestCase { // Create some paths to test. $test_cases = array( + array('path' => ''), array('path' => 'admin'), array('path' => 'admin/config/system/site-information'), array('path' => "node/{$this->node->nid}/edit"), @@ -141,7 +142,8 @@ class ShortcutLinksTestCase extends ShortcutTestCase { $this->assertResponse(200); $saved_set = shortcut_set_load($set->set_name); $paths = $this->getShortcutInformation($saved_set, 'link_path'); - $this->assertTrue(in_array(drupal_get_normal_path($test['path']), $paths), 'Shortcut created: '. $test['path']); + $test_path = empty($test['path']) ? '<front>' : $test['path']; + $this->assertTrue(in_array(drupal_get_normal_path($test_path), $paths), 'Shortcut created: '. $test['path']); $this->assertLink($title, 0, 'Shortcut link found on the page.'); } } diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php index d83dbeb6f..e3cab62a2 100644 --- a/modules/simpletest/drupal_web_test_case.php +++ b/modules/simpletest/drupal_web_test_case.php @@ -632,7 +632,7 @@ abstract class DrupalTestCase { * 'one' => array(0, 1), * 'two' => array(2, 3), * ); - * $permutations = $this->permute($parameters); + * $permutations = DrupalTestCase::generatePermutations($parameters) * // Result: * $permutations == array( * array('one' => 0, 'two' => 2), @@ -1685,13 +1685,20 @@ class DrupalWebTestCase extends DrupalTestCase { if (!isset($this->curlHandle)) { $this->curlHandle = curl_init(); + + // Some versions/configurations of cURL break on a NULL cookie jar, so + // supply a real file. + if (empty($this->cookieFile)) { + $this->cookieFile = $this->public_files_directory . '/cookie.jar'; + } + $curl_options = array( CURLOPT_COOKIEJAR => $this->cookieFile, CURLOPT_URL => $base_url, CURLOPT_FOLLOWLOCATION => FALSE, CURLOPT_RETURNTRANSFER => TRUE, - CURLOPT_SSL_VERIFYPEER => FALSE, // Required to make the tests run on https. - CURLOPT_SSL_VERIFYHOST => FALSE, // Required to make the tests run on https. + CURLOPT_SSL_VERIFYPEER => FALSE, // Required to make the tests run on HTTPS. + CURLOPT_SSL_VERIFYHOST => FALSE, // Required to make the tests run on HTTPS. CURLOPT_HEADERFUNCTION => array(&$this, 'curlHeaderCallback'), CURLOPT_USERAGENT => $this->databasePrefix, ); @@ -1699,7 +1706,12 @@ class DrupalWebTestCase extends DrupalTestCase { $curl_options[CURLOPT_HTTPAUTH] = $this->httpauth_method; $curl_options[CURLOPT_USERPWD] = $this->httpauth_credentials; } - curl_setopt_array($this->curlHandle, $this->additionalCurlOptions + $curl_options); + // curl_setopt_array() returns FALSE if any of the specified options + // cannot be set, and stops processing any further options. + $result = curl_setopt_array($this->curlHandle, $this->additionalCurlOptions + $curl_options); + if (!$result) { + throw new Exception('One or more cURL options could not be set.'); + } // By default, the child session name should be the same as the parent. $this->session_name = session_name(); @@ -2337,9 +2349,16 @@ class DrupalWebTestCase extends DrupalTestCase { if (isset($edit[$name])) { switch ($type) { case 'text': + case 'tel': case 'textarea': + case 'url': + case 'number': + case 'range': + case 'color': case 'hidden': case 'password': + case 'email': + case 'search': $post[$name] = $edit[$name]; unset($edit[$name]); break; @@ -2686,10 +2705,10 @@ class DrupalWebTestCase extends DrupalTestCase { } /** - * Get the current url from the cURL handler. + * Get the current URL from the cURL handler. * * @return - * The current url. + * The current URL. */ protected function getUrl() { return $this->url; diff --git a/modules/simpletest/simpletest.api.php b/modules/simpletest/simpletest.api.php index 04c080bfd..d262ad613 100644 --- a/modules/simpletest/simpletest.api.php +++ b/modules/simpletest/simpletest.api.php @@ -20,7 +20,7 @@ */ function hook_simpletest_alter(&$groups) { // An alternative session handler module would not want to run the original - // Session https handling test because it checks the sessions table in the + // Session HTTPS handling test because it checks the sessions table in the // database. unset($groups['Session']['testHttpsSession']); } diff --git a/modules/simpletest/simpletest.info b/modules/simpletest/simpletest.info index 587715c2c..b9a77fc6c 100644 --- a/modules/simpletest/simpletest.info +++ b/modules/simpletest/simpletest.info @@ -40,7 +40,6 @@ files[] = tests/update.test files[] = tests/xmlrpc.test files[] = tests/upgrade/upgrade.test files[] = tests/upgrade/upgrade.comment.test -files[] = tests/upgrade/update.field.test files[] = tests/upgrade/upgrade.filter.test files[] = tests/upgrade/upgrade.forum.test files[] = tests/upgrade/upgrade.locale.test @@ -49,13 +48,15 @@ files[] = tests/upgrade/upgrade.node.test files[] = tests/upgrade/upgrade.taxonomy.test files[] = tests/upgrade/upgrade.trigger.test files[] = tests/upgrade/upgrade.translatable.test -files[] = tests/upgrade/update.trigger.test files[] = tests/upgrade/upgrade.upload.test -files[] = tests/upgrade/update.user.test files[] = tests/upgrade/upgrade.user.test +files[] = tests/upgrade/update.aggregator.test +files[] = tests/upgrade/update.trigger.test +files[] = tests/upgrade/update.field.test +files[] = tests/upgrade/update.user.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/actions_loop_test.info b/modules/simpletest/tests/actions_loop_test.info index 4606cb207..6efd837dd 100644 --- a/modules/simpletest/tests/actions_loop_test.info +++ b/modules/simpletest/tests/actions_loop_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/ajax_forms_test.info b/modules/simpletest/tests/ajax_forms_test.info index 8614055f6..6b93949f8 100644 --- a/modules/simpletest/tests/ajax_forms_test.info +++ b/modules/simpletest/tests/ajax_forms_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/ajax_forms_test.module b/modules/simpletest/tests/ajax_forms_test.module index 6a95710a8..28404224e 100644 --- a/modules/simpletest/tests/ajax_forms_test.module +++ b/modules/simpletest/tests/ajax_forms_test.module @@ -7,7 +7,6 @@ /** * Implements hook_menu(). - * @return unknown_type */ function ajax_forms_test_menu() { $items = array(); @@ -94,9 +93,6 @@ function ajax_forms_test_simple_form_checkbox_callback($form, $form_state) { /** * Form to display the Ajax Commands. - * @param $form - * @param $form_state - * @return unknown_type */ function ajax_forms_test_ajax_commands_form($form, &$form_state) { $form = array(); diff --git a/modules/simpletest/tests/ajax_test.info b/modules/simpletest/tests/ajax_test.info index 275e608dd..ef9b93f84 100644 --- a/modules/simpletest/tests/ajax_test.info +++ b/modules/simpletest/tests/ajax_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/batch_test.info b/modules/simpletest/tests/batch_test.info index 7f9309775..6ded129f4 100644 --- a/modules/simpletest/tests/batch_test.info +++ b/modules/simpletest/tests/batch_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/common.test b/modules/simpletest/tests/common.test index 437b67cd1..e8e403330 100644 --- a/modules/simpletest/tests/common.test +++ b/modules/simpletest/tests/common.test @@ -1847,14 +1847,14 @@ class DrupalRenderTestCase extends DrupalWebTestCase { class ValidUrlTestCase extends DrupalUnitTestCase { public static function getInfo() { return array( - 'name' => 'Valid Url', - 'description' => "Performs tests on Drupal's valid url function.", + 'name' => 'Valid URL', + 'description' => "Performs tests on Drupal's valid URL function.", 'group' => 'System' ); } /** - * Test valid absolute urls. + * Test valid absolute URLs. */ function testValidAbsolute() { $url_schemes = array('http', 'https', 'ftp'); @@ -1889,7 +1889,7 @@ class ValidUrlTestCase extends DrupalUnitTestCase { } /** - * Test invalid absolute urls. + * Test invalid absolute URLs. */ function testInvalidAbsolute() { $url_schemes = array('http', 'https', 'ftp'); @@ -1909,7 +1909,7 @@ class ValidUrlTestCase extends DrupalUnitTestCase { } /** - * Test valid relative urls. + * Test valid relative URLs. */ function testValidRelative() { $valid_relative_urls = array( @@ -1930,7 +1930,7 @@ class ValidUrlTestCase extends DrupalUnitTestCase { } /** - * Test invalid relative urls. + * Test invalid relative URLs. */ function testInvalidRelative() { $invalid_relative_urls = array( @@ -2540,12 +2540,12 @@ class DrupalAddFeedTestCase extends DrupalWebTestCase { 'output_url' => url($path, array('absolute' => TRUE)), 'title' => '', ), - 'external url without title' => array( + 'external URL without title' => array( 'input_url' => $external_url, 'output_url' => $external_url, 'title' => '', ), - 'local url without title' => array( + 'local URL without title' => array( 'input_url' => $fully_qualified_local_url, 'output_url' => $fully_qualified_local_url, 'title' => '', @@ -2555,12 +2555,12 @@ class DrupalAddFeedTestCase extends DrupalWebTestCase { 'output_url' => url($path_for_title, array('absolute' => TRUE)), 'title' => $this->randomName(12), ), - 'external url with title' => array( + 'external URL with title' => array( 'input_url' => $external_for_title, 'output_url' => $external_for_title, 'title' => $this->randomName(12), ), - 'local url with title' => array( + 'local URL with title' => array( 'input_url' => $fully_qualified_for_title, 'output_url' => $fully_qualified_for_title, 'title' => $this->randomName(12), @@ -2581,9 +2581,36 @@ class DrupalAddFeedTestCase extends DrupalWebTestCase { * Create a pattern representing the RSS feed in the page. */ function urlToRSSLinkPattern($url, $title = '') { - // Escape any regular expression characters in the url ('?' is the worst). + // Escape any regular expression characters in the URL ('?' is the worst). $url = preg_replace('/([+?.*])/', '[$0]', $url); $generated_pattern = '%<link +rel="alternate" +type="application/rss.xml" +title="' . $title . '" +href="' . $url . '" */>%'; return $generated_pattern; } } + +/** + * Test for theme_feed_icon(). + */ +class FeedIconTest extends DrupalWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'Feed icon', + 'description' => 'Check escaping of theme_feed_icon()', + 'group' => 'System', + ); + } + + /** + * Check that special characters are correctly escaped. Test for issue #1211668. + */ + function testFeedIconEscaping() { + $variables = array(); + $variables['url'] = 'node'; + $variables['title'] = '<>&"\''; + $text = theme_feed_icon($variables); + preg_match('/title="(.*?)"/', $text, $matches); + $this->assertEqual($matches[1], 'Subscribe to &"'', 'theme_feed_icon() escapes reserved HTML characters.'); + } + +} diff --git a/modules/simpletest/tests/common_test.info b/modules/simpletest/tests/common_test.info index f3d6f50d9..b999bb068 100644 --- a/modules/simpletest/tests/common_test.info +++ b/modules/simpletest/tests/common_test.info @@ -7,8 +7,8 @@ stylesheets[all][] = common_test.css stylesheets[print][] = common_test.print.css hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/common_test_cron_helper.info b/modules/simpletest/tests/common_test_cron_helper.info index 408aae051..0ccf87db3 100644 --- a/modules/simpletest/tests/common_test_cron_helper.info +++ b/modules/simpletest/tests/common_test_cron_helper.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/database_test.info b/modules/simpletest/tests/database_test.info index 2b7a7880e..1e2a3ea01 100644 --- a/modules/simpletest/tests/database_test.info +++ b/modules/simpletest/tests/database_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/database_test.test b/modules/simpletest/tests/database_test.test index 660833606..6e1d15979 100644 --- a/modules/simpletest/tests/database_test.test +++ b/modules/simpletest/tests/database_test.test @@ -2803,14 +2803,17 @@ class DatabaseLoggingTestCase extends DatabaseTestCase { * Test that we can log the existence of a query. */ function testEnableLogging() { - Database::startLog('testing'); + $log = Database::startLog('testing'); db_query('SELECT name FROM {test} WHERE age > :age', array(':age' => 25))->fetchCol(); db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Ringo'))->fetchCol(); + // Trigger a call that does not have file in the backtrace. + call_user_func_array('db_query', array('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Ringo')))->fetchCol(); + $queries = Database::getLog('testing', 'default'); - $this->assertEqual(count($queries), 2, t('Correct number of queries recorded.')); + $this->assertEqual(count($queries), 3, t('Correct number of queries recorded.')); foreach ($queries as $query) { $this->assertEqual($query['caller']['function'], __FUNCTION__, t('Correct function in query log.')); @@ -3746,9 +3749,9 @@ class DatabaseTransactionTestCase extends DatabaseTestCase { class DatabaseNextIdCase extends DrupalWebTestCase { public static function getInfo() { return array( - 'name' => t('Sequences API'), - 'description' => t('Test the secondary sequences API.'), - 'group' => t('Database'), + 'name' => 'Sequences API', + 'description' => 'Test the secondary sequences API.', + 'group' => 'Database', ); } @@ -3773,9 +3776,9 @@ class DatabaseNextIdCase extends DrupalWebTestCase { class DatabaseEmptyStatementTestCase extends DrupalWebTestCase { public static function getInfo() { return array( - 'name' => t('Empty statement'), - 'description' => t('Test the empty pseudo-statement class.'), - 'group' => t('Database'), + 'name' => 'Empty statement', + 'description' => 'Test the empty pseudo-statement class.', + 'group' => 'Database', ); } diff --git a/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info b/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info index 0e5344c65..07a44a143 100644 --- a/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info +++ b/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info b/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info index f7b50a359..1ad4e306b 100644 --- a/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info +++ b/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/entity_cache_test.info b/modules/simpletest/tests/entity_cache_test.info index 6842cb1a7..c2f02075a 100644 --- a/modules/simpletest/tests/entity_cache_test.info +++ b/modules/simpletest/tests/entity_cache_test.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = entity_cache_test_dependency hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/entity_cache_test_dependency.info b/modules/simpletest/tests/entity_cache_test_dependency.info index 21b7233cb..71018af31 100644 --- a/modules/simpletest/tests/entity_cache_test_dependency.info +++ b/modules/simpletest/tests/entity_cache_test_dependency.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/entity_crud_hook_test.info b/modules/simpletest/tests/entity_crud_hook_test.info index e79a8f03d..9540f9ac6 100644 --- a/modules/simpletest/tests/entity_crud_hook_test.info +++ b/modules/simpletest/tests/entity_crud_hook_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/entity_crud_hook_test.module b/modules/simpletest/tests/entity_crud_hook_test.module index 873a162ce..d25dff1b3 100644 --- a/modules/simpletest/tests/entity_crud_hook_test.module +++ b/modules/simpletest/tests/entity_crud_hook_test.module @@ -1,8 +1,9 @@ <?php -// -// Presave hooks -// +/** + * @file + * Test module for the Entity CRUD API. + */ /** * Implements hook_entity_presave(). @@ -53,10 +54,6 @@ function entity_crud_hook_test_user_presave() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } -// -// Insert hooks -// - /** * Implements hook_entity_insert(). */ @@ -106,10 +103,6 @@ function entity_crud_hook_test_user_insert() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } -// -// Load hooks -// - /** * Implements hook_entity_load(). */ @@ -159,10 +152,6 @@ function entity_crud_hook_test_user_load() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } -// -// Update hooks -// - /** * Implements hook_entity_update(). */ @@ -212,10 +201,6 @@ function entity_crud_hook_test_user_update() { $_SESSION['entity_crud_hook_test'][] = (__FUNCTION__ . ' called'); } -// -// Delete hooks -// - /** * Implements hook_entity_delete(). */ diff --git a/modules/simpletest/tests/entity_crud_hook_test.test b/modules/simpletest/tests/entity_crud_hook_test.test index 3f18fc855..178e34dc7 100644 --- a/modules/simpletest/tests/entity_crud_hook_test.test +++ b/modules/simpletest/tests/entity_crud_hook_test.test @@ -1,8 +1,14 @@ <?php /** - * Test invocation of hooks when inserting, loading, updating or deleting an - * entity. Tested hooks are: + * @file + * CRUD hook tests for the Entity CRUD API. + */ + +/** + * Tests invocation of hooks when performing an action. + * + * Tested hooks are: * - hook_entity_insert() * - hook_entity_load() * - hook_entity_update() @@ -48,7 +54,7 @@ class EntityCrudHookTestCase extends DrupalWebTestCase { } /** - * Test hook invocations for CRUD operations on comments. + * Tests hook invocations for CRUD operations on comments. */ public function testCommentHooks() { $node = (object) array( @@ -108,7 +114,7 @@ class EntityCrudHookTestCase extends DrupalWebTestCase { } /** - * Test hook invocations for CRUD operations on files. + * Tests hook invocations for CRUD operations on files. */ public function testFileHooks() { $url = 'public://entity_crud_hook_test.file'; @@ -154,7 +160,7 @@ class EntityCrudHookTestCase extends DrupalWebTestCase { } /** - * Test hook invocations for CRUD operations on nodes. + * Tests hook invocations for CRUD operations on nodes. */ public function testNodeHooks() { $node = (object) array( @@ -200,7 +206,7 @@ class EntityCrudHookTestCase extends DrupalWebTestCase { } /** - * Test hook invocations for CRUD operations on taxonomy terms. + * Tests hook invocations for CRUD operations on taxonomy terms. */ public function testTaxonomyTermHooks() { $vocabulary = (object) array( @@ -248,7 +254,7 @@ class EntityCrudHookTestCase extends DrupalWebTestCase { } /** - * Test hook invocations for CRUD operations on taxonomy vocabularies. + * Tests hook invocations for CRUD operations on taxonomy vocabularies. */ public function testTaxonomyVocabularyHooks() { $vocabulary = (object) array( @@ -288,7 +294,7 @@ class EntityCrudHookTestCase extends DrupalWebTestCase { } /** - * Test hook invocations for CRUD operations on users. + * Tests hook invocations for CRUD operations on users. */ public function testUserHooks() { $edit = array( diff --git a/modules/simpletest/tests/entity_query_access_test.info b/modules/simpletest/tests/entity_query_access_test.info index 8914b4366..e5437532c 100644 --- a/modules/simpletest/tests/entity_query_access_test.info +++ b/modules/simpletest/tests/entity_query_access_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/error_test.info b/modules/simpletest/tests/error_test.info index 2c3630445..12a5a51ba 100644 --- a/modules/simpletest/tests/error_test.info +++ b/modules/simpletest/tests/error_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/file_test.info b/modules/simpletest/tests/file_test.info index 699b9d8f9..b7b761972 100644 --- a/modules/simpletest/tests/file_test.info +++ b/modules/simpletest/tests/file_test.info @@ -6,8 +6,8 @@ core = 7.x files[] = file_test.module hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/filter_test.info b/modules/simpletest/tests/filter_test.info index 758ca5712..9f58a3039 100644 --- a/modules/simpletest/tests/filter_test.info +++ b/modules/simpletest/tests/filter_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/form.test b/modules/simpletest/tests/form.test index 985abe31b..7eac198ad 100644 --- a/modules/simpletest/tests/form.test +++ b/modules/simpletest/tests/form.test @@ -189,6 +189,38 @@ class FormsTestCase extends DrupalWebTestCase { $this->assertRaw("The form_test_validate_required_form form was submitted successfully.", 'Validation form submitted successfully.'); } + /** + * Tests validation for required textfield element without title. + * + * Submits a test form containing a textfield form elements without title. + * The form is submitted twice, first without value for the required field + * and then with value. Each submission is checked for relevant error + * messages. + * + * @see form_test_validate_required_form_no_title() + */ + function testRequiredTextfieldNoTitle() { + $form = $form_state = array(); + $form = form_test_validate_required_form_no_title($form, $form_state); + + // Attempt to submit the form with no required field set. + $edit = array(); + $this->drupalPost('form-test/validate-required-no-title', $edit, 'Submit'); + $this->assertNoRaw("The form_test_validate_required_form_no_title form was submitted successfully.", 'Validation form submitted successfully.'); + + // Check the page for the error class on the textfield. + $this->assertFieldByXPath('//input[contains(@class, "error")]', FALSE, 'Error input form element class found.'); + + // Submit again with required fields set and verify that there are no + // error messages. + $edit = array( + 'textfield' => $this->randomString(), + ); + $this->drupalPost(NULL, $edit, 'Submit'); + $this->assertNoFieldByXpath('//input[contains(@class, "error")]', FALSE, 'No error input form element class found.'); + $this->assertRaw("The form_test_validate_required_form_no_title form was submitted successfully.", 'Validation form submitted successfully.'); + } + /** * Test default value handling for checkboxes. * @@ -1308,6 +1340,81 @@ class FormsRebuildTestCase extends DrupalWebTestCase { } } +/** + * Tests form redirection. + */ +class FormsRedirectTestCase extends DrupalWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'Form redirecting', + 'description' => 'Tests functionality of drupal_redirect_form().', + 'group' => 'Form API', + ); + } + + function setUp() { + parent::setUp(array('form_test')); + } + + /** + * Tests form redirection. + */ + function testRedirect() { + $path = 'form-test/redirect'; + $options = array('query' => array('foo' => 'bar')); + $options['absolute'] = TRUE; + + // Test basic redirection. + $edit = array( + 'redirection' => TRUE, + 'destination' => $this->randomName(), + ); + $this->drupalPost($path, $edit, t('Submit')); + $this->assertUrl($edit['destination'], array(), 'Basic redirection works.'); + + + // Test without redirection. + $edit = array( + 'redirection' => FALSE, + ); + $this->drupalPost($path, $edit, t('Submit')); + $this->assertUrl($path, array(), 'When redirect is set to FALSE, there should be no redirection.'); + + // Test redirection with query parameters. + $edit = array( + 'redirection' => TRUE, + 'destination' => $this->randomName(), + ); + $this->drupalPost($path, $edit, t('Submit'), $options); + $this->assertUrl($edit['destination'], array(), 'Redirection with query parameters works.'); + + // Test without redirection but with query parameters. + $edit = array( + 'redirection' => FALSE, + ); + $this->drupalPost($path, $edit, t('Submit'), $options); + $this->assertUrl($path, $options, 'When redirect is set to FALSE, there should be no redirection, and the query parameters should be passed along.'); + + // Test redirection back to the original path. + $edit = array( + 'redirection' => TRUE, + 'destination' => '', + ); + $this->drupalPost($path, $edit, t('Submit')); + $this->assertUrl($path, array(), 'When using an empty redirection string, there should be no redirection.'); + + // Test redirection back to the original path with query parameters. + $edit = array( + 'redirection' => TRUE, + 'destination' => '', + ); + $this->drupalPost($path, $edit, t('Submit'), $options); + $this->assertUrl($path, $options, 'When using an empty redirection string, there should be no redirection, and the query parameters should be passed along.'); + } + +} + /** * Test the programmatic form submission behavior. */ @@ -1675,3 +1782,34 @@ class FormCheckboxTestCase extends DrupalWebTestCase { } } } + +/** + * Tests uniqueness of generated HTML IDs. + */ +class HTMLIdTestCase extends DrupalWebTestCase { + + public static function getInfo() { + return array( + 'name' => 'Unique HTML IDs', + 'description' => 'Tests functionality of drupal_html_id().', + 'group' => 'Form API', + ); + } + + function setUp() { + parent::setUp('form_test'); + } + + /** + * Tests that HTML IDs do not get duplicated when form validation fails. + */ + function testHTMLId() { + $this->drupalGet('form-test/double-form'); + $this->assertNoDuplicateIds('There are no duplicate IDs'); + + // Submit second form with empty title. + $edit = array(); + $this->drupalPost(NULL, $edit, 'Save', array(), array(), 'form-test-html-id--2'); + $this->assertNoDuplicateIds('There are no duplicate IDs'); + } +} diff --git a/modules/simpletest/tests/form_test.info b/modules/simpletest/tests/form_test.info index f07ad5bdb..a5be94b8c 100644 --- a/modules/simpletest/tests/form_test.info +++ b/modules/simpletest/tests/form_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/form_test.module b/modules/simpletest/tests/form_test.module index e4ac77b12..b4d2f5499 100644 --- a/modules/simpletest/tests/form_test.module +++ b/modules/simpletest/tests/form_test.module @@ -30,6 +30,13 @@ function form_test_menu() { 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); + $items['form-test/validate-required-no-title'] = array( + 'title' => 'Form #required validation without #title', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('form_test_validate_required_form_no_title'), + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); $items['form-test/limit-validation-errors'] = array( 'title' => 'Form validation with some error suppression', 'page callback' => 'drupal_get_form', @@ -151,6 +158,14 @@ function form_test_menu() { 'type' => MENU_CALLBACK, ); + $items['form-test/redirect'] = array( + 'title' => 'Redirect test', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('form_test_redirect'), + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + $items['form_test/form-labels'] = array( 'title' => 'Form label test', 'page callback' => 'drupal_get_form', @@ -186,6 +201,12 @@ function form_test_menu() { 'type' => MENU_CALLBACK, ); } + $items['form-test/double-form'] = array( + 'title' => 'Double form test', + 'page callback' => 'form_test_double_form', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); $items['form-test/load-include-menu'] = array( 'title' => 'FAPI test loading includes', @@ -398,6 +419,26 @@ function form_test_validate_required_form_submit($form, &$form_state) { drupal_set_message('The form_test_validate_required_form form was submitted successfully.'); } +/** + * Form constructor to test the #required property without #title. + */ +function form_test_validate_required_form_no_title($form, &$form_state) { + $form['textfield'] = array( + '#type' => 'textfield', + '#required' => TRUE, + ); + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array('#type' => 'submit', '#value' => 'Submit'); + return $form; +} + +/** + * Form submission handler for form_test_validate_required_form_no_title(). + */ +function form_test_validate_required_form_no_title_submit($form, &$form_state) { + drupal_set_message('The form_test_validate_required_form_no_title form was submitted successfully.'); +} + /** * Builds a simple form with a button triggering partial validation. */ @@ -1643,6 +1684,43 @@ function form_test_clicked_button_submit($form, &$form_state) { drupal_set_message('Submit handler for form_test_clicked_button executed.'); } +/** + * Form builder to detect form redirect. + */ +function form_test_redirect($form, &$form_state) { + $form['redirection'] = array( + '#type' => 'checkbox', + '#title' => t('Use redirection'), + ); + $form['destination'] = array( + '#type' => 'textfield', + '#title' => t('Redirect destination'), + '#states' => array( + 'visible' => array( + ':input[name="redirection"]' => array('checked' => TRUE), + ), + ), + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + ); + + return $form; +} + +/** + * Form submit handler to test different redirect behaviours. + */ +function form_test_redirect_submit(&$form, &$form_state) { + if (!empty($form_state['values']['redirection'])) { + $form_state['redirect'] = !empty($form_state['values']['destination']) ? $form_state['values']['destination'] : NULL; + } + else { + $form_state['redirect'] = FALSE; + } +} + /** * Implements hook_form_FORM_ID_alter() for the registration form. */ @@ -1742,3 +1820,29 @@ function form_test_checkboxes_zero($form, &$form_state, $json = TRUE) { function _form_test_checkboxes_zero_no_redirect($form, &$form_state) { $form_state['redirect'] = FALSE; } + +/** + * Menu callback returns two instances of the same form. + */ +function form_test_double_form() { + return array( + 'form1' => drupal_get_form('form_test_html_id'), + 'form2' => drupal_get_form('form_test_html_id'), + ); +} + +/** + * Builds a simple form to test duplicate HTML IDs. + */ +function form_test_html_id($form, &$form_state) { + $form['name'] = array( + '#type' => 'textfield', + '#title' => 'name', + '#required' => TRUE, + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => 'Save', + ); + return $form; +} diff --git a/modules/simpletest/tests/https.php b/modules/simpletest/tests/https.php index b5ffab693..0e1a4edeb 100644 --- a/modules/simpletest/tests/https.php +++ b/modules/simpletest/tests/https.php @@ -2,13 +2,13 @@ /** * @file - * Fake an https request, for use during testing. + * Fake an HTTPS request, for use during testing. */ // Set a global variable to indicate a mock HTTPS request. $is_https_mock = empty($_SERVER['HTTPS']); -// Change to https. +// Change to HTTPS. $_SERVER['HTTPS'] = 'on'; foreach ($_SERVER as $key => $value) { $_SERVER[$key] = str_replace('modules/simpletest/tests/https.php', 'index.php', $value); diff --git a/modules/simpletest/tests/image.test b/modules/simpletest/tests/image.test index 962aa661f..403c9d7d8 100644 --- a/modules/simpletest/tests/image.test +++ b/modules/simpletest/tests/image.test @@ -14,7 +14,13 @@ class ImageToolkitTestCase extends DrupalWebTestCase { protected $image; function setUp() { - parent::setUp('image_test'); + $modules = func_get_args(); + if (isset($modules[0]) && is_array($modules[0])) { + $modules = $modules[0]; + } + $modules[] = 'image_test'; + + parent::setUp($modules); // Use the image_test.module's test toolkit. $this->toolkit = 'test'; diff --git a/modules/simpletest/tests/image_test.info b/modules/simpletest/tests/image_test.info index dcd97f6ac..f3b342290 100644 --- a/modules/simpletest/tests/image_test.info +++ b/modules/simpletest/tests/image_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/mail.test b/modules/simpletest/tests/mail.test index 09dcde60c..b7ce68544 100644 --- a/modules/simpletest/tests/mail.test +++ b/modules/simpletest/tests/mail.test @@ -150,7 +150,7 @@ class DrupalHtmlToTextTestCase extends DrupalWebTestCase { $tests = array( // @todo Trailing linefeeds should be trimmed. '<a href = "http://drupal.org">Drupal.org</a>' => "Drupal.org [1]\n\n[1] http://drupal.org\n", - // @todo Footer urls should be absolute. + // @todo Footer URLs should be absolute. "<a href = \"$base_path\">Homepage</a>" => "Homepage [1]\n\n[1] $base_url/\n", '<address>Drupal</address>' => "Drupal\n", // @todo The <address> tag is currently not supported. @@ -367,7 +367,7 @@ class DrupalHtmlToTextTestCase extends DrupalWebTestCase { . '<br /><a href="http://www.example.com">Host, no path</a>' . '<br /><a href="' . $base_path . 'node/1">Path, no host</a>' . '<br /><a href="node/1">Relative path</a>'; - // @todo Footnote urls should be absolute. + // @todo Footnote URLs should be absolute. $tt = "Host and path [1]" . "\nHost, no path [2]" // @todo The following two references should be combined. diff --git a/modules/simpletest/tests/menu.test b/modules/simpletest/tests/menu.test index b31fee6e3..1ecc1b1c1 100644 --- a/modules/simpletest/tests/menu.test +++ b/modules/simpletest/tests/menu.test @@ -599,7 +599,7 @@ class MenuRouterTestCase extends DrupalWebTestCase { } /** - * Get a url and assert the title given a case number. If override is true, + * Get a URL and assert the title given a case number. If override is true, * the title is asserted to begin with "Alternative". */ private function menuItemTitlesCasesHelper($case_no, $override = FALSE) { diff --git a/modules/simpletest/tests/menu_test.info b/modules/simpletest/tests/menu_test.info index 1c0152219..1b9c676be 100644 --- a/modules/simpletest/tests/menu_test.info +++ b/modules/simpletest/tests/menu_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/module.test b/modules/simpletest/tests/module.test index f55c08af4..769c4cf89 100644 --- a/modules/simpletest/tests/module.test +++ b/modules/simpletest/tests/module.test @@ -25,7 +25,7 @@ class ModuleUnitTest extends DrupalWebTestCase { $profile_info = install_profile_info('standard', 'en'); $module_list = $profile_info['dependencies']; - // Install profile is a module that is expected to be loaded. + // Installation profile is a module that is expected to be loaded. $module_list[] = 'standard'; sort($module_list); @@ -171,12 +171,12 @@ class ModuleUnitTest extends DrupalWebTestCase { $this->assertFalse(module_exists('php'), t('Disabling a module with unlisted dependents succeeded.')); $this->assertEqual(variable_get('test_module_disable_order', array()), array('forum', 'poll', 'php'), t('Modules were disabled in the correct order by module_disable().')); - // Disable a module that is listed as a dependency by the install profile. - // Make sure that the profile itself is not on the list of dependent - // modules to be disabled. + // Disable a module that is listed as a dependency by the installation + // profile. Make sure that the profile itself is not on the list of + // dependent modules to be disabled. $profile = drupal_get_profile(); $info = install_profile_info($profile); - $this->assertTrue(in_array('comment', $info['dependencies']), t('Comment module is listed as a dependency of the install profile.')); + $this->assertTrue(in_array('comment', $info['dependencies']), t('Comment module is listed as a dependency of the installation profile.')); $this->assertTrue(module_exists('comment'), t('Comment module is enabled.')); module_disable(array('comment')); $this->assertFalse(module_exists('comment'), t('Comment module was disabled.')); diff --git a/modules/simpletest/tests/module_test.info b/modules/simpletest/tests/module_test.info index 8a3c8a622..e591d354c 100644 --- a/modules/simpletest/tests/module_test.info +++ b/modules/simpletest/tests/module_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/path_test.info b/modules/simpletest/tests/path_test.info index e896f3676..94c850841 100644 --- a/modules/simpletest/tests/path_test.info +++ b/modules/simpletest/tests/path_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/requirements1_test.info b/modules/simpletest/tests/requirements1_test.info index f061b451c..855ada58d 100644 --- a/modules/simpletest/tests/requirements1_test.info +++ b/modules/simpletest/tests/requirements1_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/requirements1_test.install b/modules/simpletest/tests/requirements1_test.install index 651d911ab..91caca3f5 100644 --- a/modules/simpletest/tests/requirements1_test.install +++ b/modules/simpletest/tests/requirements1_test.install @@ -5,7 +5,7 @@ */ function requirements1_test_requirements($phase) { $requirements = array(); - // Ensure translations don't break at install time. + // Ensure translations don't break during installation. $t = get_t(); // Always fails requirements. diff --git a/modules/simpletest/tests/requirements2_test.info b/modules/simpletest/tests/requirements2_test.info index 1137617c2..f1d5886de 100644 --- a/modules/simpletest/tests/requirements2_test.info +++ b/modules/simpletest/tests/requirements2_test.info @@ -7,8 +7,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/session.test b/modules/simpletest/tests/session.test index e5ceb7538..a0feffbb0 100644 --- a/modules/simpletest/tests/session.test +++ b/modules/simpletest/tests/session.test @@ -289,14 +289,14 @@ class SessionTestCase extends DrupalWebTestCase { } /** - * Ensure that when running under https two session cookies are generated. + * Ensure that when running under HTTPS two session cookies are generated. */ class SessionHttpsTestCase extends DrupalWebTestCase { public static function getInfo() { return array( - 'name' => 'Session https handling', - 'description' => 'Ensure that when running under https two session cookies are generated.', + 'name' => 'Session HTTPS handling', + 'description' => 'Ensure that when running under HTTPS two session cookies are generated.', 'group' => 'Session' ); } @@ -384,7 +384,7 @@ class SessionHttpsTestCase extends DrupalWebTestCase { $this->cookies = array(); if ($is_https) { - // The functionality does not make sense when running on https. + // The functionality does not make sense when running on HTTPS. return; } diff --git a/modules/simpletest/tests/session_test.info b/modules/simpletest/tests/session_test.info index bf78757af..35b2f7f52 100644 --- a/modules/simpletest/tests/session_test.info +++ b/modules/simpletest/tests/session_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/system_dependencies_test.info b/modules/simpletest/tests/system_dependencies_test.info index 0659255a6..09e49cb82 100644 --- a/modules/simpletest/tests/system_dependencies_test.info +++ b/modules/simpletest/tests/system_dependencies_test.info @@ -6,8 +6,8 @@ core = 7.x hidden = TRUE dependencies[] = _missing_dependency -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info b/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info index bc7017a24..03de8dd73 100644 --- a/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info +++ b/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info @@ -6,8 +6,8 @@ core = 7.x hidden = TRUE dependencies[] = system_incompatible_core_version_test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/system_incompatible_core_version_test.info b/modules/simpletest/tests/system_incompatible_core_version_test.info index 55d758426..98f045a3a 100644 --- a/modules/simpletest/tests/system_incompatible_core_version_test.info +++ b/modules/simpletest/tests/system_incompatible_core_version_test.info @@ -5,8 +5,8 @@ version = VERSION core = 5.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info b/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info index a02e41b07..5cba8c5c8 100644 --- a/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info +++ b/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info @@ -7,8 +7,8 @@ hidden = TRUE ; system_incompatible_module_version_test declares version 1.0 dependencies[] = system_incompatible_module_version_test (>2.0) -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/system_incompatible_module_version_test.info b/modules/simpletest/tests/system_incompatible_module_version_test.info index 660b2c42c..229df4554 100644 --- a/modules/simpletest/tests/system_incompatible_module_version_test.info +++ b/modules/simpletest/tests/system_incompatible_module_version_test.info @@ -5,8 +5,8 @@ version = 1.0 core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/system_test.info b/modules/simpletest/tests/system_test.info index 037c7441e..f88b575ab 100644 --- a/modules/simpletest/tests/system_test.info +++ b/modules/simpletest/tests/system_test.info @@ -6,8 +6,8 @@ core = 7.x files[] = system_test.module hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/taxonomy_test.info b/modules/simpletest/tests/taxonomy_test.info index aab15a9c0..4b36f5508 100644 --- a/modules/simpletest/tests/taxonomy_test.info +++ b/modules/simpletest/tests/taxonomy_test.info @@ -6,8 +6,8 @@ core = 7.x hidden = TRUE dependencies[] = taxonomy -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/taxonomy_test.module b/modules/simpletest/tests/taxonomy_test.module index aae13a2d4..f82950c30 100644 --- a/modules/simpletest/tests/taxonomy_test.module +++ b/modules/simpletest/tests/taxonomy_test.module @@ -3,6 +3,8 @@ /** * @file * Test module for Taxonomy hooks and functions not used in core. + * + * @see TaxonomyHooksTestCase::testTaxonomyTermHooks() */ /** @@ -54,6 +56,34 @@ function taxonomy_test_taxonomy_term_delete($term) { ->execute(); } +/** + * Implements hook_taxonomy_term_view(). + */ +function taxonomy_test_taxonomy_term_view($term, $view_mode, $langcode) { + if ($view_mode == 'full') { + $term->content['taxonomy_test_term_view_check'] = array( + '#prefix' => '<div>', + '#markup' => t('The antonym is %antonym', array('%antonym' => $term->antonym)), + '#suffix' => '</div>', + '#weight' => 10, + ); + } +} + +/** + * Implements hook_entity_view(). + */ +function taxonomy_test_entity_view($entity, $type, $view_mode, $langcode) { + if ($type == 'taxonomy_term' && $view_mode == 'full') { + $entity->content['taxonomy_test_entity_view_check'] = array( + '#prefix' => '<div>', + '#markup' => t('The antonym is %antonym', array('%antonym' => $entity->antonym)), + '#suffix' => '</div>', + '#weight' => 20, + ); + } +} + /** * Implements hook_form_alter(). */ diff --git a/modules/simpletest/tests/theme.test b/modules/simpletest/tests/theme.test index 27a8e47b9..0ee473e3f 100644 --- a/modules/simpletest/tests/theme.test +++ b/modules/simpletest/tests/theme.test @@ -230,18 +230,19 @@ class ThemeItemListUnitTest extends DrupalWebTestCase { } /** - * Test nested list rendering. + * Test item list rendering. */ - function testNestedList() { - $items = array('a', array('data' => 'b', 'children' => array('c', 'd')), 'e'); + function testItemList() { + $items = array('a', array('data' => 'b', 'children' => array('c' => 'c', 'd' => 'd', 'e' => 'e')), 'f'); $expected = '<div class="item-list"><ul><li class="first">a</li> <li>b<div class="item-list"><ul><li class="first">c</li> -<li class="last">d</li> -</ul></div></li> +<li>d</li> <li class="last">e</li> +</ul></div></li> +<li class="last">f</li> </ul></div>'; $output = theme('item_list', array('items' => $items)); - $this->assertIdentical($expected, $output, 'Nested list is rendered correctly.'); + $this->assertIdentical($expected, $output, 'Item list is rendered correctly.'); } } diff --git a/modules/simpletest/tests/theme_test.info b/modules/simpletest/tests/theme_test.info index 776cce1a9..b76dee573 100644 --- a/modules/simpletest/tests/theme_test.info +++ b/modules/simpletest/tests/theme_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info b/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info index b2eeeaf9a..97553613c 100644 --- a/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info +++ b/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info @@ -6,8 +6,8 @@ hidden = TRUE settings[basetheme_only] = base theme value settings[subtheme_override] = base theme value -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info b/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info index eb81c3814..082f782ea 100644 --- a/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info +++ b/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info @@ -6,8 +6,8 @@ hidden = TRUE settings[subtheme_override] = subtheme value -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/themes/test_theme/test_theme.info b/modules/simpletest/tests/themes/test_theme/test_theme.info index 6a23f4944..fa1873538 100644 --- a/modules/simpletest/tests/themes/test_theme/test_theme.info +++ b/modules/simpletest/tests/themes/test_theme/test_theme.info @@ -17,8 +17,8 @@ stylesheets[all][] = system.base.css settings[theme_test_setting] = default value -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/update_script_test.info b/modules/simpletest/tests/update_script_test.info index 5d16cd63c..3a240fe76 100644 --- a/modules/simpletest/tests/update_script_test.info +++ b/modules/simpletest/tests/update_script_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/update_test_1.info b/modules/simpletest/tests/update_test_1.info index 8f0ea2479..c4febe3d2 100644 --- a/modules/simpletest/tests/update_test_1.info +++ b/modules/simpletest/tests/update_test_1.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/update_test_2.info b/modules/simpletest/tests/update_test_2.info index 8f0ea2479..c4febe3d2 100644 --- a/modules/simpletest/tests/update_test_2.info +++ b/modules/simpletest/tests/update_test_2.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/update_test_3.info b/modules/simpletest/tests/update_test_3.info index 8f0ea2479..c4febe3d2 100644 --- a/modules/simpletest/tests/update_test_3.info +++ b/modules/simpletest/tests/update_test_3.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/upgrade/drupal-6.forum.database.php b/modules/simpletest/tests/upgrade/drupal-6.forum.database.php index 5a2cc3324..059af6d22 100644 --- a/modules/simpletest/tests/upgrade/drupal-6.forum.database.php +++ b/modules/simpletest/tests/upgrade/drupal-6.forum.database.php @@ -258,3 +258,17 @@ db_insert('vocabulary_node_types')->fields(array( )) ->execute(); +// Provide all users with the ability to create forum topics. +$results = db_select('permission', 'p') + ->fields('p') + ->execute(); + +foreach ($results as $result) { + $permissions = $result->perm . ', create forum topics'; + db_update('permission') + ->fields(array( + 'perm' => $permissions, + )) + ->condition('rid', $result->rid) + ->execute(); +} diff --git a/modules/simpletest/tests/upgrade/drupal-6.menu.database.php b/modules/simpletest/tests/upgrade/drupal-6.menu.database.php index 8962615fb..7fae337aa 100644 --- a/modules/simpletest/tests/upgrade/drupal-6.menu.database.php +++ b/modules/simpletest/tests/upgrade/drupal-6.menu.database.php @@ -126,6 +126,33 @@ db_insert('menu_links')->fields(array( 'p9' => '0', 'updated' => '0', )) +->values(array( + 'menu_name' => 'secondary-links', + 'mlid' => '206', + 'plid' => '0', + 'link_path' => 'node', + 'router_path' => 'node', + 'link_title' => 'node-page-with-query', + 'options' => 'a:2:{s:5:"query";s:14:"page=1&node=10";s:10:"attributes";a:1:{s:5:"title";s:0:"";}}', + 'module' => 'menu', + 'hidden' => '0', + 'external' => '0', + 'has_children' => '0', + 'expanded' => '0', + 'weight' => '2', + 'depth' => '1', + 'customized' => '1', + 'p1' => '206', + 'p2' => '0', + 'p3' => '0', + 'p4' => '0', + 'p5' => '0', + 'p6' => '0', + 'p7' => '0', + 'p8' => '0', + 'p9' => '0', + 'updated' => '0', +)) ->execute(); db_insert('blocks')->fields(array( 'bid', diff --git a/modules/simpletest/tests/upgrade/drupal-6.upload.database.php b/modules/simpletest/tests/upgrade/drupal-6.upload.database.php index c7f032ecb..46ebe2cb0 100644 --- a/modules/simpletest/tests/upgrade/drupal-6.upload.database.php +++ b/modules/simpletest/tests/upgrade/drupal-6.upload.database.php @@ -416,3 +416,34 @@ db_insert('upload')->fields(array( 'weight' => '0', )) ->execute(); + +// Add series of entries for invalid node vids to the {upload} table. +for ($i = 30; $i < 250; $i += 2) { + db_insert('upload')->fields(array( + 'fid', + 'nid', + 'vid', + 'description', + 'list', + 'weight', + )) + // Invalid fid, invalid vid. + ->values(array( + 'fid' => $i, + 'nid' => '40', + 'vid' => 24 + $i, + 'description' => 'crazy-basename.png', + 'list' => '1', + 'weight' => '0', + )) + // Valid fid, invalid vid. + ->values(array( + 'fid' => 2, + 'nid' => '40', + 'vid' => 24 + $i + 1, + 'description' => 'crazy-basename.png', + 'list' => '1', + 'weight' => '0', + )) + ->execute(); +} diff --git a/modules/simpletest/tests/upgrade/drupal-7.aggregator.database.php b/modules/simpletest/tests/upgrade/drupal-7.aggregator.database.php new file mode 100644 index 000000000..00ea7d228 --- /dev/null +++ b/modules/simpletest/tests/upgrade/drupal-7.aggregator.database.php @@ -0,0 +1,149 @@ +<?php +/** + * @file + * Test content for the aggregator update path. + */ + +db_insert('aggregator_feed')->fields(array( + 'fid', + 'title', + 'url', + 'refresh', + 'checked', + 'queued', + 'link', + 'description', + 'image', + 'hash', + 'etag', + 'modified', + 'block', +)) + ->values(array( + 'fid' => '1', + 'title' => 'Drupal commit log', + 'url' => 'http://drupal.org/commitlog/feed', + 'refresh' => '3600', + 'checked' => '1347209523', + 'queued' => '0', + 'link' => 'http://drupal.org/versioncontrol/garbage/path', + 'description' => '', + 'image' => '', + 'hash' => '84f57ae5bffa7fd56942a6293be91244d8551cd18204a7c7de6a17065ea4d54d', + 'etag' => '"1347206975"', + 'modified' => '1347206975', + 'block' => '5', +)) + ->execute(); + +db_insert('aggregator_item')->fields(array( + 'iid', + 'fid', + 'title', + 'link', + 'author', + 'description', + 'timestamp', + 'guid', +)) + ->values(array( + 'iid' => '1', + 'fid' => '1', + 'title' => 'Domain Access: Commit b904022 on 7.x-2.x authored by bforchhammer, committed by agentrickard', + 'link' => 'http://drupal.org/commitlog/commit/2%2C410/b90402243b4a9dee0d2e2c4a729dcb2f58dc53c0', + 'author' => 'bforchhammer', + 'description' => "<div class=\"view view-commitlog-commit-items view-id-commitlog_commit_items view-display-id-block_1 view-dom-id-10\">\n \n \n \n <div class=\"view-content\">\n <div class=\"views-row views-row-1 views-row-odd views-row-first\">\n \n <div class=\"views-field-path\">\n <span class=\"field-content\"><a href=\"http://drupalcode.org/project/domain.git/blob/b90402243b4a9dee0d2e2c4a729dcb2f58dc53c0:/domain_source/domain_source.info\">/domain_source/domain_source.info</a></span>\n </div>\n \n <div class=\"views-field-changed-lines\">\n <span class=\"field-content\">1 addition & 1 deletion</span>\n </div>\n \n <div class=\"views-field-visual-diffstat\">\n <span class=\"field-content\"><span class=\"versioncontrol-diffstat clear-block\"><span class=\"plus\">+</span><span class=\"minus\">-</span><span class=\"no-op\"> </span><span class=\"no-op\"> </span><span class=\"no-op\"> </span><span class=\"no-op\"> </span><span class=\"no-op\"> </span></span></span>\n </div>\n </div>\n <div class=\"views-row views-row-2 views-row-even views-row-last\">\n \n <div class=\"views-field-path\">\n <span class=\"field-content\"><a href=\"http://drupalcode.org/project/domain.git/blob/b90402243b4a9dee0d2e2c4a729dcb2f58dc53c0:/domain_source/domain_source.views.inc\">/domain_source/domain_source.views.inc</a></span>\n </div>\n \n <div class=\"views-field-changed-lines\">\n <span class=\"field-content\">13 additions & 1 deletion</span>\n </div>\n \n <div class=\"views-field-visual-diffstat\">\n <span class=\"field-content\"><span class=\"versioncontrol-diffstat clear-block\"><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"minus\">-</span></span></span>\n </div>\n </div>\n </div>\n \n \n \n \n \n \n</div>\n<pre>Patch #1685658 by bforchhammer. Better handling of current domain for Domain Source.\n</pre>", + 'timestamp' => '1347206044', + 'guid' => 'VCS Operation 3936918 at http://drupal.org', +)) + ->values(array( + 'iid' => '2', + 'fid' => '1', + 'title' => 'Video: Commit b0b7ff0 on 7.x-2.x by Jorrit', + 'link' => 'http://drupal.org/commitlog/commit/846/b0b7ff08fed89c76454aa54627cc219361365d7b', + 'author' => 'Jorrit', + 'description' => "<div class=\"view view-commitlog-commit-items view-id-commitlog_commit_items view-display-id-block_1 view-dom-id-9\">\n \n \n \n <div class=\"view-content\">\n <div class=\"views-row views-row-1 views-row-odd views-row-first\">\n \n <div class=\"views-field-path\">\n <span class=\"field-content\"><a href=\"http://drupalcode.org/project/video.git/blob/b0b7ff08fed89c76454aa54627cc219361365d7b:/libraries/phpvideotoolkit/phpvideotoolkit.php5.php\">/libraries/phpvideotoolkit/phpvideotoolkit.php5.php</a></span>\n </div>\n \n <div class=\"views-field-changed-lines\">\n <span class=\"field-content\">5 additions & 5 deletions</span>\n </div>\n \n <div class=\"views-field-visual-diffstat\">\n <span class=\"field-content\"><span class=\"versioncontrol-diffstat clear-block\"><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"minus\">-</span><span class=\"minus\">-</span><span class=\"minus\">-</span><span class=\"no-op\"> </span></span></span>\n </div>\n </div>\n <div class=\"views-row views-row-2 views-row-even\">\n \n <div class=\"views-field-path\">\n <span class=\"field-content\"><a href=\"http://drupalcode.org/project/video.git/blob/b0b7ff08fed89c76454aa54627cc219361365d7b:/tests/TranscoderAbstractionFactoryFfmpeg.test\">/tests/TranscoderAbstractionFactoryFfmpeg.test</a></span>\n </div>\n \n <div class=\"views-field-changed-lines\">\n <span class=\"field-content\">21 additions & 7 deletions</span>\n </div>\n \n <div class=\"views-field-visual-diffstat\">\n <span class=\"field-content\"><span class=\"versioncontrol-diffstat clear-block\"><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"minus\">-</span><span class=\"minus\">-</span></span></span>\n </div>\n </div>\n <div class=\"views-row views-row-3 views-row-odd views-row-last\">\n \n <div class=\"views-field-path\">\n <span class=\"field-content\"><a href=\"http://drupalcode.org/project/video.git/blob/b0b7ff08fed89c76454aa54627cc219361365d7b:/transcoders/TranscoderAbstractionFactoryFfmpeg.inc\">/transcoders/TranscoderAbstractionFactoryFfmpeg.inc</a></span>\n </div>\n \n <div class=\"views-field-changed-lines\">\n <span class=\"field-content\">31 additions & 22 deletions</span>\n </div>\n \n <div class=\"views-field-visual-diffstat\">\n <span class=\"field-content\"><span class=\"versioncontrol-diffstat clear-block\"><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"minus\">-</span><span class=\"minus\">-</span><span class=\"minus\">-</span></span></span>\n </div>\n </div>\n </div>\n \n \n \n \n \n \n</div>\n<pre>Issue #1492296 by Jorrit: Added support for avconv binaries instead of FFmpeg.\n</pre>", + 'timestamp' => '1347206397', + 'guid' => 'VCS Operation 3936924 at http://drupal.org', +)) + ->values(array( + 'iid' => '3', + 'fid' => '1', + 'title' => 'Remove Login Tabs: Commit 6e1eb5a on 7.x-1.x by highrockmedia', + 'link' => 'http://drupal.org/commitlog/commit/41%2C610/6e1eb5a4a952db3264e7696e840ac3d797f4b477', + 'author' => 'highrockmedia', + 'description' => "<div class=\"view view-commitlog-commit-items view-id-commitlog_commit_items view-display-id-block_1 view-dom-id-8\">\n \n \n \n <div class=\"view-content\">\n <div class=\"views-row views-row-1 views-row-odd views-row-first views-row-last\">\n \n <div class=\"views-field-path\">\n <span class=\"field-content\"><a href=\"http://drupalcode.org/sandbox/highrockmedia/1702096.git/blob/6e1eb5a4a952db3264e7696e840ac3d797f4b477:/readme.txt\">/readme.txt</a></span>\n </div>\n \n <div class=\"views-field-changed-lines\">\n <span class=\"field-content\">10 additions & 2 deletions</span>\n </div>\n \n <div class=\"views-field-visual-diffstat\">\n <span class=\"field-content\"><span class=\"versioncontrol-diffstat clear-block\"><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"minus\">-</span></span></span>\n </div>\n </div>\n </div>\n \n \n \n \n \n \n</div>\n<pre>Updating readme\n</pre>", + 'timestamp' => '1347206401', + 'guid' => 'VCS Operation 3936920 at http://drupal.org', +)) + ->values(array( + 'iid' => '4', + 'fid' => '1', + 'title' => 'TimeGroup: Commit 6ed4c08 on 7.x-1.x by Sweetchuck', + 'link' => 'http://drupal.org/commitlog/commit/40%2C448/6ed4c085e5d9a8d33e091e1b8a65c73eab2dc99e', + 'author' => 'Sweetchuck', + 'description' => "<div class=\"view view-commitlog-commit-items view-id-commitlog_commit_items view-display-id-block_1 view-dom-id-7\">\n \n \n \n <div class=\"view-content\">\n <div class=\"views-row views-row-1 views-row-odd views-row-first views-row-last\">\n \n <div class=\"views-field-path\">\n <span class=\"field-content\"><a href=\"http://drupalcode.org/sandbox/Sweetchuck/1666642.git/blob/6ed4c085e5d9a8d33e091e1b8a65c73eab2dc99e:/includes/ctools/export_ui/timegroup.inc\">/includes/ctools/export_ui/timegroup.inc</a></span>\n </div>\n \n <div class=\"views-field-changed-lines\">\n <span class=\"field-content\">1 addition & 1 deletion</span>\n </div>\n \n <div class=\"views-field-visual-diffstat\">\n <span class=\"field-content\"><span class=\"versioncontrol-diffstat clear-block\"><span class=\"plus\">+</span><span class=\"minus\">-</span><span class=\"no-op\"> </span><span class=\"no-op\"> </span><span class=\"no-op\"> </span><span class=\"no-op\"> </span><span class=\"no-op\"> </span></span></span>\n </div>\n </div>\n </div>\n \n \n \n \n \n \n</div>\n<pre>CTools UI - Wrong default value for timeoffset fix.\n</pre>", + 'timestamp' => '1347206533', + 'guid' => 'VCS Operation 3936942 at http://drupal.org', +)) + ->values(array( + 'iid' => '5', + 'fid' => '1', + 'title' => 'Domain Access: Commit 1140172 on 6.x-2.x authored by bforchhammer, committed by agentrickard', + 'link' => 'http://drupal.org/commitlog/commit/2%2C410/11401723f5c5d11032dd141ba4939ed889a7a915', + 'author' => 'bforchhammer', + 'description' => "<div class=\"view view-commitlog-commit-items view-id-commitlog_commit_items view-display-id-block_1 view-dom-id-6\">\n \n \n \n <div class=\"view-content\">\n <div class=\"views-row views-row-1 views-row-odd views-row-first\">\n \n <div class=\"views-field-path\">\n <span class=\"field-content\"><a href=\"http://drupalcode.org/project/domain.git/blob/11401723f5c5d11032dd141ba4939ed889a7a915:/domain_source/domain_source.views.inc\">/domain_source/domain_source.views.inc</a></span>\n </div>\n \n <div class=\"views-field-changed-lines\">\n <span class=\"field-content\">33 additions & 1 deletion</span>\n </div>\n \n <div class=\"views-field-visual-diffstat\">\n <span class=\"field-content\"><span class=\"versioncontrol-diffstat clear-block\"><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"no-op\"> </span></span></span>\n </div>\n </div>\n <div class=\"views-row views-row-2 views-row-even views-row-last\">\n \n <div class=\"views-field-path\">\n <span class=\"field-content\"><a href=\"http://drupalcode.org/project/domain.git/blob/11401723f5c5d11032dd141ba4939ed889a7a915:/domain_source/includes/domain_source_handler_filter_domain_id.inc\">/domain_source/includes/domain_source_handler_filter_domain_id.inc</a></span>\n </div>\n \n <div class=\"views-field-changed-lines\">\n <span class=\"field-content\">28 additions & 0 deletions</span>\n </div>\n \n <div class=\"views-field-visual-diffstat\">\n <span class=\"field-content\"><span class=\"versioncontrol-diffstat clear-block\"><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span></span></span>\n </div>\n </div>\n </div>\n \n \n \n \n \n \n</div>\n<pre>Patch #1685658 by bforchhammer. Better handling of current domain for Domain Source.\n</pre>", + 'timestamp' => '1347206541', + 'guid' => 'VCS Operation 3936926 at http://drupal.org', +)) + ->values(array( + 'iid' => '6', + 'fid' => '1', + 'title' => 'Domain Access: Commit 19b1c36 on 7.x-2.x by agentrickard', + 'link' => 'http://drupal.org/commitlog/commit/2%2C410/19b1c366d86cecd8a9f6e1a6e835c0566f5c02db', + 'author' => 'agentrickard', + 'description' => "<div class=\"view view-commitlog-commit-items view-id-commitlog_commit_items view-display-id-block_1 view-dom-id-5\">\n \n \n \n <div class=\"view-content\">\n <div class=\"views-row views-row-1 views-row-odd views-row-first views-row-last\">\n \n <div class=\"views-field-path\">\n <span class=\"field-content\"><a href=\"http://drupalcode.org/project/domain.git/blob/19b1c366d86cecd8a9f6e1a6e835c0566f5c02db:/domain_source/includes/domain_source_handler_filter_domain_id.inc\">/domain_source/includes/domain_source_handler_filter_domain_id.inc</a></span>\n </div>\n \n <div class=\"views-field-changed-lines\">\n <span class=\"field-content\">28 additions & 0 deletions</span>\n </div>\n \n <div class=\"views-field-visual-diffstat\">\n <span class=\"field-content\"><span class=\"versioncontrol-diffstat clear-block\"><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span></span></span>\n </div>\n </div>\n </div>\n \n \n \n \n \n \n</div>\n<pre>Adds new Views file to Domain Source.\n</pre>", + 'timestamp' => '1347206601', + 'guid' => 'VCS Operation 3936928 at http://drupal.org', +)) + ->values(array( + 'iid' => '7', + 'fid' => '1', + 'title' => 'Domain Access: Commit d2d5456 on 7.x-3.x by agentrickard', + 'link' => 'http://drupal.org/commitlog/commit/2%2C410/d2d5456cad6ca57bb72e743da6a7112a74d7a331', + 'author' => 'agentrickard', + 'description' => "<div class=\"view view-commitlog-commit-items view-id-commitlog_commit_items view-display-id-block_1 view-dom-id-4\">\n \n \n \n <div class=\"view-content\">\n <div class=\"views-row views-row-1 views-row-odd views-row-first views-row-last\">\n \n <div class=\"views-field-path\">\n <span class=\"field-content\"><a href=\"http://drupalcode.org/project/domain.git/blob/d2d5456cad6ca57bb72e743da6a7112a74d7a331:/domain_source/includes/domain_source_handler_filter_domain_id.inc\">/domain_source/includes/domain_source_handler_filter_domain_id.inc</a></span>\n </div>\n \n <div class=\"views-field-changed-lines\">\n <span class=\"field-content\">29 additions & 0 deletions</span>\n </div>\n \n <div class=\"views-field-visual-diffstat\">\n <span class=\"field-content\"><span class=\"versioncontrol-diffstat clear-block\"><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span></span></span>\n </div>\n </div>\n </div>\n \n \n \n \n \n \n</div>\n<pre>Adds new Views file to Domain Source.\n</pre>", + 'timestamp' => '1347206620', + 'guid' => 'VCS Operation 3936930 at http://drupal.org', +)) + ->values(array( + 'iid' => '8', + 'fid' => '1', + 'title' => 'Skarabee: Commit 400b519 on 7.x-1.x by sboersma', + 'link' => 'http://drupal.org/commitlog/commit/23%2C278/400b5190f59b1cb58d6b27fa10ac668e9580aa73', + 'author' => 'sboersma', + 'description' => "<div class=\"view view-commitlog-commit-items view-id-commitlog_commit_items view-display-id-block_1 view-dom-id-3\">\n \n \n \n <div class=\"view-content\">\n <div class=\"views-row views-row-1 views-row-odd views-row-first views-row-last\">\n \n <div class=\"views-field-path\">\n <span class=\"field-content\"><a href=\"http://drupalcode.org/sandbox/sboersma/1176520.git/blob/400b5190f59b1cb58d6b27fa10ac668e9580aa73:/skarabee.install\">/skarabee.install</a></span>\n </div>\n \n <div class=\"views-field-changed-lines\">\n <span class=\"field-content\">3 additions & 3 deletions</span>\n </div>\n \n <div class=\"views-field-visual-diffstat\">\n <span class=\"field-content\"><span class=\"versioncontrol-diffstat clear-block\"><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"minus\">-</span><span class=\"minus\">-</span><span class=\"minus\">-</span><span class=\"no-op\"> </span></span></span>\n </div>\n </div>\n </div>\n \n \n \n \n \n \n</div>\n<pre>sboersma: Changed variable deletion method.\n</pre>", + 'timestamp' => '1347206709', + 'guid' => 'VCS Operation 3936932 at http://drupal.org', +)) + ->values(array( + 'iid' => '9', + 'fid' => '1', + 'title' => 'Config entity listing plugin API: Commit dd3fa73 on 8.x-list by damiankloip', + 'link' => 'http://drupal.org/commitlog/commit/43%2C586/dd3fa73b0bcdca833bbde1d1ddb3cefe42003693', + 'author' => 'damiankloip', + 'description' => "<div class=\"view view-commitlog-commit-items view-id-commitlog_commit_items view-display-id-block_1 view-dom-id-2\">\n \n \n \n <div class=\"view-content\">\n <div class=\"views-row views-row-1 views-row-odd views-row-first views-row-last\">\n \n <div class=\"views-field-path\">\n <span class=\"field-content\"><a href=\"http://drupalcode.org/sandbox/damiankloip/1778654.git/blob/dd3fa73b0bcdca833bbde1d1ddb3cefe42003693:/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListingTest.php\">/core/modules/config/lib/Drupal/config/Tests/ConfigEntityListingTest.php</a></span>\n </div>\n \n <div class=\"views-field-changed-lines\">\n <span class=\"field-content\">10 additions & 2 deletions</span>\n </div>\n \n <div class=\"views-field-visual-diffstat\">\n <span class=\"field-content\"><span class=\"versioncontrol-diffstat clear-block\"><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"minus\">-</span></span></span>\n </div>\n </div>\n </div>\n \n \n \n \n \n \n</div>\n<pre>Added tests for getList() method\n</pre>", + 'timestamp' => '1347206738', + 'guid' => 'VCS Operation 3936936 at http://drupal.org', +)) + ->values(array( + 'iid' => '10', + 'fid' => '1', + 'title' => 'AutoSlave: Commit 76891da on 7.x-1.x by gielfeldt', + 'link' => 'http://drupal.org/commitlog/commit/42%2C968/76891daf3cea9c294daf56a26760cb1bf33ea58a', + 'author' => 'gielfeldt', + 'description' => "<div class=\"view view-commitlog-commit-items view-id-commitlog_commit_items view-display-id-block_1 view-dom-id-1\">\n \n \n \n <div class=\"view-content\">\n <div class=\"views-row views-row-1 views-row-odd views-row-first\">\n \n <div class=\"views-field-path\">\n <span class=\"field-content\"><a href=\"http://drupalcode.org/project/autoslave.git/blob/76891daf3cea9c294daf56a26760cb1bf33ea58a:/autoslave.module\">/autoslave.module</a></span>\n </div>\n \n <div class=\"views-field-changed-lines\">\n <span class=\"field-content\">10 additions & 7 deletions</span>\n </div>\n \n <div class=\"views-field-visual-diffstat\">\n <span class=\"field-content\"><span class=\"versioncontrol-diffstat clear-block\"><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"minus\">-</span><span class=\"minus\">-</span><span class=\"minus\">-</span></span></span>\n </div>\n </div>\n <div class=\"views-row views-row-2 views-row-even views-row-last\">\n \n <div class=\"views-field-path\">\n <span class=\"field-content\"><a href=\"http://drupalcode.org/project/autoslave.git/blob/76891daf3cea9c294daf56a26760cb1bf33ea58a:/autoslave/database.inc\">/autoslave/database.inc</a></span>\n </div>\n \n <div class=\"views-field-changed-lines\">\n <span class=\"field-content\">10 additions & 2 deletions</span>\n </div>\n \n <div class=\"views-field-visual-diffstat\">\n <span class=\"field-content\"><span class=\"versioncontrol-diffstat clear-block\"><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"plus\">+</span><span class=\"minus\">-</span></span></span>\n </div>\n </div>\n </div>\n \n \n \n \n \n \n</div>\n<pre>Keep track of affected tables per commit.\n</pre>", + 'timestamp' => '1347206751', + 'guid' => 'VCS Operation 3936934 at http://drupal.org', +)) + ->execute(); diff --git a/modules/simpletest/tests/upgrade/drupal-7.filled.standard_all.database.php.gz b/modules/simpletest/tests/upgrade/drupal-7.filled.standard_all.database.php.gz index 5cc5690e15a771722e312656218f8a55ff512889..472eedb230b7d9feb3f44dc53e4851210fc5ab13 100644 GIT binary patch delta 91185 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	)Hvv# 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 delta 91148 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⪻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 diff --git a/modules/simpletest/tests/upgrade/update.aggregator.test b/modules/simpletest/tests/upgrade/update.aggregator.test new file mode 100644 index 000000000..d4135774e --- /dev/null +++ b/modules/simpletest/tests/upgrade/update.aggregator.test @@ -0,0 +1,47 @@ +<?php +/** + * @file + * Tests schema changes in aggregator.module. + */ +class AggregatorUpdatePathTestCase extends UpdatePathTestCase { + + public static function getInfo() { + return array( + 'name' => 'Aggregator update path', + 'description' => 'Aggregator update path tests.', + 'group' => 'Upgrade path', + ); + } + + public function setUp() { + // Use the normal installation and add our feed data. + $path = drupal_get_path('module', 'simpletest') . '/tests/upgrade'; + $this->databaseDumpFiles = array( + $path . '/drupal-7.bare.standard_all.database.php.gz', + $path . '/drupal-7.aggregator.database.php', + ); + parent::setUp(); + + // Our test data only relies on aggregator.module. + $this->uninstallModulesExcept(array('aggregator')); + } + + /** + * Tests that the aggregator.module update is successful. + */ + public function testAggregatorUpdate() { + // Get a selection of the fields affected by the schema update. + $query = db_select('aggregator_feed', 'af'); + $query->join('aggregator_item', 'ai', 'af.fid = ai.fid'); + $query + ->fields('af', array('url', 'link')) + ->fields('ai', array('link', 'guid')); + + $pre_update_data = $query->execute()->fetchAll(); + $this->assertTrue($this->performUpgrade(), 'The update was completed successfully.'); + $post_update_data = $query->execute()->fetchAll(); + + $this->assertTrue($pre_update_data == $post_update_data, 'Feed data was preserved during the update.'); + } + +} diff --git a/modules/simpletest/tests/upgrade/upgrade.forum.test b/modules/simpletest/tests/upgrade/upgrade.forum.test index 99269d9f4..ebac85415 100644 --- a/modules/simpletest/tests/upgrade/upgrade.forum.test +++ b/modules/simpletest/tests/upgrade/upgrade.forum.test @@ -56,5 +56,9 @@ class ForumUpgradePathTestCase extends UpgradePathTestCase { $this->drupalGet("forum/$tid"); $this->assertText('Bananas'); - } + $this->drupalLogout(); + + $this->drupalGet("node/add/forum/$tid"); + $this->assertResponse(200, t('User can access forum creation page.')); + } } diff --git a/modules/simpletest/tests/url_alter_test.info b/modules/simpletest/tests/url_alter_test.info index 741d1625c..d7fe962cf 100644 --- a/modules/simpletest/tests/url_alter_test.info +++ b/modules/simpletest/tests/url_alter_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/simpletest/tests/xmlrpc_test.info b/modules/simpletest/tests/xmlrpc_test.info index 45abde00f..b6a3cc49e 100644 --- a/modules/simpletest/tests/xmlrpc_test.info +++ b/modules/simpletest/tests/xmlrpc_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/statistics/statistics.info b/modules/statistics/statistics.info index bd7b8458a..628a94efb 100644 --- a/modules/statistics/statistics.info +++ b/modules/statistics/statistics.info @@ -6,8 +6,8 @@ core = 7.x files[] = statistics.test configure = admin/config/system/statistics -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/statistics/statistics.test b/modules/statistics/statistics.test index a40ecc80e..d2155da6c 100644 --- a/modules/statistics/statistics.test +++ b/modules/statistics/statistics.test @@ -92,18 +92,18 @@ class StatisticsLoggingTestCase extends DrupalWebTestCase { // Verify logging of an uncached page. $this->drupalGet($path); - $this->assertIdentical($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', t('Testing an uncached page.')); + $this->assertIdentical($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', 'Testing an uncached page.'); $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC); - $this->assertTrue(is_array($log) && count($log) == 1, t('Page request was logged.')); + $this->assertTrue(is_array($log) && count($log) == 1, 'Page request was logged.'); $this->assertEqual(array_intersect_key($log[0], $expected), $expected); $node_counter = statistics_get($this->node->nid); $this->assertIdentical($node_counter['totalcount'], '1'); // Verify logging of a cached page. $this->drupalGet($path); - $this->assertIdentical($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', t('Testing a cached page.')); + $this->assertIdentical($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', 'Testing a cached page.'); $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC); - $this->assertTrue(is_array($log) && count($log) == 2, t('Page request was logged.')); + $this->assertTrue(is_array($log) && count($log) == 2, 'Page request was logged.'); $this->assertEqual(array_intersect_key($log[1], $expected), $expected); $node_counter = statistics_get($this->node->nid); $this->assertIdentical($node_counter['totalcount'], '2'); @@ -113,7 +113,7 @@ class StatisticsLoggingTestCase extends DrupalWebTestCase { $this->drupalGet($path); $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC); // Check the 6th item since login and account pages are also logged - $this->assertTrue(is_array($log) && count($log) == 6, t('Page request was logged.')); + $this->assertTrue(is_array($log) && count($log) == 6, 'Page request was logged.'); $this->assertEqual(array_intersect_key($log[5], $expected), $expected); $node_counter = statistics_get($this->node->nid); $this->assertIdentical($node_counter['totalcount'], '3'); @@ -126,11 +126,16 @@ class StatisticsLoggingTestCase extends DrupalWebTestCase { ); $this->drupalGet($path); $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC); - $this->assertTrue(is_array($log) && count($log) == 7, t('Page request was logged.')); + $this->assertTrue(is_array($log) && count($log) == 7, 'Page request was logged.'); $this->assertEqual(array_intersect_key($log[6], $expected), $expected); - // Create a path longer than 255 characters. - $long_path = $this->randomName(256); + // Create a path longer than 255 characters. Drupal's .htaccess file + // instructs Apache to test paths against the file system before routing to + // index.php. Many file systems restrict file names to 255 characters + // (http://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits), and + // Apache returns a 403 when testing longer file names, but the total path + // length is not restricted. + $long_path = $this->randomName(127) . '/' . $this->randomName(128); // Test that the long path is properly truncated when logged. $this->drupalGet($long_path); @@ -158,9 +163,9 @@ class StatisticsReportsTestCase extends StatisticsTestCase { */ function testRecentHits() { $this->drupalGet('admin/reports/hits'); - $this->assertText('test', t('Hit title found.')); - $this->assertText('node/1', t('Hit URL found.')); - $this->assertText('Anonymous', t('Hit user found.')); + $this->assertText('test', 'Hit title found.'); + $this->assertText('node/1', 'Hit URL found.'); + $this->assertText('Anonymous', 'Hit user found.'); } /** @@ -168,8 +173,8 @@ class StatisticsReportsTestCase extends StatisticsTestCase { */ function testTopPages() { $this->drupalGet('admin/reports/pages'); - $this->assertText('test', t('Hit title found.')); - $this->assertText('node/1', t('Hit URL found.')); + $this->assertText('test', 'Hit title found.'); + $this->assertText('node/1', 'Hit URL found.'); } /** @@ -177,7 +182,7 @@ class StatisticsReportsTestCase extends StatisticsTestCase { */ function testTopReferrers() { $this->drupalGet('admin/reports/referrers'); - $this->assertText('http://example.com', t('Hit referrer found.')); + $this->assertText('http://example.com', 'Hit referrer found.'); } /** @@ -185,9 +190,9 @@ class StatisticsReportsTestCase extends StatisticsTestCase { */ function testDetails() { $this->drupalGet('admin/reports/access/1'); - $this->assertText('test', t('Hit title found.')); - $this->assertText('node/1', t('Hit URL found.')); - $this->assertText('Anonymous', t('Hit user found.')); + $this->assertText('test', 'Hit title found.'); + $this->assertText('node/1', 'Hit URL found.'); + $this->assertText('Anonymous', 'Hit user found.'); } /** @@ -196,8 +201,8 @@ class StatisticsReportsTestCase extends StatisticsTestCase { function testAccessLogging() { $this->drupalGet('admin/reports/referrers'); $this->drupalGet('admin/reports/hits'); - $this->assertText('Top referrers in the past 3 days', t('Hit title found.')); - $this->assertText('admin/reports/referrers', t('Hit URL found.')); + $this->assertText('Top referrers in the past 3 days', 'Hit title found.'); + $this->assertText('admin/reports/referrers', 'Hit URL found.'); } /** @@ -222,12 +227,12 @@ class StatisticsReportsTestCase extends StatisticsTestCase { // Get some page and check if the block is displayed. $this->drupalGet('user'); - $this->assertText('Popular content', t('Found the popular content block.')); - $this->assertText("Today's", t('Found today\'s popular content.')); - $this->assertText('All time', t('Found the alll time popular content.')); - $this->assertText('Last viewed', t('Found the last viewed popular content.')); + $this->assertText('Popular content', 'Found the popular content block.'); + $this->assertText("Today's", 'Found today\'s popular content.'); + $this->assertText('All time', 'Found the alll time popular content.'); + $this->assertText('Last viewed', 'Found the last viewed popular content.'); - $this->assertRaw(l($node->title, 'node/' . $node->nid), t('Found link to visited node.')); + $this->assertRaw(l($node->title, 'node/' . $node->nid), 'Found link to visited node.'); } } @@ -254,30 +259,30 @@ class StatisticsBlockVisitorsTestCase extends StatisticsTestCase { // and that a 'block IP address' link is displayed. $this->drupalLogin($this->blocking_user); $this->drupalGet('admin/reports/visitors'); - $this->assertText($test_ip_address, t('IP address found.')); - $this->assertText(t('block IP address'), t('Block IP link displayed')); + $this->assertText($test_ip_address, 'IP address found.'); + $this->assertText(t('block IP address'), 'Block IP link displayed'); // Block the IP address. $this->clickLink('block IP address'); - $this->assertText(t('IP address blocking'), t('IP blocking page displayed.')); + $this->assertText(t('IP address blocking'), 'IP blocking page displayed.'); $edit = array(); $edit['ip'] = $test_ip_address; $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add')); $ip = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $edit['ip']))->fetchField(); - $this->assertNotEqual($ip, FALSE, t('IP address found in database')); - $this->assertRaw(t('The IP address %ip has been blocked.', array('%ip' => $edit['ip'])), t('IP address was blocked.')); + $this->assertNotEqual($ip, FALSE, 'IP address found in database'); + $this->assertRaw(t('The IP address %ip has been blocked.', array('%ip' => $edit['ip'])), 'IP address was blocked.'); // Verify that the block/unblock link on the top visitors page has been // altered. $this->drupalGet('admin/reports/visitors'); - $this->assertText(t('unblock IP address'), t('Unblock IP address link displayed')); + $this->assertText(t('unblock IP address'), 'Unblock IP address link displayed'); // Unblock the IP address. $this->clickLink('unblock IP address'); - $this->assertRaw(t('Are you sure you want to delete %ip?', array('%ip' => $test_ip_address)), t('IP address deletion confirmation found.')); + $this->assertRaw(t('Are you sure you want to delete %ip?', array('%ip' => $test_ip_address)), 'IP address deletion confirmation found.'); $edit = array(); $this->drupalPost('admin/config/people/ip-blocking/delete/1', NULL, t('Delete')); - $this->assertRaw(t('The IP address %ip was deleted.', array('%ip' => $test_ip_address)), t('IP address deleted.')); + $this->assertRaw(t('The IP address %ip was deleted.', array('%ip' => $test_ip_address)), 'IP address deleted.'); } } @@ -321,32 +326,32 @@ class StatisticsAdminTestCase extends DrupalWebTestCase { * Verifies that the statistics settings page works. */ function testStatisticsSettings() { - $this->assertFalse(variable_get('statistics_enable_access_log', 0), t('Access log is disabled by default.')); - $this->assertFalse(variable_get('statistics_count_content_views', 0), t('Count content view log is disabled by default.')); + $this->assertFalse(variable_get('statistics_enable_access_log', 0), 'Access log is disabled by default.'); + $this->assertFalse(variable_get('statistics_count_content_views', 0), 'Count content view log is disabled by default.'); $this->drupalGet('admin/reports/pages'); - $this->assertRaw(t('No statistics available.'), t('Verifying text shown when no statistics is available.')); + $this->assertRaw(t('No statistics available.'), 'Verifying text shown when no statistics is available.'); // Enable access log and counter on content view. $edit['statistics_enable_access_log'] = 1; $edit['statistics_count_content_views'] = 1; $this->drupalPost('admin/config/system/statistics', $edit, t('Save configuration')); - $this->assertTrue(variable_get('statistics_enable_access_log'), t('Access log is enabled.')); - $this->assertTrue(variable_get('statistics_count_content_views'), t('Count content view log is enabled.')); + $this->assertTrue(variable_get('statistics_enable_access_log'), 'Access log is enabled.'); + $this->assertTrue(variable_get('statistics_count_content_views'), 'Count content view log is enabled.'); // Hit the node. $this->drupalGet('node/' . $this->test_node->nid); $this->drupalGet('admin/reports/pages'); - $this->assertText('node/1', t('Test node found.')); + $this->assertText('node/1', 'Test node found.'); // Hit the node again (the counter is incremented after the hit, so // "1 read" will actually be shown when the node is hit the second time). $this->drupalGet('node/' . $this->test_node->nid); - $this->assertText('1 read', t('Node is read once.')); + $this->assertText('1 read', 'Node is read once.'); $this->drupalGet('node/' . $this->test_node->nid); - $this->assertText('2 reads', t('Node is read 2 times.')); + $this->assertText('2 reads', 'Node is read 2 times.'); } /** @@ -395,10 +400,10 @@ class StatisticsAdminTestCase extends DrupalWebTestCase { $this->drupalPost(NULL, NULL, t('Cancel account')); // Confirm account cancellation request. $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login)); - $this->assertFalse(user_load($account->uid, TRUE), t('User is not found in the database.')); + $this->assertFalse(user_load($account->uid, TRUE), 'User is not found in the database.'); $this->drupalGet('admin/reports/visitors'); - $this->assertNoText($account->name, t('Did not find user in visitor statistics.')); + $this->assertNoText($account->name, 'Did not find user in visitor statistics.'); } /** @@ -412,10 +417,10 @@ class StatisticsAdminTestCase extends DrupalWebTestCase { $this->drupalGet('node/' . $this->test_node->nid); $this->drupalGet('node/' . $this->test_node->nid); - $this->assertText('1 read', t('Node is read once.')); + $this->assertText('1 read', 'Node is read once.'); $this->drupalGet('admin/reports/pages'); - $this->assertText('node/' . $this->test_node->nid, t('Hit URL found.')); + $this->assertText('node/' . $this->test_node->nid, 'Hit URL found.'); // statistics_cron will subtract the statistics_flush_accesslog_timer // variable from REQUEST_TIME in the delete query, so wait two secs here to @@ -424,14 +429,14 @@ class StatisticsAdminTestCase extends DrupalWebTestCase { $this->cronRun(); $this->drupalGet('admin/reports/pages'); - $this->assertNoText('node/' . $this->test_node->nid, t('No hit URL found.')); + $this->assertNoText('node/' . $this->test_node->nid, 'No hit URL found.'); $result = db_select('node_counter', 'nc') ->fields('nc', array('daycount')) ->condition('nid', $this->test_node->nid, '=') ->execute() ->fetchField(); - $this->assertFalse($result, t('Daycounter is zero.')); + $this->assertFalse($result, 'Daycounter is zero.'); } } @@ -470,11 +475,11 @@ class StatisticsTokenReplaceTestCase extends StatisticsTestCase { $tests['[node:last-view:short]'] = format_date($statistics['timestamp'], 'short'); // 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('node' => $node), array('language' => $language)); - $this->assertEqual($output, $expected, t('Statistics token %token replaced.', array('%token' => $input))); + $this->assertEqual($output, $expected, format_string('Statistics token %token replaced.', array('%token' => $input))); } } } diff --git a/modules/syslog/syslog.info b/modules/syslog/syslog.info index dbdd1e160..963d87c5e 100644 --- a/modules/syslog/syslog.info +++ b/modules/syslog/syslog.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = syslog.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/syslog/syslog.module b/modules/syslog/syslog.module index 132760626..af3eb0a0f 100644 --- a/modules/syslog/syslog.module +++ b/modules/syslog/syslog.module @@ -70,10 +70,11 @@ function syslog_form_system_logging_settings_alter(&$form, &$form_state) { $form['actions']['#weight'] = 1; } - /** +/** * Lists all possible syslog facilities for UNIX/Linux. * * @return array + * An array of syslog facilities for UNIX/Linux. */ function syslog_facility_list() { return array( diff --git a/modules/syslog/syslog.test b/modules/syslog/syslog.test index 1f7ab2ea8..4707bd0df 100644 --- a/modules/syslog/syslog.test +++ b/modules/syslog/syslog.test @@ -37,7 +37,7 @@ class SyslogTestCase extends DrupalWebTestCase { $this->drupalGet('admin/config/development/logging'); if ($this->parse()) { $field = $this->xpath('//option[@value=:value]', array(':value' => LOG_LOCAL6)); // Should be one field. - $this->assertTrue($field[0]['selected'] == 'selected', t('Facility value saved.')); + $this->assertTrue($field[0]['selected'] == 'selected', 'Facility value saved.'); } } } diff --git a/modules/system/html.tpl.php b/modules/system/html.tpl.php index 0e012774d..c3e24c946 100644 --- a/modules/system/html.tpl.php +++ b/modules/system/html.tpl.php @@ -39,6 +39,8 @@ * @see template_preprocess() * @see template_preprocess_html() * @see template_process() + * + * @ingroup themeable */ ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd"> diff --git a/modules/system/maintenance-page.tpl.php b/modules/system/maintenance-page.tpl.php index 31de3bb23..69d267f81 100644 --- a/modules/system/maintenance-page.tpl.php +++ b/modules/system/maintenance-page.tpl.php @@ -9,6 +9,8 @@ * * @see template_preprocess() * @see template_preprocess_maintenance_page() + * + * @ingroup themeable */ ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" diff --git a/modules/system/page.tpl.php b/modules/system/page.tpl.php index bd440afb2..bd61489e0 100644 --- a/modules/system/page.tpl.php +++ b/modules/system/page.tpl.php @@ -68,6 +68,8 @@ * @see template_preprocess_page() * @see template_process() * @see html.tpl.php + * + * @ingroup themeable */ ?> diff --git a/modules/system/region.tpl.php b/modules/system/region.tpl.php index b29e24f01..deb8d3aed 100644 --- a/modules/system/region.tpl.php +++ b/modules/system/region.tpl.php @@ -24,6 +24,8 @@ * @see template_preprocess() * @see template_preprocess_region() * @see template_process() + * + * @ingroup themeable */ ?> <?php if ($content): ?> diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc index 23a975b0c..061898c85 100644 --- a/modules/system/system.admin.inc +++ b/modules/system/system.admin.inc @@ -691,8 +691,16 @@ function _system_theme_settings_validate_path($path) { * Process system_theme_settings form submissions. */ function system_theme_settings_submit($form, &$form_state) { + // Exclude unnecessary elements before saving. + form_state_values_clean($form_state); + $values = $form_state['values']; + // Extract the name of the theme from the submitted form values, then remove + // it from the array so that it is not saved as part of the variable. + $key = $values['var']; + unset($values['var']); + // If the user uploaded a new logo or favicon, save it to a permanent location // and use it in place of the default theme-provided file. if ($file = $values['logo_upload']) { @@ -722,10 +730,7 @@ function system_theme_settings_submit($form, &$form_state) { if (empty($values['default_favicon']) && !empty($values['favicon_path'])) { $values['favicon_mimetype'] = file_get_mimetype($values['favicon_path']); } - $key = $values['var']; - // Exclude unnecessary elements before saving. - unset($values['var'], $values['submit'], $values['reset'], $values['form_id'], $values['op'], $values['form_build_id'], $values['form_token']); variable_set($key, $values); drupal_set_message(t('The configuration options have been saved.')); @@ -808,7 +813,7 @@ function system_modules($form, $form_state = array()) { // Used when checking if module implements a help page. $help_arg = module_exists('help') ? drupal_help_arg() : FALSE; - // Used when displaying modules that are required by the install profile. + // Used when displaying modules that are required by the installation profile. require_once DRUPAL_ROOT . '/includes/install.inc'; $distribution_name = check_plain(drupal_install_profile_distribution_name()); @@ -1269,8 +1274,8 @@ function system_modules_uninstall($form, $form_state = NULL) { '#title_display' => 'invisible', ); // All modules which depend on this one must be uninstalled first, before - // we can allow this module to be uninstalled. (The install profile is - // excluded from this list.) + // we can allow this module to be uninstalled. (The installation profile + // is excluded from this list.) foreach (array_keys($module->required_by) as $dependent) { if ($dependent != $profile && drupal_get_installed_schema_version($dependent) != SCHEMA_UNINSTALLED) { $dependent_name = isset($all_modules[$dependent]->info['name']) ? $all_modules[$dependent]->info['name'] : $dependent; diff --git a/modules/system/system.api.php b/modules/system/system.api.php index 79ac8f169..adef26141 100644 --- a/modules/system/system.api.php +++ b/modules/system/system.api.php @@ -85,8 +85,8 @@ function hook_hook_info_alter(&$hooks) { * - load hook: The name of the hook which should be invoked by * DrupalDefaultEntityController:attachLoad(), for example 'node_load'. * - uri callback: A function taking an entity as argument and returning the - * uri elements of the entity, e.g. 'path' and 'options'. The actual entity - * uri can be constructed by passing these elements to url(). + * URI elements of the entity, e.g. 'path' and 'options'. The actual entity + * URI can be constructed by passing these elements to url(). * - label callback: (optional) A function taking an entity and an entity type * as arguments and returning the label of the entity. The entity label is * the main string associated with an entity; for example, the title of a @@ -465,6 +465,24 @@ function hook_entity_view_alter(&$build, $type) { } } +/** + * Change the view mode of an entity that is being displayed. + * + * @param string $view_mode + * The view_mode that is to be used to display the entity. + * @param array $context + * Array with contextual information, including: + * - entity_type: The type of the entity that is being viewed. + * - entity: The entity object. + * - langcode: The langcode the entity is being viewed in. + */ +function hook_entity_view_mode_alter(&$view_mode, $context) { + // For nodes, change the view mode when it is teaser. + if ($context['entity_type'] == 'node' && $view_mode == 'teaser') { + $view_mode = 'my_custom_view_mode'; + } +} + /** * Define administrative paths. * @@ -623,7 +641,7 @@ function hook_cron_queue_info_alter(&$queues) { } /** - * Allows modules to declare their own Forms API element types and specify their + * Allows modules to declare their own Form API element types and specify their * default values. * * This hook allows modules to declare their own form element types and to @@ -689,7 +707,8 @@ function hook_element_info_alter(&$type) { * Perform cleanup tasks. * * This hook is run at the end of each page request. It is often used for - * page logging and specialized cleanup. This hook MUST NOT print anything. + * page logging and specialized cleanup. This hook MUST NOT print anything + * because by the time it runs the response is already sent to the browser. * * Only use this hook if your code must run even for cached page views. * If you have code which must run once on all non-cached pages, use @@ -1040,7 +1059,7 @@ function hook_menu_get_item_alter(&$router_item, $path, $original_map) { * This 'abc' object will then be passed into the callback functions defined * for the menu item, such as the page callback function mymodule_abc_edit() * to replace the integer 1 in the argument array. Note that a load function - * should return FALSE when it is unable to provide a loadable object. For + * should return FALSE when it is unable to provide a loadable object. For * example, the node_load() function for the 'node/%node/edit' menu item will * return FALSE for the path 'node/999/edit' if a node with a node ID of 999 * does not exist. The menu routing system will return a 404 error in this case. @@ -1632,6 +1651,7 @@ function hook_page_alter(&$page) { * * @see hook_form_BASE_FORM_ID_alter() * @see hook_form_FORM_ID_alter() + * @see forms_api_reference.html */ function hook_form_alter(&$form, &$form_state, $form_id) { if (isset($form['type']) && $form['type']['#value'] . '_node_settings' == $form_id) { @@ -1668,6 +1688,7 @@ function hook_form_alter(&$form, &$form_state, $form_id) { * @see hook_form_alter() * @see hook_form_BASE_FORM_ID_alter() * @see drupal_prepare_form() + * @see forms_api_reference.html */ function hook_form_FORM_ID_alter(&$form, &$form_state, $form_id) { // Modification for the form with the given form ID goes here. For example, if @@ -1959,7 +1980,7 @@ function hook_mail_alter(&$message) { * purposes of hook_module_implements_alter(), these variants are treated as * a single hook. Thus, to ensure that your implementation of * hook_form_FORM_ID_alter() is called at the right time, you will have to - * have to change the order of hook_form_alter() implementation in + * change the order of hook_form_alter() implementation in * hook_module_implements_alter(). * * @param $implementations @@ -2147,6 +2168,9 @@ function hook_permission() { * registers the 'node' theme hook, 'theme_node' will be assigned to its * function. If the chameleon theme registers the node hook, it will be * assigned 'chameleon_node' as its function. + * - base hook: A string declaring the base theme hook if this theme + * implementation is actually implementing a suggestion for another theme + * hook. * - pattern: A regular expression pattern to be used to allow this theme * implementation to have a dynamic name. The convention is to use __ to * differentiate the dynamic portion of the theme. For example, to allow @@ -2958,7 +2982,7 @@ function hook_file_url_alter(&$uri) { * The returned 'requirements' will be listed on the status report in the * administration section, with indication of the severity level. * Moreover, any requirement with a severity of REQUIREMENT_ERROR severity will - * result in a notice on the the administration overview page. + * result in a notice on the administration configuration page. * * @param $phase * The phase in which requirements are checked: @@ -2983,7 +3007,7 @@ function hook_file_url_alter(&$uri) { */ function hook_requirements($phase) { $requirements = array(); - // Ensure translations don't break at install time + // Ensure translations don't break during installation. $t = get_t(); // Report Drupal version @@ -3035,7 +3059,7 @@ function hook_requirements($phase) { * more tables and their related keys and indexes. A schema is defined by * hook_schema() which must live in your module's .install file. * - * This hook is called at both install and uninstall time, and in the latter + * This hook is called at install and uninstall time, and in the latter * case, it cannot rely on the .module file being loaded or hooks being known. * If the .module file is needed, it may be loaded with drupal_load(). * @@ -3284,6 +3308,17 @@ function hook_install() { * the same directory as mymodule.module. Drupal core's updates are implemented * using the system module as a name and stored in database/updates.inc. * + * Not all module functions are available from within a hook_update_N() function. + * In order to call a function from your mymodule.module or an include file, + * you need to explicitly load that file first. + * + * During database updates the schema of any module could be out of date. For + * this reason, caution is needed when using any API function within an update + * function - particularly CRUD functions, functions that depend on the schema + * (for example by using drupal_write_record()), and any functions that invoke + * hooks. See @link update_api Update versions of API functions @endlink for + * details. + * * If your update task is potentially time-consuming, you'll need to implement a * multipass update to avoid PHP timeouts. Multipass updates use the $sandbox * parameter provided by the batch API (normally, $context['sandbox']) to store @@ -3308,6 +3343,7 @@ function hook_install() { * * @see batch * @see schemaapi + * @see update_api * @see hook_update_last_removed() * @see update_get_update_list() */ @@ -3735,7 +3771,7 @@ function hook_drupal_goto_alter(&$path, &$options, &$http_response_code) { function hook_html_head_alter(&$head_elements) { foreach ($head_elements as $key => $element) { if (isset($element['#attributes']['rel']) && $element['#attributes']['rel'] == 'canonical') { - // I want a custom canonical url. + // I want a custom canonical URL. $head_elements[$key]['#attributes']['href'] = mymodule_canonical_url(); } } @@ -4631,3 +4667,114 @@ function hook_filetransfer_info_alter(&$filetransfer_info) { /** * @} End of "addtogroup hooks". */ + +/** + * @defgroup update_api Update versions of API functions + * @{ + * Functions that are similar to normal API functions, but do not invoke hooks. + * + * These simplified versions of core API functions are provided for use by + * update functions (hook_update_N() implementations). + * + * During database updates the schema of any module could be out of date. For + * this reason, caution is needed when using any API function within an update + * function - particularly CRUD functions, functions that depend on the schema + * (for example by using drupal_write_record()), and any functions that invoke + * hooks. + * + * Instead, a simplified utility function should be used. If a utility version + * of the API function you require does not already exist, then you should + * create a new function. The new utility function should be named + * _update_N_mymodule_my_function(). N is the schema version the function acts + * on (the schema version is the number N from the hook_update_N() + * implementation where this schema was introduced, or a number following the + * same numbering scheme), and mymodule_my_function is the name of the original + * API function including the module's name. + * + * Examples: + * - _update_6000_mymodule_save(): This function performs a save operation + * without invoking any hooks using the 6.x schema. + * - _update_7000_mymodule_save(): This function performs the same save + * operation using the 7.x schema. + * + * The utility function should not invoke any hooks, and should perform database + * operations using functions from the + * @link database Database abstraction layer, @endlink + * like db_insert(), db_update(), db_delete(), db_query(), and so on. + * + * If a change to the schema necessitates a change to the utility function, a + * new function should be created with a name based on the version of the schema + * it acts on. See _update_7000_bar_get_types() and _update_7001_bar_get_types() + * in the code examples that follow. + * + * For example, foo.install could contain: + * @code + * function foo_update_dependencies() { + * // foo_update_7010() needs to run after bar_update_7000(). + * $dependencies['foo'][7010] = array( + * 'bar' => 7000, + * ); + * + * // foo_update_7036() needs to run after bar_update_7001(). + * $dependencies['foo'][7036] = array( + * 'bar' => 7001, + * ); + * + * return $dependencies; + * } + * + * function foo_update_7000() { + * // No updates have been run on the {bar_types} table yet, so this needs + * // to work with the 6.x schema. + * foreach (_update_6000_bar_get_types() as $type) { + * // Rename a variable. + * } + * } + * + * function foo_update_7010() { + * // Since foo_update_7010() is going to run after bar_update_7000(), it + * // needs to operate on the new schema, not the old one. + * foreach (_update_7000_bar_get_types() as $type) { + * // Rename a different variable. + * } + * } + * + * function foo_update_7036() { + * // This update will run after bar_update_7001(). + * foreach (_update_7001_bar_get_types() as $type) { + * } + * } + * @endcode + * + * And bar.install could contain: + * @code + * function bar_update_7000() { + * // Type and bundle are confusing, so we renamed the table. + * db_rename_table('bar_types', 'bar_bundles'); + * } + * + * function bar_update_7001() { + * // Database table names should be singular when possible. + * db_rename_table('bar_bundles', 'bar_bundle'); + * } + * + * function _update_6000_bar_get_types() { + * db_query('SELECT * FROM {bar_types}')->fetchAll(); + * } + * + * function _update_7000_bar_get_types() { + * db_query('SELECT * FROM {bar_bundles'})->fetchAll(); + * } + * + * function _update_7001_bar_get_types() { + * db_query('SELECT * FROM {bar_bundle}')->fetchAll(); + * } + * @endcode + * + * @see hook_update_N() + * @see hook_update_dependencies() + */ + +/** + * @} End of "defgroup update_api". + */ diff --git a/modules/system/system.base.css b/modules/system/system.base.css index 65383dd34..412b18a82 100644 --- a/modules/system/system.base.css +++ b/modules/system/system.base.css @@ -231,6 +231,8 @@ html.js .js-hide { position: absolute !important; clip: rect(1px 1px 1px 1px); /* IE6, IE7 */ clip: rect(1px, 1px, 1px, 1px); + overflow: hidden; + height: 1px; } /** @@ -241,6 +243,8 @@ html.js .js-hide { .element-invisible.element-focusable:focus { position: static !important; clip: auto; + overflow: visible; + height: auto; } /** diff --git a/modules/system/system.info b/modules/system/system.info index e1d603846..fab267a71 100644 --- a/modules/system/system.info +++ b/modules/system/system.info @@ -12,8 +12,8 @@ files[] = system.test required = TRUE configure = admin/config/system -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/system/system.install b/modules/system/system.install index 1161d6cdd..7b667678e 100644 --- a/modules/system/system.install +++ b/modules/system/system.install @@ -16,7 +16,7 @@ function system_requirements($phase) { global $base_url; $requirements = array(); - // Ensure translations don't break at install time + // Ensure translations don't break during installation. $t = get_t(); // Report Drupal version @@ -28,8 +28,8 @@ function system_requirements($phase) { 'weight' => -10, ); - // Display the currently active install profile, if the site - // is not running the default install profile. + // Display the currently active installation profile, if the site + // is not running the default installation profile. $profile = drupal_get_profile(); if ($profile != 'standard') { $info = system_get_info('module', $profile); @@ -308,7 +308,7 @@ function system_requirements($phase) { variable_get('file_private_path', FALSE), ); - // Do not check for the temporary files directory at install time + // Do not check for the temporary files directory during installation // unless it has been set in settings.php. In this case the user has // no alternative but to fix the directory if it is not writable. if ($phase == 'install') { @@ -412,7 +412,7 @@ function system_requirements($phase) { $profile = drupal_get_profile(); $files = system_rebuild_module_data(); foreach ($files as $module => $file) { - // Ignore disabled modules and install profiles. + // Ignore disabled modules and installation profiles. if (!$file->status || $module == $profile) { continue; } @@ -810,7 +810,6 @@ function system_schema() { 'length' => 255, 'not null' => TRUE, 'default' => '', - 'binary' => TRUE, ), 'uri' => array( 'description' => 'The URI to access the file (either local or remote).', @@ -1689,6 +1688,12 @@ function system_update_dependencies() { 'block' => 7002, ); + // system_update_7061() queries the {node_revision} table, so it must run + // after node_update_7001(), which renames the {node_revisions} table. + $dependencies['system'][7061] = array( + 'node' => 7001, + ); + // system_update_7067() migrates role permissions and therefore must run // after the {role} and {role_permission} tables are properly set up, which // happens in user_update_7007(). @@ -1711,17 +1716,18 @@ function system_update_dependencies() { function system_update_7000() { $result = db_query("SELECT rid, perm FROM {permission} ORDER BY rid"); foreach ($result as $role) { - $renamed_permission = preg_replace('/(?<=^|,\ )create\ blog\ entries(?=,|$)/', 'create blog content', $role->perm); - $renamed_permission = preg_replace('/(?<=^|,\ )edit\ own\ blog\ entries(?=,|$)/', 'edit own blog content', $role->perm); - $renamed_permission = preg_replace('/(?<=^|,\ )edit\ any\ blog\ entry(?=,|$)/', 'edit any blog content', $role->perm); - $renamed_permission = preg_replace('/(?<=^|,\ )delete\ own\ blog\ entries(?=,|$)/', 'delete own blog content', $role->perm); - $renamed_permission = preg_replace('/(?<=^|,\ )delete\ any\ blog\ entry(?=,|$)/', 'delete any blog content', $role->perm); - - $renamed_permission = preg_replace('/(?<=^|,\ )create\ forum\ topics(?=,|$)/', 'create forum content', $role->perm); - $renamed_permission = preg_replace('/(?<=^|,\ )delete\ any\ forum\ topic(?=,|$)/', 'delete any forum content', $role->perm); - $renamed_permission = preg_replace('/(?<=^|,\ )delete\ own\ forum\ topics(?=,|$)/', 'delete own forum content', $role->perm); - $renamed_permission = preg_replace('/(?<=^|,\ )edit\ any\ forum\ topic(?=,|$)/', 'edit any forum content', $role->perm); - $renamed_permission = preg_replace('/(?<=^|,\ )edit\ own\ forum\ topics(?=,|$)/', 'edit own forum content', $role->perm); + $renamed_permission = $role->perm; + $renamed_permission = preg_replace('/(?<=^|,\ )create\ blog\ entries(?=,|$)/', 'create blog content', $renamed_permission); + $renamed_permission = preg_replace('/(?<=^|,\ )edit\ own\ blog\ entries(?=,|$)/', 'edit own blog content', $renamed_permission); + $renamed_permission = preg_replace('/(?<=^|,\ )edit\ any\ blog\ entry(?=,|$)/', 'edit any blog content', $renamed_permission); + $renamed_permission = preg_replace('/(?<=^|,\ )delete\ own\ blog\ entries(?=,|$)/', 'delete own blog content', $renamed_permission); + $renamed_permission = preg_replace('/(?<=^|,\ )delete\ any\ blog\ entry(?=,|$)/', 'delete any blog content', $renamed_permission); + + $renamed_permission = preg_replace('/(?<=^|,\ )create\ forum\ topics(?=,|$)/', 'create forum content', $renamed_permission); + $renamed_permission = preg_replace('/(?<=^|,\ )delete\ any\ forum\ topic(?=,|$)/', 'delete any forum content', $renamed_permission); + $renamed_permission = preg_replace('/(?<=^|,\ )delete\ own\ forum\ topics(?=,|$)/', 'delete own forum content', $renamed_permission); + $renamed_permission = preg_replace('/(?<=^|,\ )edit\ any\ forum\ topic(?=,|$)/', 'edit any forum content', $renamed_permission); + $renamed_permission = preg_replace('/(?<=^|,\ )edit\ own\ forum\ topics(?=,|$)/', 'edit own forum content', $renamed_permission); if ($renamed_permission != $role->perm) { db_update('permission') @@ -2729,6 +2735,26 @@ function system_update_7061(&$sandbox) { } if (!isset($sandbox['progress'])) { + // Delete stale rows from {upload} where the fid is not in the {files} table. + db_delete('upload') + ->notExists( + db_select('files', 'f') + ->fields('f', array('fid')) + ->where('f.fid = {upload}.fid') + ) + ->execute(); + + // Delete stale rows from {upload} where the vid is not in the + // {node_revision} table. The table has already been renamed in + // node_update_7001(). + db_delete('upload') + ->notExists( + db_select('node_revision', 'nr') + ->fields('nr', array('vid')) + ->where('nr.vid = {upload}.vid') + ) + ->execute(); + // Retrieve a list of node revisions that have uploaded files attached. // DISTINCT queries are expensive, especially when paged, so we store the // data in its own table for the duration of the update. @@ -2793,7 +2819,7 @@ function system_update_7061(&$sandbox) { $scheme = file_default_scheme() . '://'; foreach ($node_revisions as $vid => $revision) { foreach ($revision['file'][LANGUAGE_NONE] as $delta => $file) { - // We will convert filepaths to uri using the default scheme + // We will convert filepaths to URI using the default scheme // and stripping off the existing file directory path. $file['uri'] = $scheme . preg_replace('!^' . preg_quote($basename) . '!', '', $file['filepath']); $file['uri'] = file_stream_wrapper_uri_normalize($file['uri']); @@ -2958,8 +2984,9 @@ function system_update_7069() { */ /** - * @defgroup updates-7.x-extra Extra system updates for 7.x + * @defgroup updates-7.x-extra Extra updates for 7.x * @{ + * Update functions between 7.x versions. */ /** @@ -3024,6 +3051,41 @@ function system_update_7074() { // PostgreSQL. } +/** + * Convert menu_links query strings into arrays. + */ +function system_update_7076() { + $query = db_select('menu_links', 'ml', array('fetch' => PDO::FETCH_ASSOC)) + ->fields('ml', array('mlid', 'options')); + foreach ($query->execute() as $menu_link) { + if (strpos($menu_link['options'], 'query') !== FALSE) { + $menu_link['options'] = unserialize($menu_link['options']); + if (isset($menu_link['options']['query']) && is_string($menu_link['options']['query'])) { + $menu_link['options']['query'] = drupal_get_query_array($menu_link['options']['query']); + db_update('menu_links') + ->fields(array( + 'options' => serialize($menu_link['options']), + )) + ->condition('mlid', $menu_link['mlid'], '=') + ->execute(); + } + } + } +} + +/** + * Revert {file_managed}.filename changed to a binary column. + */ +function system_update_7077() { + db_change_field('file_managed', 'filename', 'filename', array( + 'description' => 'Name of the file with no path components. This may differ from the basename of the URI if the file is renamed to avoid overwriting an existing file.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + )); +} + /** * @} End of "defgroup updates-7.x-extra". * The next series of updates should start at 8000. diff --git a/modules/system/system.module b/modules/system/system.module index 9897fb25e..d47ab8a81 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -1740,16 +1740,27 @@ function _system_themes_access($theme) { /** * Setup a given callback to run via authorize.php with elevated privileges. * - * To use authorize.php, certain variables must be stashed into $_SESSION. - * This function sets up all the necessary $_SESSION variables, then returns - * the full path to authorize.php so the caller can redirect to authorize.php. - * That initiates the workflow that will eventually lead to the callback being - * invoked. The callback will be invoked at a low bootstrap level, without all - * modules being invoked, so it needs to be careful not to assume any code - * exists. + * To use authorize.php, certain variables must be stashed into $_SESSION. This + * function sets up all the necessary $_SESSION variables. The calling function + * should then redirect to authorize.php, using the full path returned by + * system_authorized_get_url(). That initiates the workflow that will eventually + * lead to the callback being invoked. The callback will be invoked at a low + * bootstrap level, without all modules being invoked, so it needs to be careful + * not to assume any code exists. Example (system_authorized_run()): + * @code + * system_authorized_init($callback, $file, $arguments, $page_title); + * drupal_goto(system_authorized_get_url()); + * @endcode + * Example (update_manager_install_form_submit()): + * @code + * system_authorized_init('update_authorize_run_install', + * drupal_get_path('module', 'update') . '/update.authorize.inc', + * $arguments, t('Update manager')); + * $form_state['redirect'] = system_authorized_get_url(); + * @endcode * * @param $callback - * The name of the function to invoke one the user authorizes the operation. + * The name of the function to invoke once the user authorizes the operation. * @param $file * The full path to the file where the callback function is implemented. * @param $arguments @@ -1785,11 +1796,13 @@ function system_authorized_init($callback, $file, $arguments = array(), $page_ti * @param array $options * Optional array of options to pass to url(). * @return - * The full URL to authorize.php, using https if available. + * The full URL to authorize.php, using HTTPS if available. + * + * @see system_authorized_init() */ function system_authorized_get_url(array $options = array()) { global $base_url; - // Force https if available, regardless of what the caller specifies. + // Force HTTPS if available, regardless of what the caller specifies. $options['https'] = TRUE; // We prefix with $base_url so we get a full path even if clean URLs are // disabled. @@ -2348,14 +2361,14 @@ function _system_rebuild_module_data() { // Find modules $modules = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.module$/', 'modules', 'name', 0); - // Include the install profile in modules that are loaded. + // Include the installation profile in modules that are loaded. $profile = drupal_get_profile(); $modules[$profile] = new stdClass(); $modules[$profile]->name = $profile; $modules[$profile]->uri = 'profiles/' . $profile . '/' . $profile . '.profile'; $modules[$profile]->filename = $profile . '.profile'; - // Install profile hooks are always executed last. + // Installation profile hooks are always executed last. $modules[$profile]->weight = 1000; // Set defaults for module info. @@ -2396,7 +2409,7 @@ function _system_rebuild_module_data() { $module->info['scripts'] = _system_info_add_path($module->info['scripts'], $path); } - // Install profiles are hidden by default, unless explicitly specified + // Installation profiles are hidden by default, unless explicitly specified // otherwise in the .info file. if ($key == $profile && !isset($modules[$key]->info['hidden'])) { $modules[$key]->info['hidden'] = TRUE; @@ -2409,7 +2422,7 @@ function _system_rebuild_module_data() { } if (isset($modules[$profile])) { - // The install profile is required, if it's a valid module. + // The installation profile is required, if it's a valid module. $modules[$profile]->info['required'] = TRUE; // Add a default distribution name if the profile did not provide one. This // matches the default value used in install_profile_info(). @@ -3759,7 +3772,7 @@ function _system_date_formats_build() { } // Get custom formats added to the database by the end user. - $result = db_query('SELECT df.dfid, df.format, df.type, df.locked, dfl.language FROM {date_formats} df LEFT JOIN {date_format_type} dft ON df.type = dft.type LEFT JOIN {date_format_locale} dfl ON df.format = dfl.format AND df.type = dfl.type ORDER BY df.type, df.format'); + $result = db_query('SELECT df.dfid, df.format, df.type, df.locked, dfl.language FROM {date_formats} df LEFT JOIN {date_format_locale} dfl ON df.format = dfl.format AND df.type = dfl.type ORDER BY df.type, df.format'); foreach ($result as $record) { // If this date type isn't set, initialise the array. if (!isset($date_formats[$record->type])) { diff --git a/modules/system/theme.api.php b/modules/system/theme.api.php index cd7ecfde8..6865421cf 100644 --- a/modules/system/theme.api.php +++ b/modules/system/theme.api.php @@ -70,8 +70,8 @@ * Allow themes to alter the theme-specific settings form. * * With this hook, themes can alter the theme-specific settings form in any way - * allowable by Drupal's Forms API, such as adding form elements, changing - * default values and removing form elements. See the Forms API documentation on + * allowable by Drupal's Form API, such as adding form elements, changing + * default values and removing form elements. See the Form API documentation on * api.drupal.org for detailed information. * * Note that the base theme's form alterations will be run before any sub-theme diff --git a/modules/taxonomy/taxonomy-term.tpl.php b/modules/taxonomy/taxonomy-term.tpl.php index b1ff20e3c..d410d1ef3 100644 --- a/modules/taxonomy/taxonomy-term.tpl.php +++ b/modules/taxonomy/taxonomy-term.tpl.php @@ -11,7 +11,7 @@ * such as render($content['field_example']). Use * hide($content['field_example']) to temporarily suppress the printing of a * given element. - * - $term_url: Direct url of the current term. + * - $term_url: Direct URL of the current term. * - $term_name: Name of the current term. * - $classes: String of classes that can be used to style contextually through * CSS. It can be manipulated through the variable $classes_array from @@ -36,6 +36,8 @@ * @see template_preprocess() * @see template_preprocess_taxonomy_term() * @see template_process() + * + * @ingroup themeable */ ?> <div id="taxonomy-term-<?php print $term->tid; ?>" class="<?php print $classes; ?>"> diff --git a/modules/taxonomy/taxonomy.api.php b/modules/taxonomy/taxonomy.api.php index cb778c9a7..5667eb96d 100644 --- a/modules/taxonomy/taxonomy.api.php +++ b/modules/taxonomy/taxonomy.api.php @@ -181,6 +181,30 @@ function hook_taxonomy_term_delete($term) { db_delete('term_synoynm')->condition('tid', $term->tid)->execute(); } +/** + * Act on a taxonomy term that is being assembled before rendering. + * + * The module may add elements to $term->content prior to rendering. The + * structure of $term->content is a renderable array as expected by + * drupal_render(). + * + * @param $term + * The term that is being assembled for rendering. + * @param $view_mode + * The $view_mode parameter from taxonomy_term_view(). + * @param $langcode + * The language code used for rendering. + * + * @see hook_entity_view() + */ +function hook_taxonomy_term_view($term, $view_mode, $langcode) { + $term->content['my_additional_field'] = array( + '#markup' => $additional_field, + '#weight' => 10, + '#theme' => 'mymodule_my_additional_field', + ); +} + /** * Alter the results of taxonomy_term_view(). * diff --git a/modules/taxonomy/taxonomy.info b/modules/taxonomy/taxonomy.info index a6ecfe202..2a565ab05 100644 --- a/modules/taxonomy/taxonomy.info +++ b/modules/taxonomy/taxonomy.info @@ -8,8 +8,8 @@ files[] = taxonomy.module files[] = taxonomy.test configure = admin/structure/taxonomy -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/taxonomy/taxonomy.install b/modules/taxonomy/taxonomy.install index 711a0f983..c353c9c8c 100644 --- a/modules/taxonomy/taxonomy.install +++ b/modules/taxonomy/taxonomy.install @@ -266,7 +266,7 @@ function taxonomy_update_dependencies() { * * This function is valid for a database schema version 7002. * - * @ingroup update-api-6.x-to-7.x + * @ingroup update_api */ function _update_7002_taxonomy_get_vocabularies() { return db_query('SELECT v.* FROM {taxonomy_vocabulary} v ORDER BY v.weight, v.name')->fetchAllAssoc('vid', PDO::FETCH_OBJ); diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module index d501282fe..9be7dfcbe 100644 --- a/modules/taxonomy/taxonomy.module +++ b/modules/taxonomy/taxonomy.module @@ -140,7 +140,7 @@ function taxonomy_entity_info() { } /** - * Entity uri callback. + * Entity URI callback. */ function taxonomy_term_uri($term) { return array( @@ -323,8 +323,8 @@ function taxonomy_menu() { ); $items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name'] = array( - 'title callback' => 'taxonomy_admin_vocabulary_title_callback', - 'title arguments' => array(3), + 'title callback' => 'entity_label', + 'title arguments' => array('taxonomy_vocabulary', 3), 'page callback' => 'drupal_get_form', 'page arguments' => array('taxonomy_overview_terms', 3), 'access arguments' => array('administer taxonomy'), @@ -375,7 +375,13 @@ function taxonomy_term_edit_access($term) { } /** - * Return the vocabulary name given the vocabulary object. + * Returns the sanitized name of a vocabulary. + * + * Deprecated. This function was previously used as a menu item title callback + * but has been replaced by using entity_label() (which does not + * sanitize the title, since the menu system does that automatically). In + * Drupal 7, use that function for title callbacks, and call check_plain() + * directly if you need a sanitized title. */ function taxonomy_admin_vocabulary_title_callback($vocabulary) { return check_plain($vocabulary->name); @@ -386,7 +392,8 @@ function taxonomy_admin_vocabulary_title_callback($vocabulary) { * * @param $vocabulary * A vocabulary object with the following properties: - * - vid: The ID of the vocabulary. + * - vid: (optional) The ID of the vocabulary (omit if creating a new + * vocabulary; only use to update an existing vocabulary). * - name: The human-readable name of the vocabulary. * - machine_name: The machine name of the vocabulary. * - description: (optional) The vocabulary's description. @@ -401,7 +408,7 @@ function taxonomy_admin_vocabulary_title_callback($vocabulary) { * * @return * Status constant indicating whether the vocabulary was inserted (SAVED_NEW) - * or updated(SAVED_UPDATED). + * or updated (SAVED_UPDATED). */ function taxonomy_vocabulary_save($vocabulary) { // Prevent leading and trailing spaces in vocabulary names. @@ -735,6 +742,114 @@ function taxonomy_term_delete($tid) { } } +/** + * Generates an array which displays a term detail page. + * + * @param term + * A taxonomy term object. + * @return + * A $page element suitable for use by drupal_page_render(). + */ +function taxonomy_term_show($term) { + return taxonomy_term_view_multiple(array($term->tid => $term), 'full'); +} + +/** + * Constructs a drupal_render() style array from an array of loaded terms. + * + * @param $terms + * An array of taxonomy terms as returned by taxonomy_term_load_multiple(). + * @param $view_mode + * View mode, e.g. 'full', 'teaser'... + * @param $weight + * An integer representing the weight of the first taxonomy term in the list. + * @param $langcode + * (optional) A language code to use for rendering. Defaults to the global + * content language of the current request. + * + * @return + * An array in the format expected by drupal_render(). + */ +function taxonomy_term_view_multiple($terms, $view_mode = 'teaser', $weight = 0, $langcode = NULL) { + field_attach_prepare_view('taxonomy_term', $terms, $view_mode, $langcode); + entity_prepare_view('taxonomy_term', $terms, $langcode); + $build = array(); + foreach ($terms as $term) { + $build['taxonomy_terms'][$term->tid] = taxonomy_term_view($term, $view_mode, $langcode); + $build['taxonomy_terms'][$term->tid]['#weight'] = $weight; + $weight++; + } + $build['taxonomy_terms']['#sorted'] = TRUE; + return $build; +} + +/** + * Builds a structured array representing the term's content. + * + * The content built for the taxonomy term (field values, file attachments or + * other term components) will vary depending on the $view_mode parameter. + * + * Drupal core defines the following view modes for terms, with the following + * default use cases: + * - full (default): term is displayed on its own page (taxonomy/term/123) + * Contributed modules might define additional view modes, or use existing + * view modes in additional contexts. + * + * @param $term + * A taxonomy term object. + * @param $view_mode + * View mode, e.g. 'full', 'teaser'... + * @param $langcode + * (optional) A language code to use for rendering. Defaults to the global + * content language of the current request. + */ +function taxonomy_term_build_content($term, $view_mode = 'full', $langcode = NULL) { + if (!isset($langcode)) { + $langcode = $GLOBALS['language_content']->language; + } + + // Remove previously built content, if exists. + $term->content = array(); + + // Allow modules to change the view mode. + $context = array( + 'entity_type' => 'taxonomy_term', + 'entity' => $term, + 'langcode' => $langcode, + ); + drupal_alter('entity_view_mode', $view_mode, $context); + + // Add the term description if the term has one and it is visible. + $type = 'taxonomy_term'; + $entity_ids = entity_extract_ids($type, $term); + $settings = field_view_mode_settings($type, $entity_ids[2]); + $fields = field_extra_fields_get_display($type, $entity_ids[2], $view_mode); + if (!empty($term->description) && isset($fields['description']) && $fields['description']['visible']) { + $term->content['description'] = array( + '#markup' => check_markup($term->description, $term->format, '', TRUE), + '#weight' => $fields['description']['weight'], + '#prefix' => '<div class="taxonomy-term-description">', + '#suffix' => '</div>', + ); + } + + // Build fields content. + // In case of a multiple view, taxonomy_term_view_multiple() already ran the + // 'prepare_view' step. An internal flag prevents the operation from running + // twice. + field_attach_prepare_view('taxonomy_term', array($term->tid => $term), $view_mode, $langcode); + entity_prepare_view('taxonomy_term', array($term->tid => $term), $langcode); + $term->content += field_attach_view('taxonomy_term', $term, $view_mode, $langcode); + + // Allow modules to make their own additions to the taxonomy term. + module_invoke_all('taxonomy_term_view', $term, $view_mode, $langcode); + module_invoke_all('entity_view', $term, 'taxonomy_term', $view_mode, $langcode); + + // Make sure the current view mode is stored if no module has already + // populated the related key. + $term->content += array('#view_mode' => $view_mode); +} + /** * Generate an array for rendering the given term. * @@ -754,31 +869,23 @@ function taxonomy_term_view($term, $view_mode = 'full', $langcode = NULL) { $langcode = $GLOBALS['language_content']->language; } - field_attach_prepare_view('taxonomy_term', array($term->tid => $term), $view_mode, $langcode); - entity_prepare_view('taxonomy_term', array($term->tid => $term), $langcode); + // Populate $term->content with a render() array. + taxonomy_term_build_content($term, $view_mode, $langcode); + $build = $term->content; + + // We don't need duplicate rendering info in $term->content. + unset($term->content); - $build = array( + $build += array( '#theme' => 'taxonomy_term', '#term' => $term, '#view_mode' => $view_mode, '#language' => $langcode, ); - $build += field_attach_view('taxonomy_term', $term, $view_mode, $langcode); - - // Add term description if the term has one. - if (!empty($term->description)) { - $build['description'] = array( - '#markup' => check_markup($term->description, $term->format, '', TRUE), - '#weight' => 0, - '#prefix' => '<div class="taxonomy-term-description">', - '#suffix' => '</div>', - ); - } - $build['#attached']['css'][] = drupal_get_path('module', 'taxonomy') . '/taxonomy.css'; - // Allow modules to modify the structured term. + // Allow modules to modify the structured taxonomy term. $type = 'taxonomy_term'; drupal_alter(array('taxonomy_term_view', 'entity_view'), $build, $type); @@ -1000,8 +1107,8 @@ function taxonomy_get_tree($vid, $parent = 0, $max_depth = NULL, $load_entities $parents = &drupal_static(__FUNCTION__ . ':parents', array()); $terms = &drupal_static(__FUNCTION__ . ':terms', array()); - // We cache trees, so it's not CPU-intensive to call get_tree() on a term - // and its children, too. + // We cache trees, so it's not CPU-intensive to call taxonomy_get_tree() on a + // term and its children, too. if (!isset($children[$vid])) { $children[$vid] = array(); $parents[$vid] = array(); @@ -1914,7 +2021,7 @@ function taxonomy_taxonomy_term_delete($term) { * Converts EntityFieldQuery instances on taxonomy terms that have an entity * condition on term bundles (vocabulary machine names). Since the vocabulary * machine name is not present in the {taxonomy_term_data} table itself, we have - * to convert the bundle condition into a proprety condition of vocabulary IDs + * to convert the bundle condition into a property condition of vocabulary IDs * to match against {taxonomy_term_data}.vid. */ function taxonomy_entity_query_alter($query) { diff --git a/modules/taxonomy/taxonomy.pages.inc b/modules/taxonomy/taxonomy.pages.inc index 501ebbe10..299c7bb6e 100644 --- a/modules/taxonomy/taxonomy.pages.inc +++ b/modules/taxonomy/taxonomy.pages.inc @@ -14,7 +14,9 @@ * The page content. */ function taxonomy_term_page($term) { - // Assign the term name as the page title. + // If there is a menu link to this term, the link becomes the last part of + // the active trail, and the link name becomes the page title. Thus, we must + // explicitly set the page title to be the term title. drupal_set_title($term->name); // Build breadcrumb based on the hierarchy of the term. @@ -33,8 +35,17 @@ function taxonomy_term_page($term) { drupal_set_breadcrumb($breadcrumb); drupal_add_feed('taxonomy/term/' . $term->tid . '/feed', 'RSS - ' . $term->name); - $build = array(); - + // Set the term path as the canonical URL to prevent duplicate content. + $uri = entity_uri('taxonomy_term', $term); + drupal_add_html_head_link(array('rel' => 'canonical', 'href' => url($uri['path'], $uri['options'])), TRUE); + // Set the non-aliased path as a default shortlink. + drupal_add_html_head_link(array('rel' => 'shortlink', 'href' => url($uri['path'], array_merge($uri['options'], array('alias' => TRUE)))), TRUE); + + // Normally we would call taxonomy_term_show() here, but for backwards + // compatibility in Drupal 7 we do not want to do that (it produces different + // data structures and HTML markup than what Drupal 7 released with). Calling + // taxonomy_term_view() directly provides essentially the same thing, but + // allows us to wrap the rendered term in our desired array structure. $build['term_heading'] = array( '#prefix' => '<div class="term-listing-heading">', '#suffix' => '</div>', @@ -47,7 +58,7 @@ function taxonomy_term_page($term) { $build['pager'] = array( '#theme' => 'pager', '#weight' => 5, - ); + ); } else { $build['no_content'] = array( diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test index 32ae84d66..123bdce40 100644 --- a/modules/taxonomy/taxonomy.test +++ b/modules/taxonomy/taxonomy.test @@ -98,6 +98,18 @@ class TaxonomyVocabularyFunctionalTest extends TaxonomyWebTestCase { $edit['machine_name'] = '!&^%'; $this->drupalPost('admin/structure/taxonomy/add', $edit, t('Save')); $this->assertText(t('The machine-readable name must contain only lowercase letters, numbers, and underscores.')); + + // Ensure that vocabulary titles are escaped properly. + $edit = array(); + $edit['name'] = 'Don\'t Panic'; + $edit['description'] = $this->randomName(); + $edit['machine_name'] = 'don_t_panic'; + $this->drupalPost('admin/structure/taxonomy/add', $edit, t('Save')); + + $site_name = variable_get('site_name', 'Drupal'); + $this->drupalGet('admin/structure/taxonomy/don_t_panic'); + $this->assertTitle(t('Don\'t Panic | @site-name', array('@site-name' => $site_name))); + $this->assertNoTitle(t('Don't Panic | @site-name', array('@site-name' => $site_name))); } /** @@ -1378,12 +1390,16 @@ class TaxonomyHooksTestCase extends TaxonomyWebTestCase { function setUp() { parent::setUp('taxonomy', 'taxonomy_test'); + module_load_include('inc', 'taxonomy', 'taxonomy.pages'); $taxonomy_admin = $this->drupalCreateUser(array('administer taxonomy')); $this->drupalLogin($taxonomy_admin); } /** - * Test that hooks are run correctly on creating, editing and deleting a term. + * Test that hooks are run correctly on creating, editing, viewing, + * and deleting a term. + * + * @see taxonomy_test.module */ function testTaxonomyTermHooks() { $vocabulary = $this->createVocabulary(); @@ -1408,6 +1424,13 @@ class TaxonomyHooksTestCase extends TaxonomyWebTestCase { $term = taxonomy_term_load($term->tid); $this->assertEqual($edit['antonym'], $term->antonym, 'Antonym was successfully edited.'); + // View the term and ensure that hook_taxonomy_term_view() and + // hook_entity_view() are invoked. + $term = taxonomy_term_load($term->tid); + $term_build = taxonomy_term_page($term); + $this->assertFalse(empty($term_build['term_heading']['term']['taxonomy_test_term_view_check']), 'hook_taxonomy_term_view() was invoked when viewing the term.'); + $this->assertFalse(empty($term_build['term_heading']['term']['taxonomy_test_entity_view_check']), 'hook_entity_view() was invoked when viewing the term.'); + // Delete the term. taxonomy_term_delete($term->tid); $antonym = db_query('SELECT tid FROM {taxonomy_term_antonym} WHERE tid = :tid', array(':tid' => $term->tid))->fetchField(); diff --git a/modules/toolbar/toolbar.info b/modules/toolbar/toolbar.info index 2f811f88c..3191b5f53 100644 --- a/modules/toolbar/toolbar.info +++ b/modules/toolbar/toolbar.info @@ -4,8 +4,8 @@ core = 7.x package = Core version = VERSION -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/toolbar/toolbar.tpl.php b/modules/toolbar/toolbar.tpl.php index 1df0cf03b..e85212997 100644 --- a/modules/toolbar/toolbar.tpl.php +++ b/modules/toolbar/toolbar.tpl.php @@ -19,6 +19,8 @@ * * @see template_preprocess() * @see template_preprocess_toolbar() + * + * @ingroup themeable */ ?> <div id="toolbar" class="<?php print $classes; ?> clearfix"> diff --git a/modules/tracker/tracker.info b/modules/tracker/tracker.info index 117e44286..d3d8706cd 100644 --- a/modules/tracker/tracker.info +++ b/modules/tracker/tracker.info @@ -6,8 +6,8 @@ version = VERSION core = 7.x files[] = tracker.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/translation/tests/translation_test.info b/modules/translation/tests/translation_test.info index 60787d0ae..d11abcf95 100644 --- a/modules/translation/tests/translation_test.info +++ b/modules/translation/tests/translation_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/translation/translation.info b/modules/translation/translation.info index 83532f55a..1449c7adf 100644 --- a/modules/translation/translation.info +++ b/modules/translation/translation.info @@ -6,8 +6,8 @@ version = VERSION core = 7.x files[] = translation.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/trigger/tests/trigger_test.info b/modules/trigger/tests/trigger_test.info index 56df2bc98..5067e6a8b 100644 --- a/modules/trigger/tests/trigger_test.info +++ b/modules/trigger/tests/trigger_test.info @@ -4,8 +4,8 @@ package = Testing core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/trigger/trigger.info b/modules/trigger/trigger.info index ffecce7d7..222b38282 100644 --- a/modules/trigger/trigger.info +++ b/modules/trigger/trigger.info @@ -6,8 +6,8 @@ core = 7.x files[] = trigger.test configure = admin/structure/trigger -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/update/tests/aaa_update_test.info b/modules/update/tests/aaa_update_test.info index dd2c362e7..7c5179a23 100644 --- a/modules/update/tests/aaa_update_test.info +++ b/modules/update/tests/aaa_update_test.info @@ -4,8 +4,8 @@ package = Testing core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/update/tests/bbb_update_test.info b/modules/update/tests/bbb_update_test.info index be2d9dd5f..d88c1fe9d 100644 --- a/modules/update/tests/bbb_update_test.info +++ b/modules/update/tests/bbb_update_test.info @@ -4,8 +4,8 @@ package = Testing core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/update/tests/ccc_update_test.info b/modules/update/tests/ccc_update_test.info index 5e4ffd789..591af8fbc 100644 --- a/modules/update/tests/ccc_update_test.info +++ b/modules/update/tests/ccc_update_test.info @@ -4,8 +4,8 @@ package = Testing core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info b/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info index c12f03fe7..9e92226dc 100644 --- a/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info +++ b/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info @@ -3,8 +3,8 @@ description = Test theme which acts as a base theme for other test subthemes. core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info b/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info index 097a88a7b..3dca01d47 100644 --- a/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info +++ b/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info @@ -4,8 +4,8 @@ core = 7.x base theme = update_test_basetheme hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/update/tests/update_test.info b/modules/update/tests/update_test.info index 9dac643f3..d6883aef6 100644 --- a/modules/update/tests/update_test.info +++ b/modules/update/tests/update_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/update/update.compare.inc b/modules/update/update.compare.inc index cd8b762d0..6e0c5feee 100644 --- a/modules/update/update.compare.inc +++ b/modules/update/update.compare.inc @@ -592,7 +592,10 @@ function update_calculate_project_update_status($project, &$project_data, $avail // See if this is a higher major version than our target and yet still // supported. If so, record it as an "Also available" release. - if ($release['version_major'] > $target_major) { + // Note: some projects have a HEAD release from CVS days, which could + // be one of those being compared. They would not have version_major + // set, so we must call isset first. + if (isset($release['version_major']) && $release['version_major'] > $target_major) { if (in_array($release['version_major'], $supported_majors)) { if (!isset($project_data['also'])) { $project_data['also'] = array(); diff --git a/modules/update/update.fetch.inc b/modules/update/update.fetch.inc index 860a1b975..bf0039f44 100644 --- a/modules/update/update.fetch.inc +++ b/modules/update/update.fetch.inc @@ -288,17 +288,25 @@ function _update_build_fetch_url($project, $site_key = '') { $name = $project['name']; $url = _update_get_fetch_url_base($project); $url .= '/' . $name . '/' . DRUPAL_CORE_COMPATIBILITY; - // Only append a site_key and the version information if we have a site_key - // in the first place, and if this is not a disabled module or theme. We do - // not want to record usage statistics for disabled code. + + // Only append usage infomation if we have a site key and the project is + // enabled. We do not want to record usage statistics for disabled projects. if (!empty($site_key) && (strpos($project['project_type'], 'disabled') === FALSE)) { + // Append the site key. $url .= (strpos($url, '?') !== FALSE) ? '&' : '?'; $url .= 'site_key='; $url .= rawurlencode($site_key); + + // Append the version. if (!empty($project['info']['version'])) { $url .= '&version='; $url .= rawurlencode($project['info']['version']); } + + // Append the list of modules or themes enabled. + $list = array_keys($project['includes']); + $url .= '&list='; + $url .= rawurlencode(implode(',', $list)); } return $url; } diff --git a/modules/update/update.info b/modules/update/update.info index cd9ec8c06..f1a00def9 100644 --- a/modules/update/update.info +++ b/modules/update/update.info @@ -6,8 +6,8 @@ core = 7.x files[] = update.test configure = admin/reports/updates/settings -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/update/update.test b/modules/update/update.test index e297194ae..b29f6ac86 100644 --- a/modules/update/update.test +++ b/modules/update/update.test @@ -769,6 +769,7 @@ class UpdateCoreUnitTestCase extends DrupalUnitTestCase { $project['project_type'] = ''; $project['info']['version'] = ''; $project['info']['project status url'] = 'http://www.example.com'; + $project['includes'] = array('module1' => 'Module 1', 'module2' => 'Module 2'); $site_key = ''; $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY; $url = _update_build_fetch_url($project, $site_key); @@ -785,14 +786,16 @@ class UpdateCoreUnitTestCase extends DrupalUnitTestCase { $project['project_type'] = ''; $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY; $expected .= '?site_key=site_key'; + $expected .= '&list=' . rawurlencode('module1,module2'); $url = _update_build_fetch_url($project, $site_key); $this->assertEqual($url, $expected, "When site_key provided, '$url' should be '$expected'."); - // http://drupal.org/node/1481156 test incorrect logic when url contains + // http://drupal.org/node/1481156 test incorrect logic when URL contains // a question mark. $project['info']['project status url'] = 'http://www.example.com/?project='; $expected = 'http://www.example.com/?project=/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY; $expected .= '&site_key=site_key'; + $expected .= '&list=' . rawurlencode('module1,module2'); $url = _update_build_fetch_url($project, $site_key); $this->assertEqual($url, $expected, "When ? is present, '$url' should be '$expected'."); diff --git a/modules/user/tests/user_form_test.info b/modules/user/tests/user_form_test.info index 577cbb106..1b33a82d6 100644 --- a/modules/user/tests/user_form_test.info +++ b/modules/user/tests/user_form_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/user/user-picture.tpl.php b/modules/user/user-picture.tpl.php index a33d2661d..ee8218786 100644 --- a/modules/user/user-picture.tpl.php +++ b/modules/user/user-picture.tpl.php @@ -12,6 +12,8 @@ * check_plain() before use. * * @see template_preprocess_user_picture() + * + * @ingroup themeable */ ?> <?php if ($user_picture): ?> diff --git a/modules/user/user-profile.tpl.php b/modules/user/user-profile.tpl.php index a1611c835..0a64fed84 100644 --- a/modules/user/user-profile.tpl.php +++ b/modules/user/user-profile.tpl.php @@ -30,6 +30,8 @@ * @see user-profile-item.tpl.php * Where the html is handled for each item in the group. * @see template_preprocess_user_profile() + * + * @ingroup themeable */ ?> <div class="profile"<?php print $attributes; ?>> diff --git a/modules/user/user.api.php b/modules/user/user.api.php index f610408dc..64c863fe4 100644 --- a/modules/user/user.api.php +++ b/modules/user/user.api.php @@ -299,6 +299,14 @@ function hook_user_login(&$edit, $account) { /** * The user just logged out. * + * Note that when this hook is invoked, the changes have not yet been written to + * the database, because a database transaction is still in progress. The + * transaction is not finalized until the save operation is entirely completed + * and user_save() goes out of scope. You should not rely on data in the + * database at this time as it is not updated yet. You should also note that any + * write/update database queries executed from this hook are also not committed + * immediately. Check user_save() and db_transaction() for more info. + * * @param $account * The user object on which the operation was just performed. */ @@ -317,6 +325,14 @@ function hook_user_logout($account) { * The module should format its custom additions for display and add them to the * $account->content array. * + * Note that when this hook is invoked, the changes have not yet been written to + * the database, because a database transaction is still in progress. The + * transaction is not finalized until the save operation is entirely completed + * and user_save() goes out of scope. You should not rely on data in the + * database at this time as it is not updated yet. You should also note that any + * write/update database queries executed from this hook are also not committed + * immediately. Check user_save() and db_transaction() for more info. + * * @param $account * The user object on which the operation is being performed. * @param $view_mode diff --git a/modules/user/user.info b/modules/user/user.info index e39c54b75..1f271a495 100644 --- a/modules/user/user.info +++ b/modules/user/user.info @@ -9,8 +9,8 @@ required = TRUE configure = admin/config/people stylesheets[all][] = user.css -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/modules/user/user.install b/modules/user/user.install index 217577de7..cff873a45 100644 --- a/modules/user/user.install +++ b/modules/user/user.install @@ -384,7 +384,7 @@ function user_update_dependencies() { * An array of permissions names. * @param $module * The name of the module defining the permissions. - * @ingroup update-api-6.x-to-7.x + * @ingroup update_api */ function _update_7000_user_role_grant_permissions($rid, array $permissions, $module) { // Grant new permissions for the role. diff --git a/modules/user/user.module b/modules/user/user.module index 47ac64273..2c02f8ce9 100644 --- a/modules/user/user.module +++ b/modules/user/user.module @@ -187,7 +187,7 @@ function user_entity_info() { } /** - * Entity uri callback. + * Entity URI callback. */ function user_uri($user) { return array( @@ -1307,7 +1307,6 @@ function user_login_block($form) { ); $form['pass'] = array('#type' => 'password', '#title' => t('Password'), - '#maxlength' => 60, '#size' => 15, '#required' => TRUE, ); @@ -1873,7 +1872,7 @@ function user_menu_link_alter(&$link) { */ function user_translated_menu_link_alter(&$link) { // Hide the "User account" link for anonymous users. - if ($link['link_path'] == 'user' && $link['module'] == 'system' && user_is_anonymous()) { + if ($link['link_path'] == 'user' && $link['module'] == 'system' && !$GLOBALS['user']->uid) { $link['hidden'] = 1; } } @@ -2574,6 +2573,14 @@ function user_build_content($account, $view_mode = 'full', $langcode = NULL) { // Remove previously built content, if exists. $account->content = array(); + // Allow modules to change the view mode. + $context = array( + 'entity_type' => 'user', + 'entity' => $account, + 'langcode' => $langcode, + ); + drupal_alter('entity_view_mode', $view_mode, $context); + // Build fields content. field_attach_prepare_view('user', array($account->uid => $account), $view_mode, $langcode); entity_prepare_view('user', array($account->uid => $account), $langcode); @@ -2582,6 +2589,10 @@ function user_build_content($account, $view_mode = 'full', $langcode = NULL) { // Populate $account->content with a render() array. module_invoke_all('user_view', $account, $view_mode, $langcode); module_invoke_all('entity_view', $account, 'user', $view_mode, $langcode); + + // Make sure the current view mode is stored if no module has already + // populated the related key. + $account->content += array('#view_mode' => $view_mode); } /** diff --git a/modules/user/user.test b/modules/user/user.test index b53db0769..92af9fa9a 100644 --- a/modules/user/user.test +++ b/modules/user/user.test @@ -1487,7 +1487,7 @@ class UserAutocompleteTestCase extends DrupalWebTestCase { /** - * Test user-links in secondary menu. + * Tests user links in the secondary menu. */ class UserAccountLinksUnitTests extends DrupalWebTestCase { public static function getInfo() { @@ -1498,6 +1498,10 @@ class UserAccountLinksUnitTests extends DrupalWebTestCase { ); } + function setUp() { + parent::setUp('menu'); + } + /** * Tests the secondary menu. */ @@ -1533,6 +1537,36 @@ class UserAccountLinksUnitTests extends DrupalWebTestCase { $element = $this->xpath('//ul[@id=:menu_id]', array(':menu_id' => 'secondary-menu-links')); $this->assertEqual(count($element), 0, 'No secondary-menu for logged-out users.'); } + + /** + * Tests disabling the 'My account' link. + */ + function testDisabledAccountLink() { + // Create an admin user and log in. + $this->drupalLogin($this->drupalCreateUser(array('access administration pages', 'administer menu'))); + + // Verify that the 'My account' link is enabled. + $this->drupalGet('admin/structure/menu/manage/user-menu'); + $this->assertFieldChecked('edit-mlid2-hidden', "The 'My account' link is enabled by default."); + + // Disable the 'My account' link. + $edit = array( + 'mlid:2[hidden]' => FALSE, + ); + $this->drupalPost('admin/structure/menu/manage/user-menu', $edit, t('Save configuration')); + + // Get the homepage. + $this->drupalGet('<front>'); + + // Verify that the 'My account' link does not appear when disabled. + $link = $this->xpath('//ul[@id=:menu_id]/li/a[contains(@href, :href) and text()=:text]', array( + ':menu_id' => 'secondary-menu-links', + ':href' => 'user', + ':text' => 'My account', + )); + $this->assertEqual(count($link), 0, 'My account link is not in the secondary menu.'); + } + } /** diff --git a/profiles/minimal/minimal.info b/profiles/minimal/minimal.info index 7981a92f3..24df0c61d 100644 --- a/profiles/minimal/minimal.info +++ b/profiles/minimal/minimal.info @@ -5,8 +5,8 @@ core = 7.x dependencies[] = block dependencies[] = dblog -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/profiles/minimal/minimal.install b/profiles/minimal/minimal.install index 6099da1ce..9cf4fa2f8 100644 --- a/profiles/minimal/minimal.install +++ b/profiles/minimal/minimal.install @@ -1,7 +1,7 @@ <?php /** * @file - * Install, update and uninstall functions for the minimal install profile. + * Install, update and uninstall functions for the minimal installation profile. */ /** diff --git a/profiles/standard/standard.info b/profiles/standard/standard.info index 36ae60e8e..ad397f4f4 100644 --- a/profiles/standard/standard.info +++ b/profiles/standard/standard.info @@ -24,8 +24,8 @@ dependencies[] = field_ui dependencies[] = file dependencies[] = rdf -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/profiles/standard/standard.install b/profiles/standard/standard.install index ab3e8a1ad..1d563a48d 100644 --- a/profiles/standard/standard.install +++ b/profiles/standard/standard.install @@ -1,7 +1,7 @@ <?php /** * @file - * Install, update and uninstall functions for the standard install profile. + * Install, update and uninstall functions for the standard installation profile. */ /** diff --git a/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info index 99563e9df..4fcb81ea9 100644 --- a/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info +++ b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info @@ -6,8 +6,8 @@ core = 7.x hidden = TRUE files[] = drupal_system_listing_compatible_test.test -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info index 347fa3f25..068432fbb 100644 --- a/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info +++ b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info @@ -8,8 +8,8 @@ version = VERSION core = 6.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/profiles/testing/testing.info b/profiles/testing/testing.info index 3bf881fc8..124c9c045 100644 --- a/profiles/testing/testing.info +++ b/profiles/testing/testing.info @@ -4,8 +4,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/scripts/drupal.sh b/scripts/drupal.sh index 5d064f571..76bd750f5 100755 --- a/scripts/drupal.sh +++ b/scripts/drupal.sh @@ -113,7 +113,7 @@ while ($param = array_shift($_SERVER['argv'])) { $_REQUEST = $_GET; } - // set file to execute or Drupal path (clean urls enabled) + // set file to execute or Drupal path (clean URLs enabled) if (isset($path['path']) && file_exists(substr($path['path'], 1))) { $_SERVER['PHP_SELF'] = $_SERVER['REQUEST_URI'] = $path['path']; $cmd = substr($path['path'], 1); diff --git a/scripts/generate-d7-content.sh b/scripts/generate-d7-content.sh index 364a25c92..1e1d13fa9 100644 --- a/scripts/generate-d7-content.sh +++ b/scripts/generate-d7-content.sh @@ -129,8 +129,7 @@ if (module_exists('taxonomy')) { } else { $instance['widget'] = array( - 'type' => 'select', - 'module' => 'options', + 'type' => 'options_select', 'settings' => array(), ); } diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh index f651f22bb..334501527 100755 --- a/scripts/run-tests.sh +++ b/scripts/run-tests.sh @@ -268,14 +268,14 @@ function simpletest_script_init($server_software) { exit(); } - // Get url from arguments. + // Get URL from arguments. if (!empty($args['url'])) { $parsed_url = parse_url($args['url']); $host = $parsed_url['host'] . (isset($parsed_url['port']) ? ':' . $parsed_url['port'] : ''); $path = isset($parsed_url['path']) ? $parsed_url['path'] : ''; // If the passed URL schema is 'https' then setup the $_SERVER variables - // properly so that testing will run under https. + // properly so that testing will run under HTTPS. if ($parsed_url['scheme'] == 'https') { $_SERVER['HTTPS'] = 'on'; } diff --git a/sites/README.txt b/sites/README.txt new file mode 100644 index 000000000..9aecef2d7 --- /dev/null +++ b/sites/README.txt @@ -0,0 +1,19 @@ +This directory structure contains the settings and configuration files specific +to your site or sites and is an integral part of multisite configuration. + +The sites/all/ subdirectory structure should be used to place your custom and +downloaded extensions including modules, themes, and third party libraries. + +Downloaded installation profiles should be placed in the /profiles directory +in the Drupal root. + +In multisite configuration, extensions found in the sites/all directory +structure are available to all sites. Alternatively, the sites/your_site_name/ +subdirectory pattern may be used to restrict extensions to a specific +site instance. + +See the respective README.txt files in sites/all/themes and sites/all/modules +for additional information about obtaining and organizing extensions. + +See INSTALL.txt in the Drupal root for information about single-site +installation or multisite configuration. diff --git a/sites/all/README.txt b/sites/all/README.txt deleted file mode 100644 index c8970883a..000000000 --- a/sites/all/README.txt +++ /dev/null @@ -1,7 +0,0 @@ - -This directory should be used to place downloaded and custom modules -and themes which are common to all sites. Keeping contributed and -custom modules and themes in the sites directory will aid in upgrading -Drupal core files. Place contributed and custom modules and themes in -the sites/all/modules and sites/all/themes directories respectively. - diff --git a/sites/all/modules/README.txt b/sites/all/modules/README.txt index f4e35b558..c72b43e4f 100644 --- a/sites/all/modules/README.txt +++ b/sites/all/modules/README.txt @@ -1,4 +1,16 @@ +Place downloaded and custom modules that extend your site functionality beyond +Drupal core in this directory to ensure clean separation from core modules and +to facilitate safe, self-contained code updates. Contributed modules from the +Drupal community may be downloaded at http://drupal.org/project/modules. -This directory should be used to place downloaded and custom modules -which are common to all sites. This will allow you to more easily -update Drupal core files. +It is safe to organize modules into subdirectories, such as "contrib" for +contributed modules, and "custom" for custom modules. Note that if you move a +module to a subdirectory after it has been enabled, you may need to clear the +Drupal cache so that it can be found. + +In multisite configuration, modules found in this directory are available to +all sites. Alternatively, the sites/your_site_name/modules directory pattern may +be used to restrict modules to a specific site instance. + +Refer to the "Developing for Drupal" section of the README.txt in the Drupal +root directory for further information on extending Drupal with custom modules. diff --git a/sites/all/themes/README.txt b/sites/all/themes/README.txt index e9425214b..e308af205 100644 --- a/sites/all/themes/README.txt +++ b/sites/all/themes/README.txt @@ -1,4 +1,14 @@ +Place downloaded and custom themes that modify your site's appearance in this +directory to ensure clean separation from Drupal core and to facilitate safe, +self-contained code updates. Contributed themes from the Drupal community may +be downloaded at http://drupal.org/project/themes. -This directory should be used to place downloaded and custom themes -which are common to all sites. This will allow you to more easily -update Drupal core files. +It is safe to organize themes into subdirectories and is recommended to use +Drupal's sub-theme functionality to ensure easy maintenance and upgrades. + +In multisite configuration, themes found in this directory are available to +all sites. Alternatively, the sites/your_site_name/themes directory pattern may +be used to restrict themes to a specific site instance. + +Refer to the "Appearance" section of the README.txt in the Drupal root +directory for further information on theming. diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php index 30699a0a2..2b207f224 100644 --- a/sites/default/default.settings.php +++ b/sites/default/default.settings.php @@ -5,41 +5,51 @@ * Drupal site-specific configuration file. * * IMPORTANT NOTE: - * This file may have been set to read-only by the Drupal installation - * program. If you make changes to this file, be sure to protect it again - * after making your modifications. Failure to remove write permissions - * to this file is a security risk. - * - * The configuration file to be loaded is based upon the rules below. - * - * The configuration directory will be discovered 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 any - * others will be ignored. If no other configuration file is found - * then the default configuration file at 'sites/default' will be used. + * This file may have been set to read-only by the Drupal installation program. + * If you make changes to this file, be sure to protect it again after making + * your modifications. Failure to remove write permissions to this file is a + * security risk. + * + * The configuration file to be loaded is based upon the rules below. However + * if the multisite aliasing file named sites/sites.php is present, it will be + * loaded, and the aliases in the array $sites will override the default + * directory rules below. See sites/example.sites.php for more information about + * aliases. + * + * The configuration directory will be discovered 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 any others will be ignored. If no + * other configuration file is found then the default configuration file at + * 'sites/default' will be used. * * For example, for a fictitious site installed at - * http://www.drupal.org/mysite/test/, the 'settings.php' - * is searched in the following directories: + * http://www.drupal.org:8080/mysite/test/, the 'settings.php' file is searched + * for in the following directories: * + * - sites/8080.www.drupal.org.mysite.test * - sites/www.drupal.org.mysite.test * - sites/drupal.org.mysite.test * - sites/org.mysite.test * + * - sites/8080.www.drupal.org.mysite * - sites/www.drupal.org.mysite * - sites/drupal.org.mysite * - sites/org.mysite * + * - sites/8080.www.drupal.org * - sites/www.drupal.org * - sites/drupal.org * - sites/org * * - sites/default * - * If you are installing on a non-standard port number, prefix the + * Note that if you are installing on a non-standard port number, prefix the * hostname with that number. For example, * http://www.drupal.org:8080/mysite/test/ could be loaded from * sites/8080.www.drupal.org.mysite.test/. + * + * @see example.sites.php + * @see conf_path() */ /** @@ -480,33 +490,64 @@ ini_set('session.cookie_lifetime', 2000000); */ $conf['404_fast_paths_exclude'] = '/\/(?:styles)\//'; $conf['404_fast_paths'] = '/\.(?:txt|png|gif|jpe?g|css|js|ico|swf|flv|cgi|bat|pl|dll|exe|asp)$/i'; -$conf['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>'; +$conf['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>'; /** - * By default, fast 404s are returned as part of the normal page request - * process, which will properly serve valid pages that happen to match and will - * also log actual 404s to the Drupal log. Alternatively you can choose to - * return a 404 now by uncommenting the following line. This will reduce server - * load, but will cause even valid pages that happen to match the pattern to - * return 404s, rather than the actual page. It will also prevent the Drupal - * system log entry. Ensure you understand the effects of this before enabling. - * - * To enable this functionality, remove the leading hash sign below. + * By default the page request process will return a fast 404 page for missing + * files if they match the regular expression set in '404_fast_paths' and not + * '404_fast_paths_exclude' above. 404 errors will simultaneously be logged in + * the Drupal system log. + * + * You can choose to return a fast 404 page earlier for missing pages (as soon + * as settings.php is loaded) by uncommenting the line below. This speeds up + * server response time when loading 404 error pages and prevents the 404 error + * from being logged in the Drupal system log. In order to prevent valid pages + * such as image styles and other generated content that may match the + * '404_fast_html' regular expression from returning 404 errors, it is necessary + * to add them to the '404_fast_paths_exclude' regular expression above. Make + * sure that you understand the effects of this feature before uncommenting the + * line below. */ # drupal_fast_404(); +/** + * External access proxy settings: + * + * If your site must access the Internet via a web proxy then you can enter + * the proxy settings here. Currently only basic authentication is supported + * by using the username and password variables. The proxy_user_agent variable + * can be set to NULL for proxies that require no User-Agent header or to a + * non-empty string for proxies that limit requests to a specific agent. The + * proxy_exceptions variable is an array of host names to be accessed directly, + * not via proxy. + */ +# $conf['proxy_server'] = ''; +# $conf['proxy_port'] = 8080; +# $conf['proxy_username'] = ''; +# $conf['proxy_password'] = ''; +# $conf['proxy_user_agent'] = ''; +# $conf['proxy_exceptions'] = array('127.0.0.1', 'localhost'); + /** * Authorized file system operations: * * The Update manager module included with Drupal provides a mechanism for * site administrators to securely install missing updates for the site - * directly through the web user interface by providing either SSH or FTP - * credentials. This allows the site to update the new files as the user who - * owns all the Drupal files, instead of as the user the webserver is running - * as. However, some sites might wish to disable this functionality, and only - * update the code directly via SSH or FTP themselves. This setting completely + * directly through the web user interface. On securely-configured servers, + * the Update manager will require the administrator to provide SSH or FTP + * credentials before allowing the installation to proceed; this allows the + * site to update the new files as the user who owns all the Drupal files, + * instead of as the user the webserver is running as. On servers where the + * webserver user is itself the owner of the Drupal files, the administrator + * will not be prompted for SSH or FTP credentials (note that these server + * setups are common on shared hosting, but are inherently insecure). + * + * Some sites might wish to disable the above functionality, and only update + * the code directly via SSH or FTP themselves. This setting completely * disables all functionality related to these authorized file operations. * + * @see http://drupal.org/node/244924 + * * Remove the leading hash signs to disable. */ # $conf['allow_authorize_operations'] = FALSE; diff --git a/sites/example.sites.php b/sites/example.sites.php index 4fa065da5..f6bf1a2f3 100644 --- a/sites/example.sites.php +++ b/sites/example.sites.php @@ -4,43 +4,55 @@ * @file * Configuration file for Drupal's multi-site directory aliasing feature. * - * Drupal searches for an appropriate configuration directory based on the - * website's hostname and pathname. A detailed description of the rules for - * discovering the configuration directory can be found in the comment - * documentation in 'sites/default/default.settings.php'. + * This file allows you to define a set of aliases that map hostnames, ports, and + * pathnames to configuration directories in the sites directory. These aliases + * are loaded prior to scanning for directories, and they are exempt from the + * normal discovery rules. See default.settings.php to view how Drupal discovers + * the configuration directory when no alias is found. * - * This file allows you to define a set of aliases that map hostnames and - * pathnames to configuration directories. These aliases are loaded prior to - * scanning for directories, and they are exempt from the normal discovery - * rules. The aliases are defined in an associative array named $sites, which - * should look similar to the following: + * Aliases are 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 in + * the database (files, system table, etc.) this will ensure the paths are + * correct when the site is deployed to a live server. * + * To use this file, copy and rename it such that its path plus filename is + * 'sites/sites.php'. If you don't need to use multi-site directory aliasing, + * then you can safely ignore this file, and Drupal will ignore it too. + * + * Aliases are defined in an associative array named $sites. The array is + * written in the format: '<port>.<domain>.<path>' => 'directory'. As an + * example, to map http://www.drupal.org:8080/mysite/test to the configuration + * directory sites/example.com, the array should be defined as: + * @code * $sites = array( - * 'devexample.com' => 'example.com', - * 'localhost.example' => 'example.com', + * '8080.www.drupal.org.mysite.test' => 'example.com', * ); + * @endcode + * The URL, http://www.drupal.org:8080/mysite/test/, could be a symbolic link or + * an Apache Alias directive that points to the Drupal root containing + * index.php. An alias could also be created for a subdomain. See the + * @link http://drupal.org/documentation/install online Drupal installation guide @endlink + * for more information on setting up domains, subdomains, and subdirectories. * - * 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. + * The following examples look for a site configuration in sites/example.com: + * @code + * URL: http://dev.drupal.org + * $sites['dev.drupal.org'] = 'example.com'; * - * To use this file, copy and rename it such that its path plus filename is - * 'sites/sites.php'. If you don't need to use multi-site directory aliasing, - * then you can safely ignore this file, and Drupal will ignore it too. - */ - -/** - * Multi-site directory aliasing: + * URL: http://localhost/example + * $sites['localhost.example'] = 'example.com'; + * + * URL: http://localhost:8080/example + * $sites['8080.localhost.example'] = 'example.com'; + * + * URL: http://www.drupal.org:8080/mysite/test/ + * $sites['8080.www.drupal.org.mysite.test'] = 'example.com'; + * @endcode * - * Edit the lines below to define directory aliases. Remove the leading hash - * signs to enable. + * @see default.settings.php + * @see conf_path() + * @see http://drupal.org/documentation/install/multi-site */ -# $sites['devexample.com'] = 'example.com'; -# $sites['localhost.example'] = 'example.com'; /** diff --git a/themes/bartik/bartik.info b/themes/bartik/bartik.info index 6486aa6a7..96e95740c 100644 --- a/themes/bartik/bartik.info +++ b/themes/bartik/bartik.info @@ -34,8 +34,8 @@ regions[footer] = Footer settings[shortcut_module_link] = 0 -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/themes/bartik/templates/comment-wrapper.tpl.php b/themes/bartik/templates/comment-wrapper.tpl.php index 864dc41c4..c0ca74b16 100644 --- a/themes/bartik/templates/comment-wrapper.tpl.php +++ b/themes/bartik/templates/comment-wrapper.tpl.php @@ -32,7 +32,6 @@ * into a string within the variable $classes. * * @see template_preprocess_comment_wrapper() - * @see theme_comment_wrapper() */ ?> <div id="comments" class="<?php print $classes; ?>"<?php print $attributes; ?>> diff --git a/themes/bartik/templates/node.tpl.php b/themes/bartik/templates/node.tpl.php index f215b477b..df5b45493 100644 --- a/themes/bartik/templates/node.tpl.php +++ b/themes/bartik/templates/node.tpl.php @@ -14,7 +14,7 @@ * - $date: Formatted creation date. Preprocess functions can reformat it by * calling format_date() with the desired parameters on the $created variable. * - $name: Themed username of node author output from theme_username(). - * - $node_url: Direct url of the current node. + * - $node_url: Direct URL of the current node. * - $display_submitted: Whether submission information should be displayed. * - $submitted: Submission information created from $name and $date during * template_preprocess_node(). @@ -22,7 +22,7 @@ * CSS. It can be manipulated through the variable $classes_array from * preprocess functions. The default values can be one or more of the * following: - * - node: The current template type, i.e., "theming hook". + * - node: The current template type; for example, "theming hook". * - node-[type]: The current node type. For example, if the node is a * "Blog entry" it would result in "node-blog". Note that the machine * name will often be in a short form of the human readable label. @@ -42,7 +42,7 @@ * * Other variables: * - $node: Full node object. Contains data that may not be safe. - * - $type: Node type, i.e. story, page, blog, etc. + * - $type: Node type; for example, story, page, blog, etc. * - $comment_count: Number of comments attached to the node. * - $uid: User ID of the node author. * - $created: Time the node was published formatted in Unix timestamp. @@ -53,7 +53,7 @@ * - $id: Position of the node. Increments each time it's output. * * Node status variables: - * - $view_mode: View mode, e.g. 'full', 'teaser'... + * - $view_mode: View mode; for example, "full", "teaser". * - $teaser: Flag for the teaser state (shortcut for $view_mode == 'teaser'). * - $page: Flag for the full page state. * - $promote: Flag for front page promotion state. @@ -67,11 +67,11 @@ * - $is_admin: Flags true when the current user is an administrator. * * Field variables: for each field instance attached to the node a corresponding - * variable is defined, e.g. $node->body becomes $body. When needing to access - * a field's raw values, developers/themers are strongly encouraged to use these - * variables. Otherwise they will have to explicitly specify the desired field - * language, e.g. $node->body['en'], thus overriding any language negotiation - * rule that was previously applied. + * variable is defined; for example, $node->body becomes $body. When needing to + * access a field's raw values, developers/themers are strongly encouraged to + * use these variables. Otherwise they will have to explicitly specify the + * desired field language; for example, $node->body['en'], thus overriding any + * language negotiation rule that was previously applied. * * @see template_preprocess() * @see template_preprocess_node() diff --git a/themes/garland/garland.info b/themes/garland/garland.info index 78db5a9b3..bfd7a17c9 100644 --- a/themes/garland/garland.info +++ b/themes/garland/garland.info @@ -7,8 +7,8 @@ stylesheets[all][] = style.css stylesheets[print][] = print.css settings[garland_width] = fluid -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/themes/seven/page.tpl.php b/themes/seven/page.tpl.php index 4d40cf89c..6ab3ae841 100644 --- a/themes/seven/page.tpl.php +++ b/themes/seven/page.tpl.php @@ -11,7 +11,7 @@ <div id="page"> <?php if ($secondary_local_tasks): ?> - <div class="tabs-secondary clearfix"><ul class="tabs secondary"><?php print render($secondary_local_tasks); ?></ul></div> + <div class="tabs-secondary clearfix"><?php print render($secondary_local_tasks); ?></div> <?php endif; ?> <div id="content" class="clearfix"> diff --git a/themes/seven/seven.info b/themes/seven/seven.info index ad2559079..705e9f3a4 100644 --- a/themes/seven/seven.info +++ b/themes/seven/seven.info @@ -13,8 +13,8 @@ regions[page_bottom] = Page bottom regions[sidebar_first] = First sidebar regions_hidden[] = sidebar_first -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" diff --git a/themes/stark/stark.info b/themes/stark/stark.info index 21736359e..f60e470f0 100644 --- a/themes/stark/stark.info +++ b/themes/stark/stark.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x stylesheets[all][] = layout.css -; Information added by drupal.org packaging script on 2012-10-17 -version = "7.16" +; Information added by drupal.org packaging script on 2012-11-07 +version = "7.17" project = "drupal" -datestamp = "1350508567" +datestamp = "1352325357" -- GitLab