diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 04cff864..fa4f2091 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,3 +1,261 @@
+Drupal 7.60, 2018-10-18
+------------------------
+- Fixed security issues. See SA-CORE-2018-006.
+
+Drupal 7.59, 2018-04-25
+-----------------------
+- Fixed security issues (remote code execution). See SA-CORE-2018-004.
+
+Drupal 7.58, 2018-03-28
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2018-002.
+
+Drupal 7.57, 2018-02-21
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2018-001.
+
+Drupal 7.56, 2017-06-21
+-----------------------
+- Fixed security issues (access bypass). See SA-CORE-2017-003.
+
+Drupal 7.55, 2017-06-07
+-----------------------
+- Fixed incompatibility with PHP versions 7.0.19 and 7.1.5 due to duplicate
+ DATE_RFC7231 definition.
+- Made Drupal core pass all automated tests on PHP 7.1.
+- Allowed services such as Let's Encrypt to work with Drupal on Apache, by
+ making Drupal's .htaccess file allow access to the .well-known directory
+ defined by RFC 5785.
+- Made new Drupal sites work correctly on Apache 2.4 when the mod_access_compat
+ Apache module is disabled.
+- Fixed Drupal's URL-generating functions to always encode '[' and ']' so that
+ the URLs will pass HTML5 validation.
+- Various additional bug fixes.
+- Various API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.54, 2017-02-01
+-----------------------
+- Modules are now able to define theme engines (API addition:
+ https://www.drupal.org/node/2826480).
+- Logging of searches can now be disabled (new option in the administrative
+ interface).
+- Added menu tree render structure to (pre-)process hooks for theme_menu_tree()
+ (API addition: https://www.drupal.org/node/2827134).
+- Added new function for determining whether an HTTPS request is being served
+ (API addition: https://www.drupal.org/node/2824590).
+- Fixed incorrect default value for short and medium date formats on the date
+ type configuration page.
+- File validation error message is now removed after subsequent upload of valid
+ file.
+- Numerous bug fixes.
+- Numerous API documentation improvements.
+- Additional performance improvements.
+- Additional automated test coverage.
+
+Drupal 7.53, 2016-12-07
+-----------------------
+- Fixed drag and drop support on newer Chrome/IE 11+ versions after 7.51 update
+ when jQuery is updated to 1.7-1.11.0.
+
+Drupal 7.52, 2016-11-16
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2016-005.
+
+Drupal 7.51, 2016-10-05
+-----------------------
+- The Update module now also checks for updates to a disabled theme that is
+ used as an admin theme.
+- Exceptions thrown in dblog_watchdog() are now caught and ignored.
+- Clarified the warning that appears when modules are missing or have moved.
+- Log messages are now XSS filtered on display.
+- Draggable tables now work on touch screen devices.
+- Added a setting for allowing double underscores in CSS identifiers
+ (https://www.drupal.org/node/2810369).
+- If a user navigates away from a page while an Ajax request is running they
+ will no longer get an error message saying "An Ajax HTTP request terminated
+ abnormally".
+- The system_region_list() API function now takes an optional third parameter
+ which allows region name translations to be skipped when they are not needed
+ (API addition: https://www.drupal.org/node/2810365).
+- Numerous performance improvements.
+- Numerous bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.50, 2016-07-07
+-----------------------
+- Added a new "administer fields" permission for trusted users, which is
+ required in addition to other permissions to use the field UI
+ (https://www.drupal.org/node/2483307).
+- Added clickjacking protection to Drupal core by setting the X-Frame-Options
+ header to SAMEORIGIN by default (https://www.drupal.org/node/2735873).
+- Added support for full UTF-8 (emojis, Asian symbols, mathematical symbols) on
+ MySQL and other database drivers when the site and database are configured to
+ allow it (https://www.drupal.org/node/2761183).
+- Improved performance by avoiding a re-scan of directories when a file is
+ missing; instead, trigger a PHP warning (minor API change:
+ https://www.drupal.org/node/2581445).
+- Made it possible to use any PHP callable in Ajax form callbacks, form API
+ form-building functions, and form API wrapper callbacks (API addition:
+ https://www.drupal.org/node/2761169).
+- Fixed that following a password reset link while logged in leaves users unable
+ to change their password (minor user interface change:
+ https://www.drupal.org/node/2759023).
+- Implemented various fixes for automated test failures on PHP 5.4+ and PHP 7.
+ Drupal core automated tests now pass in these environments.
+- Improved support for PHP 7 by fixing various problems.
+- Fixed various bugs with PHP 5.5+ imagerotate(), including when incorrect
+ color indices are passed in.
+- Fixed a regression introduced in Drupal 7.43 that allowed files uploaded by
+ anonymous users to be lost after form validation errors, and that also caused
+ regressions with certain contributed modules.
+- Fixed a regression introduced in Drupal 7.36 which caused the default value
+ of hidden textarea fields to be ignored.
+- Fixed robots.txt to allow search engines to access CSS, JavaScript and image
+ files.
+- Changed wording on the Update Manager settings page to clarify that the
+ option to check for disabled module updates also applies to uninstalled
+ modules (administrative-facing translatable string change).
+- Changed the help text when editing menu links and configuring URL redirect
+ actions so that it does not reference "Drupal" or the drupal.org website
+ (administrative-facing translatable string change).
+- Fixed the locale safety check that is used to ensure that translations are
+ safe to allow for tokens in the href/src attributes of translated strings.
+- Fixed that URL generation only works on port 80 when using domain based
+ language negotation.
+- Made method="get" forms work inside the administrative overlay. The fix adds
+ a new hidden field to these forms when they appear inside the overlay (minor
+ data structure change).
+- Increased maxlength of menu link title input fields in the node form and
+ menu link form from 128 to 255 characters.
+- Removed meaningless post-check=0 and pre-check=0 cache control headers from
+ Drupal HTTP responses.
+- Added a .editorconfig file to auto-configure editors that support it.
+- Added --directory option to run-tests.sh for easier test discovery of all
+ tests within a project.
+- Made run-tests.sh exit with a failure code when there are test fails or
+ problems running the script.
+- Fixed that cookies from previous tests are still present when a new test
+ starts in DrupalWebTestCase.
+- Improved performance of queries on the {authmap} database table.
+- Fixed handling of missing files and functions inside the registry.
+- Fixed Ajax handling for tableselect form elements that use checkboxes.
+- Fixed a bug which caused ip_address() to return nothing when the client IP
+ address and proxy IP address are the same.
+- Added a new option to format_xml_elements() to allow for already encoded
+ values.
+- Changed the {history} table's node ID field to be an unsigned integer, to
+ match the same field in the {node} table and to prevent errors with very
+ large node IDs.
+- Added an explicit page callback to the "admin/people/create" menu item in the
+ User module (minor data structure change). Previously this automatically
+ inherited the page callback from the parent "admin/people" menu item, which
+ broke contributed modules that override the "admin/people" page.
+- Numerous small bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.44, 2016-06-15
+-----------------------
+- Fixed security issues (privilege escalation). See SA-CORE-2016-002.
+
+Drupal 7.43, 2016-02-24
+-----------------------
+- Fixed security issues (multiple vulnerabilities). See SA-CORE-2016-001.
+
+Drupal 7.42, 2016-02-03
+-----------------------
+- Stopped invoking hook_flush_caches() on every cron run, since some modules
+ use that hook for expensive operations that are only needed on cache clears.
+- Changed the default .htaccess and web.config to block Composer-related files.
+- Added static caching to module_load_include() to improve performance.
+- Fixed double-encoding bugs in select field widgets provided by the Options
+ module. The fix deprecates the 'strip_tags' property on option widgets and
+ replaces it with a new 'strip_tags_and_unescape' property (minor data
+ structure change).
+- Improved MySQL 5.7 support by changing the MySQL database driver to stop
+ using the ANSI SQL mode alias, which has different meanings for different
+ MySQL versions.
+- Fixed a regression introduced in Drupal 7.39 which prevented autocomplete
+ functionality from working on servers that are not configured to
+ automatically recognize index.php.
+- Updated the Archive_Tar PEAR package to the latest 1.4.0 release, to fix bugs
+ with tar file handling on various operating systems.
+- Fixed fatal errors on node preview when a field is displayed in the node
+ teaser but hidden in the full node view. The fix removes a
+ field_attach_prepare_view() call from the node_preview() function since it is
+ redundant with one in the node preview theme layer.
+- Improved the description of the "Trimmed" format option on text fields
+ (translatable string change, and minor UI and data structure change).
+- Numerous small bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
+
+Drupal 7.41, 2015-10-21
+-----------------------
+- Fixed security issues (open redirect). See SA-CORE-2015-004.
+
+Drupal 7.40, 2015-10-14
+-----------------------
+- Made Drupal's code for parsing .info files run much faster and use much less
+ memory.
+- Prevented drupal_http_request() from returning an error when it receives a
+ 201 through 206 HTTP status code.
+- Added support for autoloading traits via the registry on sites running PHP
+ 5.4 or higher.
+- Allowed the user-picture.tpl.php theme template to have HTML classes besides
+ the default "user-picture" class printed in it (markup change).
+- Fixed the URL text filter to convert e-mail addresses with plus signs into
+ mailto: links.
+- Added alternate text to file icons displayed by the File module, to improve
+ accessibility (string change, and minor API addition to theme_file_icon()).
+- Changed one-time login link failure messages to be displayed as errors or
+ warnings as appropriate, rather than as regular status messages (minor UI
+ change and data structure change).
+- Changed the default settings.php configuration to exclude private files from
+ the "404_fast_paths" behavior.
+- Changed the page that displays filter tips for a particular text format, for
+ example filter/tips/full_html, to return "page not found" or "access denied"
+ if the format does not exist or the user does not have access to it. This
+ change adds a new menu item to the Filter module's hook_menu() entry (minor
+ data structure change).
+- Added a new hook, hook_block_cid_parts_alter(), to allow modules to alter the
+ cache keys used for caching a particular block.
+- Made drupal_set_message() display and return messages when "0" is passed in
+ as the message to set.
+- Fixed non-functional "Files displayed by default" setting on file fields.
+- The "worker callback" provided in hook_cron_queue_info() and the "finished"
+ callback specified during batch processing can now be any PHP callable
+ instead of just functions.
+- Prevented drupal_set_time_limit() from decreasing the time limit in the case
+ where the PHP maximum execution time is already unlimited.
+- Changed the default thousand marker for numeric fields from a space ("1 000")
+ to nothing ("1000") (minor UI change: https://www.drupal.org/node/1388376).
+- Prevented malformed theme .info files (without a "name" key) from causing
+ exceptions during menu rebuilds. If an .info file without a "name" key is
+ found in a module or theme directory, Drupal will now use the module or
+ theme's machine name as the display name instead.
+- Made the format column in the {date_format_locale} database table
+ case-sensitive, to match the equivalent column in the {date_formats} table.
+- Fixed a bug in the Statistics module that caused JavaScript files attached to
+ a node while it is being viewed to be omitted from the page.
+- Added an optional 'project:' prefix that can be added to dependencies in a
+ module's .info file to indicate which project the dependency resides in (API
+ addition: https://www.drupal.org/node/2299747).
+- Fixed various bugs that occurred after hooks were invoked early in the Drupal
+ bootstrap and that caused module_implements() and drupal_alter() to cache an
+ incomplete set of hook implementations for later use.
+- Set the X-Content-Type-Options header to "nosniff" when possible, to prevent
+ certain web browsers from picking an unsafe MIME type.
+- Prevented the database API from executing multiple queries at once on MySQL,
+ if the site's PHP version is new enough to do so. This is a secondary defense
+ against SQL injection (API change: https://www.drupal.org/node/2463973).
+- Fixed a bug in the Drupal 6 to Drupal 7 upgrade path which caused the upgrade
+ to fail when there were multiple file records pointing to the same file.
+- Numerous small bug fixes.
+- Numerous API documentation improvements.
+- Additional automated test coverage.
Drupal 7.39, 2015-08-19
-----------------------
@@ -86,11 +344,11 @@ Drupal 7.36, 2015-04-01
- Additional automated test coverage.
Drupal 7.35, 2015-03-18
-----------------------
+-----------------------
- Fixed security issues (multiple vulnerabilities). See SA-CORE-2015-001.
Drupal 7.34, 2014-11-19
-----------------------
+-----------------------
- Fixed security issues (multiple vulnerabilities). See SA-CORE-2014-006.
Drupal 7.33, 2014-11-07
@@ -159,11 +417,11 @@ Drupal 7.33, 2014-11-07
- Additional automated test coverage.
Drupal 7.32, 2014-10-15
-----------------------
+-----------------------
- Fixed security issues (SQL injection). See SA-CORE-2014-005.
Drupal 7.31, 2014-08-06
-----------------------
+-----------------------
- Fixed security issues (denial of service). See SA-CORE-2014-004.
Drupal 7.30, 2014-07-24
@@ -178,7 +436,7 @@ Drupal 7.30, 2014-07-24
- Additional automated test coverage.
Drupal 7.29, 2014-07-16
-----------------------
+-----------------------
- Fixed security issues (multiple vulnerabilities). See SA-CORE-2014-003.
Drupal 7.28, 2014-05-08
@@ -224,11 +482,11 @@ Drupal 7.28, 2014-05-08
- Additional automated test coverage.
Drupal 7.27, 2014-04-16
-----------------------
+-----------------------
- Fixed security issues (information disclosure). See SA-CORE-2014-002.
Drupal 7.26, 2014-01-15
-----------------------
+-----------------------
- Fixed security issues (multiple vulnerabilities). See SA-CORE-2014-001.
Drupal 7.25, 2014-01-02
@@ -294,7 +552,7 @@ Drupal 7.25, 2014-01-02
- Additional automated test coverage.
Drupal 7.24, 2013-11-20
-----------------------
+-----------------------
- Fixed security issues (multiple vulnerabilities), see SA-CORE-2013-003.
Drupal 7.23, 2013-08-07
@@ -548,8 +806,8 @@ Drupal 7.15, 2012-08-01
- Numerous API documentation improvements.
- Additional automated test coverage.
-Drupal 7.14 2012-05-02
-----------------------
+Drupal 7.14, 2012-05-02
+-----------------------
- Fixed "integrity constraint" fatal errors when rebuilding registry.
- Fixed custom logo and favicon functionality referencing incorrect paths.
- Fixed DB Case Sensitivity: Allow BINARY attribute in MySQL.
@@ -597,12 +855,12 @@ Drupal 7.14 2012-05-02
- system_update_7061() converts filepaths too aggressively.
- Trigger upgrade path: Node triggers removed when upgrading to 7-x from 6.25.
-Drupal 7.13 2012-05-02
-----------------------
+Drupal 7.13, 2012-05-02
+-----------------------
- Fixed security issues (Multiple vulnerabilities), see SA-CORE-2012-002.
Drupal 7.12, 2012-02-01
-----------------------
+-----------------------
- Fixed bug preventing custom menus from receiving an active trail.
- Fixed hook_field_delete() no longer invoked during field_purge_data().
- Fixed bug causing entity info cache to not be cleared with the rest of caches.
@@ -636,11 +894,11 @@ Drupal 7.12, 2012-02-01
cache.
Drupal 7.11, 2012-02-01
-----------------------
+-----------------------
- Fixed security issues (Multiple vulnerabilities), see SA-CORE-2012-001.
Drupal 7.10, 2011-12-05
-----------------------
+-----------------------
- Fixed Content-Language HTTP header to not cause issues with Drush 5.x.
- Reduce memory usage of theme registry (performance).
- Fixed PECL upload progress bar for FileField
@@ -993,7 +1251,7 @@ Drupal 7.0, 2011-01-05
requests.
Drupal 6.23-dev, xxxx-xx-xx (development release)
------------------------
+---------------------------
Drupal 6.22, 2011-05-25
-----------------------
@@ -1003,25 +1261,25 @@ Drupal 6.22, 2011-05-25
- Fixed a variety of other bugs.
Drupal 6.21, 2011-05-25
-----------------------
+-----------------------
- Fixed security issues (Cross site scripting), see SA-CORE-2011-001.
Drupal 6.20, 2010-12-15
-----------------------
+-----------------------
- Fixed a variety of small bugs, improved code documentation.
Drupal 6.19, 2010-08-11
-----------------------
+-----------------------
- Fixed a variety of small bugs, improved code documentation.
Drupal 6.18, 2010-08-11
-----------------------
+-----------------------
- Fixed security issues (OpenID authentication bypass, File download access
bypass, Comment unpublishing bypass, Actions cross site scripting),
see SA-CORE-2010-002.
Drupal 6.17, 2010-06-02
-----------------------
+-----------------------
- Improved PostgreSQL compatibility
- Better PHP 5.3 and PHP 4 compatibility
- Better browser compatibility of CSS and JS aggregation
@@ -1030,7 +1288,7 @@ Drupal 6.17, 2010-06-02
- Fixed a variety of other bugs.
Drupal 6.16, 2010-03-03
-----------------------
+-----------------------
- Fixed security issues (Installation cross site scripting, Open redirection,
Locale module cross site scripting, Blocked user session regeneration),
see SA-CORE-2010-001.
@@ -1042,12 +1300,12 @@ Drupal 6.16, 2010-03-03
- Fixed a variety of other bugs.
Drupal 6.15, 2009-12-16
-----------------------
+-----------------------
- Fixed security issues (Cross site scripting), see SA-CORE-2009-009.
- Fixed a variety of other bugs.
Drupal 6.14, 2009-09-16
-----------------------
+-----------------------
- Fixed security issues (OpenID association cross site request forgeries,
OpenID impersonation and File upload), see SA-CORE-2009-008.
- Changed the system modules page to not run all cache rebuilds; use the
@@ -1056,18 +1314,18 @@ Drupal 6.14, 2009-09-16
- Fixed a variety of small bugs.
Drupal 6.13, 2009-07-01
-----------------------
+-----------------------
- Fixed security issues (Cross site scripting, Input format access bypass and
Password leakage in URL), see SA-CORE-2009-007.
- Fixed a variety of small bugs.
Drupal 6.12, 2009-05-13
-----------------------
+-----------------------
- Fixed security issues (Cross site scripting), see SA-CORE-2009-006.
- Fixed a variety of small bugs.
Drupal 6.11, 2009-04-29
-----------------------
+-----------------------
- Fixed security issues (Cross site scripting and limited information
disclosure), see SA-CORE-2009-005
- Fixed performance issues with the menu router cache, the update
@@ -1075,7 +1333,7 @@ Drupal 6.11, 2009-04-29
- Fixed a variety of small bugs.
Drupal 6.10, 2009-02-25
-----------------------
+-----------------------
- Fixed a security issue, (Local file inclusion on Windows),
see SA-CORE-2009-003
- Fixed node_feed() so custom fields can show up in RSS feeds.
@@ -1471,7 +1729,7 @@ Drupal 4.7.9, 2007-12-05
- fixed a security issue (SQL injection), see SA-2007-031
Drupal 4.7.8, 2007-10-17
-----------------------
+------------------------
- fixed a security issue (HTTP response splitting), see SA-2007-024
- fixed a security issue (Cross site scripting via uploads), see SA-2007-026
- fixed a security issue (API handling of unpublished comment), see SA-2007-030
@@ -1584,7 +1842,7 @@ Drupal 4.6.11, 2007-01-05
- Fixed security issue (DoS), see SA-2007-002
Drupal 4.6.10, 2006-10-18
-------------------------
+-------------------------
- Fixed security issue (XSS), see SA-2006-024
- Fixed security issue (CSRF), see SA-2006-025
- Fixed security issue (Form action attribute injection), see SA-2006-026
diff --git a/INSTALL.txt b/INSTALL.txt
index 6f02c05a..e00c8bad 100644
--- a/INSTALL.txt
+++ b/INSTALL.txt
@@ -23,7 +23,7 @@ Drupal requires:
- Percona Server 5.1.70 (or greater) (http://www.percona.com/). Percona
Server is a backwards-compatible replacement for MySQL.
- PostgreSQL 8.3 (or greater) (http://www.postgresql.org/).
- - SQLite 3.4.2 (or greater) (http://www.sqlite.org/).
+ - SQLite 3.3.7 (or greater) (http://www.sqlite.org/).
For more detailed information about Drupal requirements, including a list of
PHP extensions and configurations that are required, see "System requirements"
diff --git a/MAINTAINERS.txt b/MAINTAINERS.txt
index f5cf6f89..5603a432 100644
--- a/MAINTAINERS.txt
+++ b/MAINTAINERS.txt
@@ -1,7 +1,8 @@
Drupal core is built and maintained by the Drupal project community. Everyone is
encouraged to submit issues and changes (patches) to improve Drupal, and to
-contribute in other ways -- see http://drupal.org/contribute to find out how.
+contribute in other ways -- see https://www.drupal.org/contribute to find out
+how.
Branch maintainers
------------------
@@ -9,154 +10,154 @@ 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' https://www.drupal.org/u/dries
+- Angela Byron 'webchick' https://www.drupal.org/u/webchick
+- Fabian Franz 'Fabianx' https://www.drupal.org/u/fabianx
+- David Rothstein 'David_Rothstein' https://www.drupal.org/u/david_rothstein
+- Stefan Ruijsenaars 'stefan.r' https://www.drupal.org/u/stefanr-0
Component maintainers
---------------------
The Drupal Core component maintainers oversee the development of Drupal
-subsystems. See http://drupal.org/contribute/core-maintainers for more
+subsystems. See https://www.drupal.org/contribute/core-maintainers for more
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' https://www.drupal.org/u/effulgentsia
+- Earl Miles 'merlinofchaos' https://www.drupal.org/u/merlinofchaos
Base system
-- Damien Tournoud 'DamZ' http://drupal.org/user/22211
-- Moshe Weitzman 'moshe weitzman' http://drupal.org/user/23
+- Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
+- Moshe Weitzman 'moshe weitzman' https://www.drupal.org/u/moshe-weitzman
Batch system
-- Yves Chedemois 'yched' http://drupal.org/user/39567
+- Yves Chedemois 'yched' https://www.drupal.org/u/yched
Cache system
-- Damien Tournoud 'DamZ' http://drupal.org/user/22211
-- Nathaniel Catchpole 'catch' http://drupal.org/user/35733
+- Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
+- Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch
Cron system
-- Derek Wright 'dww' http://drupal.org/user/46549
+- Derek Wright 'dww' https://www.drupal.org/u/dww
Database system
-- Larry Garfield 'Crell' http://drupal.org/user/26398
+- Larry Garfield 'Crell' https://www.drupal.org/u/crell
- MySQL driver
- - Larry Garfield 'Crell' http://drupal.org/user/26398
- - David Strauss 'David Strauss' http://drupal.org/user/93254
+ - Larry Garfield 'Crell' https://www.drupal.org/u/crell
+ - David Strauss 'David Strauss' https://www.drupal.org/u/david-strauss
- PostgreSQL driver
- - Damien Tournoud 'DamZ' http://drupal.org/user/22211
- - Josh Waihi 'fiasco' http://drupal.org/user/188162
+ - Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
+ - Josh Waihi 'fiasco' https://www.drupal.org/u/josh-waihi
- Sqlite driver
- - Damien Tournoud 'DamZ' http://drupal.org/user/22211
+ - Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
Database update system
-- Ashok Modi 'BTMash' http://drupal.org/user/60422
+- Ashok Modi 'BTMash' https://www.drupal.org/u/btmash
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' https://www.drupal.org/u/fago
+- Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch
+- Franz Heinzmann 'Frando' https://www.drupal.org/u/frando
File system
-- Andrew Morton 'drewish' http://drupal.org/user/34869
-- Aaron Winborn 'aaron' http://drupal.org/user/33420
+- Andrew Morton 'drewish' https://www.drupal.org/u/drewish
+- Aaron Winborn 'aaron' https://www.drupal.org/u/aaron
Form system
-- 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
+- Alex Bronstein 'effulgentsia' https://www.drupal.org/u/effulgentsia
+- Wolfgang Ziegler 'fago' https://www.drupal.org/u/fago
+- Daniel F. Kudwien 'sun' https://www.drupal.org/u/sun
+- Franz Heinzmann 'Frando' https://www.drupal.org/u/frando
Image system
-- Andrew Morton 'drewish' http://drupal.org/user/34869
-- Nathan Haug 'quicksketch' http://drupal.org/user/35821
+- Andrew Morton 'drewish' https://www.drupal.org/u/drewish
+- Nathan Haug 'quicksketch' https://www.drupal.org/u/quicksketch
Install system
-- David Rothstein 'David_Rothstein' http://drupal.org/user/124982
+- David Rothstein 'David_Rothstein' https://www.drupal.org/u/david_rothstein
JavaScript
-- 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
+- Théodore Biadala 'nod_' https://www.drupal.org/u/nod_
+- Steve De Jonghe 'seutje' https://www.drupal.org/u/seutje
Language system
-- Francesco Placella 'plach' http://drupal.org/user/183211
-- Daniel F. Kudwien 'sun' http://drupal.org/user/54136
+- Francesco Placella 'plach' https://www.drupal.org/u/plach
+- Daniel F. Kudwien 'sun' https://www.drupal.org/u/sun
Lock system
-- Damien Tournoud 'DamZ' http://drupal.org/user/22211
+- Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
Mail system
- ?
Markup
-- Jacine Luisi 'Jacine' http://drupal.org/user/88931
-- Daniel F. Kudwien 'sun' http://drupal.org/user/54136
+- Jacine Luisi 'Jacine' https://www.drupal.org/u/jacine
+- Daniel F. Kudwien 'sun' https://www.drupal.org/u/sun
Menu system
-- Peter Wolanin 'pwolanin' http://drupal.org/user/49851
+- Peter Wolanin 'pwolanin' https://www.drupal.org/u/pwolanin
Path system
-- Dave Reid 'davereid' http://drupal.org/user/53892
-- Nathaniel Catchpole 'catch' http://drupal.org/user/35733
+- Dave Reid 'davereid' https://www.drupal.org/u/dave-reid
+- Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch
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' https://www.drupal.org/u/moshe-weitzman
+- Alex Bronstein 'effulgentsia' https://www.drupal.org/u/effulgentsia
+- Franz Heinzmann 'Frando' https://www.drupal.org/u/frando
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' https://www.drupal.org/u/merlinofchaos
+- Alex Bronstein 'effulgentsia' https://www.drupal.org/u/effulgentsia
+- Joon Park 'dvessel' https://www.drupal.org/u/dvessel
+- John Albin Wilkins 'JohnAlbin' https://www.drupal.org/u/johnalbin
Token system
-- Dave Reid 'davereid' http://drupal.org/user/53892
+- Dave Reid 'davereid' https://www.drupal.org/u/dave-reid
XML-RPC system
-- Frederic G. Marand 'fgm' http://drupal.org/user/27985
+- Frederic G. Marand 'fgm' https://www.drupal.org/u/fgm
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' https://www.drupal.org/u/everett-zufelt
+- Brandon Bowersox-Johnson 'bowersox' https://www.drupal.org/u/bowersox
Documentation
-- Jennifer Hodgdon 'jhodgdon' http://drupal.org/user/155601
+- Jennifer Hodgdon 'jhodgdon' https://www.drupal.org/u/jhodgdon
Translations
-- Gerhard Killesreiter 'killes' http://drupal.org/user/83
+- Gerhard Killesreiter 'killes' https://www.drupal.org/u/gerhard-killesreiter
User experience and usability
-- Roy Scholten 'yoroy' http://drupal.org/user/41502
-- Bojhan Somers 'Bojhan' http://drupal.org/user/87969
+- Roy Scholten 'yoroy' https://www.drupal.org/u/yoroy
+- Bojhan Somers 'Bojhan' https://www.drupal.org/u/bojhan
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' https://www.drupal.org/u/moshe-weitzman
+- Ken Rickard 'agentrickard' https://www.drupal.org/u/agentrickard
Security team
-----------------
-To report a security issue, see: https://drupal.org/security-team/report-issue
+To report a security issue, see: https://www.drupal.org/security-team/report-issue
The Drupal security team provides Security Advisories for vulnerabilities,
assists developers in resolving security issues, and provides security
-documentation. See http://drupal.org/security-team for more information. The
-security team lead is:
+documentation. See https://www.drupal.org/security-team for more information.
+The security team lead is:
-- Michael Hess 'mlhess' https://drupal.org/user/102818
+- Michael Hess 'mlhess' https://www.drupal.org/u/mlhess
Module maintainers
@@ -166,142 +167,141 @@ Aggregator module
- ?
Block module
-- John Albin Wilkins 'JohnAlbin' http://drupal.org/user/32095
+- John Albin Wilkins 'JohnAlbin' https://www.drupal.org/u/johnalbin
Blog module
- ?
Book module
-- Peter Wolanin 'pwolanin' http://drupal.org/user/49851
+- Peter Wolanin 'pwolanin' https://www.drupal.org/u/pwolanin
Color module
- ?
Comment module
-- Nathaniel Catchpole 'catch' http://drupal.org/user/35733
+- Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch
Contact module
-- Dave Reid 'davereid' http://drupal.org/user/53892
+- Dave Reid 'davereid' https://www.drupal.org/u/dave-reid
Contextual module
-- Daniel F. Kudwien 'sun' http://drupal.org/user/54136
+- Daniel F. Kudwien 'sun' https://www.drupal.org/u/sun
Dashboard module
- ?
Database logging module
-- Khalid Baheyeldin 'kbahey' http://drupal.org/user/4063
+- Khalid Baheyeldin 'kbahey' https://www.drupal.org/u/kbahey
Field module
-- Yves Chedemois 'yched' http://drupal.org/user/39567
-- Barry Jaspan 'bjaspan' http://drupal.org/user/46413
+- Yves Chedemois 'yched' https://www.drupal.org/u/yched
+- Barry Jaspan 'bjaspan' https://www.drupal.org/u/bjaspan
Field UI module
-- Yves Chedemois 'yched' http://drupal.org/user/39567
+- Yves Chedemois 'yched' https://www.drupal.org/u/yched
File module
-- Aaron Winborn 'aaron' http://drupal.org/user/33420
+- Aaron Winborn 'aaron' https://www.drupal.org/u/aaron
Filter module
-- Daniel F. Kudwien 'sun' http://drupal.org/user/54136
+- Daniel F. Kudwien 'sun' https://www.drupal.org/u/sun
Forum module
-- Lee Rowlands 'larowlan' http://drupal.org/user/395439
+- Lee Rowlands 'larowlan' https://www.drupal.org/u/larowlan
Help module
- ?
Image module
-- Nathan Haug 'quicksketch' http://drupal.org/user/35821
+- Nathan Haug 'quicksketch' https://www.drupal.org/u/quicksketch
Locale module
-- Gábor Hojtsy 'Gábor Hojtsy' http://drupal.org/user/4166
+- Gábor Hojtsy 'Gábor Hojtsy' https://www.drupal.org/u/gábor-hojtsy
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' https://www.drupal.org/u/moshe-weitzman
+- David Strauss 'David Strauss' https://www.drupal.org/u/david-strauss
OpenID module
-- Vojtech Kusy 'wojtha' http://drupal.org/user/56154
-- Christian Schmidt 'c960657' http://drupal.org/user/216078
-- Damien Tournoud 'DamZ' http://drupal.org/user/22211
+- Vojtech Kusy 'wojtha' https://www.drupal.org/u/wojtha
+- Christian Schmidt 'c960657' https://www.drupal.org/u/c960657
+- Damien Tournoud 'DamZ' https://www.drupal.org/u/damien-tournoud
Overlay module
-- Katherine Senzee 'ksenzee' http://drupal.org/user/139855
+- Katherine Senzee 'ksenzee' https://www.drupal.org/u/ksenzee
Path module
-- Dave Reid 'davereid' http://drupal.org/user/53892
+- Dave Reid 'davereid' https://www.drupal.org/u/dave-reid
PHP module
- ?
Poll module
-- Andrei Mateescu 'amateescu' http://drupal.org/user/729614
+- Andrei Mateescu 'amateescu' https://www.drupal.org/u/amateescu
Profile module
- ?
RDF module
-- Stéphane Corlosquet 'scor' http://drupal.org/user/52142
+- Stéphane Corlosquet 'scor' https://www.drupal.org/u/scor
Search module
-- Doug Green 'douggreen' http://drupal.org/user/29191
+- Doug Green 'douggreen' https://www.drupal.org/u/douggreen
Shortcut module
-- David Rothstein 'David_Rothstein' http://drupal.org/user/124982
+- David Rothstein 'David_Rothstein' https://www.drupal.org/u/david_rothstein
Simpletest module
-- Jimmy Berry 'boombatower' http://drupal.org/user/214218
+- Jimmy Berry 'boombatower' https://www.drupal.org/u/boombatower
Statistics module
-- Tim Millwood 'timmillwood' http://drupal.org/user/227849
+- Tim Millwood 'timmillwood' https://www.drupal.org/u/timmillwood
Syslog module
-- Khalid Baheyeldin 'kbahey' http://drupal.org/user/4063
+- Khalid Baheyeldin 'kbahey' https://www.drupal.org/u/kbahey
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
+- Nathaniel Catchpole 'catch' https://www.drupal.org/u/catch
+- Benjamin Doherty 'bangpound' https://www.drupal.org/u/bangpound
Toolbar module
- ?
Tracker module
-- David Strauss 'David Strauss' http://drupal.org/user/93254
+- David Strauss 'David Strauss' https://www.drupal.org/u/david-strauss
Translation module
-- Francesco Placella 'plach' http://drupal.org/user/183211
+- Francesco Placella 'plach' https://www.drupal.org/u/plach
Trigger module
- ?
Update module
-- Derek Wright 'dww' http://drupal.org/user/46549
+- Derek Wright 'dww' https://www.drupal.org/u/dww
User module
-- Moshe Weitzman 'moshe weitzman' http://drupal.org/user/23
-- David Strauss 'David Strauss' http://drupal.org/user/93254
+- Moshe Weitzman 'moshe weitzman' https://www.drupal.org/u/moshe-weitzman
+- David Strauss 'David Strauss' https://www.drupal.org/u/david-strauss
Theme maintainers
-----------------
Bartik theme
-- Jen Simmons 'jensimmons' http://drupal.org/user/140882
-- Jeff Burns 'Jeff Burnz' http://drupal.org/user/61393
+- Jen Simmons 'jensimmons' https://www.drupal.org/u/jensimmons
+- Jeff Burns 'Jeff Burnz' https://www.drupal.org/u/jeff-burnz
Garland theme
-- John Albin Wilkins 'JohnAlbin' http://drupal.org/user/32095
+- John Albin Wilkins 'JohnAlbin' https://www.drupal.org/u/johnalbin
Seven theme
-- Jeff Burns 'Jeff Burnz' http://drupal.org/user/61393
+- Jeff Burns 'Jeff Burnz' https://www.drupal.org/u/jeff-burnz
Stark theme
-- John Albin Wilkins 'JohnAlbin' http://drupal.org/user/32095
+- John Albin Wilkins 'JohnAlbin' https://www.drupal.org/u/johnalbin
diff --git a/PATCHES.txt b/PATCHES.txt
index dc278579..229f703b 100644
--- a/PATCHES.txt
+++ b/PATCHES.txt
@@ -5,4 +5,4 @@ The following patches have been applied to this project:
- http://drupal.org/files/issues/drupal-7.x-allow_profile_change_sys_req-1772316-28.patch
- http://drupal.org/files/1275902-15-entity_uri_callback-D7.patch
-This file was automatically generated by Drush Make (http://drupal.org/project/drush).
\ No newline at end of file
+This file was automatically generated by Drush Make (http://drupal.org/project/drush).
diff --git a/UPGRADE.txt b/UPGRADE.txt
index e870ff0f..ae733ca1 100644
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -64,6 +64,9 @@ following the instructions in the INTRODUCTION section at the top of this file:
Sometimes an update includes changes to default.settings.php (this will be
noted in the release notes). If that's the case, follow these steps:
+ - Locate your settings.php file in the /sites/* directory. (Typically
+ sites/default.)
+
- Make a backup copy of your settings.php file, with a different file name.
- Make a copy of the new default.settings.php file, and name the copy
@@ -74,6 +77,13 @@ following the instructions in the INTRODUCTION section at the top of this file:
database information, and you will also want to copy in any other
customizations you have added.
+ You can find the release notes for your version at
+ https://www.drupal.org/project/drupal. At bottom of the project page under
+ "Downloads" use the link for your version of Drupal to view the release
+ notes. If your version is not listed, use the 'View all releases' link. From
+ this page you can scroll down or use the filter to find your version and its
+ release notes.
+
4. Download the latest Drupal 7.x release from http://drupal.org to a
directory outside of your web root. Extract the archive and copy the files
into your Drupal directory.
diff --git a/includes/ajax.inc b/includes/ajax.inc
index 50e8e28a..f059209b 100644
--- a/includes/ajax.inc
+++ b/includes/ajax.inc
@@ -394,7 +394,7 @@ function ajax_form_callback() {
if (!empty($form_state['triggering_element'])) {
$callback = $form_state['triggering_element']['#ajax']['callback'];
}
- if (!empty($callback) && function_exists($callback)) {
+ if (!empty($callback) && is_callable($callback)) {
$result = $callback($form, $form_state);
if (!(is_array($result) && isset($result['#type']) && $result['#type'] == 'ajax')) {
diff --git a/includes/batch.inc b/includes/batch.inc
index 061acd4c..e89ab8de 100644
--- a/includes/batch.inc
+++ b/includes/batch.inc
@@ -460,10 +460,10 @@ function _batch_finished() {
if (isset($batch_set['file']) && is_file($batch_set['file'])) {
include_once DRUPAL_ROOT . '/' . $batch_set['file'];
}
- if (function_exists($batch_set['finished'])) {
+ if (is_callable($batch_set['finished'])) {
$queue = _batch_queue($batch_set);
$operations = $queue->getAllItems();
- $batch_set['finished']($batch_set['success'], $batch_set['results'], $operations, format_interval($batch_set['elapsed'] / 1000));
+ call_user_func($batch_set['finished'], $batch_set['success'], $batch_set['results'], $operations, format_interval($batch_set['elapsed'] / 1000));
}
}
}
diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index 5cf78dcf..2d8b820f 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -8,7 +8,7 @@
/**
* The current system version.
*/
-define('VERSION', '7.39');
+define('VERSION', '7.60');
/**
* Core API compatibility.
@@ -254,8 +254,13 @@ define('DRUPAL_PHP_FUNCTION_PATTERN', '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*'
* http://tools.ietf.org/html/rfc7231#section-7.1.1.1
*
* Example: Sun, 06 Nov 1994 08:49:37 GMT
+ *
+ * This constant was introduced in PHP 7.0.19 and PHP 7.1.5 but needs to be
+ * defined by Drupal for earlier PHP versions.
*/
-define('DATE_RFC7231', 'D, d M Y H:i:s \G\M\T');
+if (!defined('DATE_RFC7231')) {
+ define('DATE_RFC7231', 'D, d M Y H:i:s \G\M\T');
+}
/**
* Provides a caching wrapper to be used in place of large array structures.
@@ -718,6 +723,16 @@ function drupal_valid_http_host($host) {
&& preg_match('/^\[?(?:[a-zA-Z0-9-:\]_]+\.?)+$/', $host);
}
+/**
+ * Checks whether an HTTPS request is being served.
+ *
+ * @return bool
+ * TRUE if the request is HTTPS, FALSE otherwise.
+ */
+function drupal_is_https() {
+ return isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on';
+}
+
/**
* Sets the base URL, cookie domain, and session name from configuration.
*/
@@ -731,7 +746,7 @@ function drupal_settings_initialize() {
if (file_exists(DRUPAL_ROOT . '/' . conf_path() . '/settings.php')) {
include_once DRUPAL_ROOT . '/' . conf_path() . '/settings.php';
}
- $is_https = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on';
+ $is_https = drupal_is_https();
if (isset($base_url)) {
// Parse fixed base URL from settings.php.
@@ -828,14 +843,21 @@ function drupal_settings_initialize() {
* @param $filename
* The filename of the item if it is to be set explicitly rather
* than by consulting the database.
+ * @param bool $trigger_error
+ * Whether to trigger an error when a file is missing or has unexpectedly
+ * moved. This defaults to TRUE, but can be set to FALSE by calling code that
+ * merely wants to check whether an item exists in the filesystem.
*
* @return
* The filename of the requested item or NULL if the item is not found.
*/
-function drupal_get_filename($type, $name, $filename = NULL) {
+function drupal_get_filename($type, $name, $filename = NULL, $trigger_error = TRUE) {
+ // The $files static variable will hold the locations of all requested files.
+ // We can be sure that any file listed in this static variable actually
+ // exists as all additions have gone through a file_exists() check.
// The location of files will not change during the request, so do not use
// drupal_static().
- static $files = array(), $dirs = array();
+ static $files = array();
// Profiles are a special case: they have a fixed location and naming.
if ($type == 'profile') {
@@ -847,64 +869,296 @@ function drupal_get_filename($type, $name, $filename = NULL) {
}
if (!empty($filename) && file_exists($filename)) {
+ // Prime the static cache with the provided filename.
$files[$type][$name] = $filename;
}
elseif (isset($files[$type][$name])) {
- // nothing
+ // This item had already been found earlier in the request, either through
+ // priming of the static cache (for example, in system_list()), through a
+ // lookup in the {system} table, or through a file scan (cached or not). Do
+ // nothing.
}
- // Verify that we have an active database connection, before querying
- // the database. This is required because this function is called both
- // before we have a database connection (i.e. during installation) and
- // when a database connection fails.
else {
+ // Look for the filename listed in the {system} table. Verify that we have
+ // an active database connection before doing so, since this function is
+ // called both before we have a database connection (i.e. during
+ // installation) and when a database connection fails.
+ $database_unavailable = TRUE;
try {
if (function_exists('db_query')) {
$file = db_query("SELECT filename FROM {system} WHERE name = :name AND type = :type", array(':name' => $name, ':type' => $type))->fetchField();
if ($file !== FALSE && file_exists(DRUPAL_ROOT . '/' . $file)) {
$files[$type][$name] = $file;
}
+ $database_unavailable = FALSE;
}
}
catch (Exception $e) {
// The database table may not exist because Drupal is not yet installed,
- // or the database might be down. We have a fallback for this case so we
- // hide the error completely.
+ // the database might be down, or we may have done a non-database cache
+ // flush while $conf['page_cache_without_database'] = TRUE and
+ // $conf['page_cache_invoke_hooks'] = TRUE. We have a fallback for these
+ // cases so we hide the error completely.
}
- // Fallback to searching the filesystem if the database could not find the
- // file or the file returned by the database is not found.
+ // Fall back to searching the filesystem if the database could not find the
+ // file or the file does not exist at the path returned by the database.
if (!isset($files[$type][$name])) {
- // We have a consistent directory naming: modules, themes...
- $dir = $type . 's';
- if ($type == 'theme_engine') {
- $dir = 'themes/engines';
- $extension = 'engine';
- }
- elseif ($type == 'theme') {
- $extension = 'info';
- }
- else {
- $extension = $type;
- }
+ $files[$type][$name] = _drupal_get_filename_fallback($type, $name, $trigger_error, $database_unavailable);
+ }
+ }
- if (!isset($dirs[$dir][$extension])) {
- $dirs[$dir][$extension] = TRUE;
- if (!function_exists('drupal_system_listing')) {
- require_once DRUPAL_ROOT . '/includes/common.inc';
- }
- // Scan the appropriate directories for all files with the requested
- // extension, not just the file we are currently looking for. This
- // prevents unnecessary scans from being repeated when this function is
- // called more than once in the same page request.
- $matches = drupal_system_listing("/^" . DRUPAL_PHP_FUNCTION_PATTERN . "\.$extension$/", $dir, 'name', 0);
- foreach ($matches as $matched_name => $file) {
- $files[$type][$matched_name] = $file->uri;
+ if (isset($files[$type][$name])) {
+ return $files[$type][$name];
+ }
+}
+
+/**
+ * Performs a cached file system scan as a fallback when searching for a file.
+ *
+ * This function looks for the requested file by triggering a file scan,
+ * caching the new location if the file has moved and caching the miss
+ * if the file is missing. If a file had been marked as missing in a previous
+ * file scan, or if it has been marked as moved and is still in the last known
+ * location, no new file scan will be performed.
+ *
+ * @param string $type
+ * The type of the item (theme, theme_engine, module, profile).
+ * @param string $name
+ * The name of the item for which the filename is requested.
+ * @param bool $trigger_error
+ * Whether to trigger an error when a file is missing or has unexpectedly
+ * moved.
+ * @param bool $database_unavailable
+ * Whether this function is being called because the Drupal database could
+ * not be queried for the file's location.
+ *
+ * @return
+ * The filename of the requested item or NULL if the item is not found.
+ *
+ * @see drupal_get_filename()
+ */
+function _drupal_get_filename_fallback($type, $name, $trigger_error, $database_unavailable) {
+ $file_scans = &_drupal_file_scan_cache();
+ $filename = NULL;
+
+ // If the cache indicates that the item is missing, or we can verify that the
+ // item exists in the location the cache says it exists in, use that.
+ if (isset($file_scans[$type][$name]) && ($file_scans[$type][$name] === FALSE || file_exists($file_scans[$type][$name]))) {
+ $filename = $file_scans[$type][$name];
+ }
+ // Otherwise, perform a new file scan to find the item.
+ else {
+ $filename = _drupal_get_filename_perform_file_scan($type, $name);
+ // Update the static cache, and mark the persistent cache for updating at
+ // the end of the page request. See drupal_file_scan_write_cache().
+ $file_scans[$type][$name] = $filename;
+ $file_scans['#write_cache'] = TRUE;
+ }
+
+ // If requested, trigger a user-level warning about the missing or
+ // unexpectedly moved file. If the database was unavailable, do not trigger a
+ // warning in the latter case, though, since if the {system} table could not
+ // be queried there is no way to know if the location found here was
+ // "unexpected" or not.
+ if ($trigger_error) {
+ $error_type = $filename === FALSE ? 'missing' : 'moved';
+ if ($error_type == 'missing' || !$database_unavailable) {
+ _drupal_get_filename_fallback_trigger_error($type, $name, $error_type);
+ }
+ }
+
+ // The cache stores FALSE for files that aren't found (to be able to
+ // distinguish them from files that have not yet been searched for), but
+ // drupal_get_filename() expects NULL for these instead, so convert to NULL
+ // before returning.
+ if ($filename === FALSE) {
+ $filename = NULL;
+ }
+ return $filename;
+}
+
+/**
+ * Returns the current list of cached file system scan results.
+ *
+ * @return
+ * An associative array tracking the most recent file scan results for all
+ * files that have had scans performed. The keys are the type and name of the
+ * item that was searched for, and the values can be either:
+ * - Boolean FALSE if the item was not found in the file system.
+ * - A string pointing to the location where the item was found.
+ */
+function &_drupal_file_scan_cache() {
+ $file_scans = &drupal_static(__FUNCTION__, array());
+
+ // The file scan results are stored in a persistent cache (in addition to the
+ // static cache) but because this function can be called before the
+ // persistent cache is available, we must merge any items that were found
+ // earlier in the page request into the results from the persistent cache.
+ if (!isset($file_scans['#cache_merge_done'])) {
+ try {
+ if (function_exists('cache_get')) {
+ $cache = cache_get('_drupal_file_scan_cache', 'cache_bootstrap');
+ if (!empty($cache->data)) {
+ // File scan results from the current request should take precedence
+ // over the results from the persistent cache, since they are newer.
+ $file_scans = drupal_array_merge_deep($cache->data, $file_scans);
}
+ // Set a flag to indicate that the persistent cache does not need to be
+ // merged again.
+ $file_scans['#cache_merge_done'] = TRUE;
}
}
+ catch (Exception $e) {
+ // Hide the error.
+ }
}
- if (isset($files[$type][$name])) {
- return $files[$type][$name];
+ return $file_scans;
+}
+
+/**
+ * Performs a file system scan to search for a system resource.
+ *
+ * @param $type
+ * The type of the item (theme, theme_engine, module, profile).
+ * @param $name
+ * The name of the item for which the filename is requested.
+ *
+ * @return
+ * The filename of the requested item or FALSE if the item is not found.
+ *
+ * @see drupal_get_filename()
+ * @see _drupal_get_filename_fallback()
+ */
+function _drupal_get_filename_perform_file_scan($type, $name) {
+ // The location of files will not change during the request, so do not use
+ // drupal_static().
+ static $dirs = array(), $files = array();
+
+ // We have a consistent directory naming: modules, themes...
+ $dir = $type . 's';
+ if ($type == 'theme_engine') {
+ $dir = 'themes/engines';
+ $extension = 'engine';
+ }
+ elseif ($type == 'theme') {
+ $extension = 'info';
+ }
+ else {
+ $extension = $type;
+ }
+
+ // Check if we had already scanned this directory/extension combination.
+ if (!isset($dirs[$dir][$extension])) {
+ // Log that we have now scanned this directory/extension combination
+ // into a static variable so as to prevent unnecessary file scans.
+ $dirs[$dir][$extension] = TRUE;
+ if (!function_exists('drupal_system_listing')) {
+ require_once DRUPAL_ROOT . '/includes/common.inc';
+ }
+ // Scan the appropriate directories for all files with the requested
+ // extension, not just the file we are currently looking for. This
+ // prevents unnecessary scans from being repeated when this function is
+ // called more than once in the same page request.
+ $matches = drupal_system_listing("/^" . DRUPAL_PHP_FUNCTION_PATTERN . "\.$extension$/", $dir, 'name', 0);
+ foreach ($matches as $matched_name => $file) {
+ // Log the locations found in the file scan into a static variable.
+ $files[$type][$matched_name] = $file->uri;
+ }
+ }
+
+ // Return the results of the file system scan, or FALSE to indicate the file
+ // was not found.
+ return isset($files[$type][$name]) ? $files[$type][$name] : FALSE;
+}
+
+/**
+ * Triggers a user-level warning for missing or unexpectedly moved files.
+ *
+ * @param $type
+ * The type of the item (theme, theme_engine, module, profile).
+ * @param $name
+ * The name of the item for which the filename is requested.
+ * @param $error_type
+ * The type of the error ('missing' or 'moved').
+ *
+ * @see drupal_get_filename()
+ * @see _drupal_get_filename_fallback()
+ */
+function _drupal_get_filename_fallback_trigger_error($type, $name, $error_type) {
+ // Hide messages due to known bugs that will appear on a lot of sites.
+ // @todo Remove this in https://www.drupal.org/node/2383823
+ if (empty($name)) {
+ return;
+ }
+
+ // Make sure we only show any missing or moved file errors only once per
+ // request.
+ static $errors_triggered = array();
+ if (empty($errors_triggered[$type][$name][$error_type])) {
+ // Use _drupal_trigger_error_with_delayed_logging() here since these are
+ // triggered during low-level operations that cannot necessarily be
+ // interrupted by a watchdog() call.
+ if ($error_type == 'missing') {
+ _drupal_trigger_error_with_delayed_logging(format_string('The following @type is missing from the file system: %name. For information about how to fix this, see the documentation page.', array('@type' => $type, '%name' => $name, '@documentation' => 'https://www.drupal.org/node/2487215')), E_USER_WARNING);
+ }
+ elseif ($error_type == 'moved') {
+ _drupal_trigger_error_with_delayed_logging(format_string('The following @type has moved within the file system: %name. In order to fix this, clear caches or put the @type back in its original location. For more information, see the documentation page.', array('@type' => $type, '%name' => $name, '@documentation' => 'https://www.drupal.org/node/2487215')), E_USER_WARNING);
+ }
+ $errors_triggered[$type][$name][$error_type] = TRUE;
+ }
+}
+
+/**
+ * Invokes trigger_error() with logging delayed until the end of the request.
+ *
+ * This is an alternative to PHP's trigger_error() function which can be used
+ * during low-level Drupal core operations that need to avoid being interrupted
+ * by a watchdog() call.
+ *
+ * Normally, Drupal's error handler calls watchdog() in response to a
+ * trigger_error() call. However, this invokes hook_watchdog() which can run
+ * arbitrary code. If the trigger_error() happens in the middle of an
+ * operation such as a rebuild operation which should not be interrupted by
+ * arbitrary code, that could potentially break or trigger the rebuild again.
+ * This function protects against that by delaying the watchdog() call until
+ * the end of the current page request.
+ *
+ * This is an internal function which should only be called by low-level Drupal
+ * core functions. It may be removed in a future Drupal 7 release.
+ *
+ * @param string $error_msg
+ * The error message to trigger. As with trigger_error() itself, this is
+ * limited to 1024 bytes; additional characters beyond that will be removed.
+ * @param int $error_type
+ * (optional) The type of error. This should be one of the E_USER family of
+ * constants. As with trigger_error() itself, this defaults to E_USER_NOTICE
+ * if not provided.
+ *
+ * @see _drupal_log_error()
+ */
+function _drupal_trigger_error_with_delayed_logging($error_msg, $error_type = E_USER_NOTICE) {
+ $delay_logging = &drupal_static(__FUNCTION__, FALSE);
+ $delay_logging = TRUE;
+ trigger_error($error_msg, $error_type);
+ $delay_logging = FALSE;
+}
+
+/**
+ * Writes the file scan cache to the persistent cache.
+ *
+ * This cache stores all files marked as missing or moved after a file scan
+ * to prevent unnecessary file scans in subsequent requests. This cache is
+ * cleared in system_list_reset() (i.e. after a module/theme rebuild).
+ */
+function drupal_file_scan_write_cache() {
+ // Only write to the persistent cache if requested, and if we know that any
+ // data previously in the cache was successfully loaded and merged in by
+ // _drupal_file_scan_cache().
+ $file_scans = &_drupal_file_scan_cache();
+ if (isset($file_scans['#write_cache']) && isset($file_scans['#cache_merge_done'])) {
+ unset($file_scans['#write_cache']);
+ cache_set('_drupal_file_scan_cache', $file_scans, 'cache_bootstrap');
}
}
@@ -1055,7 +1309,7 @@ function drupal_page_get_cache($check_only = FALSE) {
* Determines the cacheability of the current page.
*
* @param $allow_caching
- * Set to FALSE if you want to prevent this page to get cached.
+ * Set to FALSE if you want to prevent this page from being cached.
*
* @return
* TRUE if the current page can be cached, FALSE otherwise.
@@ -1261,7 +1515,11 @@ function drupal_page_header() {
$default_headers = array(
'Expires' => 'Sun, 19 Nov 1978 05:00:00 GMT',
- 'Cache-Control' => 'no-cache, must-revalidate, post-check=0, pre-check=0',
+ 'Cache-Control' => 'no-cache, must-revalidate',
+ // Prevent browsers from sniffing a response and picking a MIME type
+ // different from the declared content-type, since that can lead to
+ // XSS and other vulnerabilities.
+ 'X-Content-Type-Options' => 'nosniff',
);
drupal_send_headers($default_headers);
}
@@ -1435,6 +1693,23 @@ function drupal_unpack($obj, $field = 'data') {
* available to code that needs localization. See st() and get_t() for
* alternatives.
*
+ * @section sec_context String context
+ * Matching source strings are normally only translated once, and the same
+ * translation is used everywhere that has a matching string. However, in some
+ * cases, a certain English source string needs to have multiple translations.
+ * One example of this is the string "May", which could be used as either a
+ * full month name or a 3-letter abbreviated month. In other languages where
+ * the month name for May has more than 3 letters, you would need to provide
+ * two different translations (one for the full name and one abbreviated), and
+ * the correct form would need to be chosen, depending on how "May" is being
+ * used. To facilitate this, the "May" string should be provided with two
+ * different contexts in the $options parameter when calling t(). For example:
+ * @code
+ * t('May', array(), array('context' => 'Long month name')
+ * t('May', array(), array('context' => 'Abbreviated month name')
+ * @endcode
+ * See https://localize.drupal.org/node/2109 for more information.
+ *
* @param $string
* A string containing the English string to translate.
* @param $args
@@ -1445,8 +1720,9 @@ function drupal_unpack($obj, $field = 'data') {
* An associative array of additional options, with the following elements:
* - 'langcode' (defaults to the current language): The language code to
* translate to a language other than what is used to display the page.
- * - 'context' (defaults to the empty context): The context the source string
- * belongs to.
+ * - 'context' (defaults to the empty context): A string giving the context
+ * that the source string belongs to. See @ref sec_context above for more
+ * information.
*
* @return
* The translated string.
@@ -1776,7 +2052,7 @@ function watchdog($type, $message, $variables = array(), $severity = WATCHDOG_NO
* @see theme_status_messages()
*/
function drupal_set_message($message = NULL, $type = 'status', $repeat = TRUE) {
- if ($message) {
+ if ($message || $message === '0' || $message === 0) {
if (!isset($_SESSION['messages'][$type])) {
$_SESSION['messages'][$type] = array();
}
@@ -2468,6 +2744,9 @@ function _drupal_bootstrap_database() {
// the install or upgrade process.
spl_autoload_register('drupal_autoload_class');
spl_autoload_register('drupal_autoload_interface');
+ if (version_compare(PHP_VERSION, '5.4') >= 0) {
+ spl_autoload_register('drupal_autoload_trait');
+ }
}
/**
@@ -2788,10 +3067,14 @@ function language_list($field = 'language') {
}
/**
- * Returns the default language used on the site
+ * Returns the default language, as an object, or one of its properties.
*
* @param $property
- * Optional property of the language object to return
+ * (optional) The property of the language object to return.
+ *
+ * @return
+ * Either the language object for the default language used on the site,
+ * or the property of that object named in the $property parameter.
*/
function language_default($property = NULL) {
$language = variable_get('language_default', (object) array('language' => 'en', 'name' => 'English', 'native' => 'English', 'direction' => 0, 'enabled' => 1, 'plurals' => 0, 'formula' => '', 'domain' => '', 'prefix' => '', 'weight' => 0, 'javascript' => ''));
@@ -2943,8 +3226,15 @@ function ip_address() {
// Eliminate all trusted IPs.
$untrusted = array_diff($forwarded, $reverse_proxy_addresses);
- // The right-most IP is the most specific we can trust.
- $ip_address = array_pop($untrusted);
+ if (!empty($untrusted)) {
+ // The right-most IP is the most specific we can trust.
+ $ip_address = array_pop($untrusted);
+ }
+ else {
+ // All IP addresses in the forwarded array are configured proxy IPs
+ // (and thus trusted). We take the leftmost IP.
+ $ip_address = array_shift($forwarded);
+ }
}
}
}
@@ -2961,7 +3251,9 @@ function ip_address() {
* Gets the schema definition of a table, or the whole database schema.
*
* The returned schema will include any modifications made by any
- * module that implements hook_schema_alter().
+ * module that implements hook_schema_alter(). To get the schema without
+ * modifications, use drupal_get_schema_unprocessed().
+ *
*
* @param $table
* The name of the table. If not given, the schema of all tables is returned.
@@ -3116,6 +3408,22 @@ function drupal_autoload_class($class) {
return _registry_check_code('class', $class);
}
+/**
+ * Confirms that a trait is available.
+ *
+ * This function is rarely called directly. Instead, it is registered as an
+ * spl_autoload() handler, and PHP calls it for us when necessary.
+ *
+ * @param string $trait
+ * The name of the trait to check or load.
+ *
+ * @return bool
+ * TRUE if the trait is currently available, FALSE otherwise.
+ */
+function drupal_autoload_trait($trait) {
+ return _registry_check_code('trait', $trait);
+}
+
/**
* Checks for a resource in the registry.
*
@@ -3134,7 +3442,7 @@ function drupal_autoload_class($class) {
function _registry_check_code($type, $name = NULL) {
static $lookup_cache, $cache_update_needed;
- if ($type == 'class' && class_exists($name) || $type == 'interface' && interface_exists($name)) {
+ if ($type == 'class' && class_exists($name) || $type == 'interface' && interface_exists($name) || $type == 'trait' && trait_exists($name)) {
return TRUE;
}
@@ -3167,7 +3475,7 @@ function _registry_check_code($type, $name = NULL) {
$cache_key = $type[0] . $name;
if (isset($lookup_cache[$cache_key])) {
if ($lookup_cache[$cache_key]) {
- require_once DRUPAL_ROOT . '/' . $lookup_cache[$cache_key];
+ include_once DRUPAL_ROOT . '/' . $lookup_cache[$cache_key];
}
return (bool) $lookup_cache[$cache_key];
}
@@ -3192,7 +3500,7 @@ function _registry_check_code($type, $name = NULL) {
$lookup_cache[$cache_key] = $file;
if ($file) {
- require_once DRUPAL_ROOT . '/' . $file;
+ include_once DRUPAL_ROOT . '/' . $file;
return TRUE;
}
else {
diff --git a/includes/cache.inc b/includes/cache.inc
index 207bf661..945dd663 100644
--- a/includes/cache.inc
+++ b/includes/cache.inc
@@ -14,6 +14,7 @@
*
* @param $bin
* The cache bin for which the cache object should be returned.
+ *
* @return DrupalCacheInterface
* The cache object associated with the specified bin.
*
@@ -121,7 +122,12 @@ function cache_get_multiple(array &$cids, $bin = 'cache') {
* the administrator panel.
* - cache_path: Stores the system paths that have an alias.
* @param $expire
- * (optional) One of the following values:
+ * (optional) Controls the maximum lifetime of this cache entry. Note that
+ * caches might be subject to clearing at any time, so this setting does not
+ * guarantee a minimum lifetime. With this in mind, the cache should not be
+ * used for data that must be kept during a cache clear, like sessions.
+ *
+ * Use one of the following values:
* - CACHE_PERMANENT: Indicates that the item should never be removed unless
* explicitly told to using cache_clear_all() with a cache ID.
* - CACHE_TEMPORARY: Indicates that the item should be removed at the next
@@ -261,7 +267,12 @@ interface DrupalCacheInterface {
* 1MB in size to be stored by default. When caching large arrays or
* similar, take care to ensure $data does not exceed this size.
* @param $expire
- * (optional) One of the following values:
+ * (optional) Controls the maximum lifetime of this cache entry. Note that
+ * caches might be subject to clearing at any time, so this setting does not
+ * guarantee a minimum lifetime. With this in mind, the cache should not be
+ * used for data that must be kept during a cache clear, like sessions.
+ *
+ * Use one of the following values:
* - CACHE_PERMANENT: Indicates that the item should never be removed unless
* explicitly told to using cache_clear_all() with a cache ID.
* - CACHE_TEMPORARY: Indicates that the item should be removed at the next
diff --git a/includes/common.inc b/includes/common.inc
index 472485f7..a9855658 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -488,7 +488,7 @@ function drupal_http_build_query(array $query, $parent = '') {
$params = array();
foreach ($query as $key => $value) {
- $key = ($parent ? $parent . '[' . rawurlencode($key) . ']' : rawurlencode($key));
+ $key = $parent ? $parent . rawurlencode('[' . $key . ']') : rawurlencode($key);
// Recurse into children.
if (is_array($value)) {
@@ -690,6 +690,13 @@ function drupal_goto($path = '', array $options = array(), $http_response_code =
$options['fragment'] = $destination['fragment'];
}
+ // In some cases modules call drupal_goto(current_path()). We need to ensure
+ // that such a redirect is not to an external URL.
+ if ($path === current_path() && empty($options['external']) && url_is_external($path)) {
+ // Force url() to generate a non-external URL.
+ $options['external'] = FALSE;
+ }
+
drupal_alter('drupal_goto', $path, $options, $http_response_code);
// The 'Location' HTTP header must be absolute.
@@ -755,7 +762,8 @@ function drupal_access_denied() {
* - headers: An array containing request headers to send as name/value pairs.
* - method: A string containing the request method. Defaults to 'GET'.
* - data: A string containing the request body, formatted as
- * 'param=value¶m=value&...'. Defaults to NULL.
+ * 'param=value¶m=value&...'; to generate this, use http_build_query().
+ * Defaults to NULL.
* - max_redirects: An integer representing how many times a redirect
* may be followed. Defaults to 3.
* - timeout: A float representing the maximum number of seconds the function
@@ -780,6 +788,8 @@ function drupal_access_denied() {
* HTTP header names are case-insensitive (RFC 2616, section 4.2), so for
* easy access the array keys are returned in lower case.
* - data: A string containing the response body that was received.
+ *
+ * @see http_build_query()
*/
function drupal_http_request($url, array $options = array()) {
// Allow an alternate HTTP client library to replace Drupal's default
@@ -1059,6 +1069,12 @@ function drupal_http_request($url, array $options = array()) {
switch ($code) {
case 200: // OK
+ case 201: // Created
+ case 202: // Accepted
+ case 203: // Non-Authoritative Information
+ case 204: // No Content
+ case 205: // Reset Content
+ case 206: // Partial Content
case 304: // Not modified
break;
case 301: // Moved permanently
@@ -1756,9 +1772,15 @@ function format_rss_item($title, $link, $description, $args = array()) {
* - 'key': element name
* - 'value': element contents
* - 'attributes': associative array of element attributes
+ * - 'encoded': TRUE if 'value' is already encoded
*
* In both cases, 'value' can be a simple string, or it can be another array
* with the same format as $array itself for nesting.
+ *
+ * If 'encoded' is TRUE it is up to the caller to ensure that 'value' is either
+ * entity-encoded or CDATA-escaped. Using this option is not recommended when
+ * working with untrusted user input, since failing to escape the data
+ * correctly has security implications.
*/
function format_xml_elements($array) {
$output = '';
@@ -1771,7 +1793,7 @@ function format_xml_elements($array) {
}
if (isset($value['value']) && $value['value'] != '') {
- $output .= '>' . (is_array($value['value']) ? format_xml_elements($value['value']) : check_plain($value['value'])) . '' . $value['key'] . ">\n";
+ $output .= '>' . (is_array($value['value']) ? format_xml_elements($value['value']) : (!empty($value['encoded']) ? $value['value'] : check_plain($value['value']))) . '' . $value['key'] . ">\n";
}
else {
$output .= " />\n";
@@ -2216,20 +2238,11 @@ function url($path = NULL, array $options = array()) {
'prefix' => ''
);
- // A duplicate of the code from url_is_external() to avoid needing another
- // function call, since performance inside url() is critical.
+ // Determine whether this is an external link, but ensure that the current
+ // path is always treated as internal by default (to prevent external link
+ // injection vulnerabilities).
if (!isset($options['external'])) {
- // Return an external link if $path contains an allowed absolute URL. Avoid
- // calling drupal_strip_dangerous_protocols() if there is any slash (/),
- // hash (#) or question_mark (?) before the colon (:) occurrence - if any -
- // as this would clearly mean it is not a URL. If the path starts with 2
- // slashes then it is always considered an external URL without an explicit
- // protocol part.
- $colonpos = strpos($path, ':');
- $options['external'] = (strpos($path, '//') === 0)
- || ($colonpos !== FALSE
- && !preg_match('![/?#]!', substr($path, 0, $colonpos))
- && drupal_strip_dangerous_protocols($path) == $path);
+ $options['external'] = $path === $_GET['q'] ? FALSE : url_is_external($path);
}
// Preserve the original path before altering or aliasing.
@@ -2299,7 +2312,10 @@ function url($path = NULL, array $options = array()) {
$language = isset($options['language']) && isset($options['language']->language) ? $options['language']->language : '';
$alias = drupal_get_path_alias($original_path, $language);
if ($alias != $original_path) {
- $path = $alias;
+ // Strip leading slashes from internal path aliases to prevent them
+ // becoming external URLs without protocol. /example.com should not be
+ // turned into //example.com.
+ $path = ltrim($alias, '/');
}
}
@@ -2349,12 +2365,18 @@ function url($path = NULL, array $options = array()) {
*/
function url_is_external($path) {
$colonpos = strpos($path, ':');
- // Avoid calling drupal_strip_dangerous_protocols() if there is any slash (/),
- // hash (#) or question_mark (?) before the colon (:) occurrence - if any - as
- // this would clearly mean it is not a URL. If the path starts with 2 slashes
- // then it is always considered an external URL without an explicit protocol
- // part.
+ // Some browsers treat \ as / so normalize to forward slashes.
+ $path = str_replace('\\', '/', $path);
+ // If the path starts with 2 slashes then it is always considered an external
+ // URL without an explicit protocol part.
return (strpos($path, '//') === 0)
+ // Leading control characters may be ignored or mishandled by browsers, so
+ // assume such a path may lead to an external location. The \p{C} character
+ // class matches all UTF-8 control, unassigned, and private characters.
+ || (preg_match('/^\p{C}/u', $path) !== 0)
+ // Avoid calling drupal_strip_dangerous_protocols() if there is any slash
+ // (/), hash (#) or question_mark (?) before the colon (:) occurrence - if
+ // any - as this would clearly mean it is not a URL.
|| ($colonpos !== FALSE
&& !preg_match('![/?#]!', substr($path, 0, $colonpos))
&& drupal_strip_dangerous_protocols($path) == $path);
@@ -2639,6 +2661,15 @@ function drupal_deliver_html_page($page_callback_result) {
global $language;
drupal_add_http_header('Content-Language', $language->language);
+ // By default, do not allow the site to be rendered in an iframe on another
+ // domain, but provide a variable to override this. If the code running for
+ // this page request already set the X-Frame-Options header earlier, don't
+ // overwrite it here.
+ $frame_options = variable_get('x_frame_options', 'SAMEORIGIN');
+ if ($frame_options && is_null(drupal_get_http_header('X-Frame-Options'))) {
+ drupal_add_http_header('X-Frame-Options', $frame_options);
+ }
+
// Menu status constants are integers; page content is a string or array.
if (is_int($page_callback_result)) {
// @todo: Break these up into separate functions?
@@ -2753,6 +2784,7 @@ function drupal_page_footer() {
_registry_check_code(REGISTRY_WRITE_LOOKUP_CACHE);
drupal_cache_system_paths();
module_implements_write_cache();
+ drupal_file_scan_write_cache();
system_run_automated_cron();
}
@@ -2814,11 +2846,11 @@ function drupal_map_assoc($array, $function = NULL) {
* into script execution a call such as set_time_limit(20) is made, the
* script will run for a total of 45 seconds before timing out.
*
- * It also means that it is possible to decrease the total time limit if
- * the sum of the new time limit and the current time spent running the
- * script is inferior to the original time limit. It is inherent to the way
- * set_time_limit() works, it should rather be called with an appropriate
- * value every time you need to allocate a certain amount of time
+ * If the current time limit is not unlimited it is possible to decrease the
+ * total time limit if the sum of the new time limit and the current time spent
+ * running the script is inferior to the original time limit. It is inherent to
+ * the way set_time_limit() works, it should rather be called with an
+ * appropriate value every time you need to allocate a certain amount of time
* to execute a task than only once at the beginning of the script.
*
* Before calling set_time_limit(), we check if this function is available
@@ -2835,7 +2867,11 @@ function drupal_map_assoc($array, $function = NULL) {
*/
function drupal_set_time_limit($time_limit) {
if (function_exists('set_time_limit')) {
- @set_time_limit($time_limit);
+ $current = ini_get('max_execution_time');
+ // Do not set time limit if it is currently unlimited.
+ if ($current != 0) {
+ @set_time_limit($time_limit);
+ }
}
}
@@ -3016,6 +3052,13 @@ function drupal_add_html_head_link($attributes, $header = FALSE) {
*/
function drupal_add_css($data = NULL, $options = NULL) {
$css = &drupal_static(__FUNCTION__, array());
+ $count = &drupal_static(__FUNCTION__ . '_count', 0);
+
+ // If the $css variable has been reset with drupal_static_reset(), there is
+ // no longer any CSS being tracked, so set the counter back to 0 also.
+ if (count($css) === 0) {
+ $count = 0;
+ }
// Construct the options, taking the defaults into consideration.
if (isset($options)) {
@@ -3051,7 +3094,8 @@ function drupal_add_css($data = NULL, $options = NULL) {
}
// Always add a tiny value to the weight, to conserve the insertion order.
- $options['weight'] += count($css) / 1000;
+ $options['weight'] += $count / 1000;
+ $count++;
// Add the data to the CSS array depending on the type.
switch ($options['type']) {
@@ -3864,6 +3908,21 @@ function drupal_delete_file_if_stale($uri) {
* The cleaned identifier.
*/
function drupal_clean_css_identifier($identifier, $filter = array(' ' => '-', '_' => '-', '/' => '-', '[' => '-', ']' => '')) {
+ // Use the advanced drupal_static() pattern, since this is called very often.
+ static $drupal_static_fast;
+ if (!isset($drupal_static_fast)) {
+ $drupal_static_fast['allow_css_double_underscores'] = &drupal_static(__FUNCTION__ . ':allow_css_double_underscores');
+ }
+ $allow_css_double_underscores = &$drupal_static_fast['allow_css_double_underscores'];
+ if (!isset($allow_css_double_underscores)) {
+ $allow_css_double_underscores = variable_get('allow_css_double_underscores', FALSE);
+ }
+
+ // Preserve BEM-style double-underscores depending on custom setting.
+ if ($allow_css_double_underscores) {
+ $filter['__'] = '__';
+ }
+
// By default, we filter using Drupal's coding standards.
$identifier = strtr($identifier, $filter);
@@ -3935,7 +3994,11 @@ function drupal_html_id($id) {
// be merged with content already on the base page. The HTML IDs must be
// unique for the fully merged content. Therefore, initialize $seen_ids to
// take into account IDs that are already in use on the base page.
- $seen_ids_init = &drupal_static(__FUNCTION__ . ':init');
+ static $drupal_static_fast;
+ if (!isset($drupal_static_fast['seen_ids_init'])) {
+ $drupal_static_fast['seen_ids_init'] = &drupal_static(__FUNCTION__ . ':init');
+ }
+ $seen_ids_init = &$drupal_static_fast['seen_ids_init'];
if (!isset($seen_ids_init)) {
// Ideally, Drupal would provide an API to persist state information about
// prior page requests in the database, and we'd be able to add this
@@ -3980,7 +4043,10 @@ function drupal_html_id($id) {
}
}
}
- $seen_ids = &drupal_static(__FUNCTION__, $seen_ids_init);
+ if (!isset($drupal_static_fast['seen_ids'])) {
+ $drupal_static_fast['seen_ids'] = &drupal_static(__FUNCTION__, $seen_ids_init);
+ }
+ $seen_ids = &$drupal_static_fast['seen_ids'];
$id = strtr(drupal_strtolower($id), array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
@@ -5358,6 +5424,11 @@ function _drupal_bootstrap_full() {
fix_gpc_magic();
// Load all enabled modules
module_load_all();
+ // Reset drupal_alter() and module_implements() static caches as these
+ // include implementations for vital modules only when called early on
+ // in the bootstrap.
+ drupal_static_reset('drupal_alter');
+ drupal_static_reset('module_implements');
// Make sure all stream wrappers are registered.
file_get_stream_wrappers();
// Ensure mt_rand is reseeded, to prevent random values from one page load
@@ -5454,8 +5525,8 @@ function drupal_page_set_cache() {
*
* Do not call this function from a test. Use $this->cronRun() instead.
*
- * @return
- * TRUE if cron ran successfully.
+ * @return bool
+ * TRUE if cron ran successfully and FALSE if cron is already running.
*/
function drupal_cron_run() {
// Allow execution to continue even if the request gets canceled.
@@ -5517,12 +5588,12 @@ function drupal_cron_run() {
// Do not run if queue wants to skip.
continue;
}
- $function = $info['worker callback'];
+ $callback = $info['worker callback'];
$end = time() + (isset($info['time']) ? $info['time'] : 15);
$queue = DrupalQueue::get($queue_name);
while (time() < $end && ($item = $queue->claimItem())) {
try {
- $function($item->data);
+ call_user_func($callback, $item->data);
$queue->deleteItem($item);
}
catch (Exception $e) {
@@ -7229,7 +7300,8 @@ function drupal_uninstall_schema($module) {
* specification of a schema, as it was defined in a module's
* hook_schema(). No additional default values will be set,
* hook_schema_alter() is not invoked and these unprocessed
- * definitions won't be cached.
+ * definitions won't be cached. To retrieve the schema after
+ * hook_schema_alter() has been invoked use drupal_get_schema().
*
* This function can be used to retrieve a schema specification in
* hook_schema(), so it allows you to derive your tables from existing
@@ -7302,6 +7374,7 @@ function _drupal_schema_initialize(&$schema, $module, $remove_descriptions = TRU
*/
function drupal_schema_field_types($table) {
$table_schema = drupal_get_schema($table);
+ $field_types = array();
foreach ($table_schema['fields'] as $field_name => $field_info) {
$field_types[$field_name] = isset($field_info['type']) ? $field_info['type'] : NULL;
}
@@ -7509,7 +7582,16 @@ function drupal_write_record($table, &$record, $primary_keys = array()) {
* Information stored in a module .info file:
* - name: The real name of the module for display purposes.
* - description: A brief description of the module.
- * - dependencies: An array of shortnames of other modules this module requires.
+ * - dependencies: An array of dependency strings. Each is in the form
+ * 'project:module (versions)'; with the following meanings:
+ * - project: (optional) Project shortname, recommended to ensure uniqueness,
+ * if the module is part of a project hosted on drupal.org. If omitted,
+ * also omit the : that follows. The project name is currently ignored by
+ * Drupal core but is used for automated testing.
+ * - module: (required) Module shortname within the project.
+ * - (versions): Optional version information, consisting of one or more
+ * comma-separated operator/value pairs or simply version numbers, which
+ * can contain "x" as a wildcard. Examples: (>=7.22, <7.28), (7.x-3.x).
* - package: The name of the package of modules this module belongs to.
*
* See forum.info for an example of a module .info file.
@@ -7589,7 +7671,6 @@ function drupal_parse_info_file($filename) {
*/
function drupal_parse_info_format($data) {
$info = array();
- $constants = get_defined_constants();
if (preg_match_all('
@^\s* # Start at the beginning of a line, ignoring leading whitespace
@@ -7629,8 +7710,8 @@ function drupal_parse_info_format($data) {
}
// Handle PHP constants.
- if (isset($constants[$value])) {
- $value = $constants[$value];
+ if (preg_match('/^\w+$/i', $value) && defined($value)) {
+ $value = constant($value);
}
// Insert actual value.
@@ -7794,7 +7875,12 @@ function debug($data, $label = NULL, $print_r = FALSE) {
* Parses a dependency for comparison by drupal_check_incompatibility().
*
* @param $dependency
- * A dependency string, for example 'foo (>=7.x-4.5-beta5, 3.x)'.
+ * A dependency string, which specifies a module dependency, and optionally
+ * the project it comes from and versions that are supported. Supported
+ * formats include:
+ * - 'module'
+ * - 'project:module'
+ * - 'project:module (>=version, version)'
*
* @return
* An associative array with three keys:
@@ -7809,6 +7895,12 @@ function debug($data, $label = NULL, $print_r = FALSE) {
* @see drupal_check_incompatibility()
*/
function drupal_parse_dependency($dependency) {
+ $value = array();
+ // Split out the optional project name.
+ if (strpos($dependency, ':')) {
+ list($project_name, $dependency) = explode(':', $dependency);
+ $value['project'] = $project_name;
+ }
// We use named subpatterns and support every op that version_compare
// supports. Also, op is optional and defaults to equals.
$p_op = '(?P!=|==|=|<|<=|>|>=|<>)?';
@@ -7817,7 +7909,6 @@ function drupal_parse_dependency($dependency) {
$p_major = '(?P\d+)';
// By setting the minor version to x, branches can be matched.
$p_minor = '(?P(?:\d+|x)(?:-[A-Za-z]+\d+)?)';
- $value = array();
$parts = explode('(', $dependency, 2);
$value['name'] = trim($parts[0]);
if (isset($parts[1])) {
diff --git a/includes/database/database.inc b/includes/database/database.inc
index 3d776b57..6879f699 100644
--- a/includes/database/database.inc
+++ b/includes/database/database.inc
@@ -296,6 +296,20 @@ abstract class DatabaseConnection extends PDO {
*/
protected $prefixReplace = array();
+ /**
+ * List of escaped database, table, and field names, keyed by unescaped names.
+ *
+ * @var array
+ */
+ protected $escapedNames = array();
+
+ /**
+ * List of escaped aliases names, keyed by unescaped aliases.
+ *
+ * @var array
+ */
+ protected $escapedAliases = array();
+
function __construct($dsn, $username, $password, $driver_options = array()) {
// Initialize and prepare the connection prefix.
$this->setPrefix(isset($this->connectionOptions['prefix']) ? $this->connectionOptions['prefix'] : '');
@@ -656,7 +670,7 @@ abstract class DatabaseConnection extends PDO {
* @return DatabaseStatementInterface
* This method will return one of: the executed statement, the number of
* rows affected by the query (not the number matched), or the generated
- * insert IT of the last query, depending on the value of
+ * insert ID of the last query, depending on the value of
* $options['return']. Typically that value will be set by default or a
* query builder and should not be set by a user. If there is an error,
* this method will return NULL and may throw an exception if
@@ -919,11 +933,14 @@ abstract class DatabaseConnection extends PDO {
* For some database drivers, it may also wrap the table name in
* database-specific escape characters.
*
- * @return
+ * @return string
* The sanitized table name string.
*/
public function escapeTable($table) {
- return preg_replace('/[^A-Za-z0-9_.]+/', '', $table);
+ if (!isset($this->escapedNames[$table])) {
+ $this->escapedNames[$table] = preg_replace('/[^A-Za-z0-9_.]+/', '', $table);
+ }
+ return $this->escapedNames[$table];
}
/**
@@ -933,11 +950,14 @@ abstract class DatabaseConnection extends PDO {
* For some database drivers, it may also wrap the field name in
* database-specific escape characters.
*
- * @return
+ * @return string
* The sanitized field name string.
*/
public function escapeField($field) {
- return preg_replace('/[^A-Za-z0-9_.]+/', '', $field);
+ if (!isset($this->escapedNames[$field])) {
+ $this->escapedNames[$field] = preg_replace('/[^A-Za-z0-9_.]+/', '', $field);
+ }
+ return $this->escapedNames[$field];
}
/**
@@ -948,11 +968,14 @@ abstract class DatabaseConnection extends PDO {
* DatabaseConnection::escapeTable(), this doesn't allow the period (".")
* because that is not allowed in aliases.
*
- * @return
+ * @return string
* The sanitized field name string.
*/
public function escapeAlias($field) {
- return preg_replace('/[^A-Za-z0-9_]+/', '', $field);
+ if (!isset($this->escapedAliases[$field])) {
+ $this->escapedAliases[$field] = preg_replace('/[^A-Za-z0-9_]+/', '', $field);
+ }
+ return $this->escapedAliases[$field];
}
/**
@@ -1313,6 +1336,39 @@ abstract class DatabaseConnection extends PDO {
* also larger than the $existing_id if one was passed in.
*/
abstract public function nextId($existing_id = 0);
+
+ /**
+ * Checks whether utf8mb4 support is configurable in settings.php.
+ *
+ * @return bool
+ */
+ public function utf8mb4IsConfigurable() {
+ // Since 4 byte UTF-8 is not supported by default, there is nothing to
+ // configure.
+ return FALSE;
+ }
+
+ /**
+ * Checks whether utf8mb4 support is currently active.
+ *
+ * @return bool
+ */
+ public function utf8mb4IsActive() {
+ // Since 4 byte UTF-8 is not supported by default, there is nothing to
+ // activate.
+ return FALSE;
+ }
+
+ /**
+ * Checks whether utf8mb4 support is available on the current database system.
+ *
+ * @return bool
+ */
+ public function utf8mb4IsSupported() {
+ // By default we assume that the database backend may not support 4 byte
+ // UTF-8.
+ return FALSE;
+ }
}
/**
diff --git a/includes/database/mysql/database.inc b/includes/database/mysql/database.inc
index 0b84f271..356e039f 100644
--- a/includes/database/mysql/database.inc
+++ b/includes/database/mysql/database.inc
@@ -28,6 +28,12 @@ class DatabaseConnection_mysql extends DatabaseConnection {
$this->connectionOptions = $connection_options;
+ $charset = 'utf8';
+ // Check if the charset is overridden to utf8mb4 in settings.php.
+ if ($this->utf8mb4IsActive()) {
+ $charset = 'utf8mb4';
+ }
+
// The DSN should use either a socket or a host/port.
if (isset($connection_options['unix_socket'])) {
$dsn = 'mysql:unix_socket=' . $connection_options['unix_socket'];
@@ -39,7 +45,7 @@ class DatabaseConnection_mysql extends DatabaseConnection {
// Character set is added to dsn to ensure PDO uses the proper character
// set when escaping. This has security implications. See
// https://www.drupal.org/node/1201452 for further discussion.
- $dsn .= ';charset=utf8';
+ $dsn .= ';charset=' . $charset;
$dsn .= ';dbname=' . $connection_options['database'];
// Allow PDO options to be overridden.
$connection_options += array(
@@ -51,6 +57,11 @@ class DatabaseConnection_mysql extends DatabaseConnection {
// Because MySQL's prepared statements skip the query cache, because it's dumb.
PDO::ATTR_EMULATE_PREPARES => TRUE,
);
+ if (defined('PDO::MYSQL_ATTR_MULTI_STATEMENTS')) {
+ // An added connection option in PHP 5.5.21+ to optionally limit SQL to a
+ // single statement like mysqli.
+ $connection_options['pdo'] += array(PDO::MYSQL_ATTR_MULTI_STATEMENTS => FALSE);
+ }
parent::__construct($dsn, $connection_options['username'], $connection_options['password'], $connection_options['pdo']);
@@ -58,10 +69,10 @@ class DatabaseConnection_mysql extends DatabaseConnection {
// certain one has been set; otherwise, MySQL defaults to 'utf8_general_ci'
// for UTF-8.
if (!empty($connection_options['collation'])) {
- $this->exec('SET NAMES utf8 COLLATE ' . $connection_options['collation']);
+ $this->exec('SET NAMES ' . $charset . ' COLLATE ' . $connection_options['collation']);
}
else {
- $this->exec('SET NAMES utf8');
+ $this->exec('SET NAMES ' . $charset);
}
// Set MySQL init_commands if not already defined. Default Drupal's MySQL
@@ -76,10 +87,12 @@ class DatabaseConnection_mysql extends DatabaseConnection {
'init_commands' => array(),
);
$connection_options['init_commands'] += array(
- 'sql_mode' => "SET sql_mode = 'ANSI,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER'",
+ 'sql_mode' => "SET sql_mode = 'REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER'",
);
- // Set connection options.
- $this->exec(implode('; ', $connection_options['init_commands']));
+ // Execute initial commands.
+ foreach ($connection_options['init_commands'] as $sql) {
+ $this->exec($sql);
+ }
}
public function __destruct() {
@@ -199,6 +212,42 @@ class DatabaseConnection_mysql extends DatabaseConnection {
}
}
}
+
+ public function utf8mb4IsConfigurable() {
+ return TRUE;
+ }
+
+ public function utf8mb4IsActive() {
+ return isset($this->connectionOptions['charset']) && $this->connectionOptions['charset'] === 'utf8mb4';
+ }
+
+ public function utf8mb4IsSupported() {
+ // Ensure that the MySQL driver supports utf8mb4 encoding.
+ $version = $this->getAttribute(PDO::ATTR_CLIENT_VERSION);
+ if (strpos($version, 'mysqlnd') !== FALSE) {
+ // The mysqlnd driver supports utf8mb4 starting at version 5.0.9.
+ $version = preg_replace('/^\D+([\d.]+).*/', '$1', $version);
+ if (version_compare($version, '5.0.9', '<')) {
+ return FALSE;
+ }
+ }
+ else {
+ // The libmysqlclient driver supports utf8mb4 starting at version 5.5.3.
+ if (version_compare($version, '5.5.3', '<')) {
+ return FALSE;
+ }
+ }
+
+ // Ensure that the MySQL server supports large prefixes and utf8mb4.
+ try {
+ $this->query("CREATE TABLE {drupal_utf8mb4_test} (id VARCHAR(255), PRIMARY KEY(id(255))) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci ROW_FORMAT=DYNAMIC ENGINE=INNODB");
+ }
+ catch (Exception $e) {
+ return FALSE;
+ }
+ $this->query("DROP TABLE {drupal_utf8mb4_test}");
+ return TRUE;
+ }
}
diff --git a/includes/database/mysql/schema.inc b/includes/database/mysql/schema.inc
index 2a2722e6..9ba1c733 100644
--- a/includes/database/mysql/schema.inc
+++ b/includes/database/mysql/schema.inc
@@ -39,8 +39,8 @@ class DatabaseSchema_mysql extends DatabaseSchema {
$info['table'] = substr($table, ++$pos);
}
else {
- $db_info = Database::getConnectionInfo();
- $info['database'] = $db_info[$this->connection->getTarget()]['database'];
+ $db_info = $this->connection->getConnectionOptions();
+ $info['database'] = $db_info['database'];
$info['table'] = $table;
}
return $info;
@@ -81,7 +81,8 @@ class DatabaseSchema_mysql extends DatabaseSchema {
// Provide defaults if needed.
$table += array(
'mysql_engine' => 'InnoDB',
- 'mysql_character_set' => 'utf8',
+ // Allow the default charset to be overridden in settings.php.
+ 'mysql_character_set' => $this->connection->utf8mb4IsActive() ? 'utf8mb4' : 'utf8',
);
$sql = "CREATE TABLE {" . $name . "} (\n";
@@ -109,6 +110,13 @@ class DatabaseSchema_mysql extends DatabaseSchema {
$sql .= ' COLLATE ' . $info['collation'];
}
+ // The row format needs to be either DYNAMIC or COMPRESSED in order to allow
+ // for the innodb_large_prefix setting to take effect, see
+ // https://dev.mysql.com/doc/refman/5.6/en/create-table.html
+ if ($this->connection->utf8mb4IsActive()) {
+ $sql .= ' ROW_FORMAT=DYNAMIC';
+ }
+
// Add table comment.
if (!empty($table['description'])) {
$sql .= ' COMMENT ' . $this->prepareComment($table['description'], self::COMMENT_MAX_TABLE);
diff --git a/includes/database/pgsql/database.inc b/includes/database/pgsql/database.inc
index 67b49fed..fb3d0ab5 100644
--- a/includes/database/pgsql/database.inc
+++ b/includes/database/pgsql/database.inc
@@ -11,7 +11,7 @@
*/
/**
- * The name by which to obtain a lock for retrive the next insert id.
+ * The name by which to obtain a lock for retrieving the next insert id.
*/
define('POSTGRESQL_NEXTID_LOCK', 1000);
@@ -55,7 +55,7 @@ class DatabaseConnection_pgsql extends DatabaseConnection {
$connection_options['pdo'] += array(
// Prepared statements are most effective for performance when queries
// are recycled (used several times). However, if they are not re-used,
- // prepared statements become ineffecient. Since most of Drupal's
+ // prepared statements become inefficient. Since most of Drupal's
// prepared queries are not re-used, it should be faster to emulate
// the preparation than to actually ready statements for re-use. If in
// doubt, reset to FALSE and measure performance.
@@ -175,14 +175,14 @@ class DatabaseConnection_pgsql extends DatabaseConnection {
}
/**
- * Retrive a the next id in a sequence.
+ * Retrieve the next id in a sequence.
*
* PostgreSQL has built in sequences. We'll use these instead of inserting
* and updating a sequences table.
*/
public function nextId($existing = 0) {
- // Retrive the name of the sequence. This information cannot be cached
+ // Retrieve the name of the sequence. This information cannot be cached
// because the prefix may change, for example, like it does in simpletests.
$sequence_name = $this->makeSequenceName('sequences', 'value');
@@ -194,7 +194,7 @@ class DatabaseConnection_pgsql extends DatabaseConnection {
}
// PostgreSQL advisory locks are simply locks to be used by an
- // application such as Drupal. This will prevent other Drupal proccesses
+ // application such as Drupal. This will prevent other Drupal processes
// from altering the sequence while we are.
$this->query("SELECT pg_advisory_lock(" . POSTGRESQL_NEXTID_LOCK . ")");
@@ -209,13 +209,21 @@ class DatabaseConnection_pgsql extends DatabaseConnection {
// Reset the sequence to a higher value than the existing id.
$this->query("ALTER SEQUENCE " . $sequence_name . " RESTART WITH " . ($existing + 1));
- // Retrive the next id. We know this will be as high as we want it.
+ // Retrieve the next id. We know this will be as high as we want it.
$id = $this->query("SELECT nextval('" . $sequence_name . "')")->fetchField();
$this->query("SELECT pg_advisory_unlock(" . POSTGRESQL_NEXTID_LOCK . ")");
return $id;
}
+
+ public function utf8mb4IsActive() {
+ return TRUE;
+ }
+
+ public function utf8mb4IsSupported() {
+ return TRUE;
+ }
}
/**
diff --git a/includes/database/pgsql/install.inc b/includes/database/pgsql/install.inc
index c77f4ea7..122031ee 100644
--- a/includes/database/pgsql/install.inc
+++ b/includes/database/pgsql/install.inc
@@ -165,7 +165,7 @@ class DatabaseTasks_pgsql extends DatabaseTasks {
LANGUAGE \'sql\''
);
- // Using || to concatenate in Drupal is not recommeneded because there are
+ // Using || to concatenate in Drupal is not recommended because there are
// database drivers for Drupal that do not support the syntax, however
// they do support CONCAT(item1, item2) which we can replicate in
// PostgreSQL. PostgreSQL requires the function to be defined for each
diff --git a/includes/database/pgsql/select.inc b/includes/database/pgsql/select.inc
index f6a83db7..5b8736d6 100644
--- a/includes/database/pgsql/select.inc
+++ b/includes/database/pgsql/select.inc
@@ -80,7 +80,7 @@ class SelectQuery_pgsql extends SelectQuery {
}
// If a table loads all fields, it can not be added again. It would
- // result in an ambigious alias error because that field would be loaded
+ // result in an ambiguous alias error because that field would be loaded
// twice: Once through table_alias.* and once directly. If the field
// actually belongs to a different table, it must be added manually.
foreach ($this->tables as $table) {
@@ -90,7 +90,7 @@ class SelectQuery_pgsql extends SelectQuery {
}
// If $field contains an characters which are not allowed in a field name
- // it is considered an expression, these can't be handeld automatically
+ // it is considered an expression, these can't be handled automatically
// either.
if ($this->connection->escapeField($field) != $field) {
return $return;
diff --git a/includes/database/query.inc b/includes/database/query.inc
index c9c5a832..048c8a26 100644
--- a/includes/database/query.inc
+++ b/includes/database/query.inc
@@ -845,8 +845,8 @@ class DeleteQuery extends Query implements QueryConditionInterface {
/**
* Executes the DELETE query.
*
- * @return
- * The return value is dependent on the database connection.
+ * @return int
+ * The number of rows affected by the delete query.
*/
public function execute() {
$values = array();
@@ -1242,7 +1242,7 @@ class UpdateQuery extends Query implements QueryConditionInterface {
* MergeQuery::updateFields() and MergeQuery::insertFields() needs to be called
* instead. MergeQuery::fields() can also be called which calls both of these
* methods as the common case is to use the same column-value pairs for both
- * INSERT and UPDATE. However, this is not mandatory. Another convinient
+ * INSERT and UPDATE. However, this is not mandatory. Another convenient
* wrapper is MergeQuery::key() which adds the same column-value pairs to the
* condition and the INSERT query part.
*
diff --git a/includes/database/schema.inc b/includes/database/schema.inc
index 1fc92954..31862db3 100644
--- a/includes/database/schema.inc
+++ b/includes/database/schema.inc
@@ -92,7 +92,8 @@ require_once dirname(__FILE__) . '/query.inc';
* specification). Each specification is an array containing the name of
* the referenced table ('table'), and an array of column mappings
* ('columns'). Column mappings are defined by key pairs ('source_column' =>
- * 'referenced_column').
+ * 'referenced_column'). This key is for documentation purposes only; foreign
+ * keys are not created in the database, nor are they enforced by Drupal.
* - 'indexes': An associative array of indexes ('indexname' =>
* specification). Each specification is an array of one or more
* key column specifiers (see below) that form an index on the
@@ -144,6 +145,8 @@ require_once dirname(__FILE__) . '/query.inc';
* 'unique keys' => array(
* 'vid' => array('vid'),
* ),
+ * // For documentation purposes only; foreign keys are not created in the
+ * // database.
* 'foreign keys' => array(
* 'node_revision' => array(
* 'table' => 'node_revision',
@@ -161,6 +164,9 @@ require_once dirname(__FILE__) . '/query.inc';
* @see drupal_install_schema()
*/
+/**
+ * Base class for database schema definitions.
+ */
abstract class DatabaseSchema implements QueryPlaceholderInterface {
protected $connection;
@@ -288,7 +294,7 @@ abstract class DatabaseSchema implements QueryPlaceholderInterface {
protected function buildTableNameCondition($table_name, $operator = '=', $add_prefix = TRUE) {
$info = $this->connection->getConnectionOptions();
- // Retrive the table name and schema
+ // Retrieve the table name and schema
$table_info = $this->getPrefixInfo($table_name, $add_prefix);
$condition = new DatabaseCondition('AND');
diff --git a/includes/database/select.inc b/includes/database/select.inc
index 3abd205c..8d84460e 100644
--- a/includes/database/select.inc
+++ b/includes/database/select.inc
@@ -1231,6 +1231,21 @@ class SelectQuery extends Query implements SelectQueryInterface {
// Modules may alter all queries or only those having a particular tag.
if (isset($this->alterTags)) {
+ // Many contrib modules assume that query tags used for access-checking
+ // purposes follow the pattern $entity_type . '_access'. But this is
+ // not the case for taxonomy terms, since core used to add term_access
+ // instead of taxonomy_term_access to its queries. Provide backwards
+ // compatibility by adding both tags here instead of attempting to fix
+ // all contrib modules in a coordinated effort.
+ // TODO:
+ // - Extract this mechanism into a hook as part of a public (non-security)
+ // issue.
+ // - Emit E_USER_DEPRECATED if term_access is used.
+ // https://www.drupal.org/node/2575081
+ $term_access_tags = array('term_access' => 1, 'taxonomy_term_access' => 1);
+ if (array_intersect_key($this->alterTags, $term_access_tags)) {
+ $this->alterTags += $term_access_tags;
+ }
$hooks = array('query');
foreach ($this->alterTags as $tag => $value) {
$hooks[] = 'query_' . $tag;
diff --git a/includes/database/sqlite/database.inc b/includes/database/sqlite/database.inc
index 8a5ba8c9..589a1728 100644
--- a/includes/database/sqlite/database.inc
+++ b/includes/database/sqlite/database.inc
@@ -378,6 +378,14 @@ class DatabaseConnection_sqlite extends DatabaseConnection {
}
}
+ public function utf8mb4IsActive() {
+ return TRUE;
+ }
+
+ public function utf8mb4IsSupported() {
+ return TRUE;
+ }
+
}
/**
diff --git a/includes/database/sqlite/install.inc b/includes/database/sqlite/install.inc
index 62cbac38..10884e2f 100644
--- a/includes/database/sqlite/install.inc
+++ b/includes/database/sqlite/install.inc
@@ -14,8 +14,6 @@ class DatabaseTasks_sqlite extends DatabaseTasks {
/**
* Minimum engine version.
- *
- * @todo: consider upping to 3.6.8 in Drupal 8 to get SAVEPOINT support.
*/
public function minimumVersion() {
return '3.3.7';
diff --git a/includes/database/sqlite/query.inc b/includes/database/sqlite/query.inc
index 1c6289bd..c9c028bb 100644
--- a/includes/database/sqlite/query.inc
+++ b/includes/database/sqlite/query.inc
@@ -99,16 +99,15 @@ class UpdateQuery_sqlite extends UpdateQuery {
/**
* SQLite specific implementation of DeleteQuery.
- *
- * When the WHERE is omitted from a DELETE statement and the table being deleted
- * has no triggers, SQLite uses an optimization to erase the entire table content
- * without having to visit each row of the table individually.
- *
- * Prior to SQLite 3.6.5, SQLite does not return the actual number of rows deleted
- * by that optimized "truncate" optimization.
*/
class DeleteQuery_sqlite extends DeleteQuery {
public function execute() {
+ // When the WHERE is omitted from a DELETE statement and the table being
+ // deleted has no triggers, SQLite uses an optimization to erase the entire
+ // table content without having to visit each row of the table individually.
+ // Prior to SQLite 3.6.5, SQLite does not return the actual number of rows
+ // deleted by that optimized "truncate" optimization. But we want to return
+ // the number of rows affected, so we calculate it directly.
if (!count($this->condition)) {
$total_rows = $this->connection->query('SELECT COUNT(*) FROM {' . $this->connection->escapeTable($this->table) . '}')->fetchField();
parent::execute();
diff --git a/includes/database/sqlite/schema.inc b/includes/database/sqlite/schema.inc
index df19d2fa..281d8fc6 100644
--- a/includes/database/sqlite/schema.inc
+++ b/includes/database/sqlite/schema.inc
@@ -244,7 +244,7 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
// database. So the syntax '...RENAME TO database.table' would fail.
// So we must determine the full table name here rather than surrounding
// the table with curly braces incase the db_prefix contains a reference
- // to a database outside of our existsing database.
+ // to a database outside of our existing database.
$info = $this->getPrefixInfo($new_name);
$this->connection->query('ALTER TABLE {' . $table . '} RENAME TO ' . $info['table']);
diff --git a/includes/date.inc b/includes/date.inc
index 01ab131b..9e68fee4 100644
--- a/includes/date.inc
+++ b/includes/date.inc
@@ -12,11 +12,6 @@ function system_default_date_formats() {
$formats = array();
// Short date formats.
- $formats[] = array(
- 'type' => 'short',
- 'format' => 'Y-m-d H:i',
- 'locales' => array(),
- );
$formats[] = array(
'type' => 'short',
'format' => 'm/d/Y - H:i',
@@ -37,6 +32,11 @@ function system_default_date_formats() {
'format' => 'd.m.Y - H:i',
'locales' => array('de-ch', 'de-de', 'de-lu', 'fi-fi', 'fr-ch', 'is-is', 'pl-pl', 'ro-ro', 'ru-ru'),
);
+ $formats[] = array(
+ 'type' => 'short',
+ 'format' => 'Y-m-d H:i',
+ 'locales' => array(),
+ );
$formats[] = array(
'type' => 'short',
'format' => 'm/d/Y - g:ia',
@@ -84,11 +84,6 @@ function system_default_date_formats() {
);
// Medium date formats.
- $formats[] = array(
- 'type' => 'medium',
- 'format' => 'D, Y-m-d H:i',
- 'locales' => array(),
- );
$formats[] = array(
'type' => 'medium',
'format' => 'D, m/d/Y - H:i',
@@ -104,6 +99,11 @@ function system_default_date_formats() {
'format' => 'D, Y/m/d - H:i',
'locales' => array('en-ca', 'fr-ca', 'no-no', 'sv-se'),
);
+ $formats[] = array(
+ 'type' => 'medium',
+ 'format' => 'D, Y-m-d H:i',
+ 'locales' => array(),
+ );
$formats[] = array(
'type' => 'medium',
'format' => 'F j, Y - H:i',
diff --git a/includes/entity.inc b/includes/entity.inc
index 62359a94..e80ce3b8 100644
--- a/includes/entity.inc
+++ b/includes/entity.inc
@@ -446,7 +446,7 @@ class EntityFieldQueryException extends Exception {}
*
* This class allows finding entities based on entity properties (for example,
* node->changed), field values, and generic entity meta data (bundle,
- * entity type, entity id, and revision ID). It is not possible to query across
+ * entity type, entity ID, and revision ID). It is not possible to query across
* multiple entity types. For example, there is no facility to find published
* nodes written by users created in the last hour, as this would require
* querying both node->status and user->created.
@@ -688,14 +688,36 @@ class EntityFieldQuery {
* @param $field
* Either a field name or a field array.
* @param $column
- * The column that should hold the value to be matched.
+ * The column that should hold the value to be matched, defined in the
+ * hook_field_schema() of this field. If this is omitted then all of the
+ * other parameters are ignored, except $field, and this call will just be
+ * adding a condition that says that the field has a value, rather than
+ * testing the value itself.
* @param $value
- * The value to test the column value against.
+ * The value to test the column value against. In most cases, this is a
+ * scalar. For more complex options, it is an array. The meaning of each
+ * element in the array is dependent on $operator.
* @param $operator
- * The operator to be used to test the given value.
+ * The operator to be used to test the given value. The possible values are:
+ * - '=', '<>', '>', '>=', '<', '<=', 'STARTS_WITH', 'CONTAINS': These
+ * operators expect $value to be a literal of the same type as the
+ * column.
+ * - 'IN', 'NOT IN': These operators expect $value to be an array of
+ * literals of the same type as the column.
+ * - 'BETWEEN': This operator expects $value to be an array of two literals
+ * of the same type as the column.
+ * The operator can be omitted, and will default to 'IN' if the value is an
+ * array, or to '=' otherwise.
* @param $delta_group
* An arbitrary identifier: conditions in the same group must have the same
- * $delta_group.
+ * $delta_group. For example, let's presume a multivalue field which has
+ * two columns, 'color' and 'shape', and for entity ID 1, there are two
+ * values: red/square and blue/circle. Entity ID 1 does not have values
+ * corresponding to 'red circle'; however if you pass 'red' and 'circle' as
+ * conditions, it will appear in the results -- by default queries will run
+ * against any combination of deltas. By passing the conditions with the
+ * same $delta_group it will ensure that only values attached to the same
+ * delta are matched, and entity 1 would then be excluded from the results.
* @param $language_group
* An arbitrary identifier: conditions in the same group must have the same
* $language_group.
@@ -770,9 +792,11 @@ class EntityFieldQuery {
* @param $field
* Either a field name or a field array.
* @param $column
- * A column defined in the hook_field_schema() of this field. If this is
- * omitted then the query will find only entities that have data in this
- * field, using the entity and property conditions if there are any.
+ * The column that should hold the value to be matched, defined in the
+ * hook_field_schema() of this field. If this is omitted then all of the
+ * other parameters are ignored, except $field, and this call will just be
+ * adding a condition that says that the field has a value, rather than
+ * testing the value itself.
* @param $value
* The value to test the column value against. In most cases, this is a
* scalar. For more complex options, it is an array. The meaning of each
@@ -791,10 +815,10 @@ class EntityFieldQuery {
* @param $delta_group
* An arbitrary identifier: conditions in the same group must have the same
* $delta_group. For example, let's presume a multivalue field which has
- * two columns, 'color' and 'shape', and for entity id 1, there are two
+ * two columns, 'color' and 'shape', and for entity ID 1, there are two
* values: red/square and blue/circle. Entity ID 1 does not have values
* corresponding to 'red circle', however if you pass 'red' and 'circle' as
- * conditions, it will appear in the results - by default queries will run
+ * conditions, it will appear in the results -- by default queries will run
* against any combination of deltas. By passing the conditions with the
* same $delta_group it will ensure that only values attached to the same
* delta are matched, and entity 1 would then be excluded from the results.
diff --git a/includes/errors.inc b/includes/errors.inc
index a9b7b5bd..3548d1fd 100644
--- a/includes/errors.inc
+++ b/includes/errors.inc
@@ -66,7 +66,7 @@ function _drupal_error_handler_real($error_level, $message, $filename, $line, $c
_drupal_log_error(array(
'%type' => isset($types[$error_level]) ? $severity_msg : 'Unknown error',
// The standard PHP error handler considers that the error messages
- // are HTML. We mimick this behavior here.
+ // are HTML. We mimic this behavior here.
'!message' => filter_xss_admin($message),
'%function' => $caller['function'],
'%file' => $caller['file'],
@@ -114,7 +114,7 @@ function _drupal_decode_exception($exception) {
return array(
'%type' => get_class($exception),
// The standard PHP exception handler considers that the exception message
- // is plain-text. We mimick this behavior here.
+ // is plain-text. We mimic this behavior here.
'!message' => check_plain($message),
'%function' => $caller['function'],
'%file' => $caller['file'],
@@ -199,7 +199,16 @@ function _drupal_log_error($error, $fatal = FALSE) {
$number++;
}
- watchdog('php', '%type: !message in %function (line %line of %file).', $error, $error['severity_level']);
+ // Log the error immediately, unless this is a non-fatal error which has been
+ // triggered via drupal_trigger_error_with_delayed_logging(); in that case
+ // trigger it in a shutdown function. Fatal errors are always triggered
+ // immediately since for a fatal error the page request will end here anyway.
+ if (!$fatal && drupal_static('_drupal_trigger_error_with_delayed_logging')) {
+ drupal_register_shutdown_function('watchdog', 'php', '%type: !message in %function (line %line of %file).', $error, $error['severity_level']);
+ }
+ else {
+ watchdog('php', '%type: !message in %function (line %line of %file).', $error, $error['severity_level']);
+ }
if ($fatal) {
drupal_add_http_header('Status', '500 Service unavailable (with message)');
@@ -224,7 +233,7 @@ function _drupal_log_error($error, $fatal = FALSE) {
}
else {
// Display the message if the current error reporting level allows this type
- // of message to be displayed, and unconditionnaly in update.php.
+ // of message to be displayed, and unconditionally in update.php.
if (error_displayable($error)) {
$class = 'error';
diff --git a/includes/file.inc b/includes/file.inc
index d3ac87ea..fa7f5eb5 100644
--- a/includes/file.inc
+++ b/includes/file.inc
@@ -273,7 +273,9 @@ function file_default_scheme() {
* The normalized URI.
*/
function file_stream_wrapper_uri_normalize($uri) {
- $scheme = file_uri_scheme($uri);
+ // Inline file_uri_scheme() function call for performance reasons.
+ $position = strpos($uri, '://');
+ $scheme = $position ? substr($uri, 0, $position) : FALSE;
if ($scheme && file_stream_wrapper_valid_scheme($scheme)) {
$target = file_uri_target($uri);
@@ -533,7 +535,18 @@ SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
EOF;
if ($private) {
- $lines = "Deny from all\n\n" . $lines;
+ $lines = <<
+ Require all denied
+
+
+# Deny all requests from Apache 2.0-2.2.
+
+ Deny from all
+
+EOF
+ . "\n\n" . $lines;
}
return $lines;
@@ -887,7 +900,6 @@ function file_valid_uri($uri) {
*/
function file_unmanaged_copy($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
$original_source = $source;
- $original_destination = $destination;
// Assert that the source file actually exists.
if (!file_exists($source)) {
@@ -1602,6 +1614,20 @@ function file_save_upload($form_field_name, $validators = array(), $destination
// If we made it this far it's safe to record this file in the database.
if ($file = file_save($file)) {
+ // Track non-public files in the session if they were uploaded by an
+ // anonymous user. This allows modules such as the File module to only
+ // grant view access to the specific anonymous user who uploaded the file.
+ // See file_file_download().
+ // The 'file_public_schema' variable is used to allow other publicly
+ // accessible file schemes to be treated the same as the public:// scheme
+ // provided by Drupal core and to avoid adding unnecessary data to the
+ // session (and the resulting bypass of the page cache) in those cases. For
+ // security reasons, only schemes that are completely publicly accessible,
+ // with no download restrictions, should be added to this variable. See
+ // file_managed_file_value().
+ if (!$user->uid && !in_array($destination_scheme, variable_get('file_public_schema', array('public')))) {
+ $_SESSION['anonymous_allowed_file_ids'][$file->fid] = $file->fid;
+ }
// Add file to the cache.
$upload_cache[$form_field_name] = $file;
return $file;
@@ -1785,7 +1811,7 @@ function file_validate_is_image(stdClass $file) {
/**
* Verifies that image dimensions are within the specified maximum and minimum.
*
- * Non-image files will be ignored. If a image toolkit is available the image
+ * Non-image files will be ignored. If an image toolkit is available the image
* will be scaled to fit within the desired maximum dimensions.
*
* @param $file
@@ -2022,7 +2048,7 @@ function file_download() {
*
* @see file_transfer()
* @see file_download_access()
- * @see hook_file_downlaod()
+ * @see hook_file_download()
*/
function file_download_headers($uri) {
// Let other modules provide headers and control access to the file.
@@ -2551,7 +2577,6 @@ function file_directory_temp() {
* An associative array of headers, as expected by file_transfer().
*/
function file_get_content_headers($file) {
- $name = mime_header_encode($file->filename);
$type = mime_header_encode($file->filemime);
return array(
diff --git a/includes/form.inc b/includes/form.inc
index f7671bed..e749239e 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -105,7 +105,8 @@
* generate the same form (or very similar forms) using different $form_ids
* can implement hook_forms(), which maps different $form_id values to the
* proper form constructor function. Examples may be found in node_forms(),
- * and search_forms().
+ * and search_forms(). hook_forms() can also be used to define forms in
+ * classes.
* @param ...
* Any additional arguments are passed on to the functions called by
* drupal_get_form(), including the unique form constructor function. For
@@ -809,7 +810,7 @@ function drupal_retrieve_form($form_id, &$form_state) {
}
if (isset($form_definition['callback'])) {
$callback = $form_definition['callback'];
- $form_state['build_info']['base_form_id'] = $callback;
+ $form_state['build_info']['base_form_id'] = isset($form_definition['base_form_id']) ? $form_definition['base_form_id'] : $callback;
}
// In case $form_state['wrapper_callback'] is not defined already, we also
// allow hook_forms() to define one.
@@ -830,7 +831,7 @@ function drupal_retrieve_form($form_id, &$form_state) {
// the actual form builder function ($callback) expects. This allows for
// pre-populating a form with common elements for certain forms, such as
// back/next/save buttons in multi-step form wizards. See drupal_build_form().
- if (isset($form_state['wrapper_callback']) && function_exists($form_state['wrapper_callback'])) {
+ if (isset($form_state['wrapper_callback']) && is_callable($form_state['wrapper_callback'])) {
$form = call_user_func_array($form_state['wrapper_callback'], $args);
// Put the prepopulated $form into $args.
$args[0] = $form;
@@ -1175,7 +1176,7 @@ function drupal_validate_form($form_id, &$form, &$form_state) {
// If the session token was set by drupal_prepare_form(), ensure that it
// matches the current user's session. This is duplicate to code in
// form_builder() but left to protect any custom form handling code.
- if (isset($form['#token'])) {
+ if (!empty($form['#token'])) {
if (!drupal_valid_token($form_state['values']['form_token'], $form['#token']) || !empty($form_state['invalid_token'])) {
_drupal_invalid_token_set_form_error();
// Stop here and don't run any further validation handlers, because they
@@ -1836,7 +1837,7 @@ function form_builder($form_id, &$element, &$form_state) {
// If the session token was set by drupal_prepare_form(), ensure that it
// matches the current user's session.
$form_state['invalid_token'] = FALSE;
- if (isset($element['#token'])) {
+ if (!empty($element['#token'])) {
if (empty($form_state['input']['form_token']) || !drupal_valid_token($form_state['input']['form_token'], $element['#token'])) {
// Set an early form error to block certain input processing since that
// opens the door for CSRF vulnerabilities.
@@ -2571,7 +2572,7 @@ function form_type_select_value($element, $input = FALSE) {
* for this element. Return nothing to use the default.
*/
function form_type_textarea_value($element, $input = FALSE) {
- if ($input !== FALSE) {
+ if ($input !== FALSE && $input !== NULL) {
// This should be a string, but allow other scalars since they might be
// valid input in programmatic form submissions.
return is_scalar($input) ? (string) $input : '';
@@ -3028,7 +3029,7 @@ function form_process_password_confirm($element) {
function password_confirm_validate($element, &$element_state) {
$pass1 = trim($element['pass1']['#value']);
$pass2 = trim($element['pass2']['#value']);
- if (!empty($pass1) || !empty($pass2)) {
+ if (strlen($pass1) > 0 || strlen($pass2) > 0) {
if (strcmp($pass1, $pass2)) {
form_error($element, t('The specified passwords do not match.'));
}
@@ -3385,9 +3386,12 @@ function form_process_container($element, &$form_state) {
/**
* Returns HTML to wrap child elements in a container.
*
- * Used for grouped form items. Can also be used as a #theme_wrapper for any
+ * Used for grouped form items. Can also be used as a theme wrapper for any
* renderable element, to surround it with a
and add attributes such as
- * classes or an HTML id.
+ * classes or an HTML ID.
+ *
+ * See the @link forms_api_reference.html Form API reference @endlink for more
+ * information on the #theme_wrappers render array property.
*
* @param $variables
* An associative array containing:
@@ -3542,6 +3546,7 @@ function form_process_tableselect($element) {
'#return_value' => $key,
'#default_value' => isset($value[$key]) ? $key : NULL,
'#attributes' => $element['#attributes'],
+ '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
);
}
else {
@@ -3979,7 +3984,12 @@ function form_process_autocomplete($element) {
// browser interpreting the path plus search string as an actual file.
$current_clean_url = isset($GLOBALS['conf']['clean_url']) ? $GLOBALS['conf']['clean_url'] : NULL;
$GLOBALS['conf']['clean_url'] = 0;
- $element['#autocomplete_input']['#url_value'] = url($element['#autocomplete_path'], array('absolute' => TRUE));
+ // Force the script path to 'index.php', in case the server is not
+ // configured to find it automatically. Normally it is the responsibility
+ // of the site to do this themselves using hook_url_outbound_alter() (see
+ // url()) but since this code is forcing non-clean URLs on sites that don't
+ // normally use them, it is done here instead.
+ $element['#autocomplete_input']['#url_value'] = url($element['#autocomplete_path'], array('absolute' => TRUE, 'script' => 'index.php'));
$GLOBALS['conf']['clean_url'] = $current_clean_url;
}
return $element;
@@ -4484,7 +4494,7 @@ function element_validate_number($element, &$form_state) {
*
* Sample callback_batch_finished():
* @code
- * function batch_test_finished($success, $results, $operations) {
+ * function my_finished_callback($success, $results, $operations) {
* // The 'success' parameter means no fatal PHP errors were detected. All
* // other error management should be handled using 'results'.
* if ($success) {
diff --git a/includes/install.core.inc b/includes/install.core.inc
index e5a65865..b18d23d2 100644
--- a/includes/install.core.inc
+++ b/includes/install.core.inc
@@ -809,6 +809,13 @@ function install_system_module(&$install_state) {
variable_set('install_profile_modules', array_diff($modules, array('system')));
$install_state['database_tables_exist'] = TRUE;
+
+ // Prevent the hook_requirements() check from telling us to convert the
+ // database to utf8mb4.
+ $connection = Database::getConnection();
+ if ($connection->utf8mb4IsConfigurable() && $connection->utf8mb4IsActive()) {
+ variable_set('drupal_all_databases_are_utf8mb4', TRUE);
+ }
}
/**
@@ -1590,7 +1597,9 @@ function install_finished(&$install_state) {
}
/**
- * Batch callback for batch installation of modules.
+ * Implements callback_batch_operation().
+ *
+ * Performs batch installation of modules.
*/
function _install_module_batch($module, $module_name, &$context) {
// Install and enable the module right away, so that the module will be
@@ -1603,6 +1612,8 @@ function _install_module_batch($module, $module_name, &$context) {
}
/**
+ * Implements callback_batch_finished().
+ *
* 'Finished' callback for module installation batch.
*/
function _install_profile_modules_finished($success, $results, $operations) {
diff --git a/includes/install.inc b/includes/install.inc
index bd37d067..5065d35c 100644
--- a/includes/install.inc
+++ b/includes/install.inc
@@ -750,7 +750,7 @@ function drupal_install_system() {
/**
* Uninstalls a given list of disabled modules.
*
- * @param array $module_list
+ * @param string[] $module_list
* The modules to uninstall. It is the caller's responsibility to ensure that
* all modules in this list have already been disabled before this function
* is called.
@@ -769,6 +769,7 @@ function drupal_install_system() {
* included in $module_list).
*
* @see module_disable()
+ * @see module_enable()
*/
function drupal_uninstall_modules($module_list = array(), $uninstall_dependents = TRUE) {
if ($uninstall_dependents) {
diff --git a/includes/locale.inc b/includes/locale.inc
index c7f95838..11f1413e 100644
--- a/includes/locale.inc
+++ b/includes/locale.inc
@@ -435,6 +435,13 @@ function locale_language_url_rewrite_url(&$path, &$options) {
switch (variable_get('locale_language_negotiation_url_part', LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX)) {
case LOCALE_LANGUAGE_NEGOTIATION_URL_DOMAIN:
if ($options['language']->domain) {
+ // Save the original base URL. If it contains a port, we need to
+ // retain it below.
+ if (!empty($options['base_url'])) {
+ // The colon in the URL scheme messes up the port checking below.
+ $normalized_base_url = str_replace(array('https://', 'http://'), '', $options['base_url']);
+ }
+
// Ask for an absolute URL with our modified base_url.
global $is_https;
$url_scheme = ($is_https) ? 'https://' : 'http://';
@@ -449,6 +456,19 @@ function locale_language_url_rewrite_url(&$path, &$options) {
// Apply the appropriate protocol to the URL.
$options['base_url'] = $url_scheme . $host;
+
+ // In case either the original base URL or the HTTP host contains a
+ // port, retain it.
+ $http_host = $_SERVER['HTTP_HOST'];
+ if (isset($normalized_base_url) && strpos($normalized_base_url, ':') !== FALSE) {
+ list($host, $port) = explode(':', $normalized_base_url);
+ $options['base_url'] .= ':' . $port;
+ }
+ elseif (strpos($http_host, ':') !== FALSE) {
+ list($host, $port) = explode(':', $http_host);
+ $options['base_url'] .= ':' . $port;
+ }
+
if (isset($options['https']) && variable_get('https', FALSE)) {
if ($options['https'] === TRUE) {
$options['base_url'] = str_replace('http://', 'https://', $options['base_url']);
@@ -523,6 +543,22 @@ function locale_language_url_rewrite_session(&$path, &$options) {
* possible attack vector (img).
*/
function locale_string_is_safe($string) {
+ // Some strings have tokens in them. For tokens in the first part of href or
+ // src HTML attributes, filter_xss() removes part of the token, the part
+ // before the first colon. filter_xss() assumes it could be an attempt to
+ // inject javascript. When filter_xss() removes part of tokens, it causes the
+ // string to not be translatable when it should be translatable. See
+ // LocaleStringIsSafeTest::testLocaleStringIsSafe().
+ //
+ // We can recognize tokens since they are wrapped with brackets and are only
+ // composed of alphanumeric characters, colon, underscore, and dashes. We can
+ // be sure these strings are safe to strip out before the string is checked in
+ // filter_xss() because no dangerous javascript will match that pattern.
+ //
+ // @todo Do not strip out the token. Fix filter_xss() to not incorrectly
+ // alter the string. https://www.drupal.org/node/2372127
+ $string = preg_replace('/\[[a-z0-9_-]+(:[a-z0-9_-]+)+\]/i', '', $string);
+
return decode_entities($string) == decode_entities(filter_xss($string, array('a', 'abbr', 'acronym', 'address', 'b', 'bdo', 'big', 'blockquote', 'br', 'caption', 'cite', 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dl', 'dt', 'em', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'ins', 'kbd', 'li', 'ol', 'p', 'pre', 'q', 'samp', 'small', 'span', 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'tt', 'ul', 'var')));
}
@@ -631,9 +667,6 @@ function locale_add_language($langcode, $name = NULL, $native = NULL, $direction
* translations).
*/
function _locale_import_po($file, $langcode, $mode, $group = NULL) {
- // Try to allocate enough time to parse and import the data.
- drupal_set_time_limit(240);
-
// Check if we have the language already in the database.
if (!db_query("SELECT COUNT(language) FROM {languages} WHERE language = :language", array(':language' => $langcode))->fetchField()) {
drupal_set_message(t('The language selected for import is not supported.'), 'error');
@@ -717,6 +750,12 @@ function _locale_import_read_po($op, $file, $mode = NULL, $lang = NULL, $group =
$lineno = 0;
while (!feof($fd)) {
+ // Refresh the time limit every 10 parsed rows to ensure there is always
+ // enough time to import the data for large PO files.
+ if (!($lineno % 10)) {
+ drupal_set_time_limit(30);
+ }
+
// A line should not be longer than 10 * 1024.
$line = fgets($fd, 10 * 1024);
@@ -2306,6 +2345,8 @@ function _locale_batch_build($files, $finished = NULL, $components = array()) {
}
/**
+ * Implements callback_batch_operation().
+ *
* Perform interface translation import as a batch step.
*
* @param $filepath
@@ -2324,6 +2365,8 @@ function _locale_batch_import($filepath, &$context) {
}
/**
+ * Implements callback_batch_finished().
+ *
* Finished callback of system page locale import batch.
* Inform the user of translation files imported.
*/
@@ -2334,6 +2377,8 @@ function _locale_batch_system_finished($success, $results) {
}
/**
+ * Implements callback_batch_finished().
+ *
* Finished callback of language addition locale import batch.
* Inform the user of translation files imported.
*/
diff --git a/includes/mail.inc b/includes/mail.inc
index 0275922b..0e5c1780 100644
--- a/includes/mail.inc
+++ b/includes/mail.inc
@@ -566,7 +566,7 @@ function _drupal_wrap_mail_line(&$line, $key, $values) {
// Use soft-breaks only for purely quoted or unindented text.
$line = wordwrap($line, 77 - $values['length'], $values['soft'] ? " \n" : "\n");
// Break really long words at the maximum width allowed.
- $line = wordwrap($line, 996 - $values['length'], $values['soft'] ? " \n" : "\n");
+ $line = wordwrap($line, 996 - $values['length'], $values['soft'] ? " \n" : "\n", TRUE);
}
/**
diff --git a/includes/menu.inc b/includes/menu.inc
index 0e9c977c..4664d27e 100644
--- a/includes/menu.inc
+++ b/includes/menu.inc
@@ -229,12 +229,20 @@ define('MENU_CONTEXT_INLINE', 0x0002);
define('MENU_FOUND', 1);
/**
- * Internal menu status code -- Menu item was not found.
+ * Menu status code -- Not found.
+ *
+ * This can be used as the return value from a page callback, although it is
+ * preferable to use a load function to accomplish this; see the hook_menu()
+ * documentation for details.
*/
define('MENU_NOT_FOUND', 2);
/**
- * Internal menu status code -- Menu item access is denied.
+ * Menu status code -- Access denied.
+ *
+ * This can be used as the return value from a page callback, although it is
+ * preferable to use an access callback to accomplish this; see the hook_menu()
+ * documentation for details.
*/
define('MENU_ACCESS_DENIED', 3);
@@ -431,7 +439,7 @@ function menu_set_item($path, $router_item) {
*
* @param $path
* The path; for example, 'node/5'. The function will find the corresponding
- * node/% item and return that.
+ * node/% item and return that. Defaults to the current path.
* @param $router_item
* Internal use only.
*
@@ -1598,6 +1606,7 @@ function _menu_tree_data(&$links, $parents, $depth) {
* Implements template_preprocess_HOOK() for theme_menu_tree().
*/
function template_preprocess_menu_tree(&$variables) {
+ $variables['#tree'] = $variables['tree'];
$variables['tree'] = $variables['tree']['#children'];
}
@@ -2411,7 +2420,7 @@ function menu_set_active_trail($new_trail = NULL) {
// argument placeholders (%). Such links are not contained in regular
// menu trees, and have only been loaded for the additional
// translation that happens here, so as to be able to display them in
- // the breadcumb for the current page.
+ // the breadcrumb for the current page.
// @see _menu_tree_check_access()
// @see _menu_link_translate()
if (strpos($link['href'], '%') !== FALSE) {
@@ -2613,10 +2622,30 @@ function menu_get_active_breadcrumb() {
*/
function menu_get_active_title() {
$active_trail = menu_get_active_trail();
+ $local_task_title = NULL;
foreach (array_reverse($active_trail) as $item) {
- if (!(bool) ($item['type'] & MENU_IS_LOCAL_TASK)) {
- return $item['title'];
+ // Local task titles are displayed as tabs and therefore should not be
+ // repeated as the page title. However, if the local task appears in a
+ // top-level menu, it is no longer a "local task" anymore (the front page
+ // of the site does not have tabs) so it is better to use the local task
+ // title in that case than to fall back on the front page link in the
+ // active trail (which is usually "Home" and would not make sense in this
+ // context).
+ if ((bool) ($item['type'] & MENU_IS_LOCAL_TASK)) {
+ // A local task title is being skipped; track it in case it needs to be
+ // used later.
+ $local_task_title = $item['title'];
+ }
+ else {
+ // This is not a local task, so use it for the page title (unless the
+ // conditions described above are met).
+ if (isset($local_task_title) && isset($item['href']) && $item['href'] == '') {
+ return $local_task_title;
+ }
+ else {
+ return $item['title'];
+ }
}
}
}
@@ -2654,7 +2683,7 @@ function menu_link_load($mlid) {
}
/**
- * Clears the cached cached data for a single named menu.
+ * Clears the cached data for a single named menu.
*/
function menu_cache_clear($menu_name = 'navigation') {
$cache_cleared = &drupal_static(__FUNCTION__, array());
diff --git a/includes/module.inc b/includes/module.inc
index 494924f5..2e251080 100644
--- a/includes/module.inc
+++ b/includes/module.inc
@@ -227,6 +227,10 @@ function system_list_reset() {
drupal_static_reset('list_themes');
cache_clear_all('bootstrap_modules', 'cache_bootstrap');
cache_clear_all('system_list', 'cache_bootstrap');
+
+ // Clean up the bootstrap file scan cache.
+ drupal_static_reset('_drupal_file_scan_cache');
+ cache_clear_all('_drupal_file_scan_cache', 'cache_bootstrap');
}
/**
@@ -320,16 +324,27 @@ function module_load_install($module) {
* The name of the included file, if successful; FALSE otherwise.
*/
function module_load_include($type, $module, $name = NULL) {
+ static $files = array();
+
if (!isset($name)) {
$name = $module;
}
+ $key = $type . ':' . $module . ':' . $name;
+ if (isset($files[$key])) {
+ return $files[$key];
+ }
+
if (function_exists('drupal_get_path')) {
$file = DRUPAL_ROOT . '/' . drupal_get_path('module', $module) . "/$name.$type";
if (is_file($file)) {
require_once $file;
+ $files[$key] = $file;
return $file;
}
+ else {
+ $files[$key] = FALSE;
+ }
}
return FALSE;
}
@@ -365,20 +380,22 @@ function module_load_all_includes($type, $name = NULL) {
* - Invoke hook_modules_installed().
* - Invoke hook_modules_enabled().
*
- * @param $module_list
+ * @param string[] $module_list
* An array of module names.
- * @param $enable_dependencies
+ * @param bool $enable_dependencies
* If TRUE, dependencies will automatically be added and enabled in the
* correct order. This incurs a significant performance cost, so use FALSE
* if you know $module_list is already complete and in the correct order.
*
- * @return
+ * @return bool
* FALSE if one or more dependencies are missing, TRUE otherwise.
*
* @see hook_install()
* @see hook_enable()
* @see hook_modules_installed()
* @see hook_modules_enabled()
+ * @see module_disable()
+ * @see drupal_uninstall_modules()
*/
function module_enable($module_list, $enable_dependencies = TRUE) {
if ($enable_dependencies) {
@@ -505,12 +522,15 @@ function module_enable($module_list, $enable_dependencies = TRUE) {
/**
* Disables a given set of modules.
*
- * @param $module_list
+ * @param string[] $module_list
* An array of module names.
- * @param $disable_dependents
+ * @param bool $disable_dependents
* If TRUE, dependent modules will automatically be added and disabled in the
* correct order. This incurs a significant performance cost, so use FALSE
* if you know $module_list is already complete and in the correct order.
+ *
+ * @see drupal_uninstall_modules()
+ * @see module_enable()
*/
function module_disable($module_list, $disable_dependents = TRUE) {
if ($disable_dependents) {
@@ -676,12 +696,16 @@ function module_hook($module, $hook) {
/**
* Determines which modules are implementing a hook.
*
- * @param $hook
+ * Lazy-loaded include files specified with "group" via hook_hook_info() or
+ * hook_module_implements_alter() will be automatically included by this
+ * function when necessary.
+ *
+ * @param string $hook
* The name of the hook (e.g. "help" or "menu").
- * @param $sort
+ * @param bool $sort
* By default, modules are ordered by weight and filename, settings this option
* to TRUE, module list will be ordered by module name.
- * @param $reset
+ * @param bool $reset
* For internal use only: Whether to force the stored list of hook
* implementations to be regenerated (such as after enabling a new module,
* before processing hook_enable).
@@ -696,8 +720,10 @@ function module_implements($hook, $sort = FALSE, $reset = FALSE) {
static $drupal_static_fast;
if (!isset($drupal_static_fast)) {
$drupal_static_fast['implementations'] = &drupal_static(__FUNCTION__);
+ $drupal_static_fast['verified'] = &drupal_static(__FUNCTION__ . ':verified');
}
$implementations = &$drupal_static_fast['implementations'];
+ $verified = &$drupal_static_fast['verified'];
// We maintain a persistent cache of hook implementations in addition to the
// static cache to avoid looping through every module and every hook on each
@@ -711,14 +737,19 @@ function module_implements($hook, $sort = FALSE, $reset = FALSE) {
// per request.
if ($reset) {
$implementations = array();
+ $verified = array();
cache_set('module_implements', array(), 'cache_bootstrap');
drupal_static_reset('module_hook_info');
drupal_static_reset('drupal_alter');
cache_clear_all('hook_info', 'cache_bootstrap');
+ cache_clear_all('system_cache_tables', 'cache');
return;
}
// Fetch implementations from cache.
+ // This happens on the first call to module_implements(*, *, FALSE) during a
+ // request, but also when $implementations have been reset, e.g. after
+ // module_enable().
if (empty($implementations)) {
$implementations = cache_get('module_implements', 'cache_bootstrap');
if ($implementations === FALSE) {
@@ -727,12 +758,17 @@ function module_implements($hook, $sort = FALSE, $reset = FALSE) {
else {
$implementations = $implementations->data;
}
+ // Forget all previously "verified" hooks, in case that $implementations
+ // were cleared via drupal_static_reset('module_implements') instead of
+ // module_implements(*, *, TRUE).
+ $verified = array();
}
if (!isset($implementations[$hook])) {
// The hook is not cached, so ensure that whether or not it has
// implementations, that the cache is updated at the end of the request.
$implementations['#write_cache'] = TRUE;
+ // Discover implementations for this hook.
$hook_info = module_hook_info();
$implementations[$hook] = array();
$list = module_list(FALSE, FALSE, $sort);
@@ -744,13 +780,31 @@ function module_implements($hook, $sort = FALSE, $reset = FALSE) {
$implementations[$hook][$module] = $include_file ? $hook_info[$hook]['group'] : FALSE;
}
}
- // Allow modules to change the weight of specific implementations but avoid
+ // Allow modules to change the weight of specific implementations, but avoid
// an infinite loop.
if ($hook != 'module_implements_alter') {
+ // Remember the implementations before hook_module_implements_alter().
+ $implementations_before = $implementations[$hook];
drupal_alter('module_implements', $implementations[$hook], $hook);
+ // Verify implementations that were added or modified.
+ foreach (array_diff_assoc($implementations[$hook], $implementations_before) as $module => $group) {
+ // If drupal_alter('module_implements') changed or added a $group, the
+ // respective file needs to be included.
+ if ($group) {
+ module_load_include('inc', $module, "$module.$group");
+ }
+ // If a new implementation was added, verify that the function exists.
+ if (!function_exists($module . '_' . $hook)) {
+ unset($implementations[$hook][$module]);
+ }
+ }
}
+ // Implementations for this hook are now "verified".
+ $verified[$hook] = TRUE;
}
- else {
+ elseif (!isset($verified[$hook])) {
+ // Implementations for this hook were in the cache, but they are not
+ // "verified" yet.
foreach ($implementations[$hook] as $module => $group) {
// If this hook implementation is stored in a lazy-loaded file, so include
// that file first.
@@ -769,6 +823,7 @@ function module_implements($hook, $sort = FALSE, $reset = FALSE) {
$implementations['#write_cache'] = TRUE;
}
}
+ $verified[$hook] = TRUE;
}
return array_keys($implementations[$hook]);
@@ -833,6 +888,11 @@ function module_hook_info() {
* @see module_implements()
*/
function module_implements_write_cache() {
+ // The list of implementations includes vital modules only before full
+ // bootstrap, so do not write cache if we are not fully bootstrapped yet.
+ if (drupal_get_bootstrap_phase() != DRUPAL_BOOTSTRAP_FULL) {
+ return;
+ }
$implementations = &drupal_static('module_implements');
if (isset($implementations['#write_cache'])) {
unset($implementations['#write_cache']);
@@ -880,7 +940,9 @@ function module_invoke($module, $hook) {
*
* @return
* An array of return values of the hook implementations. If modules return
- * arrays from their implementations, those are merged into one array.
+ * arrays from their implementations, those are merged into one array
+ * recursively. Note: integer keys in arrays will be lost, as the merge is
+ * done using array_merge_recursive().
*
* @see drupal_alter()
*/
diff --git a/includes/path.inc b/includes/path.inc
index 2e357111..6bd48d30 100644
--- a/includes/path.inc
+++ b/includes/path.inc
@@ -347,7 +347,8 @@ function drupal_match_path($path, $patterns) {
* drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL) makes this function available.
*
* @return
- * The current Drupal URL path.
+ * The current Drupal URL path. The path is untrusted user input and must be
+ * treated as such.
*
* @see request_path()
*/
diff --git a/includes/registry.inc b/includes/registry.inc
index ac5b035d..b035cc37 100644
--- a/includes/registry.inc
+++ b/includes/registry.inc
@@ -180,7 +180,7 @@ function _registry_parse_files($files) {
* (optional) Weight of the module.
*/
function _registry_parse_file($filename, $contents, $module = '', $weight = 0) {
- if (preg_match_all('/^\s*(?:abstract|final)?\s*(class|interface)\s+([a-zA-Z0-9_]+)/m', $contents, $matches)) {
+ if (preg_match_all('/^\s*(?:abstract|final)?\s*(class|interface|trait)\s+([a-zA-Z0-9_]+)/m', $contents, $matches)) {
foreach ($matches[2] as $key => $name) {
db_merge('registry')
->key(array(
diff --git a/includes/session.inc b/includes/session.inc
index 84d1983b..25aa3475 100644
--- a/includes/session.inc
+++ b/includes/session.inc
@@ -163,7 +163,7 @@ function _drupal_session_write($sid, $value) {
try {
if (!drupal_save_session()) {
// We don't have anything to do if we are not allowed to save the session.
- return;
+ return TRUE;
}
// Check whether $_SESSION has been changed in this request.
@@ -425,7 +425,7 @@ function _drupal_session_destroy($sid) {
// Nothing to do if we are not allowed to change the session.
if (!drupal_save_session()) {
- return;
+ return TRUE;
}
// Delete session data.
@@ -446,6 +446,8 @@ function _drupal_session_destroy($sid) {
elseif (variable_get('https', FALSE)) {
_drupal_session_delete_cookie('S' . session_name(), TRUE);
}
+
+ return TRUE;
}
/**
diff --git a/includes/stream_wrappers.inc b/includes/stream_wrappers.inc
index 48829388..232ff143 100644
--- a/includes/stream_wrappers.inc
+++ b/includes/stream_wrappers.inc
@@ -133,7 +133,7 @@ interface DrupalStreamWrapperInterface extends StreamWrapperInterface {
* @param $uri
* A string containing the URI that should be used for this instance.
*/
- function setUri($uri);
+ public function setUri($uri);
/**
* Returns the stream resource URI.
@@ -219,7 +219,6 @@ interface DrupalStreamWrapperInterface extends StreamWrapperInterface {
public function dirname($uri = NULL);
}
-
/**
* Drupal stream wrapper base class for local files.
*
@@ -549,6 +548,155 @@ abstract class DrupalLocalStreamWrapper implements DrupalStreamWrapperInterface
return fclose($this->handle);
}
+ /**
+ * Sets metadata on the stream.
+ *
+ * WARNING: Do not call this method directly! It will be called internally by
+ * PHP itself when one of the following functions is called on a stream URL:
+ *
+ * @param string $uri
+ * A string containing the URI to the file to set metadata on.
+ * @param int $option
+ * One of:
+ * - STREAM_META_TOUCH: The method was called in response to touch().
+ * - STREAM_META_OWNER_NAME: The method was called in response to chown()
+ * with string parameter.
+ * - STREAM_META_OWNER: The method was called in response to chown().
+ * - STREAM_META_GROUP_NAME: The method was called in response to chgrp().
+ * - STREAM_META_GROUP: The method was called in response to chgrp().
+ * - STREAM_META_ACCESS: The method was called in response to chmod().
+ * @param mixed $value
+ * If option is:
+ * - STREAM_META_TOUCH: Array consisting of two arguments of the touch()
+ * function.
+ * - STREAM_META_OWNER_NAME or STREAM_META_GROUP_NAME: The name of the owner
+ * user/group as string.
+ * - STREAM_META_OWNER or STREAM_META_GROUP: The value of the owner
+ * user/group as integer.
+ * - STREAM_META_ACCESS: The argument of the chmod() as integer.
+ *
+ * @return bool
+ * Returns TRUE on success or FALSE on failure. If $option is not
+ * implemented, FALSE should be returned.
+ *
+ * @see touch()
+ * @see chmod()
+ * @see chown()
+ * @see chgrp()
+ * @link http://php.net/manual/streamwrapper.stream-metadata.php
+ */
+ public function stream_metadata($uri, $option, $value) {
+ $target = $this->getLocalPath($uri);
+ $return = FALSE;
+ switch ($option) {
+ case STREAM_META_TOUCH:
+ if (!empty($value)) {
+ $return = touch($target, $value[0], $value[1]);
+ }
+ else {
+ $return = touch($target);
+ }
+ break;
+
+ case STREAM_META_OWNER_NAME:
+ case STREAM_META_OWNER:
+ $return = chown($target, $value);
+ break;
+
+ case STREAM_META_GROUP_NAME:
+ case STREAM_META_GROUP:
+ $return = chgrp($target, $value);
+ break;
+
+ case STREAM_META_ACCESS:
+ $return = chmod($target, $value);
+ break;
+ }
+ if ($return) {
+ // For convenience clear the file status cache of the underlying file,
+ // since metadata operations are often followed by file status checks.
+ clearstatcache(TRUE, $target);
+ }
+ return $return;
+ }
+
+ /**
+ * Truncate stream.
+ *
+ * Will respond to truncation; e.g., through ftruncate().
+ *
+ * @param int $new_size
+ * The new size.
+ *
+ * @return bool
+ * TRUE on success, FALSE otherwise.
+ */
+ public function stream_truncate($new_size) {
+ return ftruncate($this->handle, $new_size);
+ }
+
+ /**
+ * Retrieve the underlying stream resource.
+ *
+ * This method is called in response to stream_select().
+ *
+ * @param int $cast_as
+ * Can be STREAM_CAST_FOR_SELECT when stream_select() is calling
+ * stream_cast() or STREAM_CAST_AS_STREAM when stream_cast() is called for
+ * other uses.
+ *
+ * @return resource|false
+ * The underlying stream resource or FALSE if stream_select() is not
+ * supported.
+ *
+ * @see stream_select()
+ * @link http://php.net/manual/streamwrapper.stream-cast.php
+ */
+ public function stream_cast($cast_as) {
+ return $this->handle ? $this->handle : FALSE;
+ }
+
+ /**
+ * Change stream options.
+ *
+ * This method is called to set options on the stream.
+ *
+ * Since Windows systems do not allow it and it is not needed for most use
+ * cases anyway, this method is not supported on local files and will trigger
+ * an error and return false. If needed, custom subclasses can provide
+ * OS-specific implementations for advanced use cases.
+ *
+ * @param int $option
+ * One of:
+ * - STREAM_OPTION_BLOCKING: The method was called in response to
+ * stream_set_blocking().
+ * - STREAM_OPTION_READ_TIMEOUT: The method was called in response to
+ * stream_set_timeout().
+ * - STREAM_OPTION_WRITE_BUFFER: The method was called in response to
+ * stream_set_write_buffer().
+ * @param int $arg1
+ * If option is:
+ * - STREAM_OPTION_BLOCKING: The requested blocking mode:
+ * - 1 means blocking.
+ * - 0 means not blocking.
+ * - STREAM_OPTION_READ_TIMEOUT: The timeout in seconds.
+ * - STREAM_OPTION_WRITE_BUFFER: The buffer mode, STREAM_BUFFER_NONE or
+ * STREAM_BUFFER_FULL.
+ * @param int $arg2
+ * If option is:
+ * - STREAM_OPTION_BLOCKING: This option is not set.
+ * - STREAM_OPTION_READ_TIMEOUT: The timeout in microseconds.
+ * - STREAM_OPTION_WRITE_BUFFER: The requested buffer size.
+ *
+ * @return bool
+ * TRUE on success, FALSE otherwise. If $option is not implemented, FALSE
+ * should be returned.
+ */
+ public function stream_set_option($option, $arg1, $arg2) {
+ trigger_error('stream_set_option() not supported for local file based stream wrappers', E_USER_WARNING);
+ return FALSE;
+ }
+
/**
* Support for unlink().
*
diff --git a/includes/theme.inc b/includes/theme.inc
index 8d5348df..9b606e9f 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -1248,6 +1248,7 @@ function path_to_theme() {
function drupal_find_theme_functions($cache, $prefixes) {
$implementations = array();
$functions = get_defined_functions();
+ $theme_functions = preg_grep('/^(' . implode(')|(', $prefixes) . ')_/', $functions['user']);
foreach ($cache as $hook => $info) {
foreach ($prefixes as $prefix) {
@@ -1264,7 +1265,7 @@ function drupal_find_theme_functions($cache, $prefixes) {
// intermediary suggestion.
$pattern = isset($info['pattern']) ? $info['pattern'] : ($hook . '__');
if (!isset($info['base hook']) && !empty($pattern)) {
- $matches = preg_grep('/^' . $prefix . '_' . $pattern . '/', $functions['user']);
+ $matches = preg_grep('/^' . $prefix . '_' . $pattern . '/', $theme_functions);
if ($matches) {
foreach ($matches as $match) {
$new_hook = substr($match, strlen($prefix) + 1);
@@ -1710,11 +1711,29 @@ function theme_status_messages($variables) {
* copy if none of the enabled modules or the active theme implement any
* preprocess or process functions or override this theme implementation.
*
- * @param $variables
- * An associative array containing the keys 'text', 'path', and 'options'.
- * See the l() function for information about these variables.
+ * @param array $variables
+ * An associative array containing the keys:
+ * - text: The text of the link.
+ * - path: The internal path or external URL being linked to. It is used as
+ * the $path parameter of the url() function.
+ * - options: (optional) An array that defaults to empty, but can contain:
+ * - attributes: Can contain optional attributes:
+ * - class: must be declared in an array. Example: 'class' =>
+ * array('class_name1','class_name2').
+ * - title: must be a string. Example: 'title' => 'Example title'
+ * - Others are more flexible as long as they work with
+ * drupal_attributes($variables['options']['attributes]).
+ * - html: Boolean flag that tells whether text contains HTML or plain
+ * text. If set to TRUE, the text value will not be sanitized so the
+ calling function must ensure that it already contains safe HTML.
+ * The elements $variables['options']['attributes'] and
+ * $variables['options']['html'] are used in this function similarly to the
+ * way that $options['attributes'] and $options['html'] are used in l().
+ * The link itself is built by the url() function, which takes
+ * $variables['path'] and $variables['options'] as arguments.
*
* @see l()
+ * @see url()
*/
function theme_link($variables) {
return '' . ($variables['options']['html'] ? $variables['text'] : check_plain($variables['text'])) . '';
@@ -1791,7 +1810,8 @@ function theme_links($variables) {
foreach ($links as $key => $link) {
$class = array($key);
- // Add first, last and active classes to the list of links to help out themers.
+ // Add first, last and active classes to the list of links to help out
+ // themers.
if ($i == 1) {
$class[] = 'first';
}
@@ -1809,7 +1829,8 @@ function theme_links($variables) {
$output .= l($link['title'], $link['href'], $link);
}
elseif (!empty($link['title'])) {
- // Some links are actually not links, but we wrap these in for adding title and class attributes.
+ // Some links are actually not links, but we wrap these in for
+ // adding title and class attributes.
if (empty($link['html'])) {
$link['title'] = check_plain($link['title']);
}
@@ -2618,7 +2639,7 @@ function template_preprocess_page(&$variables) {
// Move some variables to the top level for themer convenience and template cleanliness.
$variables['show_messages'] = $variables['page']['#show_messages'];
- foreach (system_region_list($GLOBALS['theme']) as $region_key => $region_name) {
+ foreach (system_region_list($GLOBALS['theme'], REGIONS_ALL, FALSE) as $region_key) {
if (!isset($variables['page'][$region_key])) {
$variables['page'][$region_key] = array();
}
diff --git a/includes/update.inc b/includes/update.inc
index a17161c9..2167db79 100644
--- a/includes/update.inc
+++ b/includes/update.inc
@@ -795,6 +795,14 @@ function update_fix_d7_requirements() {
function update_fix_d7_install_profile() {
$profile = drupal_get_profile();
+ // 'Default' profile has been renamed to 'Standard' in D7.
+ // We change the profile here to prevent a broken record in the system table.
+ // See system_update_7049().
+ if ($profile == 'default') {
+ $profile = 'standard';
+ variable_set('install_profile', $profile);
+ }
+
$results = db_select('system', 's')
->fields('s', array('name', 'schema_version'))
->condition('name', $profile)
@@ -908,6 +916,8 @@ function update_get_d6_session_name() {
}
/**
+ * Implements callback_batch_operation().
+ *
* Performs one update and stores the results for display on the results page.
*
* If an update function completes successfully, it should return a message
@@ -1078,6 +1088,8 @@ function update_batch($start, $redirect = NULL, $url = NULL, $batch = array(), $
}
/**
+ * Implements callback_batch_finished().
+ *
* Finishes the update process and stores the results for eventual display.
*
* After the updates run, all caches are flushed. The update results are
diff --git a/includes/xmlrpcs.inc b/includes/xmlrpcs.inc
index 8655c05b..c334de15 100644
--- a/includes/xmlrpcs.inc
+++ b/includes/xmlrpcs.inc
@@ -264,6 +264,10 @@ function xmlrpc_server_call($xmlrpc_server, $methodname, $args) {
*/
function xmlrpc_server_multicall($methodcalls) {
// See http://www.xmlrpc.com/discuss/msgReader$1208
+ // To avoid multicall expansion attacks, limit the number of duplicate method
+ // calls allowed with a default of 1. Set to -1 for unlimited.
+ $duplicate_method_limit = variable_get('xmlrpc_multicall_duplicate_method_limit', 1);
+ $method_count = array();
$return = array();
$xmlrpc_server = xmlrpc_server_get();
foreach ($methodcalls as $call) {
@@ -273,10 +277,14 @@ function xmlrpc_server_multicall($methodcalls) {
$ok = FALSE;
}
$method = $call['methodName'];
+ $method_count[$method] = isset($method_count[$method]) ? $method_count[$method] + 1 : 1;
$params = $call['params'];
if ($method == 'system.multicall') {
$result = xmlrpc_error(-32600, t('Recursive calls to system.multicall are forbidden.'));
}
+ elseif ($duplicate_method_limit > 0 && $method_count[$method] > $duplicate_method_limit) {
+ $result = xmlrpc_error(-156579, t('Too many duplicate method calls in system.multicall.'));
+ }
elseif ($ok) {
$result = xmlrpc_server_call($xmlrpc_server, $method, $params);
}
diff --git a/misc/ajax.js b/misc/ajax.js
index bb4a6e14..c944ebbf 100644
--- a/misc/ajax.js
+++ b/misc/ajax.js
@@ -476,7 +476,7 @@ Drupal.ajax.prototype.getEffect = function (response) {
* Handler for the form redirection error.
*/
Drupal.ajax.prototype.error = function (xmlhttprequest, uri, customMessage) {
- alert(Drupal.ajaxError(xmlhttprequest, uri, customMessage));
+ Drupal.displayAjaxError(Drupal.ajaxError(xmlhttprequest, uri, customMessage));
// Remove the progress element.
if (this.progress.element) {
$(this.progress.element).remove();
diff --git a/misc/autocomplete.js b/misc/autocomplete.js
index d71441b6..af090713 100644
--- a/misc/autocomplete.js
+++ b/misc/autocomplete.js
@@ -310,7 +310,7 @@ Drupal.ACDB.prototype.search = function (searchString) {
}
},
error: function (xmlhttp) {
- alert(Drupal.ajaxError(xmlhttp, db.uri));
+ Drupal.displayAjaxError(Drupal.ajaxError(xmlhttp, db.uri));
}
});
}, this.delay);
diff --git a/misc/drupal.js b/misc/drupal.js
index 427c4a1e..19fbc712 100644
--- a/misc/drupal.js
+++ b/misc/drupal.js
@@ -27,6 +27,42 @@ $.fn.init = function (selector, context, rootjQuery) {
};
$.fn.init.prototype = jquery_init.prototype;
+/**
+ * Pre-filter Ajax requests to guard against XSS attacks.
+ *
+ * See https://github.com/jquery/jquery/issues/2432
+ */
+if ($.ajaxPrefilter) {
+ // For newer versions of jQuery, use an Ajax prefilter to prevent
+ // auto-executing script tags from untrusted domains. This is similar to the
+ // fix that is built in to jQuery 3.0 and higher.
+ $.ajaxPrefilter(function (s) {
+ if (s.crossDomain) {
+ s.contents.script = false;
+ }
+ });
+}
+else if ($.httpData) {
+ // For the version of jQuery that ships with Drupal core, override
+ // jQuery.httpData to prevent auto-detecting "script" data types from
+ // untrusted domains.
+ var jquery_httpData = $.httpData;
+ $.httpData = function (xhr, type, s) {
+ // @todo Consider backporting code from newer jQuery versions to check for
+ // a cross-domain request here, rather than using Drupal.urlIsLocal() to
+ // block scripts from all URLs that are not on the same site.
+ if (!type && !Drupal.urlIsLocal(s.url)) {
+ var content_type = xhr.getResponseHeader('content-type') || '';
+ if (content_type.indexOf('javascript') >= 0) {
+ // Default to a safe data type.
+ type = 'text';
+ }
+ }
+ return jquery_httpData.call(this, xhr, type, s);
+ };
+ $.httpData.prototype = jquery_httpData.prototype;
+}
+
/**
* Attach all registered behaviors to a page element.
*
@@ -137,7 +173,7 @@ Drupal.detachBehaviors = function (context, settings, trigger) {
*/
Drupal.checkPlain = function (str) {
var character, regex,
- replace = { '&': '&', '"': '"', '<': '<', '>': '>' };
+ replace = { '&': '&', "'": ''', '"': '"', '<': '<', '>': '>' };
str = String(str);
for (character in replace) {
if (replace.hasOwnProperty(character)) {
@@ -168,23 +204,76 @@ Drupal.checkPlain = function (str) {
Drupal.formatString = function(str, args) {
// Transform arguments before inserting them.
for (var key in args) {
- switch (key.charAt(0)) {
- // Escaped only.
- case '@':
- args[key] = Drupal.checkPlain(args[key]);
- break;
- // Pass-through.
- case '!':
- break;
- // Escaped and placeholder.
- case '%':
- default:
- args[key] = Drupal.theme('placeholder', args[key]);
- break;
+ if (args.hasOwnProperty(key)) {
+ switch (key.charAt(0)) {
+ // Escaped only.
+ case '@':
+ args[key] = Drupal.checkPlain(args[key]);
+ break;
+ // Pass-through.
+ case '!':
+ break;
+ // Escaped and placeholder.
+ default:
+ args[key] = Drupal.theme('placeholder', args[key]);
+ break;
+ }
}
- str = str.replace(key, args[key]);
}
- return str;
+
+ return Drupal.stringReplace(str, args, null);
+};
+
+/**
+ * Replace substring.
+ *
+ * The longest keys will be tried first. Once a substring has been replaced,
+ * its new value will not be searched again.
+ *
+ * @param {String} str
+ * A string with placeholders.
+ * @param {Object} args
+ * Key-value pairs.
+ * @param {Array|null} keys
+ * Array of keys from the "args". Internal use only.
+ *
+ * @return {String}
+ * Returns the replaced string.
+ */
+Drupal.stringReplace = function (str, args, keys) {
+ if (str.length === 0) {
+ return str;
+ }
+
+ // If the array of keys is not passed then collect the keys from the args.
+ if (!$.isArray(keys)) {
+ keys = [];
+ for (var k in args) {
+ if (args.hasOwnProperty(k)) {
+ keys.push(k);
+ }
+ }
+
+ // Order the keys by the character length. The shortest one is the first.
+ keys.sort(function (a, b) { return a.length - b.length; });
+ }
+
+ if (keys.length === 0) {
+ return str;
+ }
+
+ // Take next longest one from the end.
+ var key = keys.pop();
+ var fragments = str.split(key);
+
+ if (keys.length) {
+ for (var i = 0; i < fragments.length; i++) {
+ // Process each fragment with a copy of remaining keys.
+ fragments[i] = Drupal.stringReplace(fragments[i], args, keys.slice(0));
+ }
+ }
+
+ return fragments.join(args[key]);
};
/**
@@ -251,7 +340,7 @@ Drupal.t = function (str, args, options) {
* A translated string.
*/
Drupal.formatPlural = function (count, singular, plural, args, options) {
- var args = args || {};
+ args = args || {};
args['@count'] = count;
// Determine the index of the plural form.
var index = Drupal.locale.pluralFormula ? Drupal.locale.pluralFormula(args['@count']) : ((args['@count'] == 1) ? 0 : 1);
@@ -413,6 +502,29 @@ Drupal.getSelection = function (element) {
return { 'start': element.selectionStart, 'end': element.selectionEnd };
};
+/**
+ * Add a global variable which determines if the window is being unloaded.
+ *
+ * This is primarily used by Drupal.displayAjaxError().
+ */
+Drupal.beforeUnloadCalled = false;
+$(window).bind('beforeunload pagehide', function () {
+ Drupal.beforeUnloadCalled = true;
+});
+
+/**
+ * Displays a JavaScript error from an Ajax response when appropriate to do so.
+ */
+Drupal.displayAjaxError = function (message) {
+ // Skip displaying the message if the user deliberately aborted (for example,
+ // by reloading the page or navigating to a different page) while the Ajax
+ // request was still ongoing. See, for example, the discussion at
+ // http://stackoverflow.com/questions/699941/handle-ajax-error-when-a-user-clicks-refresh.
+ if (!Drupal.beforeUnloadCalled) {
+ alert(message);
+ }
+};
+
/**
* Build an error message from an Ajax response.
*/
diff --git a/misc/states.js b/misc/states.js
index 6d98da81..5aac65d2 100644
--- a/misc/states.js
+++ b/misc/states.js
@@ -493,7 +493,11 @@ $(document).bind('state:disabled', function(e) {
$(document).bind('state:required', function(e) {
if (e.trigger) {
if (e.value) {
- $(e.target).closest('.form-item, .form-wrapper').find('label').append('*');
+ var $label = $(e.target).closest('.form-item, .form-wrapper').find('label');
+ // Avoids duplicate required markers on initialization.
+ if (!$label.find('.form-required').length) {
+ $label.append('*');
+ }
}
else {
$(e.target).closest('.form-item, .form-wrapper').find('label .form-required').remove();
diff --git a/misc/tabledrag.js b/misc/tabledrag.js
index 3cc27019..7ea88b60 100644
--- a/misc/tabledrag.js
+++ b/misc/tabledrag.js
@@ -106,8 +106,10 @@ Drupal.tableDrag = function (table, tableSettings) {
// Add mouse bindings to the document. The self variable is passed along
// as event handlers do not have direct access to the tableDrag object.
- $(document).bind('mousemove', function (event) { return self.dragRow(event, self); });
- $(document).bind('mouseup', function (event) { return self.dropRow(event, self); });
+ $(document).bind('mousemove pointermove', function (event) { return self.dragRow(event, self); });
+ $(document).bind('mouseup pointerup', function (event) { return self.dropRow(event, self); });
+ $(document).bind('touchmove', function (event) { return self.dragRow(event.originalEvent.touches[0], self); });
+ $(document).bind('touchend', function (event) { return self.dropRow(event.originalEvent.touches[0], self); });
};
/**
@@ -274,7 +276,10 @@ Drupal.tableDrag.prototype.makeDraggable = function (item) {
});
// Add the mousedown action for the handle.
- handle.mousedown(function (event) {
+ handle.bind('mousedown touchstart pointerdown', function (event) {
+ if (event.originalEvent.type == "touchstart") {
+ event = event.originalEvent.touches[0];
+ }
// Create a new dragObject recording the event information.
self.dragObject = {};
self.dragObject.initMouseOffset = self.getMouseOffset(item, event);
@@ -575,12 +580,20 @@ Drupal.tableDrag.prototype.dropRow = function (event, self) {
* Get the mouse coordinates from the event (allowing for browser differences).
*/
Drupal.tableDrag.prototype.mouseCoords = function (event) {
+ // Complete support for pointer events was only introduced to jQuery in
+ // version 1.11.1; between versions 1.7 and 1.11.0 pointer events have the
+ // clientX and clientY properties undefined. In those cases, the properties
+ // must be retrieved from the event.originalEvent object instead.
+ var clientX = event.clientX || event.originalEvent.clientX;
+ var clientY = event.clientY || event.originalEvent.clientY;
+
if (event.pageX || event.pageY) {
return { x: event.pageX, y: event.pageY };
}
+
return {
- x: event.clientX + document.body.scrollLeft - document.body.clientLeft,
- y: event.clientY + document.body.scrollTop - document.body.clientTop
+ x: clientX + document.body.scrollLeft - document.body.clientLeft,
+ y: clientY + document.body.scrollTop - document.body.clientTop
};
};
diff --git a/modules/aggregator/aggregator.info b/modules/aggregator/aggregator.info
index e7e8fa55..2d84f9d1 100644
--- a/modules/aggregator/aggregator.info
+++ b/modules/aggregator/aggregator.info
@@ -7,8 +7,7 @@ files[] = aggregator.test
configure = admin/config/services/aggregator/settings
stylesheets[all][] = aggregator.css
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/aggregator/aggregator.module b/modules/aggregator/aggregator.module
index 70f8c5cd..02c9ec46 100644
--- a/modules/aggregator/aggregator.module
+++ b/modules/aggregator/aggregator.module
@@ -455,6 +455,14 @@ function aggregator_save_category($edit) {
db_delete('aggregator_category')
->condition('cid', $edit['cid'])
->execute();
+ // Remove category from feeds.
+ db_delete('aggregator_category_feed')
+ ->condition('cid', $edit['cid'])
+ ->execute();
+ // Remove category from feed items.
+ db_delete('aggregator_category_item')
+ ->condition('cid', $edit['cid'])
+ ->execute();
// Make sure there is no active block for this category.
if (module_exists('block')) {
db_delete('block')
diff --git a/modules/aggregator/aggregator.processor.inc b/modules/aggregator/aggregator.processor.inc
index 44ed5499..534cca57 100644
--- a/modules/aggregator/aggregator.processor.inc
+++ b/modules/aggregator/aggregator.processor.inc
@@ -72,7 +72,7 @@ function aggregator_aggregator_remove($feed) {
*/
function aggregator_form_aggregator_admin_form_alter(&$form, $form_state) {
if (in_array('aggregator', variable_get('aggregator_processors', array('aggregator')))) {
- $info = module_invoke('aggregator', 'aggregator_process', 'info');
+ $info = module_invoke('aggregator', 'aggregator_process_info');
$items = drupal_map_assoc(array(3, 5, 10, 15, 20, 25), '_aggregator_items');
$period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 4838400, 9676800), 'format_interval');
$period[AGGREGATOR_CLEAR_NEVER] = t('Never');
diff --git a/modules/aggregator/aggregator.test b/modules/aggregator/aggregator.test
index d84ee785..afa791d6 100644
--- a/modules/aggregator/aggregator.test
+++ b/modules/aggregator/aggregator.test
@@ -418,7 +418,7 @@ class CategorizeFeedTestCase extends AggregatorTestCase {
}
/**
- * Creates a feed and makes sure you can add more than one category to it.
+ * Creates a feed and makes sure you can add/delete categories to it.
*/
function testCategorizeFeed() {
@@ -448,7 +448,31 @@ class CategorizeFeedTestCase extends AggregatorTestCase {
// Assert the feed has two categories.
$this->getFeedCategories($db_feed);
$this->assertEqual(count($db_feed->categories), 2, 'Feed has 2 categories');
+
+ // Use aggregator_save_feed() to delete a category.
+ $category = reset($categories);
+ aggregator_save_category(array('cid' => $category->cid));
+
+ // Assert that category is deleted.
+ $db_category = db_query("SELECT COUNT(*) FROM {aggregator_category} WHERE cid = :cid", array(':cid' => $category->cid))->fetchField();
+ $this->assertFalse($db_category, format_string('The category %title has been deleted.', array('%title' => $category->title)));
+
+ // Assert that category has been removed from feed.
+ $categorized_feeds = db_query("SELECT COUNT(*) FROM {aggregator_category_feed} WHERE cid = :cid", array(':cid' => $category->cid))->fetchField();
+ $this->assertFalse($categorized_feeds, format_string('The category %title has been removed from feed %feed_title.', array('%title' => $category->title, '%feed_title' => $feed['title'])));
+
+ // Assert that no broken links (associated with the deleted category)
+ // appear on one of the other category pages.
+ $this->createSampleNodes();
+ $this->drupalGet('admin/config/services/aggregator');
+ $this->clickLink('update items');
+ $categories = $this->getCategories();
+ $category = reset($categories);
+ $this->drupalGet('aggregator/categories/' . $category->cid);
+ global $base_path;
+ $this->assertNoRaw(',');
}
+
}
/**
@@ -685,9 +709,21 @@ class CategorizeFeedItemTestCase extends AggregatorTestCase {
}
}
+ // Delete category from feed items when category is deleted.
+ $cid = reset($feed->categories);
+ $categories = $this->getCategories();
+ $category_title = $categories[$cid]->title;
+
+ // Delete category.
+ aggregator_save_category(array('cid' => $cid));
+
+ // Assert category has been removed from feed items.
+ $categorized_count = db_query("SELECT COUNT(*) FROM {aggregator_category_item} WHERE cid = :cid", array(':cid' => $cid))->fetchField();
+ $this->assertFalse($categorized_count, format_string('The category %title has been removed from feed items.', array('%title' => $category_title)));
// Delete feed.
$this->deleteFeed($feed);
}
+
}
/**
diff --git a/modules/aggregator/tests/aggregator_test.info b/modules/aggregator/tests/aggregator_test.info
index e862225f..91811fcd 100644
--- a/modules/aggregator/tests/aggregator_test.info
+++ b/modules/aggregator/tests/aggregator_test.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/block/block.api.php b/modules/block/block.api.php
index d7453b24..e38f7d6e 100644
--- a/modules/block/block.api.php
+++ b/modules/block/block.api.php
@@ -363,6 +363,31 @@ function hook_block_list_alter(&$blocks) {
}
}
+/**
+ * Act on block cache ID (cid) parts before the cid is generated.
+ *
+ * This hook allows you to add, remove or modify the custom keys used to
+ * generate a block cache ID (by default, these keys are set to the block
+ * module and delta). These keys will be combined with the standard ones
+ * provided by drupal_render_cid_parts() to generate the final block cache ID.
+ *
+ * To change the cache granularity used by drupal_render_cid_parts(), this hook
+ * cannot be used; instead, set the 'cache' key in the block's definition in
+ * hook_block_info().
+ *
+ * @params $cid_parts
+ * An array of elements used to build the cid.
+ * @param $block
+ * The block object being acted on.
+ *
+ * @see _block_get_cache_id()
+ */
+function hook_block_cid_parts_alter(&$cid_parts, $block) {
+ global $user;
+ // This example shows how to cache a block based on the user's timezone.
+ $cid_parts[] = $user->timezone;
+}
+
/**
* @} End of "addtogroup hooks".
*/
diff --git a/modules/block/block.info b/modules/block/block.info
index e5f66a7d..f3f2c7cf 100644
--- a/modules/block/block.info
+++ b/modules/block/block.info
@@ -6,8 +6,7 @@ core = 7.x
files[] = block.test
configure = admin/structure/block
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/block/block.js b/modules/block/block.js
index acd3f5ae..721dedf1 100644
--- a/modules/block/block.js
+++ b/modules/block/block.js
@@ -24,7 +24,7 @@ Drupal.behaviors.blockSettingsSummary = {
$('fieldset#edit-node-type', context).drupalSetSummary(function (context) {
var vals = [];
$('input[type="checkbox"]:checked', context).each(function () {
- vals.push($.trim($(this).next('label').text()));
+ vals.push($.trim($(this).next('label').html()));
});
if (!vals.length) {
vals.push(Drupal.t('Not restricted'));
@@ -35,7 +35,7 @@ Drupal.behaviors.blockSettingsSummary = {
$('fieldset#edit-role', context).drupalSetSummary(function (context) {
var vals = [];
$('input[type="checkbox"]:checked', context).each(function () {
- vals.push($.trim($(this).next('label').text()));
+ vals.push($.trim($(this).next('label').html()));
});
if (!vals.length) {
vals.push(Drupal.t('Not restricted'));
@@ -49,7 +49,7 @@ Drupal.behaviors.blockSettingsSummary = {
return Drupal.t('Not customizable');
}
else {
- return $radio.next('label').text();
+ return $radio.next('label').html();
}
});
}
diff --git a/modules/block/block.module b/modules/block/block.module
index 48c80d76..d68ea9e7 100644
--- a/modules/block/block.module
+++ b/modules/block/block.module
@@ -16,7 +16,7 @@ define('BLOCK_REGION_NONE', -1);
define('BLOCK_CUSTOM_FIXED', 0);
/**
- * Shows this block by default, but lets individual users hide it.
+ * Shows this block by default, but lets individual users hide it.
*/
define('BLOCK_CUSTOM_ENABLED', 1);
@@ -59,6 +59,7 @@ function block_help($path, $arg) {
$output .= '
' . t('Users with the Administer blocks permission can add custom blocks, which are then listed on the Blocks administration page. Once created, custom blocks behave just like default and module-generated blocks.', array('@blocks' => url('admin/structure/block'), '@block-add' => url('admin/structure/block/add'))) . '
' . t('Use this page to create a new custom block.') . '
';
}
@@ -189,6 +190,7 @@ function _block_themes_access($theme) {
* @param $theme
* The theme whose blocks are being configured. If not set, the default theme
* is assumed.
+ *
* @return
* The theme that should be used for the block configuration page, or NULL
* to indicate that the default theme should be used.
@@ -283,8 +285,7 @@ function block_page_build(&$page) {
// Append region description if we are rendering the regions demo page.
$item = menu_get_item();
if ($item['path'] == 'admin/structure/block/demo/' . $theme) {
- $visible_regions = array_keys(system_region_list($theme, REGIONS_VISIBLE));
- foreach ($visible_regions as $region) {
+ foreach (system_region_list($theme, REGIONS_VISIBLE, FALSE) as $region) {
$description = '
' . $all_regions[$region] . '
';
$page[$region]['block_description'] = array(
'#markup' => $description,
@@ -343,14 +344,17 @@ function _block_get_renderable_array($list = array()) {
// to perform contextual actions on the help block, and the links needlessly
// draw attention on it.
if ($key != 'system_main' && $key != 'system_help') {
- $build[$key]['#contextual_links']['block'] = array('admin/structure/block/manage', array($block->module, $block->delta));
+ $build[$key]['#contextual_links']['block'] = array(
+ 'admin/structure/block/manage',
+ array($block->module, $block->delta),
+ );
}
$build[$key] += array(
'#block' => $block,
'#weight' => ++$weight,
);
- $build[$key]['#theme_wrappers'][] ='block';
+ $build[$key]['#theme_wrappers'][] = 'block';
}
$build['#sorted'] = TRUE;
return $build;
@@ -386,18 +390,20 @@ function _block_rehash($theme = NULL) {
// Gather the blocks defined by modules.
foreach (module_implements('block_info') as $module) {
$module_blocks = module_invoke($module, 'block_info');
+ $delta_list = array();
foreach ($module_blocks as $delta => $block) {
// Compile a condition to retrieve this block from the database.
- $condition = db_and()
- ->condition('module', $module)
- ->condition('delta', $delta);
- $or->condition($condition);
// Add identifiers.
+ $delta_list[] = $delta;
$block['module'] = $module;
- $block['delta'] = $delta;
- $block['theme'] = $theme;
+ $block['delta'] = $delta;
+ $block['theme'] = $theme;
$current_blocks[$module][$delta] = $block;
}
+ if (!empty($delta_list)) {
+ $condition = db_and()->condition('module', $module)->condition('delta', $delta_list);
+ $or->condition($condition);
+ }
}
// Save the blocks defined in code for alter context.
$code_blocks = $current_blocks;
@@ -426,23 +432,20 @@ function _block_rehash($theme = NULL) {
drupal_alter('block_info', $current_blocks, $theme, $code_blocks);
foreach ($current_blocks as $module => $module_blocks) {
foreach ($module_blocks as $delta => $block) {
- if (!isset($block['pages'])) {
- // {block}.pages is type 'text', so it cannot have a
- // default value, and not null, so we need to provide
- // value if the module did not.
- $block['pages'] = '';
- }
- // Make sure weight is set.
- if (!isset($block['weight'])) {
- $block['weight'] = 0;
- }
+ // Make sure certain attributes are set.
+ $block += array(
+ 'pages' => '',
+ 'weight' => 0,
+ 'status' => 0,
+ );
+ // Check for active blocks in regions that are not available.
if (!empty($block['region']) && $block['region'] != BLOCK_REGION_NONE && !isset($regions[$block['region']]) && $block['status'] == 1) {
drupal_set_message(t('The block %info was assigned to the invalid region %region and has been disabled.', array('%info' => $block['info'], '%region' => $block['region'])), 'warning');
// Disabled modules are moved into the BLOCK_REGION_NONE later so no
// need to move the block to another region.
$block['status'] = 0;
}
- // Set region to none if not enabled and make sure status is set.
+ // Set region to none if not enabled.
if (empty($block['status'])) {
$block['status'] = 0;
$block['region'] = BLOCK_REGION_NONE;
@@ -644,7 +647,8 @@ function block_theme_initialize($theme) {
$regions = system_region_list($theme, REGIONS_VISIBLE);
$result = db_query("SELECT * FROM {block} WHERE theme = :theme", array(':theme' => $default_theme), array('fetch' => PDO::FETCH_ASSOC));
foreach ($result as $block) {
- // If the region isn't supported by the theme, assign the block to the theme's default region.
+ // If the region isn't supported by the theme, assign the block to the
+ // theme's default region.
if ($block['status'] && !isset($regions[$block['region']])) {
$block['region'] = system_default_region($theme);
}
@@ -812,17 +816,18 @@ function block_block_list_alter(&$blocks) {
// with different case. Ex: /Page, /page, /PAGE.
$pages = drupal_strtolower($block->pages);
if ($block->visibility < BLOCK_VISIBILITY_PHP) {
- // Convert the Drupal path to lowercase
+ // Convert the Drupal path to lowercase.
$path = drupal_strtolower(drupal_get_path_alias($_GET['q']));
// Compare the lowercase internal and lowercase path alias (if any).
$page_match = drupal_match_path($path, $pages);
if ($path != $_GET['q']) {
$page_match = $page_match || drupal_match_path($_GET['q'], $pages);
}
- // When $block->visibility has a value of 0 (BLOCK_VISIBILITY_NOTLISTED),
- // the block is displayed on all pages except those listed in $block->pages.
- // When set to 1 (BLOCK_VISIBILITY_LISTED), it is displayed only on those
- // pages listed in $block->pages.
+ // When $block->visibility has a value of 0
+ // (BLOCK_VISIBILITY_NOTLISTED), the block is displayed on all pages
+ // except those listed in $block->pages. When set to 1
+ // (BLOCK_VISIBILITY_LISTED), it is displayed only on those pages
+ // listed in $block->pages.
$page_match = !($block->visibility xor $page_match);
}
elseif (module_exists('php')) {
@@ -845,7 +850,8 @@ function block_block_list_alter(&$blocks) {
* Render the content and subject for a set of blocks.
*
* @param $region_blocks
- * An array of block objects such as returned for one region by _block_load_blocks().
+ * An array of block objects such as returned for one region by
+ * _block_load_blocks().
*
* @return
* An array of visible blocks as expected by drupal_render().
@@ -953,6 +959,8 @@ function _block_render_blocks($region_blocks) {
* Theme and language contexts are automatically differentiated.
*
* @param $block
+ * The block to get the cache_id from.
+ *
* @return
* The string used as cache_id for the block.
*/
@@ -967,6 +975,7 @@ function _block_get_cache_id($block) {
// Start with common sub-patterns: block identification, theme, language.
$cid_parts[] = $block->module;
$cid_parts[] = $block->delta;
+ drupal_alter('block_cid_parts', $cid_parts, $block);
$cid_parts = array_merge($cid_parts, drupal_render_cid_parts($block->cache));
return implode(':', $cid_parts);
diff --git a/modules/block/tests/block_test.info b/modules/block/tests/block_test.info
index 59a1c5b8..f62fdd7e 100644
--- a/modules/block/tests/block_test.info
+++ b/modules/block/tests/block_test.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
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 0dc755e5..4ce61da1 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,7 @@ regions[footer] = Footer
regions[highlighted] = Highlighted
regions[help] = Help
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/blog/blog.info b/modules/blog/blog.info
index c876ba60..ea026380 100644
--- a/modules/blog/blog.info
+++ b/modules/blog/blog.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
files[] = blog.test
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/blog/blog.module b/modules/blog/blog.module
index 11e3ab95..d7b882f4 100644
--- a/modules/blog/blog.module
+++ b/modules/blog/blog.module
@@ -152,7 +152,7 @@ function blog_menu_local_tasks_alter(&$data, $router_item, $root_path) {
}
}
// Provide a helper action link to the author on the 'blog/%' page.
- elseif ($root_path == 'blog/%' && $router_item['page_arguments'][0]->uid == $user->uid) {
+ elseif ($root_path == 'blog/%' && isset($router_item['page_arguments'][0]->uid) && $router_item['page_arguments'][0]->uid == $user->uid) {
$data['actions']['output']['blog'] = array(
'#theme' => 'menu_local_action',
);
diff --git a/modules/book/book.info b/modules/book/book.info
index fd33b32b..98aca934 100644
--- a/modules/book/book.info
+++ b/modules/book/book.info
@@ -7,8 +7,7 @@ files[] = book.test
configure = admin/content/book/settings
stylesheets[all][] = book.css
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/color/color.info b/modules/color/color.info
index 994091b3..9ca6bcce 100644
--- a/modules/color/color.info
+++ b/modules/color/color.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
files[] = color.test
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/color/color.test b/modules/color/color.test
index 09043250..f29c0c26 100644
--- a/modules/color/color.test
+++ b/modules/color/color.test
@@ -122,7 +122,7 @@ class ColorTestCase extends DrupalWebTestCase {
$edit['palette[bg]'] = $color;
$this->drupalPost($settings_path, $edit, t('Save configuration'));
- if($is_valid) {
+ if ($is_valid) {
$this->assertText('The configuration options have been saved.');
}
else {
diff --git a/modules/comment/comment.info b/modules/comment/comment.info
index 77cf16aa..5ea180dc 100644
--- a/modules/comment/comment.info
+++ b/modules/comment/comment.info
@@ -9,8 +9,7 @@ files[] = comment.test
configure = admin/content/comment
stylesheets[all][] = comment.css
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/comment/comment.test b/modules/comment/comment.test
index dc7aad3e..e087a717 100644
--- a/modules/comment/comment.test
+++ b/modules/comment/comment.test
@@ -11,9 +11,15 @@ class CommentHelperCase extends DrupalWebTestCase {
protected $node;
function setUp() {
- parent::setUp('comment', 'search');
+ $modules = func_get_args();
+ if (isset($modules[0]) && is_array($modules[0])) {
+ $modules = $modules[0];
+ }
+ $modules[] = 'comment';
+ parent::setUp($modules);
+
// Create users and test node.
- $this->admin_user = $this->drupalCreateUser(array('administer content types', 'administer comments', 'administer blocks', 'administer actions'));
+ $this->admin_user = $this->drupalCreateUser(array('administer content types', 'administer comments', 'administer blocks', 'administer actions', 'administer fields'));
$this->web_user = $this->drupalCreateUser(array('access comments', 'post comments', 'create article content', 'edit own comments'));
$this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'uid' => $this->web_user->uid));
}
@@ -1490,7 +1496,7 @@ class CommentNodeAccessTest extends CommentHelperCase {
}
function setUp() {
- DrupalWebTestCase::setUp('comment', 'search', 'node_access_test');
+ parent::setUp('search', 'node_access_test');
node_access_rebuild();
// Create users and test node.
diff --git a/modules/contact/contact.info b/modules/contact/contact.info
index 08e50f99..63cf78c5 100644
--- a/modules/contact/contact.info
+++ b/modules/contact/contact.info
@@ -6,8 +6,7 @@ core = 7.x
files[] = contact.test
configure = admin/structure/contact
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/contact/contact.module b/modules/contact/contact.module
index 9a48f231..9c6671a9 100644
--- a/modules/contact/contact.module
+++ b/modules/contact/contact.module
@@ -234,7 +234,14 @@ function contact_form_user_profile_form_alter(&$form, &$form_state) {
* Implements hook_user_presave().
*/
function contact_user_presave(&$edit, $account, $category) {
- $edit['data']['contact'] = isset($edit['contact']) ? $edit['contact'] : variable_get('contact_default_status', 1);
+ if (isset($edit['contact'])) {
+ // Set new value.
+ $edit['data']['contact'] = $edit['contact'];
+ }
+ elseif (!isset($account->data['contact'])) {
+ // Use default if none has been set.
+ $edit['data']['contact'] = variable_get('contact_default_status', 1);
+ }
}
/**
diff --git a/modules/contact/contact.test b/modules/contact/contact.test
index 6693b574..6a1674a0 100644
--- a/modules/contact/contact.test
+++ b/modules/contact/contact.test
@@ -346,6 +346,28 @@ class ContactPersonalTestCase extends DrupalWebTestCase {
$this->drupalGet('user/' . $this->contact_user->uid . '/contact');
$this->assertResponse(200);
+ // Test that users can disable their contact form.
+ $this->drupalLogin($this->contact_user);
+ $edit = array('contact' => FALSE);
+ $this->drupalPost('user/' . $this->contact_user->uid . '/edit', $edit, 'Save');
+ $this->drupalLogout();
+ $this->drupalGet('user/' . $this->contact_user->uid . '/contact');
+ $this->assertResponse(403);
+
+ // Test that user's contact status stays disabled when saving.
+ $contact_user_temp = user_load($this->contact_user->uid, TRUE);
+ user_save($contact_user_temp);
+ $this->drupalGet('user/' . $this->contact_user->uid . '/contact');
+ $this->assertResponse(403);
+
+ // Test that users can enable their contact form.
+ $this->drupalLogin($this->contact_user);
+ $edit = array('contact' => TRUE);
+ $this->drupalPost('user/' . $this->contact_user->uid . '/edit', $edit, 'Save');
+ $this->drupalLogout();
+ $this->drupalGet('user/' . $this->contact_user->uid . '/contact');
+ $this->assertResponse(200);
+
// Revoke the personal contact permission for the anonymous user.
user_role_revoke_permissions(DRUPAL_ANONYMOUS_RID, array('access user contact forms'));
$this->drupalGet('user/' . $this->contact_user->uid . '/contact');
diff --git a/modules/contextual/contextual.info b/modules/contextual/contextual.info
index c7df84a0..c2f68e3b 100644
--- a/modules/contextual/contextual.info
+++ b/modules/contextual/contextual.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
files[] = contextual.test
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/dashboard/dashboard.info b/modules/dashboard/dashboard.info
index 201d71eb..d4778c67 100644
--- a/modules/dashboard/dashboard.info
+++ b/modules/dashboard/dashboard.info
@@ -7,8 +7,7 @@ files[] = dashboard.test
dependencies[] = block
configure = admin/dashboard/customize
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/dblog/dblog.admin.inc b/modules/dblog/dblog.admin.inc
index 7c1c0e20..f8a00c26 100644
--- a/modules/dblog/dblog.admin.inc
+++ b/modules/dblog/dblog.admin.inc
@@ -294,11 +294,18 @@ function theme_dblog_message($variables) {
else {
$output = t($event->message, unserialize($event->variables));
}
+ // If the output is expected to be a link, strip all the tags and
+ // special characters by using filter_xss() without any allowed tags.
+ // If not, use filter_xss_admin() to allow some tags.
if ($variables['link'] && isset($event->wid)) {
- // Truncate message to 56 chars.
+ // Truncate message to 56 chars after stripping all the tags.
$output = truncate_utf8(filter_xss($output, array()), 56, TRUE, TRUE);
$output = l($output, 'admin/reports/event/' . $event->wid, array('html' => TRUE));
}
+ else {
+ // Prevent XSS in log detail pages.
+ $output = filter_xss_admin($output);
+ }
}
return $output;
}
@@ -413,6 +420,6 @@ function dblog_clear_log_form($form) {
*/
function dblog_clear_log_submit() {
$_SESSION['dblog_overview_filter'] = array();
- db_delete('watchdog')->execute();
+ db_truncate('watchdog')->execute();
drupal_set_message(t('Database log cleared.'));
}
diff --git a/modules/dblog/dblog.info b/modules/dblog/dblog.info
index 9b5f5d74..9c78e1b4 100644
--- a/modules/dblog/dblog.info
+++ b/modules/dblog/dblog.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
files[] = dblog.test
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/dblog/dblog.install b/modules/dblog/dblog.install
index abfd9a2c..c2e41192 100644
--- a/modules/dblog/dblog.install
+++ b/modules/dblog/dblog.install
@@ -154,6 +154,15 @@ function dblog_update_7002() {
db_add_index('watchdog', 'severity', array('severity'));
}
+/**
+ * Account for possible legacy systems where dblog was not installed.
+ */
+function dblog_update_7003() {
+ if (!db_table_exists('watchdog')) {
+ db_create_table('watchdog', drupal_get_schema_unprocessed('dblog', 'watchdog'));
+ }
+}
+
/**
* @} End of "addtogroup updates-7.x-extra".
*/
diff --git a/modules/dblog/dblog.module b/modules/dblog/dblog.module
index 9183eed6..df305a2c 100644
--- a/modules/dblog/dblog.module
+++ b/modules/dblog/dblog.module
@@ -144,20 +144,30 @@ function _dblog_get_message_types() {
* Note: Some values may be truncated to meet database column size restrictions.
*/
function dblog_watchdog(array $log_entry) {
- Database::getConnection('default', 'default')->insert('watchdog')
- ->fields(array(
- 'uid' => $log_entry['uid'],
- 'type' => substr($log_entry['type'], 0, 64),
- 'message' => $log_entry['message'],
- 'variables' => serialize($log_entry['variables']),
- 'severity' => $log_entry['severity'],
- 'link' => substr($log_entry['link'], 0, 255),
- 'location' => $log_entry['request_uri'],
- 'referer' => $log_entry['referer'],
- 'hostname' => substr($log_entry['ip'], 0, 128),
- 'timestamp' => $log_entry['timestamp'],
- ))
- ->execute();
+ if (!function_exists('drupal_substr')) {
+ require_once DRUPAL_ROOT . '/includes/unicode.inc';
+ }
+ try {
+ Database::getConnection('default', 'default')->insert('watchdog')
+ ->fields(array(
+ 'uid' => $log_entry['uid'],
+ 'type' => drupal_substr($log_entry['type'], 0, 64),
+ 'message' => $log_entry['message'],
+ 'variables' => serialize($log_entry['variables']),
+ 'severity' => $log_entry['severity'],
+ 'link' => drupal_substr($log_entry['link'], 0, 255),
+ 'location' => $log_entry['request_uri'],
+ 'referer' => $log_entry['referer'],
+ 'hostname' => drupal_substr($log_entry['ip'], 0, 128),
+ 'timestamp' => $log_entry['timestamp'],
+ ))
+ ->execute();
+ }
+ catch (Exception $e) {
+ // Exception is ignored so that watchdog does not break pages during the
+ // installation process or is not able to create the watchdog table during
+ // installation.
+ }
}
/**
diff --git a/modules/dblog/dblog.test b/modules/dblog/dblog.test
index bf409c94..b0a58ba4 100644
--- a/modules/dblog/dblog.test
+++ b/modules/dblog/dblog.test
@@ -119,13 +119,18 @@ class DBLogTestCase extends DrupalWebTestCase {
private function generateLogEntries($count, $type = 'custom', $severity = WATCHDOG_NOTICE) {
global $base_root;
+ // This long URL makes it just a little bit harder to pass the link part of
+ // the test with a mix of English words and a repeating series of random
+ // percent-encoded Chinese characters.
+ $link = urldecode('/content/xo%E9%85%B1%E5%87%89%E6%8B%8C%E7%B4%A0%E9%B8%A1%E7%85%A7%E7%83%A7%E9%B8%A1%E9%BB%84%E7%8E%AB%E7%91%B0-%E7%A7%91%E5%B7%9E%E7%9A%84%E5%B0%8F%E4%B9%9D%E5%AF%A8%E6%B2%9F%E7%BB%9D%E7%BE%8E%E9%AB%98%E5%B1%B1%E6%B9%96%E6%B3%8A%E9%85%B1%E5%87%89%E6%8B%8C%E7%B4%A0%E9%B8%A1%E7%85%A7%E7%83%A7%E9%B8%A1%E9%BB%84%E7%8E%AB%E7%91%B0-%E7%A7%91%E5%B7%9E%E7%9A%84%E5%B0%8F%E4%B9%9D%E5%AF%A8%E6%B2%9F%E7%BB%9D%E7%BE%8E%E9%AB%98%E5%B1%B1%E6%B9%96%E6%B3%8A%E9%85%B1%E5%87%89%E6%8B%8C%E7%B4%A0%E9%B8%A1%E7%85%A7%E7%83%A7%E9%B8%A1%E9%BB%84%E7%8E%AB%E7%91%B0-%E7%A7%91%E5%B7%9E%E7%9A%84%E5%B0%8F%E4%B9%9D%E5%AF%A8%E6%B2%9F%E7%BB%9D%E7%BE%8E%E9%AB%98%E5%B1%B1%E6%B9%96%E6%B3%8A%E9%85%B1%E5%87%89%E6%8B%8C%E7%B4%A0%E9%B8%A1%E7%85%A7%E7%83%A7%E9%B8%A1%E9%BB%84%E7%8E%AB%E7%91%B0-%E7%A7%91%E5%B7%9E%E7%9A%84%E5%B0%8F%E4%B9%9D%E5%AF%A8%E6%B2%9F%E7%BB%9D%E7%BE%8E%E9%AB%98%E5%B1%B1%E6%B9%96%E6%B3%8A%E9%85%B1%E5%87%89%E6%8B%8C%E7%B4%A0%E9%B8%A1%E7%85%A7%E7%83%A7%E9%B8%A1%E9%BB%84%E7%8E%AB%E7%91%B0-%E7%A7%91%E5%B7%9E%E7%9A%84%E5%B0%8F%E4%B9%9D%E5%AF%A8%E6%B2%9F%E7%BB%9D%E7%BE%8E%E9%AB%98%E5%B1%B1%E6%B9%96%E6%B3%8A%E9%85%B1%E5%87%89%E6%8B%8C%E7%B4%A0%E9%B8%A1%E7%85%A7%E7%83%A7%E9%B8%A1%E9%BB%84%E7%8E%AB%E7%91%B0-%E7%A7%91%E5%B7%9E%E7%9A%84%E5%B0%8F%E4%B9%9D%E5%AF%A8%E6%B2%9F%E7%BB%9D%E7%BE%8E%E9%AB%98%E5%B1%B1%E6%B9%96%E6%B3%8A%E9%85%B1%E5%87%89%E6%8B%8C%E7%B4%A0%E9%B8%A1%E7%85%A7%E7%83%A7%E9%B8%A1%E9%BB%84%E7%8E%AB%E7%91%B0-%E7%A7%91%E5%B7%9E%E7%9A%84%E5%B0%8F%E4%B9%9D%E5%AF%A8%E6%B2%9F%E7%BB%9D%E7%BE%8E%E9%AB%98%E5%B1%B1%E6%B9%96%E6%B3%8A%E9%85%B1%E5%87%89%E6%8B%8C%E7%B4%A0%E9%B8%A1%E7%85%A7%E7%83%A7%E9%B8%A1%E9%BB%84%E7%8E%AB%E7%91%B0-%E7%A7%91%E5%B7%9E%E7%9A%84%E5%B0%8F%E4%B9%9D%E5%AF%A8%E6%B2%9F%E7%BB%9D%E7%BE%8E%E9%AB%98%E5%B1%B1%E6%B9%96%E6%B3%8A%E9%85%B1%E5%87%89%E6%8B%8C%E7%B4%A0%E9%B8%A1%E7%85%A7%E7%83%A7%E9%B8%A1%E9%BB%84%E7%8E%AB%E7%91%B0-%E7%A7%91%E5%B7%9E%E7%9A%84%E5%B0%8F%E4%B9%9D%E5%AF%A8%E6%B2%9F%E7%BB%9D%E7%BE%8E%E9%AB%98%E5%B1%B1%E6%B9%96%E6%B3%8A%E9%85%B1%E5%87%89%E6%8B%8C%E7%B4%A0%E9%B8%A1%E7%85%A7%E7%83%A7%E9%B8%A1%E9%BB%84%E7%8E%AB%E7%91%B0-%E7%A7%91%E5%B7%9E%E7%9A%84%E5%B0%8F%E4%B9%9D%E5%AF%A8%E6%B2%9F%E7%BB%9D%E7%BE%8E%E9%AB%98%E5%B1%B1%E6%B9%96%E6%B3%8A%E9%85%B1%E5%87%89%E6%8B%8C%E7%B4%A0%E9%B8%A1%E7%85%A7%E7%83%A7%E9%B8%A1%E9%BB%84%E7%8E%AB%E7%91%B0-%E7%A7%91%E5%B7%9E%E7%9A%84%E5%B0%8F%E4%B9%9D%E5%AF%A8%E6%B2%9F%E7%BB%9D%E7%BE%8E%E9%AB%98%E5%B1%B1%E6%B9%96%E6%B3%8A%E9%85%B1%E5%87%89%E6%8B%8C%E7%B4%A0%E9%B8%A1%E7%85%A7%E7%83%A7%E9%B8%A1%E9%BB%84%E7%8E%AB%E7%91%B0-%E7%A7%91%E5%B7%9E%E7%9A%84%E5%B0%8F%E4%B9%9D%E5%AF%A8%E6%B2%9F%E7%BB%9D%E7%BE%8E%E9%AB%98%E5%B1%B1%E6%B9%96%E6%B3%8A%E9%85%B1%E5%87%89%E6%8B%8C%E7%B4%A0%E9%B8%A1%E7%85%A7%E7%83%A7%E9%B8%A1%E9%BB%84%E7%8E%AB%E7%91%B0-%E7%A7%91%E5%B7%9E%E7%9A%84%E5%B0%8F%E4%B9%9D%E5%AF%A8%E6%B2%9F%E7%BB%9D%E7%BE%8E%E9%AB%98%E5%B1%B1%E6%B9%96%E6%B3%8A-lake-isabelle');
+
// Prepare the fields to be logged
$log = array(
'type' => $type,
'message' => 'Log entry added to test the dblog row limit.',
'variables' => array(),
'severity' => $severity,
- 'link' => NULL,
+ 'link' => $link,
'user' => $this->big_user,
'uid' => isset($this->big_user->uid) ? $this->big_user->uid : 0,
'request_uri' => $base_root . request_uri(),
@@ -515,6 +520,33 @@ class DBLogTestCase extends DrupalWebTestCase {
$this->assertText(t('Database log cleared.'), 'Confirmation message found');
}
+ /**
+ * Verifies that exceptions are caught in dblog_watchdog().
+ */
+ protected function testDBLogException() {
+ $log = array(
+ 'type' => 'custom',
+ 'message' => 'Log entry added to test watchdog handling of Exceptions.',
+ 'variables' => array(),
+ 'severity' => WATCHDOG_NOTICE,
+ 'link' => NULL,
+ 'user' => $this->big_user,
+ 'uid' => isset($this->big_user->uid) ? $this->big_user->uid : 0,
+ 'request_uri' => request_uri(),
+ 'referer' => $_SERVER['HTTP_REFERER'],
+ 'ip' => ip_address(),
+ 'timestamp' => REQUEST_TIME,
+ );
+
+ // Remove watchdog table temporarily to simulate it missing during
+ // installation.
+ db_query("DROP TABLE {watchdog}");
+
+ // Add a watchdog entry.
+ // This should not throw an Exception, but fail silently.
+ dblog_watchdog($log);
+ }
+
/**
* Gets the database log event information from the browser page.
*
@@ -633,5 +665,32 @@ class DBLogTestCase extends DrupalWebTestCase {
// Document Object Model (DOM).
$this->assertLink(html_entity_decode($message_text), 0, $message);
}
-}
+ /**
+ * Make sure HTML tags are filtered out in the log detail page.
+ */
+ public function testLogMessageSanitized() {
+ $this->drupalLogin($this->big_user);
+
+ // Make sure dangerous HTML tags are filtered out in log detail page.
+ $log = array(
+ 'uid' => 0,
+ 'type' => 'custom',
+ 'message' => " Lorem ipsum",
+ 'variables' => NULL,
+ 'severity' => WATCHDOG_NOTICE,
+ 'link' => 'foo/bar',
+ 'request_uri' => 'http://example.com?dblog=1',
+ 'referer' => 'http://example.org?dblog=2',
+ 'ip' => '0.0.1.0',
+ 'timestamp' => REQUEST_TIME,
+ );
+ dblog_watchdog($log);
+
+ $wid = db_query('SELECT MAX(wid) FROM {watchdog}')->fetchField();
+ $this->drupalGet('admin/reports/event/' . $wid);
+ $this->assertResponse(200);
+ $this->assertNoRaw("");
+ $this->assertRaw("alert('foo'); Lorem ipsum");
+ }
+}
diff --git a/modules/field/field.crud.inc b/modules/field/field.crud.inc
index ba377083..7c0e3a15 100644
--- a/modules/field/field.crud.inc
+++ b/modules/field/field.crud.inc
@@ -189,7 +189,7 @@ function field_create_field($field) {
}
// Clear caches
- field_cache_clear(TRUE);
+ field_cache_clear();
// Invoke external hooks after the cache is cleared for API consistency.
module_invoke_all('field_create_field', $field);
@@ -288,7 +288,7 @@ function field_update_field($field) {
drupal_write_record('field_config', $field, $primary_key);
// Clear caches
- field_cache_clear(TRUE);
+ field_cache_clear();
// Invoke external hooks after the cache is cleared for API consistency.
module_invoke_all('field_update_field', $field, $prior_field, $has_data);
@@ -430,7 +430,7 @@ function field_delete_field($field_name) {
->execute();
// Clear the cache.
- field_cache_clear(TRUE);
+ field_cache_clear();
module_invoke_all('field_delete_field', $field);
}
diff --git a/modules/field/field.info b/modules/field/field.info
index c154828c..4cfb0b6c 100644
--- a/modules/field/field.info
+++ b/modules/field/field.info
@@ -11,8 +11,7 @@ dependencies[] = field_sql_storage
required = TRUE
stylesheets[all][] = theme/field.css
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/field/field.info.class.inc b/modules/field/field.info.class.inc
index f4f1f630..772cd451 100644
--- a/modules/field/field.info.class.inc
+++ b/modules/field/field.info.class.inc
@@ -612,10 +612,12 @@ class FieldInfo {
// Fill in default values.
$display += array(
'label' => 'above',
- 'type' => $field_type_info['default_formatter'],
'settings' => array(),
'weight' => 0,
);
+ if (empty($display['type'])) {
+ $display['type'] = $field_type_info['default_formatter'];
+ }
if ($display['type'] != 'hidden') {
$formatter_type_info = field_info_formatter_types($display['type']);
// Fall back to default formatter if formatter type is not available.
diff --git a/modules/field/field.install b/modules/field/field.install
index f6948e3b..c5dd2dc7 100644
--- a/modules/field/field.install
+++ b/modules/field/field.install
@@ -467,6 +467,27 @@ function field_update_7003() {
// Empty update to force a rebuild of the registry.
}
+/**
+ * Grant the new "administer fields" permission to trusted users.
+ */
+function field_update_7004() {
+ // Assign the permission to anyone that already has a trusted core permission
+ // that would have previously let them administer fields on an entity type.
+ $rids = array();
+ $permissions = array(
+ 'administer site configuration',
+ 'administer content types',
+ 'administer users',
+ );
+ foreach ($permissions as $permission) {
+ $rids = array_merge($rids, array_keys(user_roles(FALSE, $permission)));
+ }
+ $rids = array_unique($rids);
+ foreach ($rids as $rid) {
+ _update_7000_user_role_grant_permissions($rid, array('administer fields'), 'field');
+ }
+}
+
/**
* @} End of "addtogroup updates-7.x-extra".
*/
diff --git a/modules/field/field.module b/modules/field/field.module
index e4039786..8d66813f 100644
--- a/modules/field/field.module
+++ b/modules/field/field.module
@@ -316,6 +316,21 @@ function field_help($path, $arg) {
}
}
+/**
+ * Implements hook_permission().
+ */
+function field_permission() {
+ return array(
+ 'administer fields' => array(
+ 'title' => t('Administer fields'),
+ 'description' => t('Additional permissions are required based on what the fields are attached to (for example, administer content types to manage fields attached to content).', array(
+ '@url' => '#module-node',
+ )),
+ 'restrict access' => TRUE,
+ ),
+ );
+}
+
/**
* Implements hook_theme().
*/
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 dc1631f9..29c7421a 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,7 @@ dependencies[] = field
files[] = field_sql_storage.test
required = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/field/modules/list/list.info b/modules/field/modules/list/list.info
index 49e7814f..55c539c0 100644
--- a/modules/field/modules/list/list.info
+++ b/modules/field/modules/list/list.info
@@ -7,8 +7,7 @@ dependencies[] = field
dependencies[] = options
files[] = tests/list.test
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/field/modules/list/tests/list.test b/modules/field/modules/list/tests/list.test
index 84de7e89..b476b5aa 100644
--- a/modules/field/modules/list/tests/list.test
+++ b/modules/field/modules/list/tests/list.test
@@ -212,7 +212,7 @@ class ListFieldUITestCase extends FieldTestCase {
parent::setUp('field_test', 'field_ui');
// Create test user.
- $admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer taxonomy'));
+ $admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer taxonomy', 'administer fields'));
$this->drupalLogin($admin_user);
// Create content type, with underscores.
diff --git a/modules/field/modules/list/tests/list_test.info b/modules/field/modules/list/tests/list_test.info
index 912d7bf6..ca74fe3c 100644
--- a/modules/field/modules/list/tests/list_test.info
+++ b/modules/field/modules/list/tests/list_test.info
@@ -5,8 +5,7 @@ package = Testing
version = VERSION
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/field/modules/number/number.info b/modules/field/modules/number/number.info
index ce55ee33..c2c57a20 100644
--- a/modules/field/modules/number/number.info
+++ b/modules/field/modules/number/number.info
@@ -6,8 +6,7 @@ core = 7.x
dependencies[] = field
files[] = number.test
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/field/modules/number/number.module b/modules/field/modules/number/number.module
index 60465442..2538bdd1 100644
--- a/modules/field/modules/number/number.module
+++ b/modules/field/modules/number/number.module
@@ -164,6 +164,15 @@ function number_field_presave($entity_type, $entity, $field, $instance, $langcod
}
}
}
+ if ($field['type'] == 'number_float') {
+ // Remove the decimal point from float values with decimal
+ // point but no decimal numbers.
+ foreach ($items as $delta => $item) {
+ if (isset($item['value'])) {
+ $items[$delta]['value'] = floatval($item['value']);
+ }
+ }
+ }
}
/**
@@ -188,7 +197,7 @@ function number_field_formatter_info() {
'label' => t('Default'),
'field types' => array('number_integer'),
'settings' => array(
- 'thousand_separator' => ' ',
+ 'thousand_separator' => '',
// The 'decimal_separator' and 'scale' settings are not configurable
// through the UI, and will therefore keep their default values. They
// are only present so that the 'number_integer' and 'number_decimal'
@@ -202,7 +211,7 @@ function number_field_formatter_info() {
'label' => t('Default'),
'field types' => array('number_decimal', 'number_float'),
'settings' => array(
- 'thousand_separator' => ' ',
+ 'thousand_separator' => '',
'decimal_separator' => '.',
'scale' => 2,
'prefix_suffix' => TRUE,
@@ -222,6 +231,8 @@ function number_field_formatter_settings_form($field, $instance, $view_mode, $fo
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
+ $element = array();
+
if ($display['type'] == 'number_decimal' || $display['type'] == 'number_integer') {
$options = array(
'' => t(''),
diff --git a/modules/field/modules/number/number.test b/modules/field/modules/number/number.test
index 88029cdd..839da36c 100644
--- a/modules/field/modules/number/number.test
+++ b/modules/field/modules/number/number.test
@@ -23,7 +23,7 @@ class NumberFieldTestCase extends DrupalWebTestCase {
function setUp() {
parent::setUp('field_test');
- $this->web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content', 'administer content types'));
+ $this->web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content', 'administer content types', 'administer fields'));
$this->drupalLogin($this->web_user);
}
@@ -152,4 +152,50 @@ class NumberFieldTestCase extends DrupalWebTestCase {
);
$this->drupalPost(NULL, $edit, t('Save'));
}
+
+ /**
+ * Test number_float field.
+ */
+ function testNumberFloatField() {
+ $this->field = array(
+ 'field_name' => drupal_strtolower($this->randomName()),
+ 'type' => 'number_float',
+ 'settings' => array(
+ 'precision' => 8, 'scale' => 4, 'decimal_separator' => '.',
+ )
+ );
+ field_create_field($this->field);
+ $this->instance = array(
+ 'field_name' => $this->field['field_name'],
+ 'entity_type' => 'test_entity',
+ 'bundle' => 'test_bundle',
+ 'widget' => array(
+ 'type' => 'number',
+ ),
+ 'display' => array(
+ 'default' => array(
+ 'type' => 'number_float',
+ ),
+ ),
+ );
+ field_create_instance($this->instance);
+
+ $langcode = LANGUAGE_NONE;
+ $value = array(
+ '9.' => '9',
+ '.' => '0',
+ '123.55' => '123.55',
+ '.55' => '0.55',
+ '-0.55' => '-0.55',
+ );
+ foreach($value as $key => $value) {
+ $edit = array(
+ "{$this->field['field_name']}[$langcode][0][value]" => $key,
+ );
+ $this->drupalPost('test-entity/add/test-bundle', $edit, t('Save'));
+ $this->assertNoText("PDOException");
+ $this->assertRaw($value, 'Correct value is displayed.');
+ }
+ }
+
}
diff --git a/modules/field/modules/options/options.info b/modules/field/modules/options/options.info
index 1a5ba124..71abf417 100644
--- a/modules/field/modules/options/options.info
+++ b/modules/field/modules/options/options.info
@@ -6,8 +6,7 @@ core = 7.x
dependencies[] = field
files[] = options.test
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/field/modules/options/options.module b/modules/field/modules/options/options.module
index 3862ba77..041b84a6 100644
--- a/modules/field/modules/options/options.module
+++ b/modules/field/modules/options/options.module
@@ -185,6 +185,7 @@ function _options_properties($type, $multiple, $required, $has_value) {
$base = array(
'filter_xss' => FALSE,
'strip_tags' => FALSE,
+ 'strip_tags_and_unescape' => FALSE,
'empty_option' => FALSE,
'optgroups' => FALSE,
);
@@ -195,7 +196,7 @@ function _options_properties($type, $multiple, $required, $has_value) {
case 'select':
$properties = array(
// Select boxes do not support any HTML tag.
- 'strip_tags' => TRUE,
+ 'strip_tags_and_unescape' => TRUE,
'optgroups' => TRUE,
);
if ($multiple) {
@@ -271,9 +272,16 @@ function _options_prepare_options(&$options, $properties) {
_options_prepare_options($options[$value], $properties);
}
else {
+ // The 'strip_tags' option is deprecated. Use 'strip_tags_and_unescape'
+ // when plain text is required (and where the output will be run through
+ // check_plain() before being inserted back into HTML) or 'filter_xss'
+ // when HTML is required.
if ($properties['strip_tags']) {
$options[$value] = strip_tags($label);
}
+ if ($properties['strip_tags_and_unescape']) {
+ $options[$value] = decode_entities(strip_tags($label));
+ }
if ($properties['filter_xss']) {
$options[$value] = field_filter_xss($label);
}
diff --git a/modules/field/modules/options/options.test b/modules/field/modules/options/options.test
index 7183311b..321c2a4b 100644
--- a/modules/field/modules/options/options.test
+++ b/modules/field/modules/options/options.test
@@ -23,8 +23,15 @@ class OptionsWidgetsTestCase extends FieldTestCase {
'type' => 'list_integer',
'cardinality' => 1,
'settings' => array(
- // Make sure that 0 works as an option.
- 'allowed_values' => array(0 => 'Zero', 1 => 'One', 2 => 'Some & unescaped markup'),
+ 'allowed_values' => array(
+ // Make sure that 0 works as an option.
+ 0 => 'Zero',
+ 1 => 'One',
+ // Make sure that option text is properly sanitized.
+ 2 => 'Some & unescaped markup',
+ // Make sure that HTML entities in option text are not double-encoded.
+ 3 => 'Some HTML encoded markup with < & >',
+ ),
),
);
$this->card_1 = field_create_field($this->card_1);
@@ -35,8 +42,13 @@ class OptionsWidgetsTestCase extends FieldTestCase {
'type' => 'list_integer',
'cardinality' => 2,
'settings' => array(
- // Make sure that 0 works as an option.
- 'allowed_values' => array(0 => 'Zero', 1 => 'One', 2 => 'Some & unescaped markup'),
+ 'allowed_values' => array(
+ // Make sure that 0 works as an option.
+ 0 => 'Zero',
+ 1 => 'One',
+ // Make sure that option text is properly sanitized.
+ 2 => 'Some & unescaped markup',
+ ),
),
);
$this->card_2 = field_create_field($this->card_2);
@@ -47,14 +59,18 @@ class OptionsWidgetsTestCase extends FieldTestCase {
'type' => 'list_boolean',
'cardinality' => 1,
'settings' => array(
- // Make sure that 0 works as a 'on' value'.
- 'allowed_values' => array(1 => 'Zero', 0 => 'Some & unescaped markup'),
+ 'allowed_values' => array(
+ // Make sure that 1 works as a 'on' value'.
+ 1 => 'Zero',
+ // Make sure that option text is properly sanitized.
+ 0 => 'Some & unescaped markup',
+ ),
),
);
$this->bool = field_create_field($this->bool);
// Create a web user.
- $this->web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content'));
+ $this->web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content', 'administer fields'));
$this->drupalLogin($this->web_user);
}
@@ -233,6 +249,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
$this->assertNoOptionSelected("edit-card-1-$langcode", 1);
$this->assertNoOptionSelected("edit-card-1-$langcode", 2);
$this->assertRaw('Some dangerous & unescaped markup', 'Option text was properly filtered.');
+ $this->assertRaw('Some HTML encoded markup with < & >', 'HTML entities in option text were properly handled and not double-encoded');
// Submit form: select invalid 'none' option.
$edit = array("card_1[$langcode]" => '_none');
@@ -459,7 +476,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
$this->assertNoFieldChecked("edit-bool-$langcode");
// Create admin user.
- $admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer taxonomy'));
+ $admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer taxonomy', 'administer fields'));
$this->drupalLogin($admin_user);
// Create a test field instance.
diff --git a/modules/field/modules/text/text.info b/modules/field/modules/text/text.info
index e8db6294..1de61433 100644
--- a/modules/field/modules/text/text.info
+++ b/modules/field/modules/text/text.info
@@ -7,8 +7,7 @@ dependencies[] = field
files[] = text.test
required = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/field/modules/text/text.module b/modules/field/modules/text/text.module
index 68fc3cb4..bf0d29d5 100644
--- a/modules/field/modules/text/text.module
+++ b/modules/field/modules/text/text.module
@@ -223,11 +223,13 @@ function text_field_formatter_settings_form($field, $instance, $view_mode, $form
if (strpos($display['type'], '_trimmed') !== FALSE) {
$element['trim_length'] = array(
- '#title' => t('Trim length'),
+ '#title' => t('Trimmed limit'),
'#type' => 'textfield',
+ '#field_suffix' => t('characters'),
'#size' => 10,
'#default_value' => $settings['trim_length'],
'#element_validate' => array('element_validate_integer_positive'),
+ '#description' => t('If the summary is not set, the trimmed %label field will be shorter than this character limit.', array('%label' => $instance['label'])),
'#required' => TRUE,
);
}
@@ -245,7 +247,7 @@ function text_field_formatter_settings_summary($field, $instance, $view_mode) {
$summary = '';
if (strpos($display['type'], '_trimmed') !== FALSE) {
- $summary = t('Trim length') . ': ' . check_plain($settings['trim_length']);
+ $summary = t('Trimmed limit: @trim_length characters', array('@trim_length' => $settings['trim_length']));
}
return $summary;
diff --git a/modules/field/modules/text/text.test b/modules/field/modules/text/text.test
index 2f147382..ad803cf4 100644
--- a/modules/field/modules/text/text.test
+++ b/modules/field/modules/text/text.test
@@ -424,6 +424,7 @@ class TextTranslationTestCase extends DrupalWebTestCase {
'administer content types',
'access administration pages',
'bypass node access',
+ 'administer fields',
filter_permission_name($full_html_format),
));
$this->translator = $this->drupalCreateUser(array('create article content', 'edit own article content', 'translate content'));
diff --git a/modules/field/tests/field_test.info b/modules/field/tests/field_test.info
index 0e66b280..fb1653fb 100644
--- a/modules/field/tests/field_test.info
+++ b/modules/field/tests/field_test.info
@@ -6,8 +6,7 @@ files[] = field_test.entity.inc
version = VERSION
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/field/theme/field.tpl.php b/modules/field/theme/field.tpl.php
index f0f9d583..460fd2e2 100644
--- a/modules/field/theme/field.tpl.php
+++ b/modules/field/theme/field.tpl.php
@@ -4,8 +4,10 @@
* @file field.tpl.php
* Default template implementation to display the value of a field.
*
- * This file is not used and is here as a starting point for customization only.
- * @see theme_field()
+ * This file is not used by Drupal core, which uses theme functions instead for
+ * performance reasons. The markup is the same, though, so if you want to use
+ * template files rather than functions to extend field theming, copy this to
+ * your custom theme. See theme_field() for a discussion of performance.
*
* Available variables:
* - $items: An array of field values. Use render() to output them.
@@ -45,7 +47,7 @@
*/
?>
' placeholder.
if ($mode) {
$content = $match[1];
- $hash = md5($content);
+ $hash = hash('sha256', $content);
$comments[$hash] = $content;
return "";
}
diff --git a/modules/filter/filter.pages.inc b/modules/filter/filter.pages.inc
index e602bcef..0f13da84 100644
--- a/modules/filter/filter.pages.inc
+++ b/modules/filter/filter.pages.inc
@@ -14,10 +14,9 @@
* @see filter_menu()
* @see theme_filter_tips()
*/
-function filter_tips_long() {
- $format_id = arg(2);
- if ($format_id) {
- $output = theme('filter_tips', array('tips' => _filter_tips($format_id, TRUE), 'long' => TRUE));
+function filter_tips_long($format = NULL) {
+ if (!empty($format)) {
+ $output = theme('filter_tips', array('tips' => _filter_tips($format->format, TRUE), 'long' => TRUE));
}
else {
$output = theme('filter_tips', array('tips' => _filter_tips(-1, TRUE), 'long' => TRUE));
diff --git a/modules/filter/filter.test b/modules/filter/filter.test
index ddea6afb..34dcf043 100644
--- a/modules/filter/filter.test
+++ b/modules/filter/filter.test
@@ -555,6 +555,27 @@ class FilterFormatAccessTestCase extends DrupalWebTestCase {
$this->assertTrue(isset($options[$this->allowed_format->format]), 'The allowed text format appears as an option when adding a new node.');
$this->assertFalse(isset($options[$this->disallowed_format->format]), 'The disallowed text format does not appear as an option when adding a new node.');
$this->assertTrue(isset($options[filter_fallback_format()]), 'The fallback format appears as an option when adding a new node.');
+
+ // Check regular user access to the filter tips pages.
+ $this->drupalGet('filter/tips/' . $this->allowed_format->format);
+ $this->assertResponse(200);
+ $this->drupalGet('filter/tips/' . $this->disallowed_format->format);
+ $this->assertResponse(403);
+ $this->drupalGet('filter/tips/' . filter_fallback_format());
+ $this->assertResponse(200);
+ $this->drupalGet('filter/tips/invalid-format');
+ $this->assertResponse(404);
+
+ // Check admin user access to the filter tips pages.
+ $this->drupalLogin($this->admin_user);
+ $this->drupalGet('filter/tips/' . $this->allowed_format->format);
+ $this->assertResponse(200);
+ $this->drupalGet('filter/tips/' . $this->disallowed_format->format);
+ $this->assertResponse(200);
+ $this->drupalGet('filter/tips/' . filter_fallback_format());
+ $this->assertResponse(200);
+ $this->drupalGet('filter/tips/invalid-format');
+ $this->assertResponse(404);
}
/**
@@ -1099,8 +1120,12 @@ class FilterUnitTestCase extends DrupalUnitTestCase {
$f = filter_xss("", array('img'));
$this->assertNoNormalized($f, 'cript', 'HTML scheme clearing evasion -- embedded nulls.');
- $f = filter_xss('', array('img'));
- $this->assertNoNormalized($f, 'javascript', 'HTML scheme clearing evasion -- spaces and metacharacters before scheme.');
+ // @todo This dataset currently fails under 5.4 because of
+ // https://www.drupal.org/node/1210798. Restore after it's fixed.
+ if (version_compare(PHP_VERSION, '5.4.0', '<')) {
+ $f = filter_xss('', array('img'));
+ $this->assertNoNormalized($f, 'javascript', 'HTML scheme clearing evasion -- spaces and metacharacters before scheme.');
+ }
$f = filter_xss('', array('img'));
$this->assertNoNormalized($f, 'vbscript', 'HTML scheme clearing evasion -- another scheme.');
@@ -1273,6 +1298,7 @@ class FilterUnitTestCase extends DrupalUnitTestCase {
// Create a e-mail that is too long.
$long_email = str_repeat('a', 254) . '@example.com';
$too_long_email = str_repeat('b', 255) . '@example.com';
+ $email_with_plus_sign = 'one+two@example.com';
// Filter selection/pattern matching.
@@ -1286,12 +1312,13 @@ http://example.com or www.example.com
),
// MAILTO URLs.
'
-person@example.com or mailto:person2@example.com or ' . $long_email . ' but not ' . $too_long_email . '
+person@example.com or mailto:person2@example.com or ' . $email_with_plus_sign . ' or ' . $long_email . ' but not ' . $too_long_email . '
' => array(
'person@example.com' => TRUE,
'mailto:person2@example.com' => TRUE,
'' . $long_email . '' => TRUE,
'' . $too_long_email . '' => FALSE,
+ '' . $email_with_plus_sign . '' => TRUE,
),
// URI parts and special characters.
'
@@ -1983,3 +2010,26 @@ class FilterSettingsTestCase extends DrupalWebTestCase {
}
}
}
+
+/**
+ * Tests DOMDocument serialization.
+ */
+class FilterDOMSerializeTestCase extends DrupalWebTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Serialization',
+ 'description' => 'Test serialization of DOMDocument objects.',
+ 'group' => 'Filter',
+ );
+ }
+
+ /**
+ * Tests empty DOMDocument object.
+ */
+ function testFilterEmptyDOMSerialization() {
+ $document = new DOMDocument();
+ $result = filter_dom_serialize($document);
+ $this->assertEqual('', $result);
+ }
+}
diff --git a/modules/forum/forum.info b/modules/forum/forum.info
index 5312ec02..6907509f 100644
--- a/modules/forum/forum.info
+++ b/modules/forum/forum.info
@@ -9,8 +9,7 @@ files[] = forum.test
configure = admin/structure/forum
stylesheets[all][] = forum.css
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/help/help.info b/modules/help/help.info
index f51b9062..33e6c811 100644
--- a/modules/help/help.info
+++ b/modules/help/help.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
files[] = help.test
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/image/image.info b/modules/image/image.info
index 3e9ef6be..d6b6942d 100644
--- a/modules/image/image.info
+++ b/modules/image/image.info
@@ -7,8 +7,7 @@ dependencies[] = file
files[] = image.test
configure = admin/config/media/image-styles
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/image/image.module b/modules/image/image.module
index fac8de95..dab88361 100644
--- a/modules/image/image.module
+++ b/modules/image/image.module
@@ -64,7 +64,7 @@ function image_help($path, $arg) {
$effect = image_effect_definition_load($arg[7]);
return isset($effect['help']) ? ('
Drupal';
$output = drupal_html_to_text($input);
// This awkward construct comes from includes/mail.inc lines 8-13.
$eol = variable_get('mail_line_endings', MAIL_LINE_ENDINGS);
@@ -455,7 +455,6 @@ class DrupalHtmlToTextTestCase extends DrupalWebTestCase {
$maximum_line_length = max($maximum_line_length, strlen($line . $eol));
}
$verbose = 'Maximum line length found was ' . $maximum_line_length . ' octets.';
- // @todo This should assert that $maximum_line_length <= 1000.
- $this->pass($verbose);
+ $this->assertTrue($maximum_line_length <= 1000, $verbose);
}
}
diff --git a/modules/simpletest/tests/menu_test.info b/modules/simpletest/tests/menu_test.info
index 162e912a..0599f903 100644
--- a/modules/simpletest/tests/menu_test.info
+++ b/modules/simpletest/tests/menu_test.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/simpletest/tests/module.test b/modules/simpletest/tests/module.test
index 371339f3..eea3b51e 100644
--- a/modules/simpletest/tests/module.test
+++ b/modules/simpletest/tests/module.test
@@ -302,3 +302,45 @@ class ModuleUninstallTestCase extends DrupalWebTestCase {
$this->assertEqual(0, $count, 'Permissions were all removed.');
}
}
+
+class ModuleImplementsAlterTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Module implements alter',
+ 'description' => 'Tests hook_module_implements_alter().',
+ 'group' => 'Module',
+ );
+ }
+
+ /**
+ * Tests hook_module_implements_alter() adding an implementation.
+ */
+ function testModuleImplementsAlter() {
+ module_enable(array('module_test'), FALSE);
+ $this->assertTrue(module_exists('module_test'), 'Test module is enabled.');
+
+ // Assert that module_test.module is now included.
+ $this->assertTrue(function_exists('module_test_permission'),
+ 'The file module_test.module was successfully included.');
+
+ $modules = module_implements('permission');
+ $this->assertTrue(in_array('module_test', $modules), 'module_test implements hook_permission.');
+
+ $modules = module_implements('module_implements_alter');
+ $this->assertTrue(in_array('module_test', $modules), 'module_test implements hook_module_implements_alter().');
+
+ // Assert that module_test.implementations.inc is not included yet.
+ $this->assertFalse(function_exists('module_test_altered_test_hook'),
+ 'The file module_test.implementations.inc is not included yet.');
+
+ // Assert that module_test_module_implements_alter(*, 'altered_test_hook')
+ // has added an implementation
+ $this->assertTrue(in_array('module_test', module_implements('altered_test_hook')),
+ 'module_test implements hook_altered_test_hook().');
+
+ // Assert that module_test.implementations.inc was included as part of the process.
+ $this->assertTrue(function_exists('module_test_altered_test_hook'),
+ 'The file module_test.implementations.inc was included.');
+ }
+
+}
diff --git a/modules/simpletest/tests/module_test.implementations.inc b/modules/simpletest/tests/module_test.implementations.inc
new file mode 100644
index 00000000..63c866ea
--- /dev/null
+++ b/modules/simpletest/tests/module_test.implementations.inc
@@ -0,0 +1,10 @@
+2.0)
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/simpletest/tests/system_incompatible_module_version_test.info b/modules/simpletest/tests/system_incompatible_module_version_test.info
index f469bd7f..837ea2e3 100644
--- a/modules/simpletest/tests/system_incompatible_module_version_test.info
+++ b/modules/simpletest/tests/system_incompatible_module_version_test.info
@@ -5,8 +5,7 @@ version = 1.0
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/simpletest/tests/system_project_namespace_test.info b/modules/simpletest/tests/system_project_namespace_test.info
new file mode 100644
index 00000000..1f30959e
--- /dev/null
+++ b/modules/simpletest/tests/system_project_namespace_test.info
@@ -0,0 +1,12 @@
+name = "System project namespace test"
+description = "Support module for testing project namespace dependencies."
+package = Testing
+version = VERSION
+core = 7.x
+hidden = TRUE
+dependencies[] = drupal:filter
+
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
+project = "drupal"
+datestamp = "1539816636"
diff --git a/modules/simpletest/tests/system_project_namespace_test.module b/modules/simpletest/tests/system_project_namespace_test.module
new file mode 100644
index 00000000..b3d9bbc7
--- /dev/null
+++ b/modules/simpletest/tests/system_project_namespace_test.module
@@ -0,0 +1 @@
+ MENU_CALLBACK,
);
+ $items['system-test/drupal-get-filename'] = array(
+ 'title' => 'Test drupal_get_filename()',
+ 'page callback' => 'system_test_drupal_get_filename',
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
+ );
+
+ $items['system-test/drupal-get-filename-with-schema-rebuild'] = array(
+ 'title' => 'Test drupal_get_filename() with a schema rebuild',
+ 'page callback' => 'system_test_drupal_get_filename_with_schema_rebuild',
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
+ );
+
return $items;
}
@@ -296,6 +310,9 @@ function system_test_system_info_alter(&$info, $file, $type) {
}
}
+ if ($file->name == 'system_project_namespace_test') {
+ $info['hidden'] = FALSE;
+ }
// Make the system_dependencies_test visible by default.
if ($file->name == 'system_dependencies_test') {
$info['hidden'] = FALSE;
@@ -479,3 +496,76 @@ function system_test_request_destination() {
// information.
exit;
}
+
+/**
+ * Page callback to run drupal_get_filename() on a particular module.
+ */
+function system_test_drupal_get_filename() {
+ // Prevent SimpleTest from failing as a result of the expected PHP warnings
+ // this function causes. Any warnings will be recorded in the database logs
+ // for examination by the tests.
+ define('SIMPLETEST_COLLECT_ERRORS', FALSE);
+
+ $module_name = variable_get('system_test_drupal_get_filename_test_module_name');
+ drupal_get_filename('module', $module_name);
+
+ return '';
+}
+
+/**
+ * Page callback to run drupal_get_filename() and do a schema rebuild.
+ */
+function system_test_drupal_get_filename_with_schema_rebuild() {
+ // Prevent SimpleTest from failing as a result of the expected PHP warnings
+ // this function causes.
+ define('SIMPLETEST_COLLECT_ERRORS', FALSE);
+
+ // Record the original database tables from drupal_get_schema().
+ variable_set('system_test_drupal_get_filename_with_schema_rebuild_original_tables', array_keys(drupal_get_schema(NULL, TRUE)));
+
+ // Trigger system_test_schema() and system_test_watchdog() to perform an
+ // attempted recursive rebuild when drupal_get_schema() is called. See
+ // BootstrapGetFilenameWebTestCase::testRecursiveRebuilds().
+ variable_set('system_test_drupal_get_filename_attempt_recursive_rebuild', TRUE);
+ drupal_get_schema(NULL, TRUE);
+
+ return '';
+}
+
+/**
+ * Implements hook_watchdog().
+ */
+function system_test_watchdog($log_entry) {
+ // If an attempted recursive schema rebuild has been triggered by
+ // system_test_drupal_get_filename_with_schema_rebuild(), perform the rebuild
+ // in response to the missing file message triggered by system_test_schema().
+ if (!variable_get('system_test_drupal_get_filename_attempt_recursive_rebuild')) {
+ return;
+ }
+ if ($log_entry['type'] != 'php' || $log_entry['severity'] != WATCHDOG_WARNING) {
+ return;
+ }
+ $module_name = variable_get('system_test_drupal_get_filename_test_module_name');
+ if (!isset($log_entry['variables']['!message']) || strpos($log_entry['variables']['!message'], format_string('The following module is missing from the file system: %name', array('%name' => $module_name))) === FALSE) {
+ return;
+ }
+ variable_set('system_test_drupal_get_filename_with_schema_rebuild_final_tables', array_keys(drupal_get_schema()));
+}
+
+/**
+ * Implements hook_module_implements_alter().
+ */
+function system_test_module_implements_alter(&$implementations, $hook) {
+ // For BootstrapGetFilenameWebTestCase::testRecursiveRebuilds() to work
+ // correctly, this module's hook_schema() implementation cannot be either the
+ // first implementation (since that would trigger a potential recursive
+ // rebuild before anything is in the drupal_get_schema() cache) or the last
+ // implementation (since that would trigger a potential recursive rebuild
+ // after the cache is already complete). So put it somewhere in the middle.
+ if ($hook == 'schema') {
+ $group = $implementations['system_test'];
+ unset($implementations['system_test']);
+ $count = count($implementations);
+ $implementations = array_merge(array_slice($implementations, 0, $count / 2, TRUE), array('system_test' => $group), array_slice($implementations, $count / 2, NULL, TRUE));
+ }
+}
diff --git a/modules/simpletest/tests/taxonomy_test.info b/modules/simpletest/tests/taxonomy_test.info
index ebb752e3..94aef660 100644
--- a/modules/simpletest/tests/taxonomy_test.info
+++ b/modules/simpletest/tests/taxonomy_test.info
@@ -6,8 +6,7 @@ core = 7.x
hidden = TRUE
dependencies[] = taxonomy
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/simpletest/tests/taxonomy_test.module b/modules/simpletest/tests/taxonomy_test.module
index f82950c3..f4144380 100644
--- a/modules/simpletest/tests/taxonomy_test.module
+++ b/modules/simpletest/tests/taxonomy_test.module
@@ -109,3 +109,33 @@ function taxonomy_test_get_antonym($tid) {
->execute()
->fetchField();
}
+
+/**
+ * Implements hook_query_alter().
+ */
+function taxonomy_test_query_alter(QueryAlterableInterface $query) {
+ $value = variable_get(__FUNCTION__);
+ if (isset($value)) {
+ variable_set(__FUNCTION__, ++$value);
+ }
+}
+
+/**
+ * Implements hook_query_TAG_alter().
+ */
+function taxonomy_test_query_term_access_alter(QueryAlterableInterface $query) {
+ $value = variable_get(__FUNCTION__);
+ if (isset($value)) {
+ variable_set(__FUNCTION__, ++$value);
+ }
+}
+
+/**
+ * Implements hook_query_TAG_alter().
+ */
+function taxonomy_test_query_taxonomy_term_access_alter(QueryAlterableInterface $query) {
+ $value = variable_get(__FUNCTION__);
+ if (isset($value)) {
+ variable_set(__FUNCTION__, ++$value);
+ }
+}
diff --git a/modules/simpletest/tests/theme.test b/modules/simpletest/tests/theme.test
index f5ddfa9b..5f095bd5 100644
--- a/modules/simpletest/tests/theme.test
+++ b/modules/simpletest/tests/theme.test
@@ -646,3 +646,34 @@ class ThemeDebugMarkupTestCase extends DrupalWebTestCase {
}
}
+
+/**
+ * Tests module-provided theme engines.
+ */
+class ModuleProvidedThemeEngineTestCase extends DrupalWebTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Theme engine test',
+ 'description' => 'Tests module-provided theme engines.',
+ 'group' => 'Theme',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('theme_test');
+ theme_enable(array('test_theme', 'test_theme_nyan_cat'));
+ }
+
+ /**
+ * Ensures that the module provided theme engine is found and used by core.
+ */
+ function testEngineIsFoundAndWorking() {
+ variable_set('theme_default', 'test_theme_nyan_cat');
+ variable_set('admin_theme', 'test_theme_nyan_cat');
+
+ $this->drupalGet('theme-test/engine-info-test');
+ $this->assertText('Miaou');
+ }
+
+}
diff --git a/modules/simpletest/tests/theme_test.info b/modules/simpletest/tests/theme_test.info
index 9df1b617..c3635173 100644
--- a/modules/simpletest/tests/theme_test.info
+++ b/modules/simpletest/tests/theme_test.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/simpletest/tests/theme_test.module b/modules/simpletest/tests/theme_test.module
index 948d8175..1dbc3b95 100644
--- a/modules/simpletest/tests/theme_test.module
+++ b/modules/simpletest/tests/theme_test.module
@@ -27,9 +27,18 @@ function theme_test_system_theme_info() {
$themes['test_theme'] = drupal_get_path('module', 'theme_test') . '/themes/test_theme/test_theme.info';
$themes['test_basetheme'] = drupal_get_path('module', 'theme_test') . '/themes/test_basetheme/test_basetheme.info';
$themes['test_subtheme'] = drupal_get_path('module', 'theme_test') . '/themes/test_subtheme/test_subtheme.info';
+ $themes['test_theme_nyan_cat'] = drupal_get_path('module', 'theme_test') . '/themes/test_theme_nyan_cat/test_theme_nyan_cat.info';
return $themes;
}
+/**
+ * Implements hook_system_theme_engine_info().
+ */
+function theme_test_system_theme_engine_info() {
+ $theme_engines['nyan_cat'] = drupal_get_path('module', 'theme_test') . '/themes/engines/nyan_cat/nyan_cat.engine';
+ return $theme_engines;
+}
+
/**
* Implements hook_menu().
*/
@@ -58,6 +67,12 @@ function theme_test_menu() {
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
+ $items['theme-test/engine-info-test'] = array(
+ 'description' => "Serves a simple page rendered using a Nyan Cat theme engine template.",
+ 'page callback' => '_theme_test_engine_info_test',
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
+ );
return $items;
}
@@ -139,6 +154,15 @@ function _theme_test_drupal_add_region_content() {
return 'Hello';
}
+/**
+ * Serves a simple page renderered using a Nyan Cat theme engine template.
+ */
+function _theme_test_engine_info_test() {
+ return array(
+ '#markup' => theme('theme_test_template_test'),
+ );
+}
+
/**
* Theme function for testing theme('theme_test_foo').
*/
diff --git a/modules/simpletest/tests/themes/engines/nyan_cat/nyan_cat.engine b/modules/simpletest/tests/themes/engines/nyan_cat/nyan_cat.engine
new file mode 100644
index 00000000..1b8ffef8
--- /dev/null
+++ b/modules/simpletest/tests/themes/engines/nyan_cat/nyan_cat.engine
@@ -0,0 +1,53 @@
+filename) . '/template.theme';
+ if (file_exists($file)) {
+ include_once DRUPAL_ROOT . '/' . $file;
+ }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function nyan_cat_theme($existing, $type, $theme, $path) {
+ $templates = drupal_find_theme_functions($existing, array($theme));
+ $templates += drupal_find_theme_templates($existing, '.nyan-cat.html', $path);
+ return $templates;
+}
+
+/**
+ * Implements hook_extension().
+ */
+function nyan_cat_extension() {
+ return '.nyan-cat.html';
+}
+
+/**
+ * Implements hook_render_template().
+ *
+ * @param string $template_file
+ * The filename of the template to render.
+ * @param mixed[] $variables
+ * A keyed array of variables that will appear in the output.
+ *
+ * @return string
+ * The output generated by the template.
+ */
+function nyan_cat_render_template($template_file, $variables) {
+ $output = str_replace('div', 'nyancat', file_get_contents(DRUPAL_ROOT . '/' . $template_file));
+ foreach ($variables as $key => $variable) {
+ if (strpos($output, '9' . $key) !== FALSE) {
+ $output = str_replace('9' . $key, $variable, $output);
+ }
+ }
+ return $output;
+}
diff --git a/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info b/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info
index acba3d5f..8788b00b 100644
--- a/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info
+++ b/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info
@@ -6,8 +6,7 @@ hidden = TRUE
settings[basetheme_only] = base theme value
settings[subtheme_override] = base theme value
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info b/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info
index 120fc3a6..04c5975a 100644
--- a/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info
+++ b/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info
@@ -6,8 +6,7 @@ hidden = TRUE
settings[subtheme_override] = subtheme value
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/simpletest/tests/themes/test_theme/test_theme.info b/modules/simpletest/tests/themes/test_theme/test_theme.info
index 4679f32e..e88a344d 100644
--- a/modules/simpletest/tests/themes/test_theme/test_theme.info
+++ b/modules/simpletest/tests/themes/test_theme/test_theme.info
@@ -17,8 +17,7 @@ stylesheets[all][] = system.base.css
settings[theme_test_setting] = default value
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/simpletest/tests/themes/test_theme_nyan_cat/templates/theme_test_template_test.nyan-cat.html b/modules/simpletest/tests/themes/test_theme_nyan_cat/templates/theme_test_template_test.nyan-cat.html
new file mode 100644
index 00000000..7202dd48
--- /dev/null
+++ b/modules/simpletest/tests/themes/test_theme_nyan_cat/templates/theme_test_template_test.nyan-cat.html
@@ -0,0 +1 @@
+Miaou
\ No newline at end of file
diff --git a/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info b/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info
new file mode 100644
index 00000000..12f46b5c
--- /dev/null
+++ b/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info
@@ -0,0 +1,10 @@
+name = Nyan cat engine based test theme
+description = Theme for testing the module-provided theme engines.
+core = 7.x
+hidden = TRUE
+engine = nyan_cat
+
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
+project = "drupal"
+datestamp = "1539816636"
diff --git a/modules/simpletest/tests/update_script_test.info b/modules/simpletest/tests/update_script_test.info
index 5a174fc6..2c7c5125 100644
--- a/modules/simpletest/tests/update_script_test.info
+++ b/modules/simpletest/tests/update_script_test.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/simpletest/tests/update_script_test.install b/modules/simpletest/tests/update_script_test.install
index 6955ef11..4024fb4a 100644
--- a/modules/simpletest/tests/update_script_test.install
+++ b/modules/simpletest/tests/update_script_test.install
@@ -31,6 +31,19 @@ function update_script_test_requirements($phase) {
'severity' => REQUIREMENT_ERROR,
);
break;
+ case REQUIREMENT_INFO:
+ $requirements['update_script_test_stop'] = array(
+ 'title' => 'Update script test stop',
+ 'value' => 'Error',
+ 'description' => 'This is a requirements error provided by the update_script_test module to stop the page redirect for the info.',
+ 'severity' => REQUIREMENT_ERROR,
+ );
+ $requirements['update_script_test'] = array(
+ 'title' => 'Update script test',
+ 'description' => 'This is a requirements info provided by the update_script_test module.',
+ 'severity' => REQUIREMENT_INFO,
+ );
+ break;
}
}
diff --git a/modules/simpletest/tests/update_test_1.info b/modules/simpletest/tests/update_test_1.info
index 4484ad46..36d36422 100644
--- a/modules/simpletest/tests/update_test_1.info
+++ b/modules/simpletest/tests/update_test_1.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/simpletest/tests/update_test_2.info b/modules/simpletest/tests/update_test_2.info
index 4484ad46..36d36422 100644
--- a/modules/simpletest/tests/update_test_2.info
+++ b/modules/simpletest/tests/update_test_2.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/simpletest/tests/update_test_3.info b/modules/simpletest/tests/update_test_3.info
index 4484ad46..36d36422 100644
--- a/modules/simpletest/tests/update_test_3.info
+++ b/modules/simpletest/tests/update_test_3.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/simpletest/tests/upgrade/drupal-6.filled.database.php b/modules/simpletest/tests/upgrade/drupal-6.filled.database.php
index a9162813..10b9040c 100644
--- a/modules/simpletest/tests/upgrade/drupal-6.filled.database.php
+++ b/modules/simpletest/tests/upgrade/drupal-6.filled.database.php
@@ -19919,7 +19919,7 @@
'vid' => '1',
'name' => 'vocabulary 1 (i=0)',
'description' => 'description of vocabulary 1 (i=0)',
- 'help' => '',
+ 'help' => 'help for vocabulary 1 (i=0)',
'relations' => '1',
'hierarchy' => '0',
'multiple' => '0',
@@ -19932,7 +19932,7 @@
'vid' => '2',
'name' => 'vocabulary 2 (i=1)',
'description' => 'description of vocabulary 2 (i=1)',
- 'help' => '',
+ 'help' => 'help for vocabulary 2 (i=1)',
'relations' => '1',
'hierarchy' => '1',
'multiple' => '1',
@@ -19945,7 +19945,7 @@
'vid' => '3',
'name' => 'vocabulary 3 (i=2)',
'description' => 'description of vocabulary 3 (i=2)',
- 'help' => '',
+ 'help' => 'help for vocabulary 3 (i=2)',
'relations' => '1',
'hierarchy' => '2',
'multiple' => '0',
@@ -19958,7 +19958,7 @@
'vid' => '4',
'name' => 'vocabulary 4 (i=3)',
'description' => 'description of vocabulary 4 (i=3)',
- 'help' => '',
+ 'help' => 'help for vocabulary 4 (i=3)',
'relations' => '1',
'hierarchy' => '0',
'multiple' => '1',
@@ -19971,7 +19971,7 @@
'vid' => '5',
'name' => 'vocabulary 5 (i=4)',
'description' => 'description of vocabulary 5 (i=4)',
- 'help' => '',
+ 'help' => 'help for vocabulary 5 (i=4)',
'relations' => '1',
'hierarchy' => '1',
'multiple' => '0',
@@ -19984,7 +19984,7 @@
'vid' => '6',
'name' => 'vocabulary 6 (i=5)',
'description' => 'description of vocabulary 6 (i=5)',
- 'help' => '',
+ 'help' => 'help for vocabulary 6 (i=5)',
'relations' => '1',
'hierarchy' => '2',
'multiple' => '1',
@@ -19997,7 +19997,7 @@
'vid' => '7',
'name' => 'vocabulary 7 (i=6)',
'description' => 'description of vocabulary 7 (i=6)',
- 'help' => '',
+ 'help' => 'help for vocabulary 7 (i=6)',
'relations' => '1',
'hierarchy' => '0',
'multiple' => '0',
@@ -20010,7 +20010,7 @@
'vid' => '8',
'name' => 'vocabulary 8 (i=7)',
'description' => 'description of vocabulary 8 (i=7)',
- 'help' => '',
+ 'help' => 'help for vocabulary 8 (i=7)',
'relations' => '1',
'hierarchy' => '1',
'multiple' => '1',
@@ -20023,7 +20023,7 @@
'vid' => '9',
'name' => 'vocabulary 9 (i=8)',
'description' => 'description of vocabulary 9 (i=8)',
- 'help' => '',
+ 'help' => 'help for vocabulary 9 (i=8)',
'relations' => '1',
'hierarchy' => '2',
'multiple' => '0',
@@ -20036,7 +20036,7 @@
'vid' => '10',
'name' => 'vocabulary 10 (i=9)',
'description' => 'description of vocabulary 10 (i=9)',
- 'help' => '',
+ 'help' => 'help for vocabulary 10 (i=9)',
'relations' => '1',
'hierarchy' => '0',
'multiple' => '1',
@@ -20049,7 +20049,7 @@
'vid' => '11',
'name' => 'vocabulary 11 (i=10)',
'description' => 'description of vocabulary 11 (i=10)',
- 'help' => '',
+ 'help' => 'help for vocabulary 11 (i=10)',
'relations' => '1',
'hierarchy' => '1',
'multiple' => '0',
@@ -20062,7 +20062,7 @@
'vid' => '12',
'name' => 'vocabulary 12 (i=11)',
'description' => 'description of vocabulary 12 (i=11)',
- 'help' => '',
+ 'help' => 'help for vocabulary 12 (i=11)',
'relations' => '1',
'hierarchy' => '2',
'multiple' => '1',
@@ -20075,7 +20075,7 @@
'vid' => '13',
'name' => 'vocabulary 13 (i=12)',
'description' => 'description of vocabulary 13 (i=12)',
- 'help' => '',
+ 'help' => 'help for vocabulary 13 (i=12)',
'relations' => '1',
'hierarchy' => '0',
'multiple' => '0',
@@ -20088,7 +20088,7 @@
'vid' => '14',
'name' => 'vocabulary 14 (i=13)',
'description' => 'description of vocabulary 14 (i=13)',
- 'help' => '',
+ 'help' => 'help for vocabulary 14 (i=13)',
'relations' => '1',
'hierarchy' => '1',
'multiple' => '1',
@@ -20101,7 +20101,7 @@
'vid' => '15',
'name' => 'vocabulary 15 (i=14)',
'description' => 'description of vocabulary 15 (i=14)',
- 'help' => '',
+ 'help' => 'help for vocabulary 15 (i=14)',
'relations' => '1',
'hierarchy' => '2',
'multiple' => '0',
@@ -20114,7 +20114,7 @@
'vid' => '16',
'name' => 'vocabulary 16 (i=15)',
'description' => 'description of vocabulary 16 (i=15)',
- 'help' => '',
+ 'help' => 'help for vocabulary 16 (i=15)',
'relations' => '1',
'hierarchy' => '0',
'multiple' => '1',
@@ -20127,7 +20127,7 @@
'vid' => '17',
'name' => 'vocabulary 17 (i=16)',
'description' => 'description of vocabulary 17 (i=16)',
- 'help' => '',
+ 'help' => 'help for vocabulary 17 (i=16)',
'relations' => '1',
'hierarchy' => '1',
'multiple' => '0',
@@ -20140,7 +20140,7 @@
'vid' => '18',
'name' => 'vocabulary 18 (i=17)',
'description' => 'description of vocabulary 18 (i=17)',
- 'help' => '',
+ 'help' => 'help for vocabulary 18 (i=17)',
'relations' => '1',
'hierarchy' => '2',
'multiple' => '1',
@@ -20153,7 +20153,7 @@
'vid' => '19',
'name' => 'vocabulary 19 (i=18)',
'description' => 'description of vocabulary 19 (i=18)',
- 'help' => '',
+ 'help' => 'help for vocabulary 19 (i=18)',
'relations' => '1',
'hierarchy' => '0',
'multiple' => '0',
@@ -20166,7 +20166,7 @@
'vid' => '20',
'name' => 'vocabulary 20 (i=19)',
'description' => 'description of vocabulary 20 (i=19)',
- 'help' => '',
+ 'help' => 'help for vocabulary 20 (i=19)',
'relations' => '1',
'hierarchy' => '1',
'multiple' => '1',
@@ -20179,7 +20179,7 @@
'vid' => '21',
'name' => 'vocabulary 21 (i=20)',
'description' => 'description of vocabulary 21 (i=20)',
- 'help' => '',
+ 'help' => 'help for vocabulary 21 (i=20)',
'relations' => '1',
'hierarchy' => '2',
'multiple' => '0',
@@ -20192,7 +20192,7 @@
'vid' => '22',
'name' => 'vocabulary 22 (i=21)',
'description' => 'description of vocabulary 22 (i=21)',
- 'help' => '',
+ 'help' => 'help for vocabulary 22 (i=21)',
'relations' => '1',
'hierarchy' => '0',
'multiple' => '1',
@@ -20205,7 +20205,7 @@
'vid' => '23',
'name' => 'vocabulary 23 (i=22)',
'description' => 'description of vocabulary 23 (i=22)',
- 'help' => '',
+ 'help' => 'help for vocabulary 23 (i=22)',
'relations' => '1',
'hierarchy' => '1',
'multiple' => '0',
@@ -20218,7 +20218,7 @@
'vid' => '24',
'name' => 'vocabulary 24 (i=23)',
'description' => 'description of vocabulary 24 (i=23)',
- 'help' => '',
+ 'help' => 'help for vocabulary 24 (i=23)',
'relations' => '1',
'hierarchy' => '2',
'multiple' => '1',
diff --git a/modules/simpletest/tests/upgrade/drupal-6.upload.database.php b/modules/simpletest/tests/upgrade/drupal-6.upload.database.php
index 46ebe2cb..3fd602af 100644
--- a/modules/simpletest/tests/upgrade/drupal-6.upload.database.php
+++ b/modules/simpletest/tests/upgrade/drupal-6.upload.database.php
@@ -127,6 +127,38 @@
'status' => '1',
'timestamp' => '1285708958',
))
+// On some Drupal 6 sites, more than one file can have the same filepath. See
+// https://www.drupal.org/node/1260938.
+->values(array(
+ 'fid' => '12',
+ 'uid' => '1',
+ 'filename' => 'duplicate-name.png',
+ 'filepath' => 'sites/default/files/duplicate-name.png',
+ 'filemime' => 'image/png',
+ 'filesize' => '314',
+ 'status' => '1',
+ 'timestamp' => '1285708958',
+))
+->values(array(
+ 'fid' => '13',
+ 'uid' => '1',
+ 'filename' => 'duplicate-name.png',
+ 'filepath' => 'sites/default/files/duplicate-name.png',
+ 'filemime' => 'image/png',
+ 'filesize' => '315',
+ 'status' => '1',
+ 'timestamp' => '1285708958',
+))
+->values(array(
+ 'fid' => '14',
+ 'uid' => '1',
+ 'filename' => 'duplicate-name.png',
+ 'filepath' => 'sites/default/files/duplicate-name.png',
+ 'filemime' => 'image/png',
+ 'filesize' => '316',
+ 'status' => '1',
+ 'timestamp' => '1285708958',
+))
->execute();
db_insert('node')->fields(array(
@@ -196,6 +228,23 @@
'sticky' => '0',
'tnid' => '0',
'translate' => '0',
+))
+->values(array(
+ 'nid' => '41',
+ 'vid' => '55',
+ 'type' => 'page',
+ 'language' => '',
+ 'title' => 'node title 41 revision 55',
+ 'uid' => '1',
+ 'status' => '1',
+ 'created' => '1285709012',
+ 'changed' => '1285709012',
+ 'comment' => '0',
+ 'promote' => '0',
+ 'moderate' => '0',
+ 'sticky' => '0',
+ 'tnid' => '0',
+ 'translate' => '0',
))
->execute();
@@ -253,6 +302,28 @@
'log' => '',
'timestamp' => '1285709012',
'format' => '1',
+))
+->values(array(
+ 'nid' => '41',
+ 'vid' => '54',
+ 'uid' => '1',
+ 'title' => 'node title 41 revision 54',
+ 'body' => "Attachments:\r\nduplicate-name.png",
+ 'teaser' => "Attachments:\r\nduplicate-name.png",
+ 'log' => '',
+ 'timestamp' => '1285709012',
+ 'format' => '1',
+))
+->values(array(
+ 'nid' => '41',
+ 'vid' => '55',
+ 'uid' => '1',
+ 'title' => 'node title 41 revision 55',
+ 'body' => "Attachments:\r\nduplicate-name.png\r\nduplicate-name.png",
+ 'teaser' => "Attachments:\r\nduplicate-name.png\r\nduplicate-name.png",
+ 'log' => '',
+ 'timestamp' => '1285709012',
+ 'format' => '1',
))
->execute();
@@ -415,6 +486,30 @@
'list' => '1',
'weight' => '0',
))
+->values(array(
+ 'fid' => '12',
+ 'nid' => '41',
+ 'vid' => '54',
+ 'description' => 'duplicate-name.png',
+ 'list' => '1',
+ 'weight' => '0',
+))
+->values(array(
+ 'fid' => '13',
+ 'nid' => '41',
+ 'vid' => '55',
+ 'description' => 'first description',
+ 'list' => '0',
+ 'weight' => '0',
+))
+->values(array(
+ 'fid' => '14',
+ 'nid' => '41',
+ 'vid' => '55',
+ 'description' => 'second description',
+ 'list' => '1',
+ 'weight' => '0',
+))
->execute();
// Add series of entries for invalid node vids to the {upload} table.
@@ -431,7 +526,7 @@
->values(array(
'fid' => $i,
'nid' => '40',
- 'vid' => 24 + $i,
+ 'vid' => 26 + $i,
'description' => 'crazy-basename.png',
'list' => '1',
'weight' => '0',
@@ -440,7 +535,7 @@
->values(array(
'fid' => 2,
'nid' => '40',
- 'vid' => 24 + $i + 1,
+ 'vid' => 26 + $i + 1,
'description' => 'crazy-basename.png',
'list' => '1',
'weight' => '0',
diff --git a/modules/simpletest/tests/upgrade/upgrade.taxonomy.test b/modules/simpletest/tests/upgrade/upgrade.taxonomy.test
index 58a4d5c1..51402ed7 100644
--- a/modules/simpletest/tests/upgrade/upgrade.taxonomy.test
+++ b/modules/simpletest/tests/upgrade/upgrade.taxonomy.test
@@ -74,9 +74,10 @@ class UpgradePathTaxonomyTestCase extends UpgradePathTestCase {
$this->assertEqual($voc_keys, $inst_keys, 'Node type page has instances for every vocabulary.');
// Ensure instance variables are getting through.
- foreach ($instances as $instance) {
- $this->assertTrue(isset($instance['required']), 'The required setting was preserved during the upgrade path.');
- $this->assertTrue($instance['description'], 'The description was preserved during the upgrade path');
+ foreach (array_unique($instances) as $instance) {
+ $field_instance = field_info_instance('node', $instance, 'page');
+ $this->assertTrue(isset($field_instance['required']), 'The required setting was preserved during the upgrade path.');
+ $this->assertTrue($field_instance['description'], 'The description was preserved during the upgrade path');
}
// Node type 'story' was not explicitly in $vocabulary->nodes but
diff --git a/modules/simpletest/tests/upgrade/upgrade.upload.test b/modules/simpletest/tests/upgrade/upgrade.upload.test
index be352bd4..dfa94a00 100644
--- a/modules/simpletest/tests/upgrade/upgrade.upload.test
+++ b/modules/simpletest/tests/upgrade/upgrade.upload.test
@@ -64,12 +64,35 @@ class UploadUpgradePathTestCase extends UpgradePathTestCase {
}
$this->assertIdentical($filenames, $recorded_filenames, 'The uploaded files are present in the same order after the upgrade.');
}
+
// Test for the file with repeating basename to only have the streaming
// path replaced.
$node = node_load(40, 53);
$repeated_basename_file = $node->upload[LANGUAGE_NONE][4];
$this->assertEqual($repeated_basename_file['uri'], 'private://drupal-6/file/directory/path/crazy-basename.png', "The file with the repeated basename path only had the stream portion replaced");
+ // Ensure that filepaths are deduplicated.
+ $node0 = node_load(41, 54);
+ $node1 = node_load(41, 55);
+ // Ensure that both revisions point to the same file ID.
+ $items0 = field_get_items('node', $node0, 'upload');
+ $this->assertEqual(count($items0), 1);
+ $items1 = field_get_items('node', $node1, 'upload');
+ $this->assertEqual(count($items1), 2);
+ $this->assertEqual($items0[0]['fid'], $items1[0]['fid']);
+ $this->assertEqual($items0[0]['fid'], $items1[1]['fid']);
+ // The revision with more than one reference to the same file should retain
+ // the original settings for each reference.
+ $this->assertEqual($items1[0]['description'], 'first description');
+ $this->assertEqual($items1[0]['display'], 0);
+ $this->assertEqual($items1[1]['description'], 'second description');
+ $this->assertEqual($items1[1]['display'], 1);
+ // Ensure that the latest version of the files are used.
+ $this->assertEqual($items1[0]['filesize'], 316);
+ $this->assertEqual($items1[1]['filesize'], 316);
+ // No duplicate files should remain on the Drupal 7 site.
+ $this->assertEqual(0, db_query("SELECT COUNT(*) FROM {file_managed} GROUP BY uri HAVING COUNT(fid) > 1")->fetchField());
+
// Make sure the file settings were properly migrated.
$d6_file_directory_temp = '/drupal-6/file/directory/temp';
$d6_file_directory_path = '/drupal-6/file/directory/path';
diff --git a/modules/simpletest/tests/url_alter_test.info b/modules/simpletest/tests/url_alter_test.info
index 8af9f248..e4d1812f 100644
--- a/modules/simpletest/tests/url_alter_test.info
+++ b/modules/simpletest/tests/url_alter_test.info
@@ -5,8 +5,7 @@ package = Testing
version = VERSION
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/simpletest/tests/xmlrpc.test b/modules/simpletest/tests/xmlrpc.test
index 1a9ef234..bb74f059 100644
--- a/modules/simpletest/tests/xmlrpc.test
+++ b/modules/simpletest/tests/xmlrpc.test
@@ -246,4 +246,38 @@ class XMLRPCMessagesTestCase extends DrupalWebTestCase {
$this->assertEqual($removed, 'system.methodSignature', 'Hiding builting system.methodSignature with hook_xmlrpc_alter works');
}
+ /**
+ * Test limits on system.multicall that can prevent brute-force attacks.
+ */
+ function testMulticallLimit() {
+ $url = url(NULL, array('absolute' => TRUE)) . 'xmlrpc.php';
+ $multicall_args = array();
+ $num_method_calls = 10;
+ for ($i = 0; $i < $num_method_calls; $i++) {
+ $struct = array('i' => $i);
+ $multicall_args[] = array('methodName' => 'validator1.echoStructTest', 'params' => array($struct));
+ }
+ // Test limits of 1, 5, 9, 13.
+ for ($limit = 1; $limit < $num_method_calls + 4; $limit += 4) {
+ variable_set('xmlrpc_multicall_duplicate_method_limit', $limit);
+ $results = xmlrpc($url, array('system.multicall' => array($multicall_args)));
+ $this->assertEqual($num_method_calls, count($results));
+ for ($i = 0; $i < min($limit, $num_method_calls); $i++) {
+ $x = array_shift($results);
+ $this->assertTrue(empty($x->is_error), "Result $i is not an error");
+ $this->assertEqual($multicall_args[$i]['params'][0], $x);
+ }
+ for (; $i < $num_method_calls; $i++) {
+ $x = array_shift($results);
+ $this->assertFalse(empty($x->is_error), "Result $i is an error");
+ $this->assertEqual(-156579, $x->code);
+ }
+ }
+ variable_set('xmlrpc_multicall_duplicate_method_limit', -1);
+ $results = xmlrpc($url, array('system.multicall' => array($multicall_args)));
+ $this->assertEqual($num_method_calls, count($results));
+ foreach ($results as $i => $x) {
+ $this->assertTrue(empty($x->is_error), "Result $i is not an error");
+ }
+ }
}
diff --git a/modules/simpletest/tests/xmlrpc_test.info b/modules/simpletest/tests/xmlrpc_test.info
index 0cf5bbac..70c09ca8 100644
--- a/modules/simpletest/tests/xmlrpc_test.info
+++ b/modules/simpletest/tests/xmlrpc_test.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/statistics/statistics.info b/modules/statistics/statistics.info
index 92756356..8d711697 100644
--- a/modules/statistics/statistics.info
+++ b/modules/statistics/statistics.info
@@ -6,8 +6,7 @@ core = 7.x
files[] = statistics.test
configure = admin/config/system/statistics
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/statistics/statistics.module b/modules/statistics/statistics.module
index f665a14f..356a0e25 100644
--- a/modules/statistics/statistics.module
+++ b/modules/statistics/statistics.module
@@ -118,10 +118,9 @@ function statistics_node_view($node, $view_mode) {
// Attach Ajax node count statistics if configured.
if (variable_get('statistics_count_content_views', 0) && variable_get('statistics_count_content_views_ajax', 0)) {
if (!empty($node->nid) && $view_mode == 'full' && node_is_page($node) && empty($node->in_preview)) {
- $node->content['#attached']['js'] = array(
- drupal_get_path('module', 'statistics') . '/statistics.js' => array(
- 'scope' => 'footer'
- ),
+ $statistics = drupal_get_path('module', 'statistics') . '/statistics.js';
+ $node->content['#attached']['js'][$statistics] = array(
+ 'scope' => 'footer',
);
$settings = array('data' => array('nid' => $node->nid), 'url' => url(drupal_get_path('module', 'statistics') . '/statistics.php'));
$node->content['#attached']['js'][] = array(
@@ -246,7 +245,7 @@ function statistics_user_delete($account) {
* Implements hook_cron().
*/
function statistics_cron() {
- $statistics_timestamp = variable_get('statistics_day_timestamp', '');
+ $statistics_timestamp = variable_get('statistics_day_timestamp', 0);
if ((REQUEST_TIME - $statistics_timestamp) >= 86400) {
// Reset day counts.
diff --git a/modules/statistics/statistics.php b/modules/statistics/statistics.php
index f00e0397..48340c89 100644
--- a/modules/statistics/statistics.php
+++ b/modules/statistics/statistics.php
@@ -15,17 +15,19 @@
include_once DRUPAL_ROOT . '/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES);
if (variable_get('statistics_count_content_views', 0) && variable_get('statistics_count_content_views_ajax', 0)) {
- $nid = $_POST['nid'];
- if (is_numeric($nid)) {
- db_merge('node_counter')
- ->key(array('nid' => $nid))
- ->fields(array(
- 'daycount' => 1,
- 'totalcount' => 1,
- 'timestamp' => REQUEST_TIME,
- ))
- ->expression('daycount', 'daycount + 1')
- ->expression('totalcount', 'totalcount + 1')
- ->execute();
+ if (isset($_POST['nid'])) {
+ $nid = $_POST['nid'];
+ if (is_numeric($nid)) {
+ db_merge('node_counter')
+ ->key(array('nid' => $nid))
+ ->fields(array(
+ 'daycount' => 1,
+ 'totalcount' => 1,
+ 'timestamp' => REQUEST_TIME,
+ ))
+ ->expression('daycount', 'daycount + 1')
+ ->expression('totalcount', 'totalcount + 1')
+ ->execute();
+ }
}
}
diff --git a/modules/statistics/statistics.test b/modules/statistics/statistics.test
index 7e038d61..50accd74 100644
--- a/modules/statistics/statistics.test
+++ b/modules/statistics/statistics.test
@@ -35,7 +35,7 @@ class StatisticsTestCase extends DrupalWebTestCase {
'title' => 'test',
'path' => 'node/1',
'url' => 'http://example.com',
- 'hostname' => '192.168.1.1',
+ 'hostname' => '1.2.3.3',
'uid' => 0,
'sid' => 10,
'timer' => 10,
@@ -268,7 +268,7 @@ class StatisticsBlockVisitorsTestCase extends StatisticsTestCase {
*/
function testIPAddressBlocking() {
// IP address for testing.
- $test_ip_address = '192.168.1.1';
+ $test_ip_address = '1.2.3.3';
// Verify the IP address from accesslog appears on the top visitors page
// and that a 'block IP address' link is displayed.
diff --git a/modules/syslog/syslog.info b/modules/syslog/syslog.info
index e0b8a44a..5d3304ec 100644
--- a/modules/syslog/syslog.info
+++ b/modules/syslog/syslog.info
@@ -6,8 +6,7 @@ core = 7.x
files[] = syslog.test
configure = admin/config/development/logging
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/system/image.gd.inc b/modules/system/image.gd.inc
index 913b0de5..3d0797e4 100644
--- a/modules/system/image.gd.inc
+++ b/modules/system/image.gd.inc
@@ -116,38 +116,62 @@ function image_gd_rotate(stdClass $image, $degrees, $background = NULL) {
return FALSE;
}
- $width = $image->info['width'];
- $height = $image->info['height'];
+ // PHP 5.5 GD bug: https://bugs.php.net/bug.php?id=65148: To prevent buggy
+ // behavior on negative multiples of 90 degrees we convert any negative
+ // angle to a positive one between 0 and 360 degrees.
+ $degrees -= floor($degrees / 360) * 360;
- // Convert the hexadecimal background value to a color index value.
+ // Convert the hexadecimal background value to a RGBA array.
if (isset($background)) {
- $rgb = array();
- for ($i = 16; $i >= 0; $i -= 8) {
- $rgb[] = (($background >> $i) & 0xFF);
- }
- $background = imagecolorallocatealpha($image->resource, $rgb[0], $rgb[1], $rgb[2], 0);
+ $background = array(
+ 'red' => $background >> 16 & 0xFF,
+ 'green' => $background >> 8 & 0xFF,
+ 'blue' => $background & 0xFF,
+ 'alpha' => 0,
+ );
}
- // Set the background color as transparent if $background is NULL.
else {
- // Get the current transparent color.
- $background = imagecolortransparent($image->resource);
-
- // If no transparent colors, use white.
- if ($background == 0) {
- $background = imagecolorallocatealpha($image->resource, 255, 255, 255, 0);
- }
+ // Background color is not specified: use transparent white as background.
+ $background = array(
+ 'red' => 255,
+ 'green' => 255,
+ 'blue' => 255,
+ 'alpha' => 127
+ );
}
+ // Store the color index for the background as that is what GD uses.
+ $background_idx = imagecolorallocatealpha($image->resource, $background['red'], $background['green'], $background['blue'], $background['alpha']);
+
// Images are assigned a new color palette when rotating, removing any
// transparency flags. For GIF images, keep a record of the transparent color.
if ($image->info['extension'] == 'gif') {
- $transparent_index = imagecolortransparent($image->resource);
- if ($transparent_index != 0) {
- $transparent_gif_color = imagecolorsforindex($image->resource, $transparent_index);
+ // GIF does not work with a transparency channel, but can define 1 color
+ // in its palette to act as transparent.
+
+ // Get the current transparent color, if any.
+ $gif_transparent_id = imagecolortransparent($image->resource);
+ if ($gif_transparent_id !== -1) {
+ // The gif already has a transparent color set: remember it to set it on
+ // the rotated image as well.
+ $transparent_gif_color = imagecolorsforindex($image->resource, $gif_transparent_id);
+
+ if ($background['alpha'] >= 127) {
+ // We want a transparent background: use the color already set to act
+ // as transparent, as background.
+ $background_idx = $gif_transparent_id;
+ }
+ }
+ else {
+ // The gif does not currently have a transparent color set.
+ if ($background['alpha'] >= 127) {
+ // But as the background is transparent, it should get one.
+ $transparent_gif_color = $background;
+ }
}
}
- $image->resource = imagerotate($image->resource, 360 - $degrees, $background);
+ $image->resource = imagerotate($image->resource, 360 - $degrees, $background_idx);
// GIFs need to reassign the transparent color after performing the rotate.
if (isset($transparent_gif_color)) {
diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc
index 0f525c6c..cdcc78fb 100644
--- a/modules/system/system.admin.inc
+++ b/modules/system/system.admin.inc
@@ -1856,7 +1856,7 @@ function system_image_toolkit_settings() {
if (count($toolkits_available) == 0) {
variable_del('image_toolkit');
$form['image_toolkit_help'] = array(
- '#markup' => t("No image toolkits were detected. Drupal includes support for PHP's built-in image processing functions but they were not detected on this system. You should consult your system administrator to have them enabled, or try using a third party toolkit.", array('gd-link' => url('http://php.net/gd'))),
+ '#markup' => t("No image toolkits were detected. Drupal includes support for PHP's built-in image processing functions but they were not detected on this system. You should consult your system administrator to have them enabled, or try using a third party toolkit.", array('!gd-link' => url('http://php.net/gd'))),
);
return $form;
}
@@ -2202,6 +2202,11 @@ function system_add_date_format_type_form_submit($form, &$form_state) {
* Return the date for a given format string via Ajax.
*/
function system_date_time_lookup() {
+ // This callback is protected with a CSRF token because user input from the
+ // query string is reflected in the output.
+ if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], 'admin/config/regional/date-time/formats/lookup')) {
+ return MENU_ACCESS_DENIED;
+ }
$result = format_date(REQUEST_TIME, 'custom', $_GET['format']);
drupal_json_output($result);
}
@@ -2592,6 +2597,8 @@ function theme_status_report($variables) {
if (empty($requirement['#type'])) {
$severity = $severities[isset($requirement['severity']) ? (int) $requirement['severity'] : REQUIREMENT_OK];
$severity['icon'] = '
' . $severity['title'] . '
';
+ // The requirement's 'value' key is optional, provide a default value.
+ $requirement['value'] = isset($requirement['value']) ? $requirement['value'] : '';
// Output table row(s)
if (!empty($requirement['description'])) {
@@ -2875,13 +2882,14 @@ function system_date_time_formats() {
* Allow users to add additional date formats.
*/
function system_configure_date_formats_form($form, &$form_state, $dfid = 0) {
+ $ajax_path = 'admin/config/regional/date-time/formats/lookup';
$js_settings = array(
'type' => 'setting',
'data' => array(
'dateTime' => array(
'date-format' => array(
'text' => t('Displayed as'),
- 'lookup' => url('admin/config/regional/date-time/formats/lookup'),
+ 'lookup' => url($ajax_path, array('query' => array('token' => drupal_get_token($ajax_path)))),
),
),
),
diff --git a/modules/system/system.api.php b/modules/system/system.api.php
index d6cbc769..f1855b96 100644
--- a/modules/system/system.api.php
+++ b/modules/system/system.api.php
@@ -113,21 +113,21 @@ function hook_hook_info_alter(&$hooks) {
* translation handlers. Array keys are the module names, array values
* can be any data structure the module uses to provide field translation.
* Any empty value disallows the module to appear as a translation handler.
- * - entity keys: An array describing how the Field API can extract the
- * information it needs from the objects of the type. Elements:
+ * - entity keys: (optional) An array describing how the Field API can extract
+ * the information it needs from the objects of the type. Elements:
* - id: The name of the property that contains the primary id of the
* entity. Every entity object passed to the Field API must have this
* property and its value must be numeric.
* - revision: The name of the property that contains the revision id of
* the entity. The Field API assumes that all revision ids are unique
* across all entities of a type. This entry can be omitted if the
- * entities of this type are not versionable.
+ * entities of this type are not versionable. Defaults to an empty string.
* - bundle: The name of the property that contains the bundle name for the
* entity. The bundle name defines which set of fields are attached to
* the entity (e.g. what nodes call "content type"). This entry can be
* omitted if this entity type exposes a single bundle (all entities have
* the same collection of fields). The name of this single bundle will be
- * the same as the entity type.
+ * the same as the entity type. Defaults to an empty string.
* - label: The name of the property that contains the entity label. For
* example, if the entity's label is located in $entity->subject, then
* 'subject' should be specified here. If complex logic is required to
@@ -1797,6 +1797,8 @@ function hook_form_BASE_FORM_ID_alter(&$form, &$form_state, $form_id) {
* the $form_id input matched your module's format for dynamically-generated
* form IDs, and if so, act appropriately.
*
+ * Third, forms defined in classes can be defined this way.
+ *
* @param $form_id
* The unique string identifying the desired form.
* @param $args
@@ -1807,19 +1809,22 @@ function hook_form_BASE_FORM_ID_alter(&$form, &$form_state, $form_id) {
* @return
* An associative array whose keys define form_ids and whose values are an
* associative array defining the following keys:
- * - callback: The name of the form builder function to invoke. This will be
- * used for the base form ID, for example, to target a base form using
- * hook_form_BASE_FORM_ID_alter().
+ * - callback: The callable returning the form array. If it is the name of
+ * the form builder function then this will be used for the base
+ * form ID, for example, to target a base form using
+ * hook_form_BASE_FORM_ID_alter(). Otherwise use the base_form_id key to
+ * define the base form ID.
* - callback arguments: (optional) Additional arguments to pass to the
* function defined in 'callback', which are prepended to $args.
- * - wrapper_callback: (optional) The name of a form builder function to
- * invoke before the form builder defined in 'callback' is invoked. This
- * wrapper callback may prepopulate the $form array with form elements,
- * which will then be already contained in the $form that is passed on to
- * the form builder defined in 'callback'. For example, a wrapper callback
- * could setup wizard-alike form buttons that are the same for a variety of
- * forms that belong to the wizard, which all share the same wrapper
- * callback.
+ * - base_form_id: The base form ID can be specified explicitly. This is
+ * required when callback is not the name of a function.
+ * - wrapper_callback: (optional) Any callable to invoke before the form
+ * builder defined in 'callback' is invoked. This wrapper callback may
+ * prepopulate the $form array with form elements, which will then be
+ * already contained in the $form that is passed on to the form builder
+ * defined in 'callback'. For example, a wrapper callback could setup
+ * wizard-like form buttons that are the same for a variety of forms that
+ * belong to the wizard, which all share the same wrapper callback.
*/
function hook_forms($form_id, $args) {
// Simply reroute the (non-existing) $form_id 'mymodule_first_form' to
@@ -1843,6 +1848,15 @@ function hook_forms($form_id, $args) {
'wrapper_callback' => 'mymodule_main_form_wrapper',
);
+ // Build a form with a static class callback.
+ $forms['mymodule_class_generated_form'] = array(
+ // This will call: MyClass::generateMainForm().
+ 'callback' => array('MyClass', 'generateMainForm'),
+ // The base_form_id is required when the callback is a static function in
+ // a class. This can also be used to keep newer code backwards compatible.
+ 'base_form_id' => 'mymodule_main_form',
+ );
+
return $forms;
}
@@ -2036,6 +2050,22 @@ function hook_system_theme_info() {
return $themes;
}
+/**
+ * Return additional theme engines provided by modules.
+ *
+ * This hook is invoked from _system_rebuild_theme_data() and allows modules to
+ * register additional theme engines outside of the regular 'themes/engines'
+ * directories of a Drupal installation.
+ *
+ * @return
+ * An associative array. Each key is the system name of a theme engine and
+ * each value is the corresponding path to the theme engine's .engine file.
+ */
+function hook_system_theme_engine_info() {
+ $theme_engines['izumi'] = drupal_get_path('module', 'mymodule') . '/izumi/izumi.engine';
+ return $theme_engines;
+}
+
/**
* Alter the information parsed from module and theme .info files
*
@@ -2632,6 +2662,8 @@ function hook_flush_caches() {
* module_enable() for a detailed description of the order in which install and
* enable hooks are invoked.
*
+ * This hook should be implemented in a .module file, not in an .install file.
+ *
* @param $modules
* An array of the modules that were installed.
*
@@ -3173,7 +3205,9 @@ function hook_requirements($phase) {
* creation and alteration of the supported database engines.
*
* See the Schema API Handbook at http://drupal.org/node/146843 for details on
- * schema definition structures.
+ * schema definition structures. Note that foreign key definitions are for
+ * documentation purposes only; foreign keys are not created in the database,
+ * nor are they enforced by Drupal.
*
* @return array
* A schema definition structure array. For each element of the
@@ -3225,6 +3259,8 @@ function hook_schema() {
'nid_vid' => array('nid', 'vid'),
'vid' => array('vid'),
),
+ // For documentation purposes only; foreign keys are not created in the
+ // database.
'foreign keys' => array(
'node_revision' => array(
'table' => 'node_revision',
diff --git a/modules/system/system.info b/modules/system/system.info
index 97f3bdf3..730dff6f 100644
--- a/modules/system/system.info
+++ b/modules/system/system.info
@@ -12,8 +12,7 @@ files[] = system.test
required = TRUE
configure = admin/config/system
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/system/system.install b/modules/system/system.install
index 89e7d5b8..2aab53e7 100644
--- a/modules/system/system.install
+++ b/modules/system/system.install
@@ -170,7 +170,7 @@ function system_requirements($phase) {
if (empty($drivers)) {
$database_ok = FALSE;
$pdo_message = $t('Your web server does not appear to support any common PDO database extensions. Check with your hosting provider to see if they support PDO (PHP Data Objects) and offer any databases that Drupal supports.', array(
- '@drupal-databases' => 'http://drupal.org/node/270#database',
+ '@drupal-databases' => 'https://www.drupal.org/requirements/database',
));
}
// Make sure the native PDO extension is available, not the older PEAR
@@ -206,6 +206,12 @@ function system_requirements($phase) {
);
}
+ // Test database-specific multi-byte UTF-8 related requirements.
+ $charset_requirements = _system_check_db_utf8mb4_requirements($phase);
+ if (!empty($charset_requirements)) {
+ $requirements['database_charset'] = $charset_requirements;
+ }
+
// Test PHP memory_limit
$memory_limit = ini_get('memory_limit');
$requirements['php_memory_limit'] = array(
@@ -527,6 +533,75 @@ function system_requirements($phase) {
return $requirements;
}
+/**
+ * Checks whether the requirements for multi-byte UTF-8 support are met.
+ *
+ * @param string $phase
+ * The hook_requirements() stage.
+ *
+ * @return array
+ * A requirements array with the result of the charset check.
+ */
+function _system_check_db_utf8mb4_requirements($phase) {
+ global $install_state;
+ // In the requirements check of the installer, skip the utf8mb4 check unless
+ // the database connection info has been preconfigured by hand with valid
+ // information before running the installer, as otherwise we cannot get a
+ // valid database connection object.
+ if (isset($install_state['settings_verified']) && !$install_state['settings_verified']) {
+ return array();
+ }
+
+ $connection = Database::getConnection();
+ $t = get_t();
+ $requirements['title'] = $t('Database 4 byte UTF-8 support');
+
+ $utf8mb4_configurable = $connection->utf8mb4IsConfigurable();
+ $utf8mb4_active = $connection->utf8mb4IsActive();
+ $utf8mb4_supported = $connection->utf8mb4IsSupported();
+ $driver = $connection->driver();
+ $documentation_url = 'https://www.drupal.org/node/2754539';
+
+ if ($utf8mb4_active) {
+ if ($utf8mb4_supported) {
+ if ($phase != 'install' && $utf8mb4_configurable && !variable_get('drupal_all_databases_are_utf8mb4', FALSE)) {
+ // Supported, active, and configurable, but not all database tables
+ // have been converted yet.
+ $requirements['value'] = $t('Enabled, but database tables need conversion');
+ $requirements['description'] = $t('Please convert all database tables to utf8mb4 prior to enabling it in settings.php. See the documentation on adding 4 byte UTF-8 support for more information.', array('@url' => $documentation_url));
+ $requirements['severity'] = REQUIREMENT_ERROR;
+ }
+ else {
+ // Supported, active.
+ $requirements['value'] = $t('Enabled');
+ $requirements['description'] = $t('4 byte UTF-8 for @driver is enabled.', array('@driver' => $driver));
+ $requirements['severity'] = REQUIREMENT_OK;
+ }
+ }
+ else {
+ // Not supported, active.
+ $requirements['value'] = $t('Not supported');
+ $requirements['description'] = $t('4 byte UTF-8 for @driver is activated, but not supported on your system. Please turn this off in settings.php, or ensure that all database-related requirements are met. See the documentation on adding 4 byte UTF-8 support for more information.', array('@driver' => $driver, '@url' => $documentation_url));
+ $requirements['severity'] = REQUIREMENT_ERROR;
+ }
+ }
+ else {
+ if ($utf8mb4_supported) {
+ // Supported, not active.
+ $requirements['value'] = $t('Not enabled');
+ $requirements['description'] = $t('4 byte UTF-8 for @driver is not activated, but it is supported on your system. It is recommended that you enable this to allow 4-byte UTF-8 input such as emojis, Asian symbols and mathematical symbols to be stored correctly. See the documentation on adding 4 byte UTF-8 support for more information.', array('@driver' => $driver, '@url' => $documentation_url));
+ $requirements['severity'] = REQUIREMENT_INFO;
+ }
+ else {
+ // Not supported, not active.
+ $requirements['value'] = $t('Disabled');
+ $requirements['description'] = $t('4 byte UTF-8 for @driver is disabled. See the documentation on adding 4 byte UTF-8 support for more information.', array('@driver' => $driver, '@url' => $documentation_url));
+ $requirements['severity'] = REQUIREMENT_INFO;
+ }
+ }
+ return $requirements;
+}
+
/**
* Implements hook_install().
*/
@@ -542,6 +617,9 @@ function system_install() {
module_list(TRUE);
module_implements('', FALSE, TRUE);
+ // Ensure the schema versions are not based on a previous module list.
+ drupal_static_reset('drupal_get_schema_versions');
+
// Load system theme data appropriately.
system_rebuild_theme_data();
@@ -810,6 +888,7 @@ function system_schema() {
'type' => 'varchar',
'length' => 100,
'not null' => TRUE,
+ 'binary' => TRUE,
),
'type' => array(
'description' => 'The date format type, e.g. medium.',
@@ -2813,6 +2892,16 @@ function system_update_7061(&$sandbox) {
->from($query)
->execute();
+ // Retrieve a list of duplicate files with the same filepath. Only the
+ // most-recently uploaded of these will be moved to the new {file_managed}
+ // table (and all references will be updated to point to it), since
+ // duplicate file URIs are not allowed in Drupal 7.
+ // Since the Drupal 6 to 7 upgrade path leaves the {files} table behind
+ // after it's done, custom or contributed modules which need to migrate
+ // file references of their own can use a similar query to determine the
+ // file IDs that duplicate filepaths were mapped to.
+ $sandbox['duplicate_filepath_fids_to_use'] = db_query("SELECT filepath, MAX(fid) FROM {files} GROUP BY filepath HAVING COUNT(*) > 1")->fetchAllKeyed();
+
// Initialize batch update information.
$sandbox['progress'] = 0;
$sandbox['last_vid_processed'] = -1;
@@ -2842,6 +2931,16 @@ function system_update_7061(&$sandbox) {
continue;
}
+ // If this file has a duplicate filepath, replace it with the
+ // most-recently uploaded file that has the same filepath.
+ if (isset($sandbox['duplicate_filepath_fids_to_use'][$file['filepath']]) && $record->fid != $sandbox['duplicate_filepath_fids_to_use'][$file['filepath']]) {
+ $file = db_select('files', 'f')
+ ->fields('f', array('fid', 'uid', 'filename', 'filepath', 'filemime', 'filesize', 'status', 'timestamp'))
+ ->condition('f.fid', $sandbox['duplicate_filepath_fids_to_use'][$file['filepath']])
+ ->execute()
+ ->fetchAssoc();
+ }
+
// Add in the file information from the upload table.
$file['description'] = $record->description;
$file['display'] = $record->list;
@@ -3167,6 +3266,35 @@ function system_update_7079() {
db_change_field('file_managed', 'filesize', 'filesize', $spec);
}
+/**
+ * Convert the 'format' column in {date_format_locale} to case sensitive varchar.
+ */
+function system_update_7080() {
+ $spec = array(
+ 'description' => 'The date format string.',
+ 'type' => 'varchar',
+ 'length' => 100,
+ 'not null' => TRUE,
+ 'binary' => TRUE,
+ );
+ db_change_field('date_format_locale', 'format', 'format', $spec);
+}
+
+/**
+ * Remove the Drupal 6 default install profile if it is still in the database.
+ */
+function system_update_7081() {
+ // Sites which used the default install profile in Drupal 6 and then updated
+ // to Drupal 7.44 or earlier will still have a record of this install profile
+ // in the database that needs to be deleted.
+ db_delete('system')
+ ->condition('filename', 'profiles/default/default.profile')
+ ->condition('type', 'module')
+ ->condition('status', 0)
+ ->condition('schema_version', 0)
+ ->execute();
+}
+
/**
* @} End of "defgroup updates-7.x-extra".
* The next series of updates should start at 8000.
diff --git a/modules/system/system.js b/modules/system/system.js
index 910fb5d3..c0e76d38 100644
--- a/modules/system/system.js
+++ b/modules/system/system.js
@@ -105,7 +105,7 @@ Drupal.behaviors.dateTime = {
// Attach keyup handler to custom format inputs.
$('input' + source, context).once('date-time').keyup(function () {
var input = $(this);
- var url = fieldSettings.lookup + (/\?q=/.test(fieldSettings.lookup) ? '&format=' : '?format=') + encodeURIComponent(input.val());
+ var url = fieldSettings.lookup + (/\?/.test(fieldSettings.lookup) ? '&format=' : '?format=') + encodeURIComponent(input.val());
$.getJSON(url, function (data) {
$(suffix).empty().append(' ' + fieldSettings.text + ': ' + data + '');
});
diff --git a/modules/system/system.mail.inc b/modules/system/system.mail.inc
index 443e5740..9a17f55f 100644
--- a/modules/system/system.mail.inc
+++ b/modules/system/system.mail.inc
@@ -70,7 +70,9 @@ class DefaultMailSystem implements MailSystemInterface {
// hosts. The return value of this method will still indicate whether mail
// was sent successfully.
if (!isset($_SERVER['WINDIR']) && strpos($_SERVER['SERVER_SOFTWARE'], 'Win32') === FALSE) {
- if (isset($message['Return-Path']) && !ini_get('safe_mode')) {
+ // We validate the return path, unless it is equal to the site mail, which
+ // we assume to be safe.
+ if (isset($message['Return-Path']) && !ini_get('safe_mode') && (variable_get('site_mail', ini_get('sendmail_from')) === $message['Return-Path'] || self::_isShellSafe($message['Return-Path']))) {
// On most non-Windows systems, the "-f" option to the sendmail command
// is used to set the Return-Path. There is no space between -f and
// the value of the return path.
@@ -109,6 +111,36 @@ class DefaultMailSystem implements MailSystemInterface {
}
return $mail_result;
}
+
+ /**
+ * Disallows potentially unsafe shell characters.
+ *
+ * Functionally similar to PHPMailer::isShellSafe() which resulted from
+ * CVE-2016-10045. Note that escapeshellarg and escapeshellcmd are inadequate
+ * for this purpose.
+ *
+ * @param string $string
+ * The string to be validated.
+ *
+ * @return bool
+ * True if the string is shell-safe.
+ *
+ * @see https://github.com/PHPMailer/PHPMailer/issues/924
+ * @see https://github.com/PHPMailer/PHPMailer/blob/v5.2.21/class.phpmailer.php#L1430
+ *
+ * @todo Rename to ::isShellSafe() and/or discuss whether this is the correct
+ * location for this helper.
+ */
+ protected static function _isShellSafe($string) {
+ if (escapeshellcmd($string) !== $string || !in_array(escapeshellarg($string), array("'$string'", "\"$string\""))) {
+ return FALSE;
+ }
+ if (preg_match('/[^a-zA-Z0-9@_\-.]/', $string) !== 0) {
+ return FALSE;
+ }
+ return TRUE;
+ }
+
}
/**
diff --git a/modules/system/system.module b/modules/system/system.module
index 284597f8..f891998e 100644
--- a/modules/system/system.module
+++ b/modules/system/system.module
@@ -2417,6 +2417,10 @@ function _system_rebuild_module_data() {
// Merge in defaults and save.
$modules[$key]->info = $module->info + $defaults;
+ // The "name" key is required, but to avoid a fatal error in the menu system
+ // we set a reasonable default if it is not provided.
+ $modules[$key]->info += array('name' => $key);
+
// Prefix stylesheets and scripts with module path.
$path = dirname($module->uri);
if (isset($module->info['stylesheets'])) {
@@ -2523,6 +2527,16 @@ function _system_rebuild_theme_data() {
// Find theme engines
$engines = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.engine$/', 'themes/engines');
+ // Allow modules to add further theme engines.
+ if ($module_engines = module_invoke_all('system_theme_engine_info')) {
+ foreach ($module_engines as $name => $theme_engine_path) {
+ $engines[$name] = (object) array(
+ 'uri' => $theme_engine_path,
+ 'filename' => basename($theme_engine_path),
+ 'name' => $name,
+ );
+ }
+ }
// Set defaults for theme info.
$defaults = array(
@@ -2552,6 +2566,10 @@ function _system_rebuild_theme_data() {
$themes[$key]->filename = $theme->uri;
$themes[$key]->info = drupal_parse_info_file($theme->uri) + $defaults;
+ // The "name" key is required, but to avoid a fatal error in the menu system
+ // we set a reasonable default if it is not provided.
+ $themes[$key]->info += array('name' => $key);
+
// Add the info file modification time, so it becomes available for
// contributed modules to use for ordering theme lists.
$themes[$key]->info['mtime'] = filemtime($theme->uri);
@@ -2703,10 +2721,17 @@ function system_find_base_themes($themes, $key, $used_keys = array()) {
* @param $show
* Possible values: REGIONS_ALL or REGIONS_VISIBLE. Visible excludes hidden
* regions.
- * @return
- * An array of regions in the form $region['name'] = 'description'.
+ * @param bool $labels
+ * (optional) Boolean to specify whether the human readable machine names
+ * should be returned or not. Defaults to TRUE, but calling code can set
+ * this to FALSE for better performance, if it only needs machine names.
+ *
+ * @return array
+ * An associative array of regions in the form $region['name'] = 'description'
+ * if $labels is set to TRUE, or $region['name'] = 'name', if $labels is set
+ * to FALSE.
*/
-function system_region_list($theme_key, $show = REGIONS_ALL) {
+function system_region_list($theme_key, $show = REGIONS_ALL, $labels = TRUE) {
$themes = list_themes();
if (!isset($themes[$theme_key])) {
return array();
@@ -2717,10 +2742,14 @@ function system_region_list($theme_key, $show = REGIONS_ALL) {
// If requested, suppress hidden regions. See block_admin_display_form().
foreach ($info['regions'] as $name => $label) {
if ($show == REGIONS_ALL || !isset($info['regions_hidden']) || !in_array($name, $info['regions_hidden'])) {
- $list[$name] = t($label);
+ if ($labels) {
+ $list[$name] = t($label);
+ }
+ else {
+ $list[$name] = $name;
+ }
}
}
-
return $list;
}
@@ -2741,12 +2770,13 @@ function system_system_info_alter(&$info, $file, $type) {
*
* @param $theme
* The name of a theme.
+ *
* @return
* A string that is the region name.
*/
function system_default_region($theme) {
- $regions = array_keys(system_region_list($theme, REGIONS_VISIBLE));
- return isset($regions[0]) ? $regions[0] : '';
+ $regions = system_region_list($theme, REGIONS_VISIBLE, FALSE);
+ return $regions ? reset($regions) : '';
}
/**
@@ -2813,7 +2843,7 @@ function system_settings_form_submit($form, &$form_state) {
function _system_sort_requirements($a, $b) {
if (!isset($a['weight'])) {
if (!isset($b['weight'])) {
- return strcmp($a['title'], $b['title']);
+ return strcasecmp($a['title'], $b['title']);
}
return -$b['weight'];
}
@@ -2869,7 +2899,7 @@ function confirm_form($form, $question, $path, $description = NULL, $yes = NULL,
// Prepare cancel link.
if (isset($_GET['destination'])) {
- $options = drupal_parse_url(urldecode($_GET['destination']));
+ $options = drupal_parse_url($_GET['destination']);
}
elseif (is_array($path)) {
$options = $path;
@@ -3054,8 +3084,20 @@ function system_cron() {
}
}
- $core = array('cache', 'cache_path', 'cache_filter', 'cache_page', 'cache_form', 'cache_menu');
- $cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
+ // Delete expired cache entries.
+ // Avoid invoking hook_flush_cashes() on every cron run because some modules
+ // use this hook to perform expensive rebuilding operations (which are only
+ // designed to happen on full cache clears), rather than just returning a
+ // list of cache tables to be cleared.
+ $cache_object = cache_get('system_cache_tables');
+ if (empty($cache_object)) {
+ $core = array('cache', 'cache_path', 'cache_filter', 'cache_page', 'cache_form', 'cache_menu');
+ $cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
+ cache_set('system_cache_tables', $cache_tables);
+ }
+ else {
+ $cache_tables = $cache_object->data;
+ }
foreach ($cache_tables as $table) {
cache_clear_all(NULL, $table);
}
@@ -3303,7 +3345,7 @@ function system_goto_action_form($context) {
$form['url'] = array(
'#type' => 'textfield',
'#title' => t('URL'),
- '#description' => t('The URL to which the user should be redirected. This can be an internal URL like node/1234 or an external URL like http://drupal.org.'),
+ '#description' => t('The URL to which the user should be redirected. This can be an internal path like node/1234 or an external URL like http://example.com.'),
'#default_value' => isset($context['url']) ? $context['url'] : '',
'#required' => TRUE,
);
@@ -3340,7 +3382,8 @@ function system_goto_action($entity, $context) {
*/
function system_block_ip_action() {
$ip = ip_address();
- db_insert('blocked_ips')
+ db_merge('blocked_ips')
+ ->key(array('ip' => $ip))
->fields(array('ip' => $ip))
->execute();
watchdog('action', 'Banned IP address %ip', array('%ip' => $ip));
@@ -3502,8 +3545,7 @@ function system_retrieve_file($url, $destination = NULL, $managed = FALSE, $repl
function system_page_alter(&$page) {
// Find all non-empty page regions, and add a theme wrapper function that
// allows them to be consistently themed.
- $regions = system_region_list($GLOBALS['theme']);
- foreach (array_keys($regions) as $region) {
+ foreach (system_region_list($GLOBALS['theme'], REGIONS_ALL, FALSE) as $region) {
if (!empty($page[$region])) {
$page[$region]['#theme_wrappers'][] = 'region';
$page[$region]['#region'] = $region;
diff --git a/modules/system/system.queue.inc b/modules/system/system.queue.inc
index 6eeaae19..c17084de 100644
--- a/modules/system/system.queue.inc
+++ b/modules/system/system.queue.inc
@@ -326,6 +326,7 @@ class MemoryQueue implements DrupalQueueInterface {
$item->created = time();
$item->expire = 0;
$this->queue[$item->item_id] = $item;
+ return TRUE;
}
public function numberOfItems() {
diff --git a/modules/system/system.tar.inc b/modules/system/system.tar.inc
index 32bf7f06..86e4e3de 100644
--- a/modules/system/system.tar.inc
+++ b/modules/system/system.tar.inc
@@ -30,81 +30,148 @@
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- *
- * @category File_Formats
- * @package Archive_Tar
- * @author Vincent Blavet
- * @copyright 1997-2008 The Authors
- * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
- * @version CVS: Id: Tar.php,v 1.43 2008/10/30 17:58:42 dufuz Exp
- * @link http://pear.php.net/package/Archive_Tar
+ * @category File_Formats
+ * @package Archive_Tar
+ * @author Vincent Blavet
+ * @copyright 1997-2010 The Authors
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @version CVS: $Id$
+ * @link http://pear.php.net/package/Archive_Tar
+ */
+
+ /**
+ * Note on Drupal 8 porting.
+ * This file origin is Tar.php, release 1.4.0 (stable) with some code
+ * from PEAR.php, release 1.9.5 (stable) both at http://pear.php.net.
+ * To simplify future porting from pear of this file, you should not
+ * do cosmetic or other non significant changes to this file.
+ * The following changes have been done:
+ * Added namespace Drupal\Core\Archiver.
+ * Removed require_once 'PEAR.php'.
+ * Added defintion of OS_WINDOWS taken from PEAR.php.
+ * Renamed class to ArchiveTar.
+ * Removed extends PEAR from class.
+ * Removed call parent:: __construct().
+ * Changed PEAR::loadExtension($extname) to this->loadExtension($extname).
+ * Added function loadExtension() taken from PEAR.php.
+ * Changed all calls of unlink() to drupal_unlink().
+ * Changed $this->error_object = &$this->raiseError($p_message)
+ * to throw new \Exception($p_message).
+ */
+
+ /**
+ * Note on Drupal 7 backporting from Drupal 8.
+ * File origin is core/lib/Drupal/Core/Archiver/ArchiveTar.php from Drupal 8.
+ * The following changes have been done:
+ * Removed namespace Drupal\Core\Archiver.
+ * Renamed class to Archive_Tar.
+ * Changed \Exception to Exception.
*/
-//require_once 'PEAR.php';
-//
-//
-define ('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
-define ('ARCHIVE_TAR_END_BLOCK', pack("a512", ''));
+
+// Drupal removal require_once 'PEAR.php'.
+
+// Drupal addition OS_WINDOWS as defined in PEAR.php.
+if (substr(PHP_OS, 0, 3) == 'WIN') {
+ define('OS_WINDOWS', true);
+} else {
+ define('OS_WINDOWS', false);
+}
+
+define('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
+define('ARCHIVE_TAR_END_BLOCK', pack("a512", ''));
+
+if (!function_exists('gzopen') && function_exists('gzopen64')) {
+ function gzopen($filename, $mode, $use_include_path = 0)
+ {
+ return gzopen64($filename, $mode, $use_include_path);
+ }
+}
+
+if (!function_exists('gztell') && function_exists('gztell64')) {
+ function gztell($zp)
+ {
+ return gztell64($zp);
+ }
+}
+
+if (!function_exists('gzseek') && function_exists('gzseek64')) {
+ function gzseek($zp, $offset, $whence = SEEK_SET)
+ {
+ return gzseek64($zp, $offset, $whence);
+ }
+}
/**
-* Creates a (compressed) Tar archive
-*
-* @author Vincent Blavet
-* @version Revision: 1.43
-* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
-* @package Archive_Tar
-*/
-class Archive_Tar // extends PEAR
+ * Creates a (compressed) Tar archive
+ *
+ * @package Archive_Tar
+ * @author Vincent Blavet
+ * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
+ * @version $Revision$
+ */
+// Drupal change class Archive_Tar extends PEAR.
+class Archive_Tar
{
/**
- * @var string Name of the Tar
- */
- var $_tarname='';
+ * @var string Name of the Tar
+ */
+ public $_tarname = '';
/**
- * @var boolean if true, the Tar file will be gzipped
- */
- var $_compress=false;
+ * @var boolean if true, the Tar file will be gzipped
+ */
+ public $_compress = false;
/**
- * @var string Type of compression : 'none', 'gz' or 'bz2'
- */
- var $_compress_type='none';
+ * @var string Type of compression : 'none', 'gz', 'bz2' or 'lzma2'
+ */
+ public $_compress_type = 'none';
/**
- * @var string Explode separator
- */
- var $_separator=' ';
+ * @var string Explode separator
+ */
+ public $_separator = ' ';
/**
- * @var file descriptor
- */
- var $_file=0;
+ * @var file descriptor
+ */
+ public $_file = 0;
/**
- * @var string Local Tar name of a remote Tar (http:// or ftp://)
- */
- var $_temp_tarname='';
+ * @var string Local Tar name of a remote Tar (http:// or ftp://)
+ */
+ public $_temp_tarname = '';
- // {{{ constructor
/**
- * Archive_Tar Class constructor. This flavour of the constructor only
- * declare a new Archive_Tar object, identifying it by the name of the
- * tar file.
- * If the compress argument is set the tar will be read or created as a
- * gzip or bz2 compressed TAR file.
- *
- * @param string $p_tarname The name of the tar archive to create
- * @param string $p_compress can be null, 'gz' or 'bz2'. This
- * parameter indicates if gzip or bz2 compression
- * is required. For compatibility reason the
- * boolean value 'true' means 'gz'.
- * @access public
- */
-// function Archive_Tar($p_tarname, $p_compress = null)
- function __construct($p_tarname, $p_compress = null)
+ * @var string regular expression for ignoring files or directories
+ */
+ public $_ignore_regexp = '';
+
+ /**
+ * @var object PEAR_Error object
+ */
+ public $error_object = null;
+
+ /**
+ * Archive_Tar Class constructor. This flavour of the constructor only
+ * declare a new Archive_Tar object, identifying it by the name of the
+ * tar file.
+ * If the compress argument is set the tar will be read or created as a
+ * gzip or bz2 compressed TAR file.
+ *
+ * @param string $p_tarname The name of the tar archive to create
+ * @param string $p_compress can be null, 'gz', 'bz2' or 'lzma2'. This
+ * parameter indicates if gzip, bz2 or lzma2 compression
+ * is required. For compatibility reason the
+ * boolean value 'true' means 'gz'.
+ *
+ * @return bool
+ */
+ public function __construct($p_tarname, $p_compress = null)
{
-// $this->PEAR();
+ // Drupal removal parent::__construct().
+
$this->_compress = false;
$this->_compress_type = 'none';
if (($p_compress === null) || ($p_compress == '')) {
@@ -116,10 +183,13 @@ class Archive_Tar // extends PEAR
if ($data == "\37\213") {
$this->_compress = true;
$this->_compress_type = 'gz';
- // No sure it's enought for a magic code ....
+ // No sure it's enought for a magic code ....
} elseif ($data == "BZ") {
$this->_compress = true;
$this->_compress_type = 'bz2';
+ } elseif (file_get_contents($p_tarname, false, null, 1, 4) == '7zXZ') {
+ $this->_compress = true;
+ $this->_compress_type = 'lzma2';
}
}
} else {
@@ -129,151 +199,177 @@ class Archive_Tar // extends PEAR
$this->_compress = true;
$this->_compress_type = 'gz';
} elseif ((substr($p_tarname, -3) == 'bz2') ||
- (substr($p_tarname, -2) == 'bz')) {
+ (substr($p_tarname, -2) == 'bz')
+ ) {
$this->_compress = true;
$this->_compress_type = 'bz2';
+ } else {
+ if (substr($p_tarname, -2) == 'xz') {
+ $this->_compress = true;
+ $this->_compress_type = 'lzma2';
+ }
}
}
} else {
if (($p_compress === true) || ($p_compress == 'gz')) {
$this->_compress = true;
$this->_compress_type = 'gz';
- } else if ($p_compress == 'bz2') {
- $this->_compress = true;
- $this->_compress_type = 'bz2';
} else {
- die("Unsupported compression type '$p_compress'\n".
- "Supported types are 'gz' and 'bz2'.\n");
- return false;
+ if ($p_compress == 'bz2') {
+ $this->_compress = true;
+ $this->_compress_type = 'bz2';
+ } else {
+ if ($p_compress == 'lzma2') {
+ $this->_compress = true;
+ $this->_compress_type = 'lzma2';
+ } else {
+ $this->_error(
+ "Unsupported compression type '$p_compress'\n" .
+ "Supported types are 'gz', 'bz2' and 'lzma2'.\n"
+ );
+ return false;
+ }
+ }
}
}
$this->_tarname = $p_tarname;
- if ($this->_compress) { // assert zlib or bz2 extension support
- if ($this->_compress_type == 'gz')
+ if ($this->_compress) { // assert zlib or bz2 or xz extension support
+ if ($this->_compress_type == 'gz') {
$extname = 'zlib';
- else if ($this->_compress_type == 'bz2')
- $extname = 'bz2';
+ } else {
+ if ($this->_compress_type == 'bz2') {
+ $extname = 'bz2';
+ } else {
+ if ($this->_compress_type == 'lzma2') {
+ $extname = 'xz';
+ }
+ }
+ }
if (!extension_loaded($extname)) {
-// PEAR::loadExtension($extname);
+ // Drupal change PEAR::loadExtension($extname).
$this->loadExtension($extname);
}
if (!extension_loaded($extname)) {
- die("The extension '$extname' couldn't be found.\n".
- "Please make sure your version of PHP was built ".
- "with '$extname' support.\n");
+ $this->_error(
+ "The extension '$extname' couldn't be found.\n" .
+ "Please make sure your version of PHP was built " .
+ "with '$extname' support.\n"
+ );
return false;
}
}
}
- // }}}
+ public function __destruct()
+ {
+ $this->_close();
+ // ----- Look for a local copy to delete
+ if ($this->_temp_tarname != '') {
+ @drupal_unlink($this->_temp_tarname);
+ }
+ }
+
+ // Drupal addition from PEAR.php.
/**
* OS independent PHP extension load. Remember to take care
* on the correct extension name for case sensitive OSes.
- * The function is the copy of PEAR::loadExtension().
*
* @param string $ext The extension name
* @return bool Success or not on the dl() call
*/
function loadExtension($ext)
{
- if (!extension_loaded($ext)) {
- // if either returns true dl() will produce a FATAL error, stop that
- if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) {
- return false;
- }
+ if (extension_loaded($ext)) {
+ return true;
+ }
- if (OS_WINDOWS) {
- $suffix = '.dll';
- } elseif (PHP_OS == 'HP-UX') {
- $suffix = '.sl';
- } elseif (PHP_OS == 'AIX') {
- $suffix = '.a';
- } elseif (PHP_OS == 'OSX') {
- $suffix = '.bundle';
- } else {
- $suffix = '.so';
- }
+ // if either returns true dl() will produce a FATAL error, stop that
+ if (
+ function_exists('dl') === false ||
+ ini_get('enable_dl') != 1 ||
+ ini_get('safe_mode') == 1
+ ) {
+ return false;
+ }
- return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix);
+ if (OS_WINDOWS) {
+ $suffix = '.dll';
+ } elseif (PHP_OS == 'HP-UX') {
+ $suffix = '.sl';
+ } elseif (PHP_OS == 'AIX') {
+ $suffix = '.a';
+ } elseif (PHP_OS == 'OSX') {
+ $suffix = '.bundle';
+ } else {
+ $suffix = '.so';
}
- return true;
+ return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix);
}
- // {{{ destructor
-// function _Archive_Tar()
- function __destruct()
- {
- $this->_close();
- // ----- Look for a local copy to delete
- if ($this->_temp_tarname != '')
- @drupal_unlink($this->_temp_tarname);
-// $this->_PEAR();
- }
- // }}}
-
- // {{{ create()
/**
- * This method creates the archive file and add the files / directories
- * that are listed in $p_filelist.
- * If a file with the same name exist and is writable, it is replaced
- * by the new tar.
- * The method return false and a PEAR error text.
- * The $p_filelist parameter can be an array of string, each string
- * representing a filename or a directory name with their path if
- * needed. It can also be a single string with names separated by a
- * single blank.
- * For each directory added in the archive, the files and
- * sub-directories are also added.
- * See also createModify() method for more details.
- *
- * @param array $p_filelist An array of filenames and directory names, or a
- * single string with names separated by a single
- * blank space.
- * @return true on success, false on error.
- * @see createModify()
- * @access public
- */
- function create($p_filelist)
+ * This method creates the archive file and add the files / directories
+ * that are listed in $p_filelist.
+ * If a file with the same name exist and is writable, it is replaced
+ * by the new tar.
+ * The method return false and a PEAR error text.
+ * The $p_filelist parameter can be an array of string, each string
+ * representing a filename or a directory name with their path if
+ * needed. It can also be a single string with names separated by a
+ * single blank.
+ * For each directory added in the archive, the files and
+ * sub-directories are also added.
+ * See also createModify() method for more details.
+ *
+ * @param array $p_filelist An array of filenames and directory names, or a
+ * single string with names separated by a single
+ * blank space.
+ *
+ * @return true on success, false on error.
+ * @see createModify()
+ */
+ public function create($p_filelist)
{
return $this->createModify($p_filelist, '', '');
}
- // }}}
- // {{{ add()
/**
- * This method add the files / directories that are listed in $p_filelist in
- * the archive. If the archive does not exist it is created.
- * The method return false and a PEAR error text.
- * The files and directories listed are only added at the end of the archive,
- * even if a file with the same name is already archived.
- * See also createModify() method for more details.
- *
- * @param array $p_filelist An array of filenames and directory names, or a
- * single string with names separated by a single
- * blank space.
- * @return true on success, false on error.
- * @see createModify()
- * @access public
- */
- function add($p_filelist)
+ * This method add the files / directories that are listed in $p_filelist in
+ * the archive. If the archive does not exist it is created.
+ * The method return false and a PEAR error text.
+ * The files and directories listed are only added at the end of the archive,
+ * even if a file with the same name is already archived.
+ * See also createModify() method for more details.
+ *
+ * @param array $p_filelist An array of filenames and directory names, or a
+ * single string with names separated by a single
+ * blank space.
+ *
+ * @return true on success, false on error.
+ * @see createModify()
+ * @access public
+ */
+ public function add($p_filelist)
{
return $this->addModify($p_filelist, '', '');
}
- // }}}
- // {{{ extract()
- function extract($p_path='')
+ /**
+ * @param string $p_path
+ * @param bool $p_preserve
+ * @return bool
+ */
+ public function extract($p_path = '', $p_preserve = false)
{
- return $this->extractModify($p_path, '');
+ return $this->extractModify($p_path, '', $p_preserve);
}
- // }}}
- // {{{ listContent()
- function listContent()
+ /**
+ * @return array|int
+ */
+ public function listContent()
{
$v_list_detail = array();
@@ -287,57 +383,56 @@ class Archive_Tar // extends PEAR
return $v_list_detail;
}
- // }}}
- // {{{ createModify()
/**
- * This method creates the archive file and add the files / directories
- * that are listed in $p_filelist.
- * If the file already exists and is writable, it is replaced by the
- * new tar. It is a create and not an add. If the file exists and is
- * read-only or is a directory it is not replaced. The method return
- * false and a PEAR error text.
- * The $p_filelist parameter can be an array of string, each string
- * representing a filename or a directory name with their path if
- * needed. It can also be a single string with names separated by a
- * single blank.
- * The path indicated in $p_remove_dir will be removed from the
- * memorized path of each file / directory listed when this path
- * exists. By default nothing is removed (empty path '')
- * The path indicated in $p_add_dir will be added at the beginning of
- * the memorized path of each file / directory listed. However it can
- * be set to empty ''. The adding of a path is done after the removing
- * of path.
- * The path add/remove ability enables the user to prepare an archive
- * for extraction in a different path than the origin files are.
- * See also addModify() method for file adding properties.
- *
- * @param array $p_filelist An array of filenames and directory names,
- * or a single string with names separated by
- * a single blank space.
- * @param string $p_add_dir A string which contains a path to be added
- * to the memorized path of each element in
- * the list.
- * @param string $p_remove_dir A string which contains a path to be
- * removed from the memorized path of each
- * element in the list, when relevant.
- * @return boolean true on success, false on error.
- * @access public
- * @see addModify()
- */
- function createModify($p_filelist, $p_add_dir, $p_remove_dir='')
+ * This method creates the archive file and add the files / directories
+ * that are listed in $p_filelist.
+ * If the file already exists and is writable, it is replaced by the
+ * new tar. It is a create and not an add. If the file exists and is
+ * read-only or is a directory it is not replaced. The method return
+ * false and a PEAR error text.
+ * The $p_filelist parameter can be an array of string, each string
+ * representing a filename or a directory name with their path if
+ * needed. It can also be a single string with names separated by a
+ * single blank.
+ * The path indicated in $p_remove_dir will be removed from the
+ * memorized path of each file / directory listed when this path
+ * exists. By default nothing is removed (empty path '')
+ * The path indicated in $p_add_dir will be added at the beginning of
+ * the memorized path of each file / directory listed. However it can
+ * be set to empty ''. The adding of a path is done after the removing
+ * of path.
+ * The path add/remove ability enables the user to prepare an archive
+ * for extraction in a different path than the origin files are.
+ * See also addModify() method for file adding properties.
+ *
+ * @param array $p_filelist An array of filenames and directory names,
+ * or a single string with names separated by
+ * a single blank space.
+ * @param string $p_add_dir A string which contains a path to be added
+ * to the memorized path of each element in
+ * the list.
+ * @param string $p_remove_dir A string which contains a path to be
+ * removed from the memorized path of each
+ * element in the list, when relevant.
+ *
+ * @return boolean true on success, false on error.
+ * @see addModify()
+ */
+ public function createModify($p_filelist, $p_add_dir, $p_remove_dir = '')
{
$v_result = true;
- if (!$this->_openWrite())
+ if (!$this->_openWrite()) {
return false;
+ }
if ($p_filelist != '') {
- if (is_array($p_filelist))
+ if (is_array($p_filelist)) {
$v_list = $p_filelist;
- elseif (is_string($p_filelist))
+ } elseif (is_string($p_filelist)) {
$v_list = explode($this->_separator, $p_filelist);
- else {
+ } else {
$this->_cleanFile();
$this->_error('Invalid file list');
return false;
@@ -349,67 +444,69 @@ class Archive_Tar // extends PEAR
if ($v_result) {
$this->_writeFooter();
$this->_close();
- } else
+ } else {
$this->_cleanFile();
+ }
return $v_result;
}
- // }}}
- // {{{ addModify()
/**
- * This method add the files / directories listed in $p_filelist at the
- * end of the existing archive. If the archive does not yet exists it
- * is created.
- * The $p_filelist parameter can be an array of string, each string
- * representing a filename or a directory name with their path if
- * needed. It can also be a single string with names separated by a
- * single blank.
- * The path indicated in $p_remove_dir will be removed from the
- * memorized path of each file / directory listed when this path
- * exists. By default nothing is removed (empty path '')
- * The path indicated in $p_add_dir will be added at the beginning of
- * the memorized path of each file / directory listed. However it can
- * be set to empty ''. The adding of a path is done after the removing
- * of path.
- * The path add/remove ability enables the user to prepare an archive
- * for extraction in a different path than the origin files are.
- * If a file/dir is already in the archive it will only be added at the
- * end of the archive. There is no update of the existing archived
- * file/dir. However while extracting the archive, the last file will
- * replace the first one. This results in a none optimization of the
- * archive size.
- * If a file/dir does not exist the file/dir is ignored. However an
- * error text is send to PEAR error.
- * If a file/dir is not readable the file/dir is ignored. However an
- * error text is send to PEAR error.
- *
- * @param array $p_filelist An array of filenames and directory
- * names, or a single string with names
- * separated by a single blank space.
- * @param string $p_add_dir A string which contains a path to be
- * added to the memorized path of each
- * element in the list.
- * @param string $p_remove_dir A string which contains a path to be
- * removed from the memorized path of
- * each element in the list, when
- * relevant.
- * @return true on success, false on error.
- * @access public
- */
- function addModify($p_filelist, $p_add_dir, $p_remove_dir='')
+ * This method add the files / directories listed in $p_filelist at the
+ * end of the existing archive. If the archive does not yet exists it
+ * is created.
+ * The $p_filelist parameter can be an array of string, each string
+ * representing a filename or a directory name with their path if
+ * needed. It can also be a single string with names separated by a
+ * single blank.
+ * The path indicated in $p_remove_dir will be removed from the
+ * memorized path of each file / directory listed when this path
+ * exists. By default nothing is removed (empty path '')
+ * The path indicated in $p_add_dir will be added at the beginning of
+ * the memorized path of each file / directory listed. However it can
+ * be set to empty ''. The adding of a path is done after the removing
+ * of path.
+ * The path add/remove ability enables the user to prepare an archive
+ * for extraction in a different path than the origin files are.
+ * If a file/dir is already in the archive it will only be added at the
+ * end of the archive. There is no update of the existing archived
+ * file/dir. However while extracting the archive, the last file will
+ * replace the first one. This results in a none optimization of the
+ * archive size.
+ * If a file/dir does not exist the file/dir is ignored. However an
+ * error text is send to PEAR error.
+ * If a file/dir is not readable the file/dir is ignored. However an
+ * error text is send to PEAR error.
+ *
+ * @param array $p_filelist An array of filenames and directory
+ * names, or a single string with names
+ * separated by a single blank space.
+ * @param string $p_add_dir A string which contains a path to be
+ * added to the memorized path of each
+ * element in the list.
+ * @param string $p_remove_dir A string which contains a path to be
+ * removed from the memorized path of
+ * each element in the list, when
+ * relevant.
+ *
+ * @return true on success, false on error.
+ */
+ public function addModify($p_filelist, $p_add_dir, $p_remove_dir = '')
{
$v_result = true;
- if (!$this->_isArchive())
- $v_result = $this->createModify($p_filelist, $p_add_dir,
- $p_remove_dir);
- else {
- if (is_array($p_filelist))
+ if (!$this->_isArchive()) {
+ $v_result = $this->createModify(
+ $p_filelist,
+ $p_add_dir,
+ $p_remove_dir
+ );
+ } else {
+ if (is_array($p_filelist)) {
$v_list = $p_filelist;
- elseif (is_string($p_filelist))
+ } elseif (is_string($p_filelist)) {
$v_list = explode($this->_separator, $p_filelist);
- else {
+ } else {
$this->_error('Invalid file list');
return false;
}
@@ -419,24 +516,41 @@ class Archive_Tar // extends PEAR
return $v_result;
}
- // }}}
- // {{{ addString()
/**
- * This method add a single string as a file at the
- * end of the existing archive. If the archive does not yet exists it
- * is created.
- *
- * @param string $p_filename A string which contains the full
- * filename path that will be associated
- * with the string.
- * @param string $p_string The content of the file added in
- * the archive.
- * @return true on success, false on error.
- * @access public
- */
- function addString($p_filename, $p_string)
+ * This method add a single string as a file at the
+ * end of the existing archive. If the archive does not yet exists it
+ * is created.
+ *
+ * @param string $p_filename A string which contains the full
+ * filename path that will be associated
+ * with the string.
+ * @param string $p_string The content of the file added in
+ * the archive.
+ * @param bool|int $p_datetime A custom date/time (unix timestamp)
+ * for the file (optional).
+ * @param array $p_params An array of optional params:
+ * stamp => the datetime (replaces
+ * datetime above if it exists)
+ * mode => the permissions on the
+ * file (600 by default)
+ * type => is this a link? See the
+ * tar specification for details.
+ * (default = regular file)
+ * uid => the user ID of the file
+ * (default = 0 = root)
+ * gid => the group ID of the file
+ * (default = 0 = root)
+ *
+ * @return true on success, false on error.
+ */
+ public function addString($p_filename, $p_string, $p_datetime = false, $p_params = array())
{
+ $p_stamp = @$p_params["stamp"] ? $p_params["stamp"] : ($p_datetime ? $p_datetime : time());
+ $p_mode = @$p_params["mode"] ? $p_params["mode"] : 0600;
+ $p_type = @$p_params["type"] ? $p_params["type"] : "";
+ $p_uid = @$p_params["uid"] ? $p_params["uid"] : "";
+ $p_gid = @$p_params["gid"] ? $p_params["gid"] : "";
$v_result = true;
if (!$this->_isArchive()) {
@@ -446,11 +560,12 @@ class Archive_Tar // extends PEAR
$this->_close();
}
- if (!$this->_openAppend())
+ if (!$this->_openAppend()) {
return false;
+ }
// Need to check the get back to the temporary file ? ....
- $v_result = $this->_addString($p_filename, $p_string);
+ $v_result = $this->_addString($p_filename, $p_string, $p_datetime, $p_params);
$this->_writeFooter();
@@ -458,131 +573,138 @@ class Archive_Tar // extends PEAR
return $v_result;
}
- // }}}
- // {{{ extractModify()
/**
- * This method extract all the content of the archive in the directory
- * indicated by $p_path. When relevant the memorized path of the
- * files/dir can be modified by removing the $p_remove_path path at the
- * beginning of the file/dir path.
- * While extracting a file, if the directory path does not exists it is
- * created.
- * While extracting a file, if the file already exists it is replaced
- * without looking for last modification date.
- * While extracting a file, if the file already exists and is write
- * protected, the extraction is aborted.
- * While extracting a file, if a directory with the same name already
- * exists, the extraction is aborted.
- * While extracting a directory, if a file with the same name already
- * exists, the extraction is aborted.
- * While extracting a file/directory if the destination directory exist
- * and is write protected, or does not exist but can not be created,
- * the extraction is aborted.
- * If after extraction an extracted file does not show the correct
- * stored file size, the extraction is aborted.
- * When the extraction is aborted, a PEAR error text is set and false
- * is returned. However the result can be a partial extraction that may
- * need to be manually cleaned.
- *
- * @param string $p_path The path of the directory where the
- * files/dir need to by extracted.
- * @param string $p_remove_path Part of the memorized path that can be
- * removed if present at the beginning of
- * the file/dir path.
- * @return boolean true on success, false on error.
- * @access public
- * @see extractList()
- */
- function extractModify($p_path, $p_remove_path)
+ * This method extract all the content of the archive in the directory
+ * indicated by $p_path. When relevant the memorized path of the
+ * files/dir can be modified by removing the $p_remove_path path at the
+ * beginning of the file/dir path.
+ * While extracting a file, if the directory path does not exists it is
+ * created.
+ * While extracting a file, if the file already exists it is replaced
+ * without looking for last modification date.
+ * While extracting a file, if the file already exists and is write
+ * protected, the extraction is aborted.
+ * While extracting a file, if a directory with the same name already
+ * exists, the extraction is aborted.
+ * While extracting a directory, if a file with the same name already
+ * exists, the extraction is aborted.
+ * While extracting a file/directory if the destination directory exist
+ * and is write protected, or does not exist but can not be created,
+ * the extraction is aborted.
+ * If after extraction an extracted file does not show the correct
+ * stored file size, the extraction is aborted.
+ * When the extraction is aborted, a PEAR error text is set and false
+ * is returned. However the result can be a partial extraction that may
+ * need to be manually cleaned.
+ *
+ * @param string $p_path The path of the directory where the
+ * files/dir need to by extracted.
+ * @param string $p_remove_path Part of the memorized path that can be
+ * removed if present at the beginning of
+ * the file/dir path.
+ * @param boolean $p_preserve Preserve user/group ownership of files
+ *
+ * @return boolean true on success, false on error.
+ * @see extractList()
+ */
+ public function extractModify($p_path, $p_remove_path, $p_preserve = false)
{
$v_result = true;
$v_list_detail = array();
if ($v_result = $this->_openRead()) {
- $v_result = $this->_extractList($p_path, $v_list_detail,
- "complete", 0, $p_remove_path);
+ $v_result = $this->_extractList(
+ $p_path,
+ $v_list_detail,
+ "complete",
+ 0,
+ $p_remove_path,
+ $p_preserve
+ );
$this->_close();
}
return $v_result;
}
- // }}}
- // {{{ extractInString()
/**
- * This method extract from the archive one file identified by $p_filename.
- * The return value is a string with the file content, or NULL on error.
- * @param string $p_filename The path of the file to extract in a string.
- * @return a string with the file content or NULL.
- * @access public
- */
- function extractInString($p_filename)
+ * This method extract from the archive one file identified by $p_filename.
+ * The return value is a string with the file content, or NULL on error.
+ *
+ * @param string $p_filename The path of the file to extract in a string.
+ *
+ * @return a string with the file content or NULL.
+ */
+ public function extractInString($p_filename)
{
if ($this->_openRead()) {
$v_result = $this->_extractInString($p_filename);
$this->_close();
} else {
- $v_result = NULL;
+ $v_result = null;
}
return $v_result;
}
- // }}}
- // {{{ extractList()
/**
- * This method extract from the archive only the files indicated in the
- * $p_filelist. These files are extracted in the current directory or
- * in the directory indicated by the optional $p_path parameter.
- * If indicated the $p_remove_path can be used in the same way as it is
- * used in extractModify() method.
- * @param array $p_filelist An array of filenames and directory names,
- * or a single string with names separated
- * by a single blank space.
- * @param string $p_path The path of the directory where the
- * files/dir need to by extracted.
- * @param string $p_remove_path Part of the memorized path that can be
- * removed if present at the beginning of
- * the file/dir path.
- * @return true on success, false on error.
- * @access public
- * @see extractModify()
- */
- function extractList($p_filelist, $p_path='', $p_remove_path='')
+ * This method extract from the archive only the files indicated in the
+ * $p_filelist. These files are extracted in the current directory or
+ * in the directory indicated by the optional $p_path parameter.
+ * If indicated the $p_remove_path can be used in the same way as it is
+ * used in extractModify() method.
+ *
+ * @param array $p_filelist An array of filenames and directory names,
+ * or a single string with names separated
+ * by a single blank space.
+ * @param string $p_path The path of the directory where the
+ * files/dir need to by extracted.
+ * @param string $p_remove_path Part of the memorized path that can be
+ * removed if present at the beginning of
+ * the file/dir path.
+ * @param boolean $p_preserve Preserve user/group ownership of files
+ *
+ * @return true on success, false on error.
+ * @see extractModify()
+ */
+ public function extractList($p_filelist, $p_path = '', $p_remove_path = '', $p_preserve = false)
{
$v_result = true;
$v_list_detail = array();
- if (is_array($p_filelist))
+ if (is_array($p_filelist)) {
$v_list = $p_filelist;
- elseif (is_string($p_filelist))
+ } elseif (is_string($p_filelist)) {
$v_list = explode($this->_separator, $p_filelist);
- else {
+ } else {
$this->_error('Invalid string list');
return false;
}
if ($v_result = $this->_openRead()) {
- $v_result = $this->_extractList($p_path, $v_list_detail, "partial",
- $v_list, $p_remove_path);
+ $v_result = $this->_extractList(
+ $p_path,
+ $v_list_detail,
+ "partial",
+ $v_list,
+ $p_remove_path,
+ $p_preserve
+ );
$this->_close();
}
return $v_result;
}
- // }}}
- // {{{ setAttribute()
/**
- * This method set specific attributes of the archive. It uses a variable
- * list of parameters, in the format attribute code + attribute values :
- * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');
- * @param mixed $argv variable list of attributes and values
- * @return true on success, false on error.
- * @access public
- */
- function setAttribute()
+ * This method set specific attributes of the archive. It uses a variable
+ * list of parameters, in the format attribute code + attribute values :
+ * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');
+ *
+ * @return true on success, false on error.
+ */
+ public function setAttribute()
{
$v_result = true;
@@ -592,30 +714,32 @@ class Archive_Tar // extends PEAR
}
// ----- Get the arguments
- $v_att_list = &func_get_args();
+ $v_att_list = & func_get_args();
// ----- Read the attributes
- $i=0;
- while ($i<$v_size) {
+ $i = 0;
+ while ($i < $v_size) {
// ----- Look for next option
switch ($v_att_list[$i]) {
// ----- Look for options that request a string value
case ARCHIVE_TAR_ATT_SEPARATOR :
// ----- Check the number of parameters
- if (($i+1) >= $v_size) {
- $this->_error('Invalid number of parameters for '
- .'attribute ARCHIVE_TAR_ATT_SEPARATOR');
+ if (($i + 1) >= $v_size) {
+ $this->_error(
+ 'Invalid number of parameters for '
+ . 'attribute ARCHIVE_TAR_ATT_SEPARATOR'
+ );
return false;
}
// ----- Get the value
- $this->_separator = $v_att_list[$i+1];
+ $this->_separator = $v_att_list[$i + 1];
$i++;
- break;
+ break;
default :
- $this->_error('Unknow attribute code '.$v_att_list[$i].'');
+ $this->_error('Unknown attribute code ' . $v_att_list[$i] . '');
return false;
}
@@ -625,151 +749,248 @@ class Archive_Tar // extends PEAR
return $v_result;
}
- // }}}
- // {{{ _error()
- function _error($p_message)
+ /**
+ * This method sets the regular expression for ignoring files and directories
+ * at import, for example:
+ * $arch->setIgnoreRegexp("#CVS|\.svn#");
+ *
+ * @param string $regexp regular expression defining which files or directories to ignore
+ */
+ public function setIgnoreRegexp($regexp)
+ {
+ $this->_ignore_regexp = $regexp;
+ }
+
+ /**
+ * This method sets the regular expression for ignoring all files and directories
+ * matching the filenames in the array list at import, for example:
+ * $arch->setIgnoreList(array('CVS', '.svn', 'bin/tool'));
+ *
+ * @param array $list a list of file or directory names to ignore
+ *
+ * @access public
+ */
+ public function setIgnoreList($list)
+ {
+ $regexp = str_replace(array('#', '.', '^', '$'), array('\#', '\.', '\^', '\$'), $list);
+ $regexp = '#/' . join('$|/', $list) . '#';
+ $this->setIgnoreRegexp($regexp);
+ }
+
+ /**
+ * @param string $p_message
+ */
+ public function _error($p_message)
{
- // ----- To be completed
-// $this->raiseError($p_message);
+ // Drupal change $this->error_object = $this->raiseError($p_message).
throw new Exception($p_message);
}
- // }}}
- // {{{ _warning()
- function _warning($p_message)
+ /**
+ * @param string $p_message
+ */
+ public function _warning($p_message)
{
- // ----- To be completed
-// $this->raiseError($p_message);
+ // Drupal change $this->error_object = $this->raiseError($p_message).
throw new Exception($p_message);
}
- // }}}
- // {{{ _isArchive()
- function _isArchive($p_filename=NULL)
+ /**
+ * @param string $p_filename
+ * @return bool
+ */
+ public function _isArchive($p_filename = null)
{
- if ($p_filename == NULL) {
+ if ($p_filename == null) {
$p_filename = $this->_tarname;
}
clearstatcache();
return @is_file($p_filename) && !@is_link($p_filename);
}
- // }}}
- // {{{ _openWrite()
- function _openWrite()
+ /**
+ * @return bool
+ */
+ public function _openWrite()
{
- if ($this->_compress_type == 'gz')
+ if ($this->_compress_type == 'gz' && function_exists('gzopen')) {
$this->_file = @gzopen($this->_tarname, "wb9");
- else if ($this->_compress_type == 'bz2')
- $this->_file = @bzopen($this->_tarname, "w");
- else if ($this->_compress_type == 'none')
- $this->_file = @fopen($this->_tarname, "wb");
- else
- $this->_error('Unknown or missing compression type ('
- .$this->_compress_type.')');
+ } else {
+ if ($this->_compress_type == 'bz2' && function_exists('bzopen')) {
+ $this->_file = @bzopen($this->_tarname, "w");
+ } else {
+ if ($this->_compress_type == 'lzma2' && function_exists('xzopen')) {
+ $this->_file = @xzopen($this->_tarname, 'w');
+ } else {
+ if ($this->_compress_type == 'none') {
+ $this->_file = @fopen($this->_tarname, "wb");
+ } else {
+ $this->_error(
+ 'Unknown or missing compression type ('
+ . $this->_compress_type . ')'
+ );
+ return false;
+ }
+ }
+ }
+ }
if ($this->_file == 0) {
- $this->_error('Unable to open in write mode \''
- .$this->_tarname.'\'');
+ $this->_error(
+ 'Unable to open in write mode \''
+ . $this->_tarname . '\''
+ );
return false;
}
return true;
}
- // }}}
- // {{{ _openRead()
- function _openRead()
+ /**
+ * @return bool
+ */
+ public function _openRead()
{
if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
- // ----- Look if a local copy need to be done
- if ($this->_temp_tarname == '') {
- $this->_temp_tarname = uniqid('tar').'.tmp';
- if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
- $this->_error('Unable to open in read mode \''
- .$this->_tarname.'\'');
- $this->_temp_tarname = '';
- return false;
- }
- if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
- $this->_error('Unable to open in write mode \''
- .$this->_temp_tarname.'\'');
- $this->_temp_tarname = '';
- return false;
- }
- while ($v_data = @fread($v_file_from, 1024))
- @fwrite($v_file_to, $v_data);
- @fclose($v_file_from);
- @fclose($v_file_to);
- }
+ // ----- Look if a local copy need to be done
+ if ($this->_temp_tarname == '') {
+ $this->_temp_tarname = uniqid('tar') . '.tmp';
+ if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
+ $this->_error(
+ 'Unable to open in read mode \''
+ . $this->_tarname . '\''
+ );
+ $this->_temp_tarname = '';
+ return false;
+ }
+ if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
+ $this->_error(
+ 'Unable to open in write mode \''
+ . $this->_temp_tarname . '\''
+ );
+ $this->_temp_tarname = '';
+ return false;
+ }
+ while ($v_data = @fread($v_file_from, 1024)) {
+ @fwrite($v_file_to, $v_data);
+ }
+ @fclose($v_file_from);
+ @fclose($v_file_to);
+ }
- // ----- File to open if the local copy
- $v_filename = $this->_temp_tarname;
+ // ----- File to open if the local copy
+ $v_filename = $this->_temp_tarname;
+ } else {
+ // ----- File to open if the normal Tar file
- } else
- // ----- File to open if the normal Tar file
- $v_filename = $this->_tarname;
+ $v_filename = $this->_tarname;
+ }
- if ($this->_compress_type == 'gz')
+ if ($this->_compress_type == 'gz' && function_exists('gzopen')) {
$this->_file = @gzopen($v_filename, "rb");
- else if ($this->_compress_type == 'bz2')
- $this->_file = @bzopen($v_filename, "r");
- else if ($this->_compress_type == 'none')
- $this->_file = @fopen($v_filename, "rb");
- else
- $this->_error('Unknown or missing compression type ('
- .$this->_compress_type.')');
+ } else {
+ if ($this->_compress_type == 'bz2' && function_exists('bzopen')) {
+ $this->_file = @bzopen($v_filename, "r");
+ } else {
+ if ($this->_compress_type == 'lzma2' && function_exists('xzopen')) {
+ $this->_file = @xzopen($v_filename, "r");
+ } else {
+ if ($this->_compress_type == 'none') {
+ $this->_file = @fopen($v_filename, "rb");
+ } else {
+ $this->_error(
+ 'Unknown or missing compression type ('
+ . $this->_compress_type . ')'
+ );
+ return false;
+ }
+ }
+ }
+ }
if ($this->_file == 0) {
- $this->_error('Unable to open in read mode \''.$v_filename.'\'');
+ $this->_error('Unable to open in read mode \'' . $v_filename . '\'');
return false;
}
return true;
}
- // }}}
- // {{{ _openReadWrite()
- function _openReadWrite()
+ /**
+ * @return bool
+ */
+ public function _openReadWrite()
{
- if ($this->_compress_type == 'gz')
+ if ($this->_compress_type == 'gz') {
$this->_file = @gzopen($this->_tarname, "r+b");
- else if ($this->_compress_type == 'bz2') {
- $this->_error('Unable to open bz2 in read/write mode \''
- .$this->_tarname.'\' (limitation of bz2 extension)');
- return false;
- } else if ($this->_compress_type == 'none')
- $this->_file = @fopen($this->_tarname, "r+b");
- else
- $this->_error('Unknown or missing compression type ('
- .$this->_compress_type.')');
+ } else {
+ if ($this->_compress_type == 'bz2') {
+ $this->_error(
+ 'Unable to open bz2 in read/write mode \''
+ . $this->_tarname . '\' (limitation of bz2 extension)'
+ );
+ return false;
+ } else {
+ if ($this->_compress_type == 'lzma2') {
+ $this->_error(
+ 'Unable to open lzma2 in read/write mode \''
+ . $this->_tarname . '\' (limitation of lzma2 extension)'
+ );
+ return false;
+ } else {
+ if ($this->_compress_type == 'none') {
+ $this->_file = @fopen($this->_tarname, "r+b");
+ } else {
+ $this->_error(
+ 'Unknown or missing compression type ('
+ . $this->_compress_type . ')'
+ );
+ return false;
+ }
+ }
+ }
+ }
if ($this->_file == 0) {
- $this->_error('Unable to open in read/write mode \''
- .$this->_tarname.'\'');
+ $this->_error(
+ 'Unable to open in read/write mode \''
+ . $this->_tarname . '\''
+ );
return false;
}
return true;
}
- // }}}
- // {{{ _close()
- function _close()
+ /**
+ * @return bool
+ */
+ public function _close()
{
//if (isset($this->_file)) {
if (is_resource($this->_file)) {
- if ($this->_compress_type == 'gz')
+ if ($this->_compress_type == 'gz') {
@gzclose($this->_file);
- else if ($this->_compress_type == 'bz2')
- @bzclose($this->_file);
- else if ($this->_compress_type == 'none')
- @fclose($this->_file);
- else
- $this->_error('Unknown or missing compression type ('
- .$this->_compress_type.')');
+ } else {
+ if ($this->_compress_type == 'bz2') {
+ @bzclose($this->_file);
+ } else {
+ if ($this->_compress_type == 'lzma2') {
+ @xzclose($this->_file);
+ } else {
+ if ($this->_compress_type == 'none') {
+ @fclose($this->_file);
+ } else {
+ $this->_error(
+ 'Unknown or missing compression type ('
+ . $this->_compress_type . ')'
+ );
+ }
+ }
+ }
+ }
$this->_file = 0;
}
@@ -783,10 +1004,11 @@ class Archive_Tar // extends PEAR
return true;
}
- // }}}
- // {{{ _cleanFile()
- function _cleanFile()
+ /**
+ * @return bool
+ */
+ public function _cleanFile()
{
$this->_close();
@@ -803,296 +1025,419 @@ class Archive_Tar // extends PEAR
return true;
}
- // }}}
- // {{{ _writeBlock()
- function _writeBlock($p_binary_data, $p_len=null)
+ /**
+ * @param mixed $p_binary_data
+ * @param integer $p_len
+ * @return bool
+ */
+ public function _writeBlock($p_binary_data, $p_len = null)
{
- if (is_resource($this->_file)) {
- if ($p_len === null) {
- if ($this->_compress_type == 'gz')
- @gzputs($this->_file, $p_binary_data);
- else if ($this->_compress_type == 'bz2')
- @bzwrite($this->_file, $p_binary_data);
- else if ($this->_compress_type == 'none')
- @fputs($this->_file, $p_binary_data);
- else
- $this->_error('Unknown or missing compression type ('
- .$this->_compress_type.')');
- } else {
- if ($this->_compress_type == 'gz')
- @gzputs($this->_file, $p_binary_data, $p_len);
- else if ($this->_compress_type == 'bz2')
- @bzwrite($this->_file, $p_binary_data, $p_len);
- else if ($this->_compress_type == 'none')
- @fputs($this->_file, $p_binary_data, $p_len);
- else
- $this->_error('Unknown or missing compression type ('
- .$this->_compress_type.')');
-
- }
- }
- return true;
+ if (is_resource($this->_file)) {
+ if ($p_len === null) {
+ if ($this->_compress_type == 'gz') {
+ @gzputs($this->_file, $p_binary_data);
+ } else {
+ if ($this->_compress_type == 'bz2') {
+ @bzwrite($this->_file, $p_binary_data);
+ } else {
+ if ($this->_compress_type == 'lzma2') {
+ @xzwrite($this->_file, $p_binary_data);
+ } else {
+ if ($this->_compress_type == 'none') {
+ @fputs($this->_file, $p_binary_data);
+ } else {
+ $this->_error(
+ 'Unknown or missing compression type ('
+ . $this->_compress_type . ')'
+ );
+ }
+ }
+ }
+ }
+ } else {
+ if ($this->_compress_type == 'gz') {
+ @gzputs($this->_file, $p_binary_data, $p_len);
+ } else {
+ if ($this->_compress_type == 'bz2') {
+ @bzwrite($this->_file, $p_binary_data, $p_len);
+ } else {
+ if ($this->_compress_type == 'lzma2') {
+ @xzwrite($this->_file, $p_binary_data, $p_len);
+ } else {
+ if ($this->_compress_type == 'none') {
+ @fputs($this->_file, $p_binary_data, $p_len);
+ } else {
+ $this->_error(
+ 'Unknown or missing compression type ('
+ . $this->_compress_type . ')'
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
}
- // }}}
- // {{{ _readBlock()
- function _readBlock()
+ /**
+ * @return null|string
+ */
+ public function _readBlock()
{
- $v_block = null;
- if (is_resource($this->_file)) {
- if ($this->_compress_type == 'gz')
- $v_block = @gzread($this->_file, 512);
- else if ($this->_compress_type == 'bz2')
- $v_block = @bzread($this->_file, 512);
- else if ($this->_compress_type == 'none')
- $v_block = @fread($this->_file, 512);
- else
- $this->_error('Unknown or missing compression type ('
- .$this->_compress_type.')');
- }
- return $v_block;
+ $v_block = null;
+ if (is_resource($this->_file)) {
+ if ($this->_compress_type == 'gz') {
+ $v_block = @gzread($this->_file, 512);
+ } else {
+ if ($this->_compress_type == 'bz2') {
+ $v_block = @bzread($this->_file, 512);
+ } else {
+ if ($this->_compress_type == 'lzma2') {
+ $v_block = @xzread($this->_file, 512);
+ } else {
+ if ($this->_compress_type == 'none') {
+ $v_block = @fread($this->_file, 512);
+ } else {
+ $this->_error(
+ 'Unknown or missing compression type ('
+ . $this->_compress_type . ')'
+ );
+ }
+ }
+ }
+ }
+ }
+ return $v_block;
}
- // }}}
- // {{{ _jumpBlock()
- function _jumpBlock($p_len=null)
- {
- if (is_resource($this->_file)) {
- if ($p_len === null)
- $p_len = 1;
-
- if ($this->_compress_type == 'gz') {
- @gzseek($this->_file, gztell($this->_file)+($p_len*512));
- }
- else if ($this->_compress_type == 'bz2') {
- // ----- Replace missing bztell() and bzseek()
- for ($i=0; $i<$p_len; $i++)
- $this->_readBlock();
- } else if ($this->_compress_type == 'none')
- @fseek($this->_file, ftell($this->_file)+($p_len*512));
- else
- $this->_error('Unknown or missing compression type ('
- .$this->_compress_type.')');
-
- }
- return true;
- }
- // }}}
+ /**
+ * @param null $p_len
+ * @return bool
+ */
+ public function _jumpBlock($p_len = null)
+ {
+ if (is_resource($this->_file)) {
+ if ($p_len === null) {
+ $p_len = 1;
+ }
+
+ if ($this->_compress_type == 'gz') {
+ @gzseek($this->_file, gztell($this->_file) + ($p_len * 512));
+ } else {
+ if ($this->_compress_type == 'bz2') {
+ // ----- Replace missing bztell() and bzseek()
+ for ($i = 0; $i < $p_len; $i++) {
+ $this->_readBlock();
+ }
+ } else {
+ if ($this->_compress_type == 'lzma2') {
+ // ----- Replace missing xztell() and xzseek()
+ for ($i = 0; $i < $p_len; $i++) {
+ $this->_readBlock();
+ }
+ } else {
+ if ($this->_compress_type == 'none') {
+ @fseek($this->_file, $p_len * 512, SEEK_CUR);
+ } else {
+ $this->_error(
+ 'Unknown or missing compression type ('
+ . $this->_compress_type . ')'
+ );
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @return bool
+ */
+ public function _writeFooter()
+ {
+ if (is_resource($this->_file)) {
+ // ----- Write the last 0 filled block for end of archive
+ $v_binary_data = pack('a1024', '');
+ $this->_writeBlock($v_binary_data);
+ }
+ return true;
+ }
+
+ /**
+ * @param array $p_list
+ * @param string $p_add_dir
+ * @param string $p_remove_dir
+ * @return bool
+ */
+ public function _addList($p_list, $p_add_dir, $p_remove_dir)
+ {
+ $v_result = true;
+ $v_header = array();
+
+ // ----- Remove potential windows directory separator
+ $p_add_dir = $this->_translateWinPath($p_add_dir);
+ $p_remove_dir = $this->_translateWinPath($p_remove_dir, false);
+
+ if (!$this->_file) {
+ $this->_error('Invalid file descriptor');
+ return false;
+ }
+
+ if (sizeof($p_list) == 0) {
+ return true;
+ }
+
+ foreach ($p_list as $v_filename) {
+ if (!$v_result) {
+ break;
+ }
+
+ // ----- Skip the current tar name
+ if ($v_filename == $this->_tarname) {
+ continue;
+ }
+
+ if ($v_filename == '') {
+ continue;
+ }
+
+ // ----- ignore files and directories matching the ignore regular expression
+ if ($this->_ignore_regexp && preg_match($this->_ignore_regexp, '/' . $v_filename)) {
+ $this->_warning("File '$v_filename' ignored");
+ continue;
+ }
+
+ if (!file_exists($v_filename) && !is_link($v_filename)) {
+ $this->_warning("File '$v_filename' does not exist");
+ continue;
+ }
+
+ // ----- Add the file or directory header
+ if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir)) {
+ return false;
+ }
+
+ if (@is_dir($v_filename) && !@is_link($v_filename)) {
+ if (!($p_hdir = opendir($v_filename))) {
+ $this->_warning("Directory '$v_filename' can not be read");
+ continue;
+ }
+ while (false !== ($p_hitem = readdir($p_hdir))) {
+ if (($p_hitem != '.') && ($p_hitem != '..')) {
+ if ($v_filename != ".") {
+ $p_temp_list[0] = $v_filename . '/' . $p_hitem;
+ } else {
+ $p_temp_list[0] = $p_hitem;
+ }
+
+ $v_result = $this->_addList(
+ $p_temp_list,
+ $p_add_dir,
+ $p_remove_dir
+ );
+ }
+ }
+
+ unset($p_temp_list);
+ unset($p_hdir);
+ unset($p_hitem);
+ }
+ }
- // {{{ _writeFooter()
- function _writeFooter()
- {
- if (is_resource($this->_file)) {
- // ----- Write the last 0 filled block for end of archive
- $v_binary_data = pack('a1024', '');
- $this->_writeBlock($v_binary_data);
- }
- return true;
+ return $v_result;
}
- // }}}
- // {{{ _addList()
- function _addList($p_list, $p_add_dir, $p_remove_dir)
+ /**
+ * @param string $p_filename
+ * @param mixed $p_header
+ * @param string $p_add_dir
+ * @param string $p_remove_dir
+ * @param null $v_stored_filename
+ * @return bool
+ */
+ public function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir, $v_stored_filename = null)
{
- $v_result=true;
- $v_header = array();
+ if (!$this->_file) {
+ $this->_error('Invalid file descriptor');
+ return false;
+ }
- // ----- Remove potential windows directory separator
- $p_add_dir = $this->_translateWinPath($p_add_dir);
- $p_remove_dir = $this->_translateWinPath($p_remove_dir, false);
+ if ($p_filename == '') {
+ $this->_error('Invalid file name');
+ return false;
+ }
- if (!$this->_file) {
- $this->_error('Invalid file descriptor');
- return false;
- }
+ if (is_null($v_stored_filename)) {
+ // ----- Calculate the stored filename
+ $p_filename = $this->_translateWinPath($p_filename, false);
+ $v_stored_filename = $p_filename;
- if (sizeof($p_list) == 0)
- return true;
+ if (strcmp($p_filename, $p_remove_dir) == 0) {
+ return true;
+ }
- foreach ($p_list as $v_filename) {
- if (!$v_result) {
- break;
- }
+ if ($p_remove_dir != '') {
+ if (substr($p_remove_dir, -1) != '/') {
+ $p_remove_dir .= '/';
+ }
- // ----- Skip the current tar name
- if ($v_filename == $this->_tarname)
- continue;
+ if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) {
+ $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
+ }
+ }
- if ($v_filename == '')
- continue;
+ $v_stored_filename = $this->_translateWinPath($v_stored_filename);
+ if ($p_add_dir != '') {
+ if (substr($p_add_dir, -1) == '/') {
+ $v_stored_filename = $p_add_dir . $v_stored_filename;
+ } else {
+ $v_stored_filename = $p_add_dir . '/' . $v_stored_filename;
+ }
+ }
- if (!file_exists($v_filename)) {
- $this->_warning("File '$v_filename' does not exist");
- continue;
+ $v_stored_filename = $this->_pathReduction($v_stored_filename);
}
- // ----- Add the file or directory header
- if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir))
- return false;
+ if ($this->_isArchive($p_filename)) {
+ if (($v_file = @fopen($p_filename, "rb")) == 0) {
+ $this->_warning(
+ "Unable to open file '" . $p_filename
+ . "' in binary read mode"
+ );
+ return true;
+ }
- if (@is_dir($v_filename) && !@is_link($v_filename)) {
- if (!($p_hdir = opendir($v_filename))) {
- $this->_warning("Directory '$v_filename' can not be read");
- continue;
+ if (!$this->_writeHeader($p_filename, $v_stored_filename)) {
+ return false;
}
- while (false !== ($p_hitem = readdir($p_hdir))) {
- if (($p_hitem != '.') && ($p_hitem != '..')) {
- if ($v_filename != ".")
- $p_temp_list[0] = $v_filename.'/'.$p_hitem;
- else
- $p_temp_list[0] = $p_hitem;
-
- $v_result = $this->_addList($p_temp_list,
- $p_add_dir,
- $p_remove_dir);
- }
+
+ while (($v_buffer = fread($v_file, 512)) != '') {
+ $v_binary_data = pack("a512", "$v_buffer");
+ $this->_writeBlock($v_binary_data);
}
- unset($p_temp_list);
- unset($p_hdir);
- unset($p_hitem);
+ fclose($v_file);
+ } else {
+ // ----- Only header for dir
+ if (!$this->_writeHeader($p_filename, $v_stored_filename)) {
+ return false;
+ }
}
- }
- return $v_result;
+ return true;
}
- // }}}
- // {{{ _addFile()
- function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir)
+ /**
+ * @param string $p_filename
+ * @param string $p_string
+ * @param bool $p_datetime
+ * @param array $p_params
+ * @return bool
+ */
+ public function _addString($p_filename, $p_string, $p_datetime = false, $p_params = array())
{
- if (!$this->_file) {
- $this->_error('Invalid file descriptor');
- return false;
- }
-
- if ($p_filename == '') {
- $this->_error('Invalid file name');
- return false;
- }
-
- // ----- Calculate the stored filename
- $p_filename = $this->_translateWinPath($p_filename, false);;
- $v_stored_filename = $p_filename;
- if (strcmp($p_filename, $p_remove_dir) == 0) {
- return true;
- }
- if ($p_remove_dir != '') {
- if (substr($p_remove_dir, -1) != '/')
- $p_remove_dir .= '/';
-
- if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir)
- $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
- }
- $v_stored_filename = $this->_translateWinPath($v_stored_filename);
- if ($p_add_dir != '') {
- if (substr($p_add_dir, -1) == '/')
- $v_stored_filename = $p_add_dir.$v_stored_filename;
- else
- $v_stored_filename = $p_add_dir.'/'.$v_stored_filename;
- }
-
- $v_stored_filename = $this->_pathReduction($v_stored_filename);
-
- if ($this->_isArchive($p_filename)) {
- if (($v_file = @fopen($p_filename, "rb")) == 0) {
- $this->_warning("Unable to open file '".$p_filename
- ."' in binary read mode");
- return true;
- }
-
- if (!$this->_writeHeader($p_filename, $v_stored_filename))
- return false;
-
- while (($v_buffer = fread($v_file, 512)) != '') {
- $v_binary_data = pack("a512", "$v_buffer");
- $this->_writeBlock($v_binary_data);
- }
-
- fclose($v_file);
-
- } else {
- // ----- Only header for dir
- if (!$this->_writeHeader($p_filename, $v_stored_filename))
- return false;
- }
-
- return true;
- }
- // }}}
+ $p_stamp = @$p_params["stamp"] ? $p_params["stamp"] : ($p_datetime ? $p_datetime : time());
+ $p_mode = @$p_params["mode"] ? $p_params["mode"] : 0600;
+ $p_type = @$p_params["type"] ? $p_params["type"] : "";
+ $p_uid = @$p_params["uid"] ? $p_params["uid"] : 0;
+ $p_gid = @$p_params["gid"] ? $p_params["gid"] : 0;
+ if (!$this->_file) {
+ $this->_error('Invalid file descriptor');
+ return false;
+ }
- // {{{ _addString()
- function _addString($p_filename, $p_string)
- {
- if (!$this->_file) {
- $this->_error('Invalid file descriptor');
- return false;
- }
-
- if ($p_filename == '') {
- $this->_error('Invalid file name');
- return false;
- }
-
- // ----- Calculate the stored filename
- $p_filename = $this->_translateWinPath($p_filename, false);;
-
- if (!$this->_writeHeaderBlock($p_filename, strlen($p_string),
- time(), 384, "", 0, 0))
- return false;
-
- $i=0;
- while (($v_buffer = substr($p_string, (($i++)*512), 512)) != '') {
- $v_binary_data = pack("a512", $v_buffer);
- $this->_writeBlock($v_binary_data);
- }
-
- return true;
+ if ($p_filename == '') {
+ $this->_error('Invalid file name');
+ return false;
+ }
+
+ // ----- Calculate the stored filename
+ $p_filename = $this->_translateWinPath($p_filename, false);
+
+ // ----- If datetime is not specified, set current time
+ if ($p_datetime === false) {
+ $p_datetime = time();
+ }
+
+ if (!$this->_writeHeaderBlock(
+ $p_filename,
+ strlen($p_string),
+ $p_stamp,
+ $p_mode,
+ $p_type,
+ $p_uid,
+ $p_gid
+ )
+ ) {
+ return false;
+ }
+
+ $i = 0;
+ while (($v_buffer = substr($p_string, (($i++) * 512), 512)) != '') {
+ $v_binary_data = pack("a512", $v_buffer);
+ $this->_writeBlock($v_binary_data);
+ }
+
+ return true;
}
- // }}}
- // {{{ _writeHeader()
- function _writeHeader($p_filename, $p_stored_filename)
+ /**
+ * @param string $p_filename
+ * @param string $p_stored_filename
+ * @return bool
+ */
+ public function _writeHeader($p_filename, $p_stored_filename)
{
- if ($p_stored_filename == '')
+ if ($p_stored_filename == '') {
$p_stored_filename = $p_filename;
+ }
$v_reduce_filename = $this->_pathReduction($p_stored_filename);
if (strlen($v_reduce_filename) > 99) {
- if (!$this->_writeLongHeader($v_reduce_filename))
- return false;
+ if (!$this->_writeLongHeader($v_reduce_filename)) {
+ return false;
+ }
}
$v_info = lstat($p_filename);
- $v_uid = sprintf("%6s ", DecOct($v_info[4]));
- $v_gid = sprintf("%6s ", DecOct($v_info[5]));
- $v_perms = sprintf("%6s ", DecOct($v_info['mode']));
+ $v_uid = sprintf("%07s", DecOct($v_info[4]));
+ $v_gid = sprintf("%07s", DecOct($v_info[5]));
+ $v_perms = sprintf("%07s", DecOct($v_info['mode'] & 000777));
- $v_mtime = sprintf("%11s", DecOct($v_info['mode']));
+ $v_mtime = sprintf("%011s", DecOct($v_info['mtime']));
$v_linkname = '';
if (@is_link($p_filename)) {
- $v_typeflag = '2';
- $v_linkname = readlink($p_filename);
- $v_size = sprintf("%11s ", DecOct(0));
+ $v_typeflag = '2';
+ $v_linkname = readlink($p_filename);
+ $v_size = sprintf("%011s", DecOct(0));
} elseif (@is_dir($p_filename)) {
- $v_typeflag = "5";
- $v_size = sprintf("%11s ", DecOct(0));
+ $v_typeflag = "5";
+ $v_size = sprintf("%011s", DecOct(0));
} else {
- $v_typeflag = '';
- clearstatcache();
- $v_size = sprintf("%11s ", DecOct($v_info['size']));
+ $v_typeflag = '0';
+ clearstatcache();
+ $v_size = sprintf("%011s", DecOct($v_info['size']));
}
- $v_magic = '';
+ $v_magic = 'ustar ';
- $v_version = '';
+ $v_version = ' ';
- $v_uname = '';
+ if (function_exists('posix_getpwuid')) {
+ $userinfo = posix_getpwuid($v_info[4]);
+ $groupinfo = posix_getgrgid($v_info[5]);
- $v_gname = '';
+ $v_uname = $userinfo['name'];
+ $v_gname = $groupinfo['name'];
+ } else {
+ $v_uname = '';
+ $v_gname = '';
+ }
$v_devmajor = '';
@@ -1100,31 +1445,49 @@ class Archive_Tar // extends PEAR
$v_prefix = '';
- $v_binary_data_first = pack("a100a8a8a8a12A12",
- $v_reduce_filename, $v_perms, $v_uid,
- $v_gid, $v_size, $v_mtime);
- $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
- $v_typeflag, $v_linkname, $v_magic,
- $v_version, $v_uname, $v_gname,
- $v_devmajor, $v_devminor, $v_prefix, '');
+ $v_binary_data_first = pack(
+ "a100a8a8a8a12a12",
+ $v_reduce_filename,
+ $v_perms,
+ $v_uid,
+ $v_gid,
+ $v_size,
+ $v_mtime
+ );
+ $v_binary_data_last = pack(
+ "a1a100a6a2a32a32a8a8a155a12",
+ $v_typeflag,
+ $v_linkname,
+ $v_magic,
+ $v_version,
+ $v_uname,
+ $v_gname,
+ $v_devmajor,
+ $v_devminor,
+ $v_prefix,
+ ''
+ );
// ----- Calculate the checksum
$v_checksum = 0;
// ..... First part of the header
- for ($i=0; $i<148; $i++)
- $v_checksum += ord(substr($v_binary_data_first,$i,1));
+ for ($i = 0; $i < 148; $i++) {
+ $v_checksum += ord(substr($v_binary_data_first, $i, 1));
+ }
// ..... Ignore the checksum value and replace it by ' ' (space)
- for ($i=148; $i<156; $i++)
+ for ($i = 148; $i < 156; $i++) {
$v_checksum += ord(' ');
+ }
// ..... Last part of the header
- for ($i=156, $j=0; $i<512; $i++, $j++)
- $v_checksum += ord(substr($v_binary_data_last,$j,1));
+ for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
+ $v_checksum += ord(substr($v_binary_data_last, $j, 1));
+ }
// ----- Write the first 148 bytes of the header in the archive
$this->_writeBlock($v_binary_data_first, 148);
// ----- Write the calculated checksum
- $v_checksum = sprintf("%6s ", DecOct($v_checksum));
+ $v_checksum = sprintf("%06s ", DecOct($v_checksum));
$v_binary_data = pack("a8", $v_checksum);
$this->_writeBlock($v_binary_data, 8);
@@ -1133,40 +1496,62 @@ class Archive_Tar // extends PEAR
return true;
}
- // }}}
- // {{{ _writeHeaderBlock()
- function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0,
- $p_type='', $p_uid=0, $p_gid=0)
- {
+ /**
+ * @param string $p_filename
+ * @param int $p_size
+ * @param int $p_mtime
+ * @param int $p_perms
+ * @param string $p_type
+ * @param int $p_uid
+ * @param int $p_gid
+ * @return bool
+ */
+ public function _writeHeaderBlock(
+ $p_filename,
+ $p_size,
+ $p_mtime = 0,
+ $p_perms = 0,
+ $p_type = '',
+ $p_uid = 0,
+ $p_gid = 0
+ ) {
$p_filename = $this->_pathReduction($p_filename);
if (strlen($p_filename) > 99) {
- if (!$this->_writeLongHeader($p_filename))
- return false;
+ if (!$this->_writeLongHeader($p_filename)) {
+ return false;
+ }
}
if ($p_type == "5") {
- $v_size = sprintf("%11s ", DecOct(0));
+ $v_size = sprintf("%011s", DecOct(0));
} else {
- $v_size = sprintf("%11s ", DecOct($p_size));
+ $v_size = sprintf("%011s", DecOct($p_size));
}
- $v_uid = sprintf("%6s ", DecOct($p_uid));
- $v_gid = sprintf("%6s ", DecOct($p_gid));
- $v_perms = sprintf("%6s ", DecOct($p_perms));
+ $v_uid = sprintf("%07s", DecOct($p_uid));
+ $v_gid = sprintf("%07s", DecOct($p_gid));
+ $v_perms = sprintf("%07s", DecOct($p_perms & 000777));
$v_mtime = sprintf("%11s", DecOct($p_mtime));
$v_linkname = '';
- $v_magic = '';
+ $v_magic = 'ustar ';
- $v_version = '';
+ $v_version = ' ';
- $v_uname = '';
+ if (function_exists('posix_getpwuid')) {
+ $userinfo = posix_getpwuid($p_uid);
+ $groupinfo = posix_getgrgid($p_gid);
- $v_gname = '';
+ $v_uname = $userinfo['name'];
+ $v_gname = $groupinfo['name'];
+ } else {
+ $v_uname = '';
+ $v_gname = '';
+ }
$v_devmajor = '';
@@ -1174,31 +1559,49 @@ class Archive_Tar // extends PEAR
$v_prefix = '';
- $v_binary_data_first = pack("a100a8a8a8a12A12",
- $p_filename, $v_perms, $v_uid, $v_gid,
- $v_size, $v_mtime);
- $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
- $p_type, $v_linkname, $v_magic,
- $v_version, $v_uname, $v_gname,
- $v_devmajor, $v_devminor, $v_prefix, '');
+ $v_binary_data_first = pack(
+ "a100a8a8a8a12A12",
+ $p_filename,
+ $v_perms,
+ $v_uid,
+ $v_gid,
+ $v_size,
+ $v_mtime
+ );
+ $v_binary_data_last = pack(
+ "a1a100a6a2a32a32a8a8a155a12",
+ $p_type,
+ $v_linkname,
+ $v_magic,
+ $v_version,
+ $v_uname,
+ $v_gname,
+ $v_devmajor,
+ $v_devminor,
+ $v_prefix,
+ ''
+ );
// ----- Calculate the checksum
$v_checksum = 0;
// ..... First part of the header
- for ($i=0; $i<148; $i++)
- $v_checksum += ord(substr($v_binary_data_first,$i,1));
+ for ($i = 0; $i < 148; $i++) {
+ $v_checksum += ord(substr($v_binary_data_first, $i, 1));
+ }
// ..... Ignore the checksum value and replace it by ' ' (space)
- for ($i=148; $i<156; $i++)
+ for ($i = 148; $i < 156; $i++) {
$v_checksum += ord(' ');
+ }
// ..... Last part of the header
- for ($i=156, $j=0; $i<512; $i++, $j++)
- $v_checksum += ord(substr($v_binary_data_last,$j,1));
+ for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
+ $v_checksum += ord(substr($v_binary_data_last, $j, 1));
+ }
// ----- Write the first 148 bytes of the header in the archive
$this->_writeBlock($v_binary_data_first, 148);
// ----- Write the calculated checksum
- $v_checksum = sprintf("%6s ", DecOct($v_checksum));
+ $v_checksum = sprintf("%06s ", DecOct($v_checksum));
$v_binary_data = pack("a8", $v_checksum);
$this->_writeBlock($v_binary_data, 8);
@@ -1207,10 +1610,12 @@ class Archive_Tar // extends PEAR
return true;
}
- // }}}
- // {{{ _writeLongHeader()
- function _writeLongHeader($p_filename)
+ /**
+ * @param string $p_filename
+ * @return bool
+ */
+ public function _writeLongHeader($p_filename)
{
$v_size = sprintf("%11s ", DecOct(strlen($p_filename)));
@@ -1232,30 +1637,49 @@ class Archive_Tar // extends PEAR
$v_prefix = '';
- $v_binary_data_first = pack("a100a8a8a8a12A12",
- '././@LongLink', 0, 0, 0, $v_size, 0);
- $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
- $v_typeflag, $v_linkname, $v_magic,
- $v_version, $v_uname, $v_gname,
- $v_devmajor, $v_devminor, $v_prefix, '');
+ $v_binary_data_first = pack(
+ "a100a8a8a8a12a12",
+ '././@LongLink',
+ 0,
+ 0,
+ 0,
+ $v_size,
+ 0
+ );
+ $v_binary_data_last = pack(
+ "a1a100a6a2a32a32a8a8a155a12",
+ $v_typeflag,
+ $v_linkname,
+ $v_magic,
+ $v_version,
+ $v_uname,
+ $v_gname,
+ $v_devmajor,
+ $v_devminor,
+ $v_prefix,
+ ''
+ );
// ----- Calculate the checksum
$v_checksum = 0;
// ..... First part of the header
- for ($i=0; $i<148; $i++)
- $v_checksum += ord(substr($v_binary_data_first,$i,1));
+ for ($i = 0; $i < 148; $i++) {
+ $v_checksum += ord(substr($v_binary_data_first, $i, 1));
+ }
// ..... Ignore the checksum value and replace it by ' ' (space)
- for ($i=148; $i<156; $i++)
+ for ($i = 148; $i < 156; $i++) {
$v_checksum += ord(' ');
+ }
// ..... Last part of the header
- for ($i=156, $j=0; $i<512; $i++, $j++)
- $v_checksum += ord(substr($v_binary_data_last,$j,1));
+ for ($i = 156, $j = 0; $i < 512; $i++, $j++) {
+ $v_checksum += ord(substr($v_binary_data_last, $j, 1));
+ }
// ----- Write the first 148 bytes of the header in the archive
$this->_writeBlock($v_binary_data_first, 148);
// ----- Write the calculated checksum
- $v_checksum = sprintf("%6s ", DecOct($v_checksum));
+ $v_checksum = sprintf("%06s ", DecOct($v_checksum));
$v_binary_data = pack("a8", $v_checksum);
$this->_writeBlock($v_binary_data, 8);
@@ -1263,27 +1687,30 @@ class Archive_Tar // extends PEAR
$this->_writeBlock($v_binary_data_last, 356);
// ----- Write the filename as content of the block
- $i=0;
- while (($v_buffer = substr($p_filename, (($i++)*512), 512)) != '') {
+ $i = 0;
+ while (($v_buffer = substr($p_filename, (($i++) * 512), 512)) != '') {
$v_binary_data = pack("a512", "$v_buffer");
$this->_writeBlock($v_binary_data);
}
return true;
}
- // }}}
- // {{{ _readHeader()
- function _readHeader($v_binary_data, &$v_header)
+ /**
+ * @param mixed $v_binary_data
+ * @param mixed $v_header
+ * @return bool
+ */
+ public function _readHeader($v_binary_data, &$v_header)
{
- if (strlen($v_binary_data)==0) {
+ if (strlen($v_binary_data) == 0) {
$v_header['filename'] = '';
return true;
}
if (strlen($v_binary_data) != 512) {
$v_header['filename'] = '';
- $this->_error('Invalid block size : '.strlen($v_binary_data));
+ $this->_error('Invalid block size : ' . strlen($v_binary_data));
return false;
}
@@ -1293,19 +1720,32 @@ class Archive_Tar // extends PEAR
// ----- Calculate the checksum
$v_checksum = 0;
// ..... First part of the header
- for ($i=0; $i<148; $i++)
- $v_checksum+=ord(substr($v_binary_data,$i,1));
+ for ($i = 0; $i < 148; $i++) {
+ $v_checksum += ord(substr($v_binary_data, $i, 1));
+ }
// ..... Ignore the checksum value and replace it by ' ' (space)
- for ($i=148; $i<156; $i++)
+ for ($i = 148; $i < 156; $i++) {
$v_checksum += ord(' ');
+ }
// ..... Last part of the header
- for ($i=156; $i<512; $i++)
- $v_checksum+=ord(substr($v_binary_data,$i,1));
+ for ($i = 156; $i < 512; $i++) {
+ $v_checksum += ord(substr($v_binary_data, $i, 1));
+ }
- $v_data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/"
- ."a8checksum/a1typeflag/a100link/a6magic/a2version/"
- ."a32uname/a32gname/a8devmajor/a8devminor",
- $v_binary_data);
+ if (version_compare(PHP_VERSION, "5.5.0-dev") < 0) {
+ $fmt = "a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" .
+ "a8checksum/a1typeflag/a100link/a6magic/a2version/" .
+ "a32uname/a32gname/a8devmajor/a8devminor/a131prefix";
+ } else {
+ $fmt = "Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/" .
+ "Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/" .
+ "Z32uname/Z32gname/Z8devmajor/Z8devminor/Z131prefix";
+ }
+ $v_data = unpack($fmt, $v_binary_data);
+
+ if (strlen($v_data["prefix"]) > 0) {
+ $v_data["filename"] = "$v_data[prefix]/$v_data[filename]";
+ }
// ----- Extract the checksum
$v_header['checksum'] = OctDec(trim($v_data['checksum']));
@@ -1313,20 +1753,25 @@ class Archive_Tar // extends PEAR
$v_header['filename'] = '';
// ----- Look for last block (empty block)
- if (($v_checksum == 256) && ($v_header['checksum'] == 0))
+ if (($v_checksum == 256) && ($v_header['checksum'] == 0)) {
return true;
+ }
- $this->_error('Invalid checksum for file "'.$v_data['filename']
- .'" : '.$v_checksum.' calculated, '
- .$v_header['checksum'].' expected');
+ $this->_error(
+ 'Invalid checksum for file "' . $v_data['filename']
+ . '" : ' . $v_checksum . ' calculated, '
+ . $v_header['checksum'] . ' expected'
+ );
return false;
}
// ----- Extract the properties
- $v_header['filename'] = trim($v_data['filename']);
+ $v_header['filename'] = rtrim($v_data['filename'], "\0");
if ($this->_maliciousFilename($v_header['filename'])) {
- $this->_error('Malicious .tar detected, file "' . $v_header['filename'] .
- '" will not install in desired directory tree');
+ $this->_error(
+ 'Malicious .tar detected, file "' . $v_header['filename'] .
+ '" will not install in desired directory tree'
+ );
return false;
}
$v_header['mode'] = OctDec(trim($v_data['mode']));
@@ -1335,11 +1780,11 @@ class Archive_Tar // extends PEAR
$v_header['size'] = OctDec(trim($v_data['size']));
$v_header['mtime'] = OctDec(trim($v_data['mtime']));
if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
- $v_header['size'] = 0;
+ $v_header['size'] = 0;
}
$v_header['link'] = trim($v_data['link']);
/* ----- All these fields are removed form the header because
- they do not carry interesting info
+ they do not carry interesting info
$v_header[magic] = trim($v_data[magic]);
$v_header[version] = trim($v_data[version]);
$v_header[uname] = trim($v_data[uname]);
@@ -1350,17 +1795,15 @@ class Archive_Tar // extends PEAR
return true;
}
- // }}}
- // {{{ _maliciousFilename()
/**
* Detect and report a malicious file name
*
* @param string $file
+ *
* @return bool
- * @access private
*/
- function _maliciousFilename($file)
+ private function _maliciousFilename($file)
{
if (strpos($file, '/../') !== false) {
return true;
@@ -1370,386 +1813,507 @@ class Archive_Tar // extends PEAR
}
return false;
}
- // }}}
- // {{{ _readLongHeader()
- function _readLongHeader(&$v_header)
+ /**
+ * @param $v_header
+ * @return bool
+ */
+ public function _readLongHeader(&$v_header)
{
- $v_filename = '';
- $n = floor($v_header['size']/512);
- for ($i=0; $i<$n; $i++) {
- $v_content = $this->_readBlock();
- $v_filename .= $v_content;
- }
- if (($v_header['size'] % 512) != 0) {
- $v_content = $this->_readBlock();
- $v_filename .= $v_content;
- }
-
- // ----- Read the next header
- $v_binary_data = $this->_readBlock();
-
- if (!$this->_readHeader($v_binary_data, $v_header))
- return false;
+ $v_filename = '';
+ $v_filesize = $v_header['size'];
+ $n = floor($v_header['size'] / 512);
+ for ($i = 0; $i < $n; $i++) {
+ $v_content = $this->_readBlock();
+ $v_filename .= $v_content;
+ }
+ if (($v_header['size'] % 512) != 0) {
+ $v_content = $this->_readBlock();
+ $v_filename .= $v_content;
+ }
- $v_filename = trim($v_filename);
- $v_header['filename'] = $v_filename;
+ // ----- Read the next header
+ $v_binary_data = $this->_readBlock();
+
+ if (!$this->_readHeader($v_binary_data, $v_header)) {
+ return false;
+ }
+
+ $v_filename = rtrim(substr($v_filename, 0, $v_filesize), "\0");
+ $v_header['filename'] = $v_filename;
if ($this->_maliciousFilename($v_filename)) {
- $this->_error('Malicious .tar detected, file "' . $v_filename .
- '" will not install in desired directory tree');
+ $this->_error(
+ 'Malicious .tar detected, file "' . $v_filename .
+ '" will not install in desired directory tree'
+ );
return false;
- }
+ }
- return true;
+ return true;
}
- // }}}
- // {{{ _extractInString()
/**
- * This method extract from the archive one file identified by $p_filename.
- * The return value is a string with the file content, or NULL on error.
- * @param string $p_filename The path of the file to extract in a string.
- * @return a string with the file content or NULL.
- * @access private
- */
- function _extractInString($p_filename)
+ * This method extract from the archive one file identified by $p_filename.
+ * The return value is a string with the file content, or null on error.
+ *
+ * @param string $p_filename The path of the file to extract in a string.
+ *
+ * @return a string with the file content or null.
+ */
+ private function _extractInString($p_filename)
{
$v_result_str = "";
- While (strlen($v_binary_data = $this->_readBlock()) != 0)
- {
- if (!$this->_readHeader($v_binary_data, $v_header))
- return NULL;
-
- if ($v_header['filename'] == '')
- continue;
-
- // ----- Look for long filename
- if ($v_header['typeflag'] == 'L') {
- if (!$this->_readLongHeader($v_header))
- return NULL;
- }
-
- if ($v_header['filename'] == $p_filename) {
- if ($v_header['typeflag'] == "5") {
- $this->_error('Unable to extract in string a directory '
- .'entry {'.$v_header['filename'].'}');
- return NULL;
- } else {
- $n = floor($v_header['size']/512);
- for ($i=0; $i<$n; $i++) {
- $v_result_str .= $this->_readBlock();
- }
- if (($v_header['size'] % 512) != 0) {
- $v_content = $this->_readBlock();
- $v_result_str .= substr($v_content, 0,
- ($v_header['size'] % 512));
- }
- return $v_result_str;
- }
- } else {
- $this->_jumpBlock(ceil(($v_header['size']/512)));
- }
- }
-
- return NULL;
- }
- // }}}
+ while (strlen($v_binary_data = $this->_readBlock()) != 0) {
+ if (!$this->_readHeader($v_binary_data, $v_header)) {
+ return null;
+ }
- // {{{ _extractList()
- function _extractList($p_path, &$p_list_detail, $p_mode,
- $p_file_list, $p_remove_path)
- {
- $v_result=true;
- $v_nb = 0;
- $v_extract_all = true;
- $v_listing = false;
-
- $p_path = $this->_translateWinPath($p_path, false);
- if ($p_path == '' || (substr($p_path, 0, 1) != '/'
- && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) {
- $p_path = "./".$p_path;
- }
- $p_remove_path = $this->_translateWinPath($p_remove_path);
-
- // ----- Look for path to remove format (should end by /)
- if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/'))
- $p_remove_path .= '/';
- $p_remove_path_size = strlen($p_remove_path);
-
- switch ($p_mode) {
- case "complete" :
- $v_extract_all = TRUE;
- $v_listing = FALSE;
- break;
- case "partial" :
- $v_extract_all = FALSE;
- $v_listing = FALSE;
- break;
- case "list" :
- $v_extract_all = FALSE;
- $v_listing = TRUE;
- break;
- default :
- $this->_error('Invalid extract mode ('.$p_mode.')');
- return false;
+ if ($v_header['filename'] == '') {
+ continue;
+ }
+
+ // ----- Look for long filename
+ if ($v_header['typeflag'] == 'L') {
+ if (!$this->_readLongHeader($v_header)) {
+ return null;
+ }
+ }
+
+ if ($v_header['filename'] == $p_filename) {
+ if ($v_header['typeflag'] == "5") {
+ $this->_error(
+ 'Unable to extract in string a directory '
+ . 'entry {' . $v_header['filename'] . '}'
+ );
+ return null;
+ } else {
+ $n = floor($v_header['size'] / 512);
+ for ($i = 0; $i < $n; $i++) {
+ $v_result_str .= $this->_readBlock();
+ }
+ if (($v_header['size'] % 512) != 0) {
+ $v_content = $this->_readBlock();
+ $v_result_str .= substr(
+ $v_content,
+ 0,
+ ($v_header['size'] % 512)
+ );
+ }
+ return $v_result_str;
+ }
+ } else {
+ $this->_jumpBlock(ceil(($v_header['size'] / 512)));
+ }
+ }
+
+ return null;
}
- clearstatcache();
+ /**
+ * @param string $p_path
+ * @param string $p_list_detail
+ * @param string $p_mode
+ * @param string $p_file_list
+ * @param string $p_remove_path
+ * @param bool $p_preserve
+ * @return bool
+ */
+ public function _extractList(
+ $p_path,
+ &$p_list_detail,
+ $p_mode,
+ $p_file_list,
+ $p_remove_path,
+ $p_preserve = false
+ ) {
+ $v_result = true;
+ $v_nb = 0;
+ $v_extract_all = true;
+ $v_listing = false;
+
+ $p_path = $this->_translateWinPath($p_path, false);
+ if ($p_path == '' || (substr($p_path, 0, 1) != '/'
+ && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))
+ ) {
+ $p_path = "./" . $p_path;
+ }
+ $p_remove_path = $this->_translateWinPath($p_remove_path);
+
+ // ----- Look for path to remove format (should end by /)
+ if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/')) {
+ $p_remove_path .= '/';
+ }
+ $p_remove_path_size = strlen($p_remove_path);
- while (strlen($v_binary_data = $this->_readBlock()) != 0)
- {
- $v_extract_file = FALSE;
- $v_extraction_stopped = 0;
+ switch ($p_mode) {
+ case "complete" :
+ $v_extract_all = true;
+ $v_listing = false;
+ break;
+ case "partial" :
+ $v_extract_all = false;
+ $v_listing = false;
+ break;
+ case "list" :
+ $v_extract_all = false;
+ $v_listing = true;
+ break;
+ default :
+ $this->_error('Invalid extract mode (' . $p_mode . ')');
+ return false;
+ }
- if (!$this->_readHeader($v_binary_data, $v_header))
- return false;
+ clearstatcache();
- if ($v_header['filename'] == '') {
- continue;
- }
-
- // ----- Look for long filename
- if ($v_header['typeflag'] == 'L') {
- if (!$this->_readLongHeader($v_header))
- return false;
- }
-
- if ((!$v_extract_all) && (is_array($p_file_list))) {
- // ----- By default no unzip if the file is not found
- $v_extract_file = false;
-
- for ($i=0; $i strlen($p_file_list[$i]))
- && (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
- == $p_file_list[$i])) {
- $v_extract_file = TRUE;
- break;
+ while (strlen($v_binary_data = $this->_readBlock()) != 0) {
+ $v_extract_file = false;
+ $v_extraction_stopped = 0;
+
+ if (!$this->_readHeader($v_binary_data, $v_header)) {
+ return false;
+ }
+
+ if ($v_header['filename'] == '') {
+ continue;
}
- }
-
- // ----- It is a file, so compare the file names
- elseif ($p_file_list[$i] == $v_header['filename']) {
- $v_extract_file = TRUE;
- break;
- }
- }
- } else {
- $v_extract_file = TRUE;
- }
-
- // ----- Look if this file need to be extracted
- if (($v_extract_file) && (!$v_listing))
- {
- if (($p_remove_path != '')
- && (substr($v_header['filename'], 0, $p_remove_path_size)
- == $p_remove_path))
- $v_header['filename'] = substr($v_header['filename'],
- $p_remove_path_size);
- if (($p_path != './') && ($p_path != '/')) {
- while (substr($p_path, -1) == '/')
- $p_path = substr($p_path, 0, strlen($p_path)-1);
-
- if (substr($v_header['filename'], 0, 1) == '/')
- $v_header['filename'] = $p_path.$v_header['filename'];
- else
- $v_header['filename'] = $p_path.'/'.$v_header['filename'];
- }
- if (file_exists($v_header['filename'])) {
- if ( (@is_dir($v_header['filename']))
- && ($v_header['typeflag'] == '')) {
- $this->_error('File '.$v_header['filename']
- .' already exists as a directory');
- return false;
- }
- if ( ($this->_isArchive($v_header['filename']))
- && ($v_header['typeflag'] == "5")) {
- $this->_error('Directory '.$v_header['filename']
- .' already exists as a file');
- return false;
- }
- if (!is_writeable($v_header['filename'])) {
- $this->_error('File '.$v_header['filename']
- .' already exists and is write protected');
- return false;
- }
- if (filemtime($v_header['filename']) > $v_header['mtime']) {
- // To be completed : An error or silent no replace ?
- }
- }
-
- // ----- Check the directory availability and create it if necessary
- elseif (($v_result
- = $this->_dirCheck(($v_header['typeflag'] == "5"
- ?$v_header['filename']
- :dirname($v_header['filename'])))) != 1) {
- $this->_error('Unable to create path for '.$v_header['filename']);
- return false;
- }
- if ($v_extract_file) {
- if ($v_header['typeflag'] == "5") {
- if (!@file_exists($v_header['filename'])) {
- // Drupal integration.
- // Changed the code to use drupal_mkdir() instead of mkdir().
- if (!@drupal_mkdir($v_header['filename'], 0777)) {
- $this->_error('Unable to create directory {'
- .$v_header['filename'].'}');
+ // ----- Look for long filename
+ if ($v_header['typeflag'] == 'L') {
+ if (!$this->_readLongHeader($v_header)) {
return false;
}
}
- } elseif ($v_header['typeflag'] == "2") {
- if (@file_exists($v_header['filename'])) {
- @drupal_unlink($v_header['filename']);
- }
- if (!@symlink($v_header['link'], $v_header['filename'])) {
- $this->_error('Unable to extract symbolic link {'
- .$v_header['filename'].'}');
- return false;
- }
- } else {
- if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
- $this->_error('Error while opening {'.$v_header['filename']
- .'} in write binary mode');
- return false;
- } else {
- $n = floor($v_header['size']/512);
- for ($i=0; $i<$n; $i++) {
- $v_content = $this->_readBlock();
- fwrite($v_dest_file, $v_content, 512);
- }
- if (($v_header['size'] % 512) != 0) {
- $v_content = $this->_readBlock();
- fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
- }
- @fclose($v_dest_file);
+ // ignore extended / pax headers
+ if ($v_header['typeflag'] == 'x' || $v_header['typeflag'] == 'g') {
+ $this->_jumpBlock(ceil(($v_header['size'] / 512)));
+ continue;
+ }
- // ----- Change the file mode, mtime
- @touch($v_header['filename'], $v_header['mtime']);
- if ($v_header['mode'] & 0111) {
- // make file executable, obey umask
- $mode = fileperms($v_header['filename']) | (~umask() & 0111);
- @chmod($v_header['filename'], $mode);
+ if ((!$v_extract_all) && (is_array($p_file_list))) {
+ // ----- By default no unzip if the file is not found
+ $v_extract_file = false;
+
+ for ($i = 0; $i < sizeof($p_file_list); $i++) {
+ // ----- Look if it is a directory
+ if (substr($p_file_list[$i], -1) == '/') {
+ // ----- Look if the directory is in the filename path
+ if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
+ && (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
+ == $p_file_list[$i])
+ ) {
+ $v_extract_file = true;
+ break;
+ }
+ } // ----- It is a file, so compare the file names
+ elseif ($p_file_list[$i] == $v_header['filename']) {
+ $v_extract_file = true;
+ break;
+ }
+ }
+ } else {
+ $v_extract_file = true;
}
- }
-
- // ----- Check the file size
- clearstatcache();
- if (filesize($v_header['filename']) != $v_header['size']) {
- $this->_error('Extracted file '.$v_header['filename']
- .' does not have the correct file size \''
- .filesize($v_header['filename'])
- .'\' ('.$v_header['size']
- .' expected). Archive may be corrupted.');
- return false;
- }
- }
- } else {
- $this->_jumpBlock(ceil(($v_header['size']/512)));
- }
- } else {
- $this->_jumpBlock(ceil(($v_header['size']/512)));
- }
- /* TBC : Seems to be unused ...
- if ($this->_compress)
- $v_end_of_file = @gzeof($this->_file);
- else
- $v_end_of_file = @feof($this->_file);
- */
+ // ----- Look if this file need to be extracted
+ if (($v_extract_file) && (!$v_listing)) {
+ if (($p_remove_path != '')
+ && (substr($v_header['filename'] . '/', 0, $p_remove_path_size)
+ == $p_remove_path)
+ ) {
+ $v_header['filename'] = substr(
+ $v_header['filename'],
+ $p_remove_path_size
+ );
+ if ($v_header['filename'] == '') {
+ continue;
+ }
+ }
+ if (($p_path != './') && ($p_path != '/')) {
+ while (substr($p_path, -1) == '/') {
+ $p_path = substr($p_path, 0, strlen($p_path) - 1);
+ }
- if ($v_listing || $v_extract_file || $v_extraction_stopped) {
- // ----- Log extracted files
- if (($v_file_dir = dirname($v_header['filename']))
- == $v_header['filename'])
- $v_file_dir = '';
- if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == ''))
- $v_file_dir = '/';
+ if (substr($v_header['filename'], 0, 1) == '/') {
+ $v_header['filename'] = $p_path . $v_header['filename'];
+ } else {
+ $v_header['filename'] = $p_path . '/' . $v_header['filename'];
+ }
+ }
+ if (file_exists($v_header['filename'])) {
+ if ((@is_dir($v_header['filename']))
+ && ($v_header['typeflag'] == '')
+ ) {
+ $this->_error(
+ 'File ' . $v_header['filename']
+ . ' already exists as a directory'
+ );
+ return false;
+ }
+ if (($this->_isArchive($v_header['filename']))
+ && ($v_header['typeflag'] == "5")
+ ) {
+ $this->_error(
+ 'Directory ' . $v_header['filename']
+ . ' already exists as a file'
+ );
+ return false;
+ }
+ if (!is_writeable($v_header['filename'])) {
+ $this->_error(
+ 'File ' . $v_header['filename']
+ . ' already exists and is write protected'
+ );
+ return false;
+ }
+ if (filemtime($v_header['filename']) > $v_header['mtime']) {
+ // To be completed : An error or silent no replace ?
+ }
+ } // ----- Check the directory availability and create it if necessary
+ elseif (($v_result
+ = $this->_dirCheck(
+ ($v_header['typeflag'] == "5"
+ ? $v_header['filename']
+ : dirname($v_header['filename']))
+ )) != 1
+ ) {
+ $this->_error('Unable to create path for ' . $v_header['filename']);
+ return false;
+ }
- $p_list_detail[$v_nb++] = $v_header;
- if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) {
- return true;
+ if ($v_extract_file) {
+ if ($v_header['typeflag'] == "5") {
+ if (!@file_exists($v_header['filename'])) {
+ if (!@mkdir($v_header['filename'], 0777)) {
+ $this->_error(
+ 'Unable to create directory {'
+ . $v_header['filename'] . '}'
+ );
+ return false;
+ }
+ }
+ } elseif ($v_header['typeflag'] == "2") {
+ if (@file_exists($v_header['filename'])) {
+ @drupal_unlink($v_header['filename']);
+ }
+ if (!@symlink($v_header['link'], $v_header['filename'])) {
+ $this->_error(
+ 'Unable to extract symbolic link {'
+ . $v_header['filename'] . '}'
+ );
+ return false;
+ }
+ } else {
+ if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
+ $this->_error(
+ 'Error while opening {' . $v_header['filename']
+ . '} in write binary mode'
+ );
+ return false;
+ } else {
+ $n = floor($v_header['size'] / 512);
+ for ($i = 0; $i < $n; $i++) {
+ $v_content = $this->_readBlock();
+ fwrite($v_dest_file, $v_content, 512);
+ }
+ if (($v_header['size'] % 512) != 0) {
+ $v_content = $this->_readBlock();
+ fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
+ }
+
+ @fclose($v_dest_file);
+
+ if ($p_preserve) {
+ @chown($v_header['filename'], $v_header['uid']);
+ @chgrp($v_header['filename'], $v_header['gid']);
+ }
+
+ // ----- Change the file mode, mtime
+ @touch($v_header['filename'], $v_header['mtime']);
+ if ($v_header['mode'] & 0111) {
+ // make file executable, obey umask
+ $mode = fileperms($v_header['filename']) | (~umask() & 0111);
+ @chmod($v_header['filename'], $mode);
+ }
+ }
+
+ // ----- Check the file size
+ clearstatcache();
+ if (!is_file($v_header['filename'])) {
+ $this->_error(
+ 'Extracted file ' . $v_header['filename']
+ . 'does not exist. Archive may be corrupted.'
+ );
+ return false;
+ }
+
+ $filesize = filesize($v_header['filename']);
+ if ($filesize != $v_header['size']) {
+ $this->_error(
+ 'Extracted file ' . $v_header['filename']
+ . ' does not have the correct file size \''
+ . $filesize
+ . '\' (' . $v_header['size']
+ . ' expected). Archive may be corrupted.'
+ );
+ return false;
+ }
+ }
+ } else {
+ $this->_jumpBlock(ceil(($v_header['size'] / 512)));
+ }
+ } else {
+ $this->_jumpBlock(ceil(($v_header['size'] / 512)));
+ }
+
+ /* TBC : Seems to be unused ...
+ if ($this->_compress)
+ $v_end_of_file = @gzeof($this->_file);
+ else
+ $v_end_of_file = @feof($this->_file);
+ */
+
+ if ($v_listing || $v_extract_file || $v_extraction_stopped) {
+ // ----- Log extracted files
+ if (($v_file_dir = dirname($v_header['filename']))
+ == $v_header['filename']
+ ) {
+ $v_file_dir = '';
+ }
+ if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == '')) {
+ $v_file_dir = '/';
+ }
+
+ $p_list_detail[$v_nb++] = $v_header;
+ if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) {
+ return true;
+ }
+ }
}
- }
- }
return true;
}
- // }}}
- // {{{ _openAppend()
- function _openAppend()
+ /**
+ * @return bool
+ */
+ public function _openAppend()
{
- if (filesize($this->_tarname) == 0)
- return $this->_openWrite();
+ if (filesize($this->_tarname) == 0) {
+ return $this->_openWrite();
+ }
if ($this->_compress) {
$this->_close();
- if (!@rename($this->_tarname, $this->_tarname.".tmp")) {
- $this->_error('Error while renaming \''.$this->_tarname
- .'\' to temporary file \''.$this->_tarname
- .'.tmp\'');
+ if (!@rename($this->_tarname, $this->_tarname . ".tmp")) {
+ $this->_error(
+ 'Error while renaming \'' . $this->_tarname
+ . '\' to temporary file \'' . $this->_tarname
+ . '.tmp\''
+ );
return false;
}
- if ($this->_compress_type == 'gz')
- $v_temp_tar = @gzopen($this->_tarname.".tmp", "rb");
- elseif ($this->_compress_type == 'bz2')
- $v_temp_tar = @bzopen($this->_tarname.".tmp", "r");
+ if ($this->_compress_type == 'gz') {
+ $v_temp_tar = @gzopen($this->_tarname . ".tmp", "rb");
+ } elseif ($this->_compress_type == 'bz2') {
+ $v_temp_tar = @bzopen($this->_tarname . ".tmp", "r");
+ } elseif ($this->_compress_type == 'lzma2') {
+ $v_temp_tar = @xzopen($this->_tarname . ".tmp", "r");
+ }
+
if ($v_temp_tar == 0) {
- $this->_error('Unable to open file \''.$this->_tarname
- .'.tmp\' in binary read mode');
- @rename($this->_tarname.".tmp", $this->_tarname);
+ $this->_error(
+ 'Unable to open file \'' . $this->_tarname
+ . '.tmp\' in binary read mode'
+ );
+ @rename($this->_tarname . ".tmp", $this->_tarname);
return false;
}
if (!$this->_openWrite()) {
- @rename($this->_tarname.".tmp", $this->_tarname);
+ @rename($this->_tarname . ".tmp", $this->_tarname);
return false;
}
if ($this->_compress_type == 'gz') {
+ $end_blocks = 0;
+
while (!@gzeof($v_temp_tar)) {
$v_buffer = @gzread($v_temp_tar, 512);
- if ($v_buffer == ARCHIVE_TAR_END_BLOCK) {
+ if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
+ $end_blocks++;
// do not copy end blocks, we will re-make them
// after appending
continue;
+ } elseif ($end_blocks > 0) {
+ for ($i = 0; $i < $end_blocks; $i++) {
+ $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
+ }
+ $end_blocks = 0;
}
$v_binary_data = pack("a512", $v_buffer);
$this->_writeBlock($v_binary_data);
}
@gzclose($v_temp_tar);
- }
- elseif ($this->_compress_type == 'bz2') {
+ } elseif ($this->_compress_type == 'bz2') {
+ $end_blocks = 0;
+
while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) {
- if ($v_buffer == ARCHIVE_TAR_END_BLOCK) {
+ if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
+ $end_blocks++;
+ // do not copy end blocks, we will re-make them
+ // after appending
continue;
+ } elseif ($end_blocks > 0) {
+ for ($i = 0; $i < $end_blocks; $i++) {
+ $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
+ }
+ $end_blocks = 0;
}
$v_binary_data = pack("a512", $v_buffer);
$this->_writeBlock($v_binary_data);
}
@bzclose($v_temp_tar);
- }
+ } elseif ($this->_compress_type == 'lzma2') {
+ $end_blocks = 0;
+
+ while (strlen($v_buffer = @xzread($v_temp_tar, 512)) > 0) {
+ if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
+ $end_blocks++;
+ // do not copy end blocks, we will re-make them
+ // after appending
+ continue;
+ } elseif ($end_blocks > 0) {
+ for ($i = 0; $i < $end_blocks; $i++) {
+ $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
+ }
+ $end_blocks = 0;
+ }
+ $v_binary_data = pack("a512", $v_buffer);
+ $this->_writeBlock($v_binary_data);
+ }
- if (!@drupal_unlink($this->_tarname.".tmp")) {
- $this->_error('Error while deleting temporary file \''
- .$this->_tarname.'.tmp\'');
+ @xzclose($v_temp_tar);
}
+ if (!@drupal_unlink($this->_tarname . ".tmp")) {
+ $this->_error(
+ 'Error while deleting temporary file \''
+ . $this->_tarname . '.tmp\''
+ );
+ }
} else {
// ----- For not compressed tar, just add files before the last
- // one or two 512 bytes block
- if (!$this->_openReadWrite())
- return false;
+ // one or two 512 bytes block
+ if (!$this->_openReadWrite()) {
+ return false;
+ }
clearstatcache();
$v_size = filesize($this->_tarname);
@@ -1760,32 +2324,34 @@ class Archive_Tar // extends PEAR
fseek($this->_file, $v_size - 1024);
if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
fseek($this->_file, $v_size - 1024);
- }
- elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
+ } elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) {
fseek($this->_file, $v_size - 512);
}
}
return true;
}
- // }}}
- // {{{ _append()
- function _append($p_filelist, $p_add_dir='', $p_remove_dir='')
+ /**
+ * @param $p_filelist
+ * @param string $p_add_dir
+ * @param string $p_remove_dir
+ * @return bool
+ */
+ public function _append($p_filelist, $p_add_dir = '', $p_remove_dir = '')
{
- if (!$this->_openAppend())
+ if (!$this->_openAppend()) {
return false;
+ }
- if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir))
- $this->_writeFooter();
+ if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir)) {
+ $this->_writeFooter();
+ }
$this->_close();
return true;
}
- // }}}
-
- // {{{ _dirCheck()
/**
* Check if a directory exists and create it (including parent
@@ -1793,24 +2359,25 @@ class Archive_Tar // extends PEAR
*
* @param string $p_dir directory to check
*
- * @return bool TRUE if the directory exists or was created
+ * @return bool true if the directory exists or was created
*/
- function _dirCheck($p_dir)
+ public function _dirCheck($p_dir)
{
clearstatcache();
- if ((@is_dir($p_dir)) || ($p_dir == ''))
+ if ((@is_dir($p_dir)) || ($p_dir == '')) {
return true;
+ }
$p_parent_dir = dirname($p_dir);
if (($p_parent_dir != $p_dir) &&
($p_parent_dir != '') &&
- (!$this->_dirCheck($p_parent_dir)))
- return false;
+ (!$this->_dirCheck($p_parent_dir))
+ ) {
+ return false;
+ }
- // Drupal integration.
- // Changed the code to use drupal_mkdir() instead of mkdir().
- if (!@drupal_mkdir($p_dir, 0777)) {
+ if (!@mkdir($p_dir, 0777)) {
$this->_error("Unable to create directory '$p_dir'");
return false;
}
@@ -1818,10 +2385,6 @@ class Archive_Tar // extends PEAR
return true;
}
- // }}}
-
- // {{{ _pathReduction()
-
/**
* Compress path by changing for example "/dir/foo/../bar" to "/dir/bar",
* rand emove double slashes.
@@ -1829,11 +2392,8 @@ class Archive_Tar // extends PEAR
* @param string $p_dir path to reduce
*
* @return string reduced path
- *
- * @access private
- *
*/
- function _pathReduction($p_dir)
+ private function _pathReduction($p_dir)
{
$v_result = '';
@@ -1843,50 +2403,57 @@ class Archive_Tar // extends PEAR
$v_list = explode('/', $p_dir);
// ----- Study directories from last to first
- for ($i=sizeof($v_list)-1; $i>=0; $i--) {
+ for ($i = sizeof($v_list) - 1; $i >= 0; $i--) {
// ----- Look for current path
if ($v_list[$i] == ".") {
// ----- Ignore this directory
// Should be the first $i=0, but no check is done
- }
- else if ($v_list[$i] == "..") {
- // ----- Ignore it and ignore the $i-1
- $i--;
- }
- else if ( ($v_list[$i] == '')
- && ($i!=(sizeof($v_list)-1))
- && ($i!=0)) {
- // ----- Ignore only the double '//' in path,
- // but not the first and last /
} else {
- $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?'/'
- .$v_result:'');
+ if ($v_list[$i] == "..") {
+ // ----- Ignore it and ignore the $i-1
+ $i--;
+ } else {
+ if (($v_list[$i] == '')
+ && ($i != (sizeof($v_list) - 1))
+ && ($i != 0)
+ ) {
+ // ----- Ignore only the double '//' in path,
+ // but not the first and last /
+ } else {
+ $v_result = $v_list[$i] . ($i != (sizeof($v_list) - 1) ? '/'
+ . $v_result : '');
+ }
+ }
}
}
}
- $v_result = strtr($v_result, '\\', '/');
+
+ if (defined('OS_WINDOWS') && OS_WINDOWS) {
+ $v_result = strtr($v_result, '\\', '/');
+ }
+
return $v_result;
}
- // }}}
-
- // {{{ _translateWinPath()
- function _translateWinPath($p_path, $p_remove_disk_letter=true)
+ /**
+ * @param $p_path
+ * @param bool $p_remove_disk_letter
+ * @return string
+ */
+ public function _translateWinPath($p_path, $p_remove_disk_letter = true)
{
- if (defined('OS_WINDOWS') && OS_WINDOWS) {
- // ----- Look for potential disk letter
- if ( ($p_remove_disk_letter)
- && (($v_position = strpos($p_path, ':')) != false)) {
- $p_path = substr($p_path, $v_position+1);
- }
- // ----- Change potential windows directory separator
- if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
- $p_path = strtr($p_path, '\\', '/');
- }
- }
- return $p_path;
+ if (defined('OS_WINDOWS') && OS_WINDOWS) {
+ // ----- Look for potential disk letter
+ if (($p_remove_disk_letter)
+ && (($v_position = strpos($p_path, ':')) != false)
+ ) {
+ $p_path = substr($p_path, $v_position + 1);
+ }
+ // ----- Change potential windows directory separator
+ if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) {
+ $p_path = strtr($p_path, '\\', '/');
+ }
+ }
+ return $p_path;
}
- // }}}
-
}
-?>
diff --git a/modules/system/system.test b/modules/system/system.test
index d4c98f0a..9eaf562b 100644
--- a/modules/system/system.test
+++ b/modules/system/system.test
@@ -389,6 +389,18 @@ class ModuleDependencyTestCase extends ModuleTestCase {
);
}
+ /**
+ * Checks functionality of project namespaces for dependencies.
+ */
+ function testProjectNamespaceForDependencies() {
+ // Enable module with project namespace to ensure nothing breaks.
+ $edit = array(
+ 'modules[Testing][system_project_namespace_test][enable]' => TRUE,
+ );
+ $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+ $this->assertModules(array('system_project_namespace_test'), TRUE);
+ }
+
/**
* Attempt to enable translation module without locale enabled.
*/
@@ -714,7 +726,7 @@ class IPAddressBlockingTestCase extends DrupalWebTestCase {
// Block a valid IP address.
$edit = array();
- $edit['ip'] = '192.168.1.1';
+ $edit['ip'] = '1.2.3.3';
$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->assertTrue($ip, t('IP address found in database.'));
@@ -722,7 +734,7 @@ class IPAddressBlockingTestCase extends DrupalWebTestCase {
// Try to block an IP address that's already blocked.
$edit = array();
- $edit['ip'] = '192.168.1.1';
+ $edit['ip'] = '1.2.3.3';
$this->drupalPost('admin/config/people/ip-blocking', $edit, t('Add'));
$this->assertText(t('This IP address is already blocked.'));
@@ -758,6 +770,25 @@ class IPAddressBlockingTestCase extends DrupalWebTestCase {
// $this->drupalPost('admin/config/people/ip-blocking', $edit, t('Save'));
// $this->assertText(t('You may not block your own IP address.'));
}
+
+ /**
+ * Test duplicate IP addresses are not present in the 'blocked_ips' table.
+ */
+ function testDuplicateIpAddress() {
+ drupal_static_reset('ip_address');
+ $submit_ip = $_SERVER['REMOTE_ADDR'] = '192.168.1.1';
+ system_block_ip_action();
+ system_block_ip_action();
+ $ip_count = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $submit_ip))->rowCount();
+ $this->assertEqual('1', $ip_count);
+ drupal_static_reset('ip_address');
+ $submit_ip = $_SERVER['REMOTE_ADDR'] = ' ';
+ system_block_ip_action();
+ system_block_ip_action();
+ system_block_ip_action();
+ $ip_count = db_query("SELECT iid from {blocked_ips} WHERE ip = :ip", array(':ip' => $submit_ip))->rowCount();
+ $this->assertEqual('1', $ip_count);
+ }
}
class CronRunTestCase extends DrupalWebTestCase {
@@ -893,6 +924,29 @@ class CronRunTestCase extends DrupalWebTestCase {
$result = variable_get('common_test_cron');
$this->assertEqual($result, 'success', 'Cron correctly handles exceptions thrown during hook_cron() invocations.');
}
+
+ /**
+ * Tests that hook_flush_caches() is not invoked on every single cron run.
+ *
+ * @see system_cron()
+ */
+ public function testCronCacheExpiration() {
+ module_enable(array('system_cron_test'));
+ variable_del('system_cron_test_flush_caches');
+
+ // Invoke cron the first time: hook_flush_caches() should be called and then
+ // get cached.
+ drupal_cron_run();
+ $this->assertEqual(variable_get('system_cron_test_flush_caches'), 1, 'hook_flush_caches() was invoked the first time.');
+ $cache = cache_get('system_cache_tables');
+ $this->assertEqual(empty($cache), FALSE, 'Cache is filled with cache table data.');
+
+ // Run cron again and ensure that hook_flush_caches() is not called.
+ variable_del('system_cron_test_flush_caches');
+ drupal_cron_run();
+ $this->assertNull(variable_get('system_cron_test_flush_caches'), 'hook_flush_caches() was not invoked the second time.');
+ }
+
}
/**
@@ -911,7 +965,7 @@ class CronQueueTestCase extends DrupalWebTestCase {
}
function setUp() {
- parent::setUp(array('common_test', 'common_test_cron_helper'));
+ parent::setUp(array('common_test', 'common_test_cron_helper', 'cron_queue_test'));
}
/**
@@ -931,6 +985,23 @@ class CronQueueTestCase extends DrupalWebTestCase {
$this->assertEqual($queue->numberOfItems(), 1, 'Failing item still in the queue after throwing an exception.');
}
+ /**
+ * Tests worker defined as a class method callable.
+ */
+ function testCallable() {
+ $queue = DrupalQueue::get('cron_queue_test_callback');
+
+ // Enqueue an item for processing.
+ $queue->createItem(array($this->randomName() => $this->randomName()));
+
+ // Run cron; the worker should perform the task and delete the item from the
+ // queue.
+ $this->cronRun();
+
+ // The queue should be empty.
+ $this->assertEqual($queue->numberOfItems(), 0);
+ }
+
}
class AdminMetaTagTestCase extends DrupalWebTestCase {
@@ -1298,7 +1369,23 @@ class DateTimeFunctionalTest extends DrupalWebTestCase {
$this->assertEqual($this->getUrl(), url('admin/config/regional/date-time/formats', array('absolute' => TRUE)), 'Correct page redirection.');
$this->assertText(t('Custom date format updated.'), 'Custom date format successfully updated.');
+ // Check that ajax callback is protected by CSRF token.
+ $this->drupalGet('admin/config/regional/date-time/formats/lookup', array('query' => array('format' => 'Y m d')));
+ $this->assertResponse(403, 'Access denied with no token');
+ $this->drupalGet('admin/config/regional/date-time/formats/lookup', array('query' => array('token' => 'invalid', 'format' => 'Y m d')));
+ $this->assertResponse(403, 'Access denied with invalid token');
+ $this->drupalGet('admin/config/regional/date-time/formats');
+ $this->clickLink(t('edit'));
+ $settings = $this->drupalGetSettings();
+ $lookup_url = $settings['dateTime']['date-format']['lookup'];
+ preg_match('/token=([^&]+)/', $lookup_url, $matches);
+ $this->assertFalse(empty($matches[1]), 'Found token value');
+ $this->drupalGet('admin/config/regional/date-time/formats/lookup', array('query' => array('token' => $matches[1], 'format' => 'Y m d')));
+ $this->assertResponse(200, 'Access allowed with valid token');
+ $this->assertText(format_date(time(), 'custom', 'Y m d'));
+
// Delete custom date format.
+ $this->drupalGet('admin/config/regional/date-time/formats');
$this->clickLink(t('delete'));
$this->drupalPost($this->getUrl(), array(), t('Remove'));
$this->assertEqual($this->getUrl(), url('admin/config/regional/date-time/formats', array('absolute' => TRUE)), 'Correct page redirection.');
@@ -1374,6 +1461,60 @@ class DateTimeFunctionalTest extends DrupalWebTestCase {
}
}
+/**
+ * Tests date format configuration.
+ */
+class DateFormatTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Date format',
+ 'description' => 'Test date format configuration and defaults.',
+ 'group' => 'System',
+ );
+ }
+
+ function setUp() {
+ parent::setUp();
+
+ // Create admin user and log in admin user.
+ $this->admin_user = $this->drupalCreateUser(array('administer site configuration'));
+ $this->drupalLogin($this->admin_user);
+ }
+
+ /**
+ * Test the default date type formats are consistent.
+ */
+ function testDefaultDateFormats() {
+ // These are the default format values from format_date().
+ $default_formats = array(
+ 'short' => 'm/d/Y - H:i',
+ 'medium' => 'D, m/d/Y - H:i',
+ 'long' => 'l, F j, Y - H:i',
+ );
+
+ // Clear the date format variables.
+ variable_del('date_format_short');
+ variable_del('date_format_medium');
+ variable_del('date_format_long');
+
+ $this->drupalGet('admin/config/regional/date-time');
+
+ foreach ($default_formats as $format_name => $format_value) {
+ $id = 'edit-date-format-' . $format_name;
+ // Check that the configuration fields match the default format.
+ $this->assertOptionSelected(
+ $id,
+ $format_value,
+ format_string('The @type format type matches the expected format @format.',
+ array(
+ '@type' => $format_name,
+ '@format' => $format_value,
+ )
+ ));
+ }
+ }
+}
+
class PageTitleFiltering extends DrupalWebTestCase {
protected $content_user;
protected $saved_title;
@@ -2286,6 +2427,20 @@ class UpdateScriptFunctionalTest extends DrupalWebTestCase {
$this->update_user = $this->drupalCreateUser(array('administer software updates'));
}
+ /**
+ * Tests that there are no pending updates for the first test method.
+ */
+ function testNoPendingUpdates() {
+ // Ensure that for the first test method in a class, there are no pending
+ // updates. This tests a drupal_get_schema_versions() bug that previously
+ // led to the wrong schema version being recorded for the initial install
+ // of a child site during automated testing.
+ $this->drupalLogin($this->update_user);
+ $this->drupalGet($this->update_url, array('external' => TRUE));
+ $this->drupalPost(NULL, array(), t('Continue'));
+ $this->assertText(t('No pending updates.'), 'End of update process was reached.');
+ }
+
/**
* Tests access to the update script.
*/
@@ -2367,6 +2522,12 @@ class UpdateScriptFunctionalTest extends DrupalWebTestCase {
$this->assertText('This is a requirements error provided by the update_script_test module.');
$this->clickLink('try again');
$this->assertText('This is a requirements error provided by the update_script_test module.');
+
+ // Check if the optional 'value' key displays without a notice.
+ variable_set('update_script_test_requirement_type', REQUIREMENT_INFO);
+ $this->drupalGet($this->update_url, array('external' => TRUE));
+ $this->assertText('This is a requirements info provided by the update_script_test module.');
+ $this->assertNoText('Notice: Undefined index: value in theme_status_report()');
}
/**
diff --git a/modules/system/system.updater.inc b/modules/system/system.updater.inc
index a14d788b..2a32c4b5 100644
--- a/modules/system/system.updater.inc
+++ b/modules/system/system.updater.inc
@@ -24,7 +24,7 @@ class ModuleUpdater extends Updater implements DrupalUpdaterInterface {
* found on your system, and if there was a copy in sites/all, we'd see it.
*/
public function getInstallDirectory() {
- if ($relative_path = drupal_get_path('module', $this->name)) {
+ if ($this->isInstalled() && ($relative_path = drupal_get_path('module', $this->name))) {
$relative_path = dirname($relative_path);
}
else {
@@ -34,7 +34,7 @@ class ModuleUpdater extends Updater implements DrupalUpdaterInterface {
}
public function isInstalled() {
- return (bool) drupal_get_path('module', $this->name);
+ return (bool) drupal_get_filename('module', $this->name, NULL, FALSE);
}
public static function canUpdateDirectory($directory) {
@@ -109,7 +109,7 @@ class ThemeUpdater extends Updater implements DrupalUpdaterInterface {
* found on your system, and if there was a copy in sites/all, we'd see it.
*/
public function getInstallDirectory() {
- if ($relative_path = drupal_get_path('theme', $this->name)) {
+ if ($this->isInstalled() && ($relative_path = drupal_get_path('theme', $this->name))) {
$relative_path = dirname($relative_path);
}
else {
@@ -119,7 +119,7 @@ class ThemeUpdater extends Updater implements DrupalUpdaterInterface {
}
public function isInstalled() {
- return (bool) drupal_get_path('theme', $this->name);
+ return (bool) drupal_get_filename('theme', $this->name, NULL, FALSE);
}
static function canUpdateDirectory($directory) {
diff --git a/modules/system/tests/cron_queue_test.info b/modules/system/tests/cron_queue_test.info
index 09f8a323..ef94eeda 100644
--- a/modules/system/tests/cron_queue_test.info
+++ b/modules/system/tests/cron_queue_test.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/system/tests/cron_queue_test.module b/modules/system/tests/cron_queue_test.module
index e95c6b6a..0df6396a 100644
--- a/modules/system/tests/cron_queue_test.module
+++ b/modules/system/tests/cron_queue_test.module
@@ -7,9 +7,21 @@ function cron_queue_test_cron_queue_info() {
$queues['cron_queue_test_exception'] = array(
'worker callback' => 'cron_queue_test_exception',
);
+ $queues['cron_queue_test_callback'] = array(
+ 'worker callback' => array('CronQueueTestCallbackClass', 'foo'),
+ );
+
return $queues;
}
function cron_queue_test_exception($item) {
throw new Exception('That is not supposed to happen.');
}
+
+class CronQueueTestCallbackClass {
+
+ static public function foo() {
+ // Do nothing.
+ }
+
+}
diff --git a/modules/system/tests/system_cron_test.info b/modules/system/tests/system_cron_test.info
new file mode 100644
index 00000000..d9d4edd3
--- /dev/null
+++ b/modules/system/tests/system_cron_test.info
@@ -0,0 +1,11 @@
+name = System Cron Test
+description = 'Support module for testing the system_cron().'
+package = Testing
+version = VERSION
+core = 7.x
+hidden = TRUE
+
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
+project = "drupal"
+datestamp = "1539816636"
diff --git a/modules/system/tests/system_cron_test.module b/modules/system/tests/system_cron_test.module
new file mode 100644
index 00000000..9ef80e23
--- /dev/null
+++ b/modules/system/tests/system_cron_test.module
@@ -0,0 +1,15 @@
+ $bundle->type,
'settings' => array(),
'description' => 'Debris left over after upgrade from Drupal 6',
+ 'required' => FALSE,
'widget' => array(
'type' => 'taxonomy_autocomplete',
'module' => 'taxonomy',
@@ -557,7 +558,7 @@ function taxonomy_update_7005(&$sandbox) {
// of term references stored so far for the current revision, which
// provides the delta value for each term reference data insert. The
// deltas are reset for each new revision.
-
+
$conditions = array(
'type' => 'taxonomy_term_reference',
'deleted' => 0,
diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module
index e147c1ca..981649d2 100644
--- a/modules/taxonomy/taxonomy.module
+++ b/modules/taxonomy/taxonomy.module
@@ -25,7 +25,7 @@ function taxonomy_help($path, $arg) {
$output .= '
' . t('Uses') . '
';
$output .= '
';
$output .= '
' . t('Creating vocabularies') . '
';
- $output .= '
' . t('Users with sufficient permissions can create vocabularies and terms through the Taxonomy page. The page listing the terms provides a drag-and-drop interface for controlling the order of the terms and sub-terms within a vocabulary, in a hierarchical fashion. A controlled vocabulary classifying music by genre with terms and sub-terms could look as follows:', array('@taxo' => url('admin/structure/taxonomy'), '@perm' => url('admin/people/permissions', array('fragment'=>'module-taxonomy'))));
+ $output .= '
' . t('Users with sufficient permissions can create vocabularies and terms through the Taxonomy page. The page listing the terms provides a drag-and-drop interface for controlling the order of the terms and sub-terms within a vocabulary, in a hierarchical fashion. A controlled vocabulary classifying music by genre with terms and sub-terms could look as follows:', array('@taxo' => url('admin/structure/taxonomy'), '@perm' => url('admin/people/permissions', array('fragment' => 'module-taxonomy'))));
$output .= '
' . t('vocabulary: Music') . '
';
$output .= '
' . t('term: Jazz') . '
';
$output .= '
' . t('sub-term: Swing') . '
';
@@ -1023,7 +1023,7 @@ function taxonomy_get_parents($tid) {
$query->join('taxonomy_term_hierarchy', 'h', 'h.parent = t.tid');
$query->addField('t', 'tid');
$query->condition('h.tid', $tid);
- $query->addTag('term_access');
+ $query->addTag('taxonomy_term_access');
$query->orderBy('t.weight');
$query->orderBy('t.name');
$tids = $query->execute()->fetchCol();
@@ -1081,7 +1081,7 @@ function taxonomy_get_children($tid, $vid = 0) {
if ($vid) {
$query->condition('t.vid', $vid);
}
- $query->addTag('term_access');
+ $query->addTag('taxonomy_term_access');
$query->orderBy('t.weight');
$query->orderBy('t.name');
$tids = $query->execute()->fetchCol();
@@ -1129,7 +1129,7 @@ function taxonomy_get_tree($vid, $parent = 0, $max_depth = NULL, $load_entities
$query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
$result = $query
->addTag('translatable')
- ->addTag('term_access')
+ ->addTag('taxonomy_term_access')
->fields('t')
->fields('h', array('parent'))
->condition('t.vid', $vid)
@@ -1249,7 +1249,7 @@ class TaxonomyTermController extends DrupalDefaultEntityController {
protected function buildQuery($ids, $conditions = array(), $revision_id = FALSE) {
$query = parent::buildQuery($ids, $conditions, $revision_id);
$query->addTag('translatable');
- $query->addTag('term_access');
+ $query->addTag('taxonomy_term_access');
// When name is passed as a condition use LIKE.
if (isset($conditions['name'])) {
$query_conditions = &$query->conditions();
diff --git a/modules/taxonomy/taxonomy.pages.inc b/modules/taxonomy/taxonomy.pages.inc
index 975ff120..38b24b3b 100644
--- a/modules/taxonomy/taxonomy.pages.inc
+++ b/modules/taxonomy/taxonomy.pages.inc
@@ -150,7 +150,7 @@ function taxonomy_autocomplete($field_name = '', $tags_typed = '') {
$query = db_select('taxonomy_term_data', 't');
$query->addTag('translatable');
- $query->addTag('term_access');
+ $query->addTag('taxonomy_term_access');
// Do not select already entered terms.
if (!empty($tags_typed)) {
diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test
index fdf354b7..a4b7ee83 100644
--- a/modules/taxonomy/taxonomy.test
+++ b/modules/taxonomy/taxonomy.test
@@ -1025,7 +1025,7 @@ class TaxonomyRSSTestCase extends TaxonomyWebTestCase {
function setUp() {
parent::setUp('taxonomy');
- $this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'bypass node access', 'administer content types'));
+ $this->admin_user = $this->drupalCreateUser(array('administer taxonomy', 'bypass node access', 'administer content types', 'administer fields'));
$this->drupalLogin($this->admin_user);
$this->vocabulary = $this->createVocabulary();
@@ -1983,3 +1983,113 @@ class TaxonomyEFQTestCase extends TaxonomyWebTestCase {
}
}
+
+/**
+ * Tests that appropriate query tags are added.
+ */
+class TaxonomyQueryAlterTestCase extends TaxonomyWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Taxonomy query tags',
+ 'description' => 'Verifies that taxonomy_term_access tags are added to queries.',
+ 'group' => 'Taxonomy',
+ );
+ }
+
+ public function setUp() {
+ parent::setUp('taxonomy_test');
+ }
+
+ /**
+ * Tests that appropriate tags are added when querying the database.
+ */
+ public function testTaxonomyQueryAlter() {
+ // Create a new vocabulary and add a few terms to it.
+ $vocabulary = $this->createVocabulary();
+ $terms = array();
+ for ($i = 0; $i < 5; $i++) {
+ $terms[$i] = $this->createTerm($vocabulary);
+ }
+
+ // Set up hierarchy. Term 2 is a child of 1.
+ $terms[2]->parent = array($terms[1]->tid);
+ taxonomy_term_save($terms[2]);
+
+ $this->setupQueryTagTestHooks();
+ $loaded_term = taxonomy_term_load($terms[0]->tid);
+ $this->assertEqual($loaded_term->tid, $terms[0]->tid, 'First term was loaded');
+ $this->assertQueryTagTestResult(1, 'taxonomy_term_load()');
+
+ $this->setupQueryTagTestHooks();
+ $loaded_terms = taxonomy_get_tree($vocabulary->vid);
+ $this->assertEqual(count($loaded_terms), count($terms), 'All terms were loaded');
+ $this->assertQueryTagTestResult(1, 'taxonomy_get_tree()');
+
+ $this->setupQueryTagTestHooks();
+ $loaded_terms = taxonomy_get_parents($terms[2]->tid);
+ $this->assertEqual(count($loaded_terms), 1, 'All parent terms were loaded');
+ $this->assertQueryTagTestResult(2, 'taxonomy_get_parents()');
+
+ $this->setupQueryTagTestHooks();
+ $loaded_terms = taxonomy_get_children($terms[1]->tid);
+ $this->assertEqual(count($loaded_terms), 1, 'All child terms were loaded');
+ $this->assertQueryTagTestResult(2, 'taxonomy_get_children()');
+
+ $this->setupQueryTagTestHooks();
+ $query = db_select('taxonomy_term_data', 't');
+ $query->addField('t', 'tid');
+ $query->addTag('taxonomy_term_access');
+ $tids = $query->execute()->fetchCol();
+ $this->assertEqual(count($tids), count($terms), 'All term IDs were retrieved');
+ $this->assertQueryTagTestResult(1, 'custom db_select() with taxonomy_term_access tag (preferred)');
+
+ $this->setupQueryTagTestHooks();
+ $query = db_select('taxonomy_term_data', 't');
+ $query->addField('t', 'tid');
+ $query->addTag('term_access');
+ $tids = $query->execute()->fetchCol();
+ $this->assertEqual(count($tids), count($terms), 'All term IDs were retrieved');
+ $this->assertQueryTagTestResult(1, 'custom db_select() with term_access tag (deprecated)');
+
+ $this->setupQueryTagTestHooks();
+ $query = new EntityFieldQuery();
+ $query->entityCondition('entity_type', 'taxonomy_term');
+ $query->addTag('taxonomy_term_access');
+ $result = $query->execute();
+ $this->assertEqual(count($result['taxonomy_term']), count($terms), 'All term IDs were retrieved');
+ $this->assertQueryTagTestResult(1, 'custom EntityFieldQuery with taxonomy_term_access tag (preferred)');
+
+ $this->setupQueryTagTestHooks();
+ $query = new EntityFieldQuery();
+ $query->entityCondition('entity_type', 'taxonomy_term');
+ $query->addTag('term_access');
+ $result = $query->execute();
+ $this->assertEqual(count($result['taxonomy_term']), count($terms), 'All term IDs were retrieved');
+ $this->assertQueryTagTestResult(1, 'custom EntityFieldQuery with term_access tag (deprecated)');
+ }
+
+ /**
+ * Sets up the hooks in the test module.
+ */
+ protected function setupQueryTagTestHooks() {
+ taxonomy_terms_static_reset();
+ variable_set('taxonomy_test_query_alter', 0);
+ variable_set('taxonomy_test_query_term_access_alter', 0);
+ variable_set('taxonomy_test_query_taxonomy_term_access_alter', 0);
+ }
+
+ /**
+ * Verifies invocation of the hooks in the test module.
+ *
+ * @param int $expected_invocations
+ * The number of times the hooks are expected to have been invoked.
+ * @param string $method
+ * A string describing the invoked function which generated the query.
+ */
+ protected function assertQueryTagTestResult($expected_invocations, $method) {
+ $this->assertIdentical($expected_invocations, variable_get('taxonomy_test_query_alter'), 'hook_query_alter() invoked when executing ' . $method);
+ $this->assertIdentical($expected_invocations, variable_get('taxonomy_test_query_term_access_alter'), 'Deprecated hook_query_term_access_alter() invoked when executing ' . $method);
+ $this->assertIdentical($expected_invocations, variable_get('taxonomy_test_query_taxonomy_term_access_alter'), 'Preferred hook_query_taxonomy_term_access_alter() invoked when executing ' . $method);
+ }
+
+}
diff --git a/modules/toolbar/toolbar.info b/modules/toolbar/toolbar.info
index 75a670ea..ffa40ee7 100644
--- a/modules/toolbar/toolbar.info
+++ b/modules/toolbar/toolbar.info
@@ -4,8 +4,7 @@ core = 7.x
package = Core
version = VERSION
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/tracker/tracker.info b/modules/tracker/tracker.info
index 43ddc511..dbd7384c 100644
--- a/modules/tracker/tracker.info
+++ b/modules/tracker/tracker.info
@@ -6,8 +6,7 @@ version = VERSION
core = 7.x
files[] = tracker.test
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/tracker/tracker.test b/modules/tracker/tracker.test
index 8a48ea81..e4729788 100644
--- a/modules/tracker/tracker.test
+++ b/modules/tracker/tracker.test
@@ -151,7 +151,6 @@ class TrackerTest extends DrupalWebTestCase {
$node = $this->drupalCreateNode(array(
'comment' => 2,
- 'title' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(8)))),
));
// Add a comment to the page.
diff --git a/modules/translation/tests/translation_test.info b/modules/translation/tests/translation_test.info
index 14da1a48..9d5b4a5b 100644
--- a/modules/translation/tests/translation_test.info
+++ b/modules/translation/tests/translation_test.info
@@ -5,8 +5,7 @@ package = Testing
version = VERSION
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/translation/translation.info b/modules/translation/translation.info
index 533412ce..6ed39ca6 100644
--- a/modules/translation/translation.info
+++ b/modules/translation/translation.info
@@ -6,8 +6,7 @@ version = VERSION
core = 7.x
files[] = translation.test
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/trigger/tests/trigger_test.info b/modules/trigger/tests/trigger_test.info
index b4f052fc..196cfcf1 100644
--- a/modules/trigger/tests/trigger_test.info
+++ b/modules/trigger/tests/trigger_test.info
@@ -4,8 +4,7 @@ package = Testing
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/trigger/trigger.info b/modules/trigger/trigger.info
index 2b088436..b78c34d7 100644
--- a/modules/trigger/trigger.info
+++ b/modules/trigger/trigger.info
@@ -6,8 +6,7 @@ core = 7.x
files[] = trigger.test
configure = admin/structure/trigger
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/trigger/trigger.test b/modules/trigger/trigger.test
index 9e5f1142..09169b72 100644
--- a/modules/trigger/trigger.test
+++ b/modules/trigger/trigger.test
@@ -85,7 +85,7 @@ class TriggerContentTestCase extends TriggerWebTestCase {
$this->assertRaw(t('!post %title has been created.', array('!post' => 'Basic page', '%title' => $edit["title"])), 'Make sure the Basic page has actually been created');
// Action should have been fired.
$loaded_node = $this->drupalGetNodeByTitle($edit["title"]);
- $this->assertTrue($loaded_node->$info['property'] == $info['expected'], format_string('Make sure the @action action fired.', array('@action' => $info['name'])));
+ $this->assertTrue($loaded_node->{$info['property']} == $info['expected'], format_string('Make sure the @action action fired.', array('@action' => $info['name'])));
// Leave action assigned for next test
// There should be an error when the action is assigned to the trigger
diff --git a/modules/update/tests/aaa_update_test.info b/modules/update/tests/aaa_update_test.info
index e0bbebd5..620e82ee 100644
--- a/modules/update/tests/aaa_update_test.info
+++ b/modules/update/tests/aaa_update_test.info
@@ -4,8 +4,7 @@ package = Testing
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/update/tests/bbb_update_test.info b/modules/update/tests/bbb_update_test.info
index 94c8adea..b9953c16 100644
--- a/modules/update/tests/bbb_update_test.info
+++ b/modules/update/tests/bbb_update_test.info
@@ -4,8 +4,7 @@ package = Testing
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/update/tests/ccc_update_test.info b/modules/update/tests/ccc_update_test.info
index 09598697..e855562a 100644
--- a/modules/update/tests/ccc_update_test.info
+++ b/modules/update/tests/ccc_update_test.info
@@ -4,8 +4,7 @@ package = Testing
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info b/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info
new file mode 100644
index 00000000..cf1d3c36
--- /dev/null
+++ b/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info
@@ -0,0 +1,9 @@
+name = Update test admin theme
+description = Test theme which is used as admin theme.
+core = 7.x
+hidden = TRUE
+
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
+project = "drupal"
+datestamp = "1539816636"
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 6954b3d4..11c81321 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,7 @@ 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 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
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 81c222ef..aa5bc12c 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,7 @@ core = 7.x
base theme = update_test_basetheme
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/update/tests/update_test.info b/modules/update/tests/update_test.info
index f899512e..6b4802f6 100644
--- a/modules/update/tests/update_test.info
+++ b/modules/update/tests/update_test.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/update/tests/update_test.module b/modules/update/tests/update_test.module
index 6fe4bdde..594f80f0 100644
--- a/modules/update/tests/update_test.module
+++ b/modules/update/tests/update_test.module
@@ -11,6 +11,7 @@
function update_test_system_theme_info() {
$themes['update_test_basetheme'] = drupal_get_path('module', 'update_test') . '/themes/update_test_basetheme/update_test_basetheme.info';
$themes['update_test_subtheme'] = drupal_get_path('module', 'update_test') . '/themes/update_test_subtheme/update_test_subtheme.info';
+ $themes['update_test_admintheme'] = drupal_get_path('module', 'update_test') . '/themes/update_test_admintheme/update_test_admintheme.info';
return $themes;
}
diff --git a/modules/update/update.authorize.inc b/modules/update/update.authorize.inc
index 6ddd2c53..03d37049 100644
--- a/modules/update/update.authorize.inc
+++ b/modules/update/update.authorize.inc
@@ -97,7 +97,9 @@ function update_authorize_run_install($filetransfer, $project, $updater_name, $l
}
/**
- * Batch callback: Copies project to its proper place when authorized to do so.
+ * Implements callback_batch_operation().
+ *
+ * Copies project to its proper place when authorized to do so.
*
* @param string $project
* The canonical short name of the project being installed.
@@ -168,7 +170,9 @@ function update_authorize_batch_copy_project($project, $updater_name, $local_url
}
/**
- * Batch callback: Performs actions when the authorized update batch is done.
+ * Implements callback_batch_finished().
+ *
+ * Performs actions when the authorized update batch is done.
*
* This processes the results and stashes them into SESSION such that
* authorize.php will render a report. Also responsible for putting the site
@@ -235,7 +239,9 @@ function update_authorize_update_batch_finished($success, $results) {
}
/**
- * Batch callback: Performs actions when the authorized install batch is done.
+ * Implements callback_batch_finished().
+ *
+ * Performs actions when the authorized install batch is done.
*
* This processes the results and stashes them into SESSION such that
* authorize.php will render a report. Also responsible for putting the site
diff --git a/modules/update/update.compare.inc b/modules/update/update.compare.inc
index 072a0daa..e3e0de3b 100644
--- a/modules/update/update.compare.inc
+++ b/modules/update/update.compare.inc
@@ -104,7 +104,13 @@ function update_get_projects() {
* @see update_get_projects()
*/
function _update_process_info_list(&$projects, $list, $project_type, $status) {
+ $admin_theme = variable_get('admin_theme', 'seven');
foreach ($list as $file) {
+ // The admin theme is a special case. It should always be considered enabled
+ // for the purposes of update checking.
+ if ($file->name === $admin_theme) {
+ $file->status = TRUE;
+ }
// A disabled base theme of an enabled sub-theme still has all of its code
// run by the sub-theme, so we include it in our "enabled" projects list.
if ($status && !$file->status && !empty($file->sub_themes)) {
diff --git a/modules/update/update.fetch.inc b/modules/update/update.fetch.inc
index 9dd2f0ba..428cace6 100644
--- a/modules/update/update.fetch.inc
+++ b/modules/update/update.fetch.inc
@@ -29,7 +29,9 @@ function update_manual_status() {
}
/**
- * Batch callback: Processes a step in batch for fetching available update data.
+ * Implements callback_batch_operation().
+ *
+ * Processes a step in batch for fetching available update data.
*
* @param $context
* Reference to an array used for Batch API storage.
@@ -77,7 +79,9 @@ function update_fetch_data_batch(&$context) {
}
/**
- * Batch callback: Performs actions when all fetch tasks have been completed.
+ * Implements callback_batch_finished().
+ *
+ * Performs actions when all fetch tasks have been completed.
*
* @param $success
* TRUE if the batch operation was successful; FALSE if there were errors.
diff --git a/modules/update/update.info b/modules/update/update.info
index ddd1bde6..4b4dde91 100644
--- a/modules/update/update.info
+++ b/modules/update/update.info
@@ -6,8 +6,7 @@ core = 7.x
files[] = update.test
configure = admin/reports/updates/settings
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/update/update.manager.inc b/modules/update/update.manager.inc
index 85b587de..c7c4e4a6 100644
--- a/modules/update/update.manager.inc
+++ b/modules/update/update.manager.inc
@@ -59,7 +59,7 @@
* @see update_menu()
* @ingroup forms
*/
-function update_manager_update_form($form, $form_state = array(), $context) {
+function update_manager_update_form($form, $form_state, $context) {
if (!_update_manager_check_backends($form, 'update')) {
return $form;
}
@@ -335,6 +335,8 @@ function update_manager_update_form_submit($form, &$form_state) {
}
/**
+ * Implements callback_batch_finished().
+ *
* Batch callback: Performs actions when the download batch is completed.
*
* @param $success
@@ -847,7 +849,9 @@ function update_manager_file_get($url) {
}
/**
- * Batch callback: Downloads, unpacks, and verifies a project.
+ * Implements callback_batch_operation().
+ *
+ * Downloads, unpacks, and verifies a project.
*
* This function assumes that the provided URL points to a file archive of some
* sort. The URL can have any scheme that we have a file stream wrapper to
diff --git a/modules/update/update.settings.inc b/modules/update/update.settings.inc
index 5cd24149..75de6cdd 100644
--- a/modules/update/update.settings.inc
+++ b/modules/update/update.settings.inc
@@ -26,7 +26,7 @@ function update_settings($form) {
$form['update_check_disabled'] = array(
'#type' => 'checkbox',
- '#title' => t('Check for updates of disabled modules and themes'),
+ '#title' => t('Check for updates of disabled and uninstalled modules and themes'),
'#default_value' => variable_get('update_check_disabled', FALSE),
);
@@ -98,10 +98,11 @@ function update_settings_validate($form, &$form_state) {
* Form submission handler for update_settings().
*
* Also invalidates the cache of available updates if the "Check for updates of
- * disabled modules and themes" setting is being changed. The available updates
- * report needs to refetch available update data after this setting changes or
- * it would show misleading things (e.g., listing the disabled projects on the
- * site with the "No available releases found" warning).
+ * disabled and uninstalled modules and themes" setting is being changed. The
+ * available updates report needs to refetch available update data after this
+ * setting changes or it would show misleading things (e.g., listing the
+ * disabled projects on the site with the "No available releases found"
+ * warning).
*
* @see update_settings_validate()
*/
diff --git a/modules/update/update.test b/modules/update/update.test
index 9e04cdae..5ce5bb88 100644
--- a/modules/update/update.test
+++ b/modules/update/update.test
@@ -462,6 +462,55 @@ class UpdateTestContribCase extends UpdateTestHelper {
$this->assertRaw(l(t('Update test base theme'), 'http://example.com/project/update_test_basetheme'), 'Link to the Update test base theme project appears.');
}
+ /**
+ * Tests that the admin theme is always notified about security updates.
+ */
+ function testUpdateAdminThemeSecurityUpdate() {
+ // Disable the admin theme.
+ db_update('system')
+ ->fields(array('status' => 0))
+ ->condition('type', 'theme')
+ ->condition('name', 'update_test_%', 'LIKE')
+ ->execute();
+
+ variable_set('admin_theme', 'update_test_admintheme');
+
+ // Define the initial state for core and the themes.
+ $system_info = array(
+ '#all' => array(
+ 'version' => '7.0',
+ ),
+ 'update_test_admintheme' => array(
+ 'project' => 'update_test_admintheme',
+ 'version' => '7.x-1.0',
+ 'hidden' => FALSE,
+ ),
+ 'update_test_basetheme' => array(
+ 'project' => 'update_test_basetheme',
+ 'version' => '7.x-1.1',
+ 'hidden' => FALSE,
+ ),
+ 'update_test_subtheme' => array(
+ 'project' => 'update_test_subtheme',
+ 'version' => '7.x-1.0',
+ 'hidden' => FALSE,
+ ),
+ );
+ variable_set('update_test_system_info', $system_info);
+ variable_set('update_check_disabled', FALSE);
+ $xml_mapping = array(
+ // This is enough because we don't check the update status of the admin
+ // theme. We want to check that the admin theme is included in the list.
+ 'drupal' => '0',
+ );
+ $this->refreshUpdateStatus($xml_mapping);
+ // The admin theme is displayed even if it's disabled.
+ $this->assertText('update_test_admintheme', "The admin theme is checked for update even if it's disabled");
+ // The other disabled themes are not displayed.
+ $this->assertNoText('update_test_basetheme', 'Disabled theme is not checked for update in the list.');
+ $this->assertNoText('update_test_subtheme', 'Disabled theme is not checked for update in the list.');
+ }
+
/**
* Tests that disabled themes are only shown when desired.
*/
@@ -800,4 +849,4 @@ class UpdateCoreUnitTestCase extends DrupalUnitTestCase {
$this->assertEqual($url, $expected, "When ? is present, '$url' should be '$expected'.");
}
-}
\ No newline at end of file
+}
diff --git a/modules/user/tests/user_form_test.info b/modules/user/tests/user_form_test.info
index c8eeeabe..d5a554be 100644
--- a/modules/user/tests/user_form_test.info
+++ b/modules/user/tests/user_form_test.info
@@ -5,8 +5,7 @@ version = VERSION
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/user/tests/user_form_test.module b/modules/user/tests/user_form_test.module
index 4e907f36..382bc57b 100644
--- a/modules/user/tests/user_form_test.module
+++ b/modules/user/tests/user_form_test.module
@@ -62,3 +62,21 @@ function user_form_test_current_password($form, &$form_state, $account) {
function user_form_test_current_password_submit($form, &$form_state) {
drupal_set_message(t('The password has been validated and the form submitted successfully.'));
}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function user_form_test_form_user_profile_form_alter(&$form, &$form_state) {
+ if (variable_get('user_form_test_user_profile_form_rebuild', FALSE)) {
+ $form['#submit'][] = 'user_form_test_user_account_submit';
+ }
+}
+
+/**
+ * Submit function for user_profile_form().
+ */
+function user_form_test_user_account_submit($form, &$form_state) {
+ // Rebuild the form instead of letting the process end. This allows us to
+ // test for bugs that can be triggered in contributed modules.
+ $form_state['rebuild'] = TRUE;
+}
diff --git a/modules/user/user-picture.tpl.php b/modules/user/user-picture.tpl.php
index ee821878..11d92cc5 100644
--- a/modules/user/user-picture.tpl.php
+++ b/modules/user/user-picture.tpl.php
@@ -17,7 +17,7 @@
*/
?>
-
+
diff --git a/modules/user/user.api.php b/modules/user/user.api.php
index edc61bd3..f205a85b 100644
--- a/modules/user/user.api.php
+++ b/modules/user/user.api.php
@@ -123,8 +123,8 @@ function hook_user_cancel($edit, $account, $method) {
* description is NOT used for the radio button, but instead should provide
* additional explanation to the user seeking to cancel their account.
* - access: (optional) A boolean value indicating whether the user can access
- * a method. If #access is defined, the method cannot be configured as default
- * method.
+ * a method. If access is defined, the method cannot be configured as the
+ * default method.
*
* @param $methods
* An array containing user account cancellation methods, keyed by method id.
@@ -183,7 +183,23 @@ function hook_user_operations() {
}
/**
- * Retrieve a list of user setting or profile information categories.
+ * Define a list of user settings or profile information categories.
+ *
+ * There are two steps to using hook_user_categories():
+ * - Create the category with hook_user_categories().
+ * - Display that category on the form ID of "user_profile_form" with
+ * hook_form_FORM_ID_alter().
+ *
+ * Step one builds out the category but it won't be visible on your form until
+ * you explicitly tell it to do so.
+ *
+ * The function in step two should contain the following code in order to
+ * display your new category:
+ * @code
+ * if ($form['#user_category'] == 'mycategory') {
+ * // Return your form here.
+ * }
+ * @endcode
*
* @return
* An array of associative arrays. Each inner array has elements:
diff --git a/modules/user/user.info b/modules/user/user.info
index aaebd74b..3e10c7ee 100644
--- a/modules/user/user.info
+++ b/modules/user/user.info
@@ -9,8 +9,7 @@ required = TRUE
configure = admin/config/people
stylesheets[all][] = user.css
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.39"
+; Information added by Drupal.org packaging script on 2018-10-17
+version = "7.60"
project = "drupal"
-datestamp = "1440020197"
-
+datestamp = "1539816636"
diff --git a/modules/user/user.install b/modules/user/user.install
index b573e72d..7a74766a 100644
--- a/modules/user/user.install
+++ b/modules/user/user.install
@@ -49,6 +49,9 @@ function user_schema() {
'columns' => array('uid' => 'uid'),
),
),
+ 'indexes' => array(
+ 'uid_module' => array('uid', 'module'),
+ ),
);
$schema['role_permission'] = array(
@@ -910,6 +913,15 @@ function user_update_7018() {
}
}
+/**
+ * Ensure there is a combined index on {authmap}.uid and {authmap}.module.
+ */
+function user_update_7019() {
+ // Check first in case it was already added manually.
+ if (!db_index_exists('authmap', 'uid_module')) {
+ db_add_index('authmap', 'uid_module', array('uid', 'module'));
+ }
+}
/**
* @} End of "addtogroup updates-7.x-extra".
*/
diff --git a/modules/user/user.js b/modules/user/user.js
index d182066a..4cf98161 100644
--- a/modules/user/user.js
+++ b/modules/user/user.js
@@ -93,6 +93,8 @@ Drupal.behaviors.password = {
* Returns the estimated strength and the relevant output message.
*/
Drupal.evaluatePasswordStrength = function (password, translate) {
+ password = $.trim(password);
+
var weaknesses = 0, strength = 100, msg = [];
var hasLowercase = /[a-z]+/.test(password);
diff --git a/modules/user/user.module b/modules/user/user.module
index 9637a716..12ca2800 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -418,13 +418,11 @@ function user_load_by_name($name) {
*
* @return
* A fully-loaded $user object upon successful save or FALSE if the save failed.
- *
- * @todo D8: Drop $edit and fix user_save() to be consistent with others.
*/
function user_save($account, $edit = array(), $category = 'account') {
$transaction = db_transaction();
try {
- if (!empty($edit['pass'])) {
+ if (isset($edit['pass']) && strlen(trim($edit['pass'])) > 0) {
// Allow alternate password hashing schemes.
require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
$edit['pass'] = user_hash_password(trim($edit['pass']));
@@ -791,7 +789,7 @@ function user_role_permissions($roles = array()) {
* (optional) The account to check, if not given use currently logged in user.
*
* @return
- * Boolean TRUE if the current user has the requested permission.
+ * Boolean TRUE if the user has the requested permission.
*
* All permission checks in Drupal should go through this function. This
* way, we guarantee consistent behavior, and ensure that the superuser
@@ -958,6 +956,8 @@ function user_search_access() {
*/
function user_search_execute($keys = NULL, $conditions = NULL) {
$find = array();
+ // Escape for LIKE matching.
+ $keys = db_like($keys);
// Replace wildcards with MySQL/PostgreSQL wildcards.
$keys = preg_replace('!\*+!', '%', $keys);
$query = db_select('users')->extend('PagerDefault');
@@ -967,13 +967,13 @@ function user_search_execute($keys = NULL, $conditions = NULL) {
// and they don't need to be restricted to only active users.
$query->fields('users', array('mail'));
$query->condition(db_or()->
- condition('name', '%' . db_like($keys) . '%', 'LIKE')->
- condition('mail', '%' . db_like($keys) . '%', 'LIKE'));
+ condition('name', '%' . $keys . '%', 'LIKE')->
+ condition('mail', '%' . $keys . '%', 'LIKE'));
}
else {
// Regular users can only search via usernames, and we do not show them
// blocked accounts.
- $query->condition('name', '%' . db_like($keys) . '%', 'LIKE')
+ $query->condition('name', '%' . $keys . '%', 'LIKE')
->condition('status', 1);
}
$uids = $query
@@ -1088,13 +1088,16 @@ function user_account_form(&$form, &$form_state) {
'#description' => t('To change the current user password, enter the new password in both fields.'),
);
// To skip the current password field, the user must have logged in via a
- // one-time link and have the token in the URL.
- $pass_reset = isset($_SESSION['pass_reset_' . $account->uid]) && isset($_GET['pass-reset-token']) && ($_GET['pass-reset-token'] == $_SESSION['pass_reset_' . $account->uid]);
+ // one-time link and have the token in the URL. Store this in $form_state
+ // so it persists even on subsequent Ajax requests.
+ if (!isset($form_state['user_pass_reset'])) {
+ $form_state['user_pass_reset'] = isset($_SESSION['pass_reset_' . $account->uid]) && isset($_GET['pass-reset-token']) && ($_GET['pass-reset-token'] == $_SESSION['pass_reset_' . $account->uid]);
+ }
$protected_values = array();
$current_pass_description = '';
// The user may only change their own password without their current
// password if they logged in via a one-time login link.
- if (!$pass_reset) {
+ if (!$form_state['user_pass_reset']) {
$protected_values['mail'] = $form['account']['mail']['#title'];
$protected_values['pass'] = t('Password');
$request_new = l(t('Request new password'), 'user/password', array('attributes' => array('title' => t('Request new password via e-mail.'))));
@@ -1160,7 +1163,7 @@ function user_account_form(&$form, &$form_state) {
$form['account']['roles'] = array(
'#type' => 'checkboxes',
'#title' => t('Roles'),
- '#default_value' => (!$register && isset($account->roles) ? array_keys($account->roles) : array()),
+ '#default_value' => (!$register && !empty($account->roles) ? array_keys(array_filter($account->roles)) : array()),
'#options' => $roles,
'#access' => $roles && user_access('administer permissions'),
DRUPAL_AUTHENTICATED_RID => $checkbox_authenticated,
@@ -1230,7 +1233,7 @@ function user_validate_current_pass(&$form, &$form_state) {
// that prevent them from being empty if they are changed.
if ((strlen(trim($form_state['values'][$key])) > 0) && ($form_state['values'][$key] != $account->$key)) {
require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc');
- $current_pass_failed = empty($form_state['values']['current_pass']) || !user_check_password($form_state['values']['current_pass'], $account);
+ $current_pass_failed = strlen(trim($form_state['values']['current_pass'])) == 0 || !user_check_password($form_state['values']['current_pass'], $account);
if ($current_pass_failed) {
form_set_error('current_pass', t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => $name)));
form_set_error($key);
@@ -1306,10 +1309,12 @@ function user_user_presave(&$edit, $account, $category) {
elseif (!empty($edit['picture_delete'])) {
$edit['picture'] = NULL;
}
- // Prepare user roles.
- if (isset($edit['roles'])) {
- $edit['roles'] = array_filter($edit['roles']);
- }
+ }
+
+ // Filter out roles with empty values to avoid granting extra roles when
+ // processing custom form submissions.
+ if (isset($edit['roles'])) {
+ $edit['roles'] = array_filter($edit['roles']);
}
// Move account cancellation information into $user->data.
@@ -1751,9 +1756,11 @@ function user_menu() {
$items['admin/people/create'] = array(
'title' => 'Add user',
+ 'page callback' => 'user_admin',
'page arguments' => array('create'),
'access arguments' => array('administer users'),
'type' => MENU_LOCAL_ACTION,
+ 'file' => 'user.admin.inc',
);
// Administration pages.
@@ -1911,13 +1918,13 @@ function user_menu_link_alter(&$link) {
// for authenticated users. Authenticated users should see "My account", but
// anonymous users should not see it at all. Therefore, invoke
// user_translated_menu_link_alter() to conditionally hide the link.
- if ($link['link_path'] == 'user' && $link['module'] == 'system') {
+ if ($link['link_path'] == 'user' && isset($link['module']) && $link['module'] == 'system') {
$link['options']['alter'] = TRUE;
}
// Force the Logout link to appear on the top-level of 'user-menu' menu by
// default (i.e., unless it has been customized).
- if ($link['link_path'] == 'user/logout' && $link['module'] == 'system' && empty($link['customized'])) {
+ if ($link['link_path'] == 'user/logout' && isset($link['module']) && $link['module'] == 'system' && empty($link['customized'])) {
$link['plid'] = 0;
}
}
@@ -2161,7 +2168,7 @@ function user_login_name_validate($form, &$form_state) {
*/
function user_login_authenticate_validate($form, &$form_state) {
$password = trim($form_state['values']['pass']);
- if (!empty($form_state['values']['name']) && !empty($password)) {
+ if (!empty($form_state['values']['name']) && strlen(trim($password)) > 0) {
// Do not allow any login from the current user's IP if the limit has been
// reached. Default is 50 failed attempts allowed in one hour. This is
// independent of the per-user limit to catch attempts from one IP to log
@@ -2225,7 +2232,11 @@ function user_login_final_validate($form, &$form_state) {
}
}
else {
- form_set_error('name', t('Sorry, unrecognized username or password. Have you forgotten your password?', array('@password' => url('user/password', array('query' => array('name' => $form_state['values']['name']))))));
+ // Use $form_state['input']['name'] here to guarantee that we send
+ // exactly what the user typed in. $form_state['values']['name'] may have
+ // been modified by validation handlers that ran earlier than this one.
+ $query = isset($form_state['input']['name']) ? array('name' => $form_state['input']['name']) : array();
+ form_set_error('name', t('Sorry, unrecognized username or password. Have you forgotten your password?', array('@password' => url('user/password', array('query' => $query)))));
watchdog('user', 'Login attempt failed for %user.', array('%user' => $form_state['values']['name']));
}
}
@@ -2248,7 +2259,7 @@ function user_login_final_validate($form, &$form_state) {
*/
function user_authenticate($name, $password) {
$uid = FALSE;
- if (!empty($name) && !empty($password)) {
+ if (!empty($name) && strlen(trim($password)) > 0) {
$account = user_load_by_name($name);
if ($account) {
// Allow alternate password hashing schemes.
@@ -2488,7 +2499,9 @@ function user_cancel($edit, $uid, $method) {
}
/**
- * Last batch processing step for cancelling a user account.
+ * Implements callback_batch_operation().
+ *
+ * Last step for cancelling a user account.
*
* Since batch and session API require a valid user account, the actual
* cancellation of a user account needs to happen last.
@@ -2536,6 +2549,8 @@ function _user_cancel($edit, $account, $method) {
}
/**
+ * Implements callback_batch_finished().
+ *
* Finished batch processing callback for cancelling a user account.
*
* @see user_cancel()
@@ -3039,6 +3054,11 @@ function user_role_delete($role) {
$role = user_role_load_by_name($role);
}
+ // If this is the administrator role, delete the user_admin_role variable.
+ if ($role->rid == variable_get('user_admin_role')) {
+ variable_del('user_admin_role');
+ }
+
db_delete('role')
->condition('rid', $role->rid)
->execute();
@@ -3654,12 +3674,7 @@ function user_form_process_password_confirm($element) {
);
$element['#attached']['js'][] = drupal_get_path('module', 'user') . '/user.js';
- // Ensure settings are only added once per page.
- static $already_added = FALSE;
- if (!$already_added) {
- $already_added = TRUE;
- $element['#attached']['js'][] = array('data' => $js_settings, 'type' => 'setting');
- }
+ $element['#attached']['js'][] = array('data' => $js_settings, 'type' => 'setting');
return $element;
}
diff --git a/modules/user/user.pages.inc b/modules/user/user.pages.inc
index f21bd134..2a1b291b 100644
--- a/modules/user/user.pages.inc
+++ b/modules/user/user.pages.inc
@@ -44,6 +44,12 @@ function user_pass() {
$form['name']['#value'] = $user->mail;
$form['mail'] = array(
'#prefix' => '
',
+ // As of https://www.drupal.org/node/889772 the user no longer must log
+ // out (if they are still logged in when using the password reset link,
+ // they will be logged out automatically then), but this text is kept as
+ // is to avoid breaking translations as well as to encourage the user to
+ // log out manually at a time of their own choosing (when it will not
+ // interrupt anything else they may have been in the middle of doing).
'#markup' => t('Password reset instructions will be mailed to %email. You must log out to use the password reset link in the e-mail.', array('%email' => $user->mail)),
'#suffix' => '
',
);
@@ -54,6 +60,11 @@ function user_pass() {
return $form;
}
+/**
+ * Form validation handler for user_pass().
+ *
+ * @see user_pass_submit()
+ */
function user_pass_validate($form, &$form_state) {
$name = trim($form_state['values']['name']);
// Try to load by email.
@@ -72,6 +83,11 @@ function user_pass_validate($form, &$form_state) {
}
}
+/**
+ * Form submission handler for user_pass().
+ *
+ * @see user_pass_validate()
+ */
function user_pass_submit($form, &$form_state) {
global $language;
@@ -96,22 +112,33 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
// When processing the one-time login link, we have to make sure that a user
// isn't already logged in.
if ($user->uid) {
- // The existing user is already logged in.
+ // The existing user is already logged in. Log them out and reload the
+ // current page so the password reset process can continue.
if ($user->uid == $uid) {
- drupal_set_message(t('You are logged in as %user. Change your password.', array('%user' => $user->name, '!user_edit' => url("user/$user->uid/edit"))));
+ // Preserve the current destination (if any) and ensure the redirect goes
+ // back to the current page; any custom destination set in
+ // hook_user_logout() and intended for regular logouts would not be
+ // appropriate here.
+ $destination = array();
+ if (isset($_GET['destination'])) {
+ $destination = drupal_get_destination();
+ }
+ user_logout_current_user();
+ unset($_GET['destination']);
+ drupal_goto(current_path(), array('query' => drupal_get_query_parameters() + $destination));
}
// A different user is already logged in on the computer.
else {
$reset_link_account = user_load($uid);
if (!empty($reset_link_account)) {
drupal_set_message(t('Another user (%other_user) is already logged into the site on this computer, but you tried to use a one-time link for user %resetting_user. Please logout and try using the link again.',
- array('%other_user' => $user->name, '%resetting_user' => $reset_link_account->name, '!logout' => url('user/logout'))));
+ array('%other_user' => $user->name, '%resetting_user' => $reset_link_account->name, '!logout' => url('user/logout'))), 'warning');
} else {
// Invalid one-time link specifies an unknown user.
- drupal_set_message(t('The one-time login link you clicked is invalid.'));
+ drupal_set_message(t('The one-time login link you clicked is invalid.'), 'error');
}
+ drupal_goto();
}
- drupal_goto();
}
else {
// Time out, in seconds, until login URL expires. Defaults to 24 hours =
@@ -123,7 +150,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
if ($timestamp <= $current && $account = reset($users)) {
// No time out for first time login.
if ($account->login && $current - $timestamp > $timeout) {
- drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'));
+ drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'), 'error');
drupal_goto('user/password');
}
elseif ($account->uid && $timestamp >= $account->login && $timestamp <= $current && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid)) {
@@ -151,7 +178,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
}
}
else {
- drupal_set_message(t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'));
+ drupal_set_message(t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'), 'error');
drupal_goto('user/password');
}
}
@@ -168,6 +195,14 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
* Menu callback; logs the current user out, and redirects to the home page.
*/
function user_logout() {
+ user_logout_current_user();
+ drupal_goto();
+}
+
+/**
+ * Logs the current user out.
+ */
+function user_logout_current_user() {
global $user;
watchdog('user', 'Session closed for %name.', array('%name' => $user->name));
@@ -176,8 +211,6 @@ function user_logout() {
// Destroy the current session, and reset $user to the anonymous user.
session_destroy();
-
- drupal_goto();
}
/**
@@ -294,14 +327,18 @@ function user_profile_form($form, &$form_state, $account, $category = 'account')
}
/**
- * Validation function for the user account and profile editing form.
+ * Form validation handler for user_profile_form().
+ *
+ * @see user_profile_form_submit()
*/
function user_profile_form_validate($form, &$form_state) {
entity_form_field_validate('user', $form, $form_state);
}
/**
- * Submit function for the user account and profile editing form.
+ * Form submission handler for user_profile_form().
+ *
+ * @see user_profile_form_validate()
*/
function user_profile_form_submit($form, &$form_state) {
$account = $form_state['user'];
@@ -533,7 +570,7 @@ function user_cancel_confirm($account, $timestamp = 0, $hashed_pass = '') {
batch_process('');
}
else {
- drupal_set_message(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'));
+ drupal_set_message(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'), 'error');
drupal_goto("user/$account->uid/cancel");
}
}
diff --git a/modules/user/user.test b/modules/user/user.test
index 07be4c2c..0875e0ac 100644
--- a/modules/user/user.test
+++ b/modules/user/user.test
@@ -465,6 +465,19 @@ class UserPasswordResetTestCase extends DrupalWebTestCase {
);
}
+ /**
+ * Retrieves password reset email and extracts the login link.
+ */
+ public function getResetURL() {
+ // Assume the most recent email.
+ $_emails = $this->drupalGetMails();
+ $email = end($_emails);
+ $urls = array();
+ preg_match('#.+user/reset/.+#', $email['body'], $urls);
+
+ return $urls[0];
+ }
+
/**
* Tests password reset functionality.
*/
@@ -478,6 +491,77 @@ class UserPasswordResetTestCase extends DrupalWebTestCase {
$this->drupalPost('user/password', $edit, t('E-mail new password'));
// Confirm the password reset.
$this->assertText(t('Further instructions have been sent to your e-mail address.'), 'Password reset instructions mailed message displayed.');
+
+ // Create an image field to enable an Ajax request on the user profile page.
+ $field = array(
+ 'field_name' => 'field_avatar',
+ 'type' => 'image',
+ 'settings' => array(),
+ 'cardinality' => 1,
+ );
+ field_create_field($field);
+
+ $instance = array(
+ 'field_name' => $field['field_name'],
+ 'entity_type' => 'user',
+ 'label' => 'Avatar',
+ 'bundle' => 'user',
+ 'required' => FALSE,
+ 'settings' => array(),
+ 'widget' => array(
+ 'type' => 'image_image',
+ 'settings' => array(),
+ ),
+ );
+ field_create_instance($instance);
+
+ $resetURL = $this->getResetURL();
+ $this->drupalGet($resetURL);
+
+ // Check successful login.
+ $this->drupalPost(NULL, NULL, t('Log in'));
+
+ // Make sure the Ajax request from uploading a file does not invalidate the
+ // reset token.
+ $image = current($this->drupalGetTestFiles('image'));
+ $edit = array(
+ 'files[field_avatar_und_0]' => drupal_realpath($image->uri),
+ );
+ $this->drupalPostAJAX(NULL, $edit, 'field_avatar_und_0_upload_button');
+
+ // Change the forgotten password.
+ $password = user_password();
+ $edit = array('pass[pass1]' => $password, 'pass[pass2]' => $password);
+ $this->drupalPost(NULL, $edit, t('Save'));
+ $this->assertText(t('The changes have been saved.'), 'Forgotten password changed.');
+ }
+
+ /**
+ * Test user password reset while logged in.
+ */
+ function testUserPasswordResetLoggedIn() {
+ $account = $this->drupalCreateUser();
+ $this->drupalLogin($account);
+ // Make sure the test account has a valid password.
+ user_save($account, array('pass' => user_password()));
+
+ // Generate one time login link.
+ $reset_url = user_pass_reset_url($account);
+ $this->drupalGet($reset_url);
+
+ $this->assertText('Reset password');
+ $this->drupalPost(NULL, NULL, t('Log in'));
+
+ $this->assertText('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.');
+
+ $pass = user_password();
+ $edit = array(
+ 'pass[pass1]' => $pass,
+ 'pass[pass2]' => $pass,
+ );
+ $this->drupalPost(NULL, $edit, t('Save'));
+
+ $this->assertText('The changes have been saved.');
}
/**
@@ -1501,7 +1585,13 @@ class UserTimeZoneFunctionalTest extends DrupalWebTestCase {
// Setup date/time settings for Los Angeles time.
variable_set('date_default_timezone', 'America/Los_Angeles');
variable_set('configurable_timezones', 1);
- variable_set('date_format_medium', 'Y-m-d H:i T');
+
+ // Override the 'medium' date format, which is the default for node
+ // creation time. Since we are testing time zones with Daylight Saving
+ // Time, and need to future proof against changes to the zoneinfo database,
+ // we choose the 'I' format placeholder instead of a human-readable zone
+ // name. With 'I', a 1 means the date is in DST, and 0 if not.
+ variable_set('date_format_medium', 'Y-m-d H:i I');
// Create a user account and login.
$web_user = $this->drupalCreateUser();
@@ -1519,11 +1609,11 @@ class UserTimeZoneFunctionalTest extends DrupalWebTestCase {
// Confirm date format and time zone.
$this->drupalGet("node/$node1->nid");
- $this->assertText('2007-03-09 21:00 PST', 'Date should be PST.');
+ $this->assertText('2007-03-09 21:00 0', 'Date should be PST.');
$this->drupalGet("node/$node2->nid");
- $this->assertText('2007-03-11 01:00 PST', 'Date should be PST.');
+ $this->assertText('2007-03-11 01:00 0', 'Date should be PST.');
$this->drupalGet("node/$node3->nid");
- $this->assertText('2007-03-20 21:00 PDT', 'Date should be PDT.');
+ $this->assertText('2007-03-20 21:00 1', 'Date should be PDT.');
// Change user time zone to Santiago time.
$edit = array();
@@ -1534,11 +1624,11 @@ class UserTimeZoneFunctionalTest extends DrupalWebTestCase {
// Confirm date format and time zone.
$this->drupalGet("node/$node1->nid");
- $this->assertText('2007-03-10 02:00 CLST', 'Date should be Chile summer time; five hours ahead of PST.');
+ $this->assertText('2007-03-10 02:00 1', 'Date should be Chile summer time; five hours ahead of PST.');
$this->drupalGet("node/$node2->nid");
- $this->assertText('2007-03-11 05:00 CLT', 'Date should be Chile time; four hours ahead of PST');
+ $this->assertText('2007-03-11 05:00 0', 'Date should be Chile time; four hours ahead of PST');
$this->drupalGet("node/$node3->nid");
- $this->assertText('2007-03-21 00:00 CLT', 'Date should be Chile time; three hours ahead of PDT.');
+ $this->assertText('2007-03-21 00:00 0', 'Date should be Chile time; three hours ahead of PDT.');
}
}
@@ -1849,6 +1939,19 @@ class UserCreateTestCase extends DrupalWebTestCase {
$this->drupalGet('admin/people');
$this->assertText($edit['name'], 'User found in list of users');
}
+
+ // Test that the password '0' is considered a password.
+ $name = $this->randomName();
+ $edit = array(
+ 'name' => $name,
+ 'mail' => $name . '@example.com',
+ 'pass[pass1]' => 0,
+ 'pass[pass2]' => 0,
+ 'notify' => FALSE,
+ );
+ $this->drupalPost('admin/people/create', $edit, t('Create new account'));
+ $this->assertText(t('Created a new user account for @name. No e-mail has been sent.', array('@name' => $edit['name'])), 'User created with password 0');
+ $this->assertNoText('Password field is required');
}
}
@@ -1926,6 +2029,74 @@ class UserEditTestCase extends DrupalWebTestCase {
$this->drupalLogin($user1);
$this->drupalLogout();
}
+
+ /**
+ * Tests setting the password to "0".
+ */
+ public function testUserWith0Password() {
+ $admin = $this->drupalCreateUser(array('administer users'));
+ $this->drupalLogin($admin);
+ // Create a regular user.
+ $user1 = $this->drupalCreateUser(array());
+
+ $edit = array('pass[pass1]' => '0', 'pass[pass2]' => '0');
+ $this->drupalPost("user/" . $user1->uid . "/edit", $edit, t('Save'));
+ $this->assertRaw(t("The changes have been saved."));
+
+ $this->drupalLogout();
+ $user1->pass_raw = '0';
+ $this->drupalLogin($user1);
+ $this->drupalLogout();
+ }
+}
+
+/**
+ * Tests editing a user account with and without a form rebuild.
+ */
+class UserEditRebuildTestCase extends DrupalWebTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'User edit with form rebuild',
+ 'description' => 'Test user edit page when a form rebuild is triggered.',
+ 'group' => 'User',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('user_form_test');
+ }
+
+ /**
+ * Test user edit page when the form is set to rebuild.
+ */
+ function testUserEditFormRebuild() {
+ $user1 = $this->drupalCreateUser(array('change own username'));
+ $this->drupalLogin($user1);
+
+ $roles = array_keys($user1->roles);
+ // Save the user form twice.
+ $edit = array();
+ $edit['current_pass'] = $user1->pass_raw;
+ $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
+ $this->assertRaw(t("The changes have been saved."));
+ $this->drupalPost(NULL, $edit, t('Save'));
+ $this->assertRaw(t("The changes have been saved."));
+ $saved_user1 = entity_load_unchanged('user', $user1->uid);
+ $this->assertEqual(count($roles), count($saved_user1->roles), 'Count of user roles in database matches original count.');
+ $diff = array_diff(array_keys($saved_user1->roles), $roles);
+ $this->assertTrue(empty($diff), format_string('User roles in database match original: @roles', array('@roles' => implode(', ', $saved_user1->roles))));
+ // Set variable that causes the form to be rebuilt in user_form_test.module.
+ variable_set('user_form_test_user_profile_form_rebuild', TRUE);
+ $this->drupalPost("user/$user1->uid/edit", $edit, t('Save'));
+ $this->assertRaw(t("The changes have been saved."));
+ $this->drupalPost(NULL, $edit, t('Save'));
+ $this->assertRaw(t("The changes have been saved."));
+ $saved_user1 = entity_load_unchanged('user', $user1->uid);
+ $this->assertEqual(count($roles), count($saved_user1->roles), 'Count of user roles in database matches original count.');
+ $diff = array_diff(array_keys($saved_user1->roles), $roles);
+ $this->assertTrue(empty($diff), format_string('User roles in database match original: @roles', array('@roles' => implode(', ', $saved_user1->roles))));
+ }
}
/**
@@ -2095,12 +2266,16 @@ class UserRoleAdminTestCase extends DrupalWebTestCase {
$this->assertFalse(user_role_load_by_name($old_name), 'The role can no longer be retrieved from the database using its old name.');
$this->assertTrue(is_object(user_role_load_by_name($role_name)), 'The role can be retrieved from the database using its new name.');
- // Test deleting a role.
+ // Test deleting the default administrator role.
+ $role_name = 'administrator';
+ $role = user_role_load_by_name($role_name);
$this->drupalPost("admin/people/permissions/roles/edit/{$role->rid}", NULL, t('Delete role'));
$this->drupalPost(NULL, NULL, t('Delete'));
$this->assertText(t('The role has been deleted.'), 'The role has been deleted');
$this->assertNoLinkByHref("admin/people/permissions/roles/edit/{$role->rid}", 'Role edit link removed.');
$this->assertFalse(user_role_load_by_name($role_name), 'A deleted role can no longer be loaded.');
+ // Make sure this role is no longer configured as the administrator role.
+ $this->assertNull(variable_get('user_admin_role'), 'The administrator role is no longer configured as the administrator role.');
// Make sure that the system-defined roles cannot be edited via the user
// interface.
@@ -2226,6 +2401,20 @@ class UserUserSearchTestCase extends DrupalWebTestCase {
$this->drupalPost('search/user/', $edit, t('Search'));
$this->assertText($keys);
+ // Verify that wildcard search works.
+ $keys = $user1->name;
+ $keys = substr($keys, 0, 2) . '*' . substr($keys, 4, 2);
+ $edit = array('keys' => $keys);
+ $this->drupalPost('search/user/', $edit, t('Search'));
+ $this->assertText($user1->name, 'Search for username wildcard resulted in user name on page for administrative user.');
+
+ // Verify that wildcard search works for email.
+ $keys = $user1->mail;
+ $keys = substr($keys, 0, 2) . '*' . substr($keys, 4, 2);
+ $edit = array('keys' => $keys);
+ $this->drupalPost('search/user/', $edit, t('Search'));
+ $this->assertText($user1->name, 'Search for email wildcard resulted in user name on page for administrative user.');
+
// Create a blocked user.
$blocked_user = $this->drupalCreateUser();
$edit = array('status' => 0);
diff --git a/profiles/README.txt b/profiles/README.txt
new file mode 100644
index 00000000..91d012ba
--- /dev/null
+++ b/profiles/README.txt
@@ -0,0 +1,28 @@
+Installation profiles define additional steps that run after the base
+installation provided by Drupal core when Drupal is first installed.
+
+WHAT TO PLACE IN THIS DIRECTORY?
+--------------------------------
+
+Place downloaded and custom installation profiles in this directory.
+Installation profiles are generally provided as part of a Drupal distribution.
+They only impact the installation of your site. They do not have any effect on
+an already running site.
+
+DOWNLOAD ADDITIONAL DISTRIBUTIONS
+---------------------------------
+
+Contributed distributions from the Drupal community may be downloaded at
+https://www.drupal.org/project/project_distribution.
+
+MULTISITE CONFIGURATION
+-----------------------
+
+In multisite configurations, installation profiles found in this directory are
+available to all sites during their initial site installation.
+
+MORE INFORMATION
+----------------
+
+Refer to the "Installation profiles" section of the README.txt in the Drupal
+root directory for further information on extending Drupal with custom profiles.
diff --git a/profiles/commerce_kickstart/.gitignore b/profiles/commerce_kickstart/.gitignore
index 3c445852..d2332d28 100644
--- a/profiles/commerce_kickstart/.gitignore
+++ b/profiles/commerce_kickstart/.gitignore
@@ -5,3 +5,4 @@
!.htaccess
nbproject/
*.kpf
+tests/behat/failures
diff --git a/profiles/commerce_kickstart/.travis.yml b/profiles/commerce_kickstart/.travis.yml
index 761490b3..0628a290 100644
--- a/profiles/commerce_kickstart/.travis.yml
+++ b/profiles/commerce_kickstart/.travis.yml
@@ -1,8 +1,10 @@
language: php
sudo: false
-
+dist: trusty
+addons:
+ chrome: stable
php:
- - 5.4
+ - 5.6
branches:
except:
@@ -15,39 +17,45 @@ mysql:
env:
- UPGRADE=none
- - UPGRADE=7.x-2.26
- - UPGRADE=7.x-2.25
- - UPGRADE=7.x-2.24
- - UPGRADE=7.x-2.23
- - UPGRADE=7.x-2.22
- - UPGRADE=7.x-2.21
- - UPGRADE=7.x-2.20
- - UPGRADE=7.x-2.19
- - UPGRADE=7.x-2.18
- - UPGRADE=7.x-2.17
- - UPGRADE=7.x-2.16
- - UPGRADE=7.x-2.15
- - UPGRADE=7.x-2.14
- - UPGRADE=7.x-2.13
- - UPGRADE=7.x-2.12
+ - UPGRADE=7.x-2.49
+ - UPGRADE=7.x-2.48
+ - UPGRADE=7.x-2.47
+ - UPGRADE=7.x-2.46
+ - UPGRADE=7.x-2.45
+ - UPGRADE=7.x-2.44
+ - UPGRADE=7.x-2.43
+ - UPGRADE=7.x-2.42
+ - UPGRADE=7.x-2.41
+ - UPGRADE=7.x-2.40
matrix:
fast_finish: true
include:
- - php: 5.5
- env: UPGRADE=none
- - php: 5.5
- env: UPGRADE=7.x-2.23 TEST_FEATURES_OVERRIDES=1
- php: 5.6
+ env: UPGRADE=7.x-2.23 TEST_FEATURES_OVERRIDES=1
+ - php: 7.0
+ env: UPGRADE=none
+ - php: 7.1
env: UPGRADE=none
+ allow_failures:
+ - php: 7.0
+ - php: 7.1
# Cache Composer & Drush directories.
cache:
directories:
- $HOME/.composer/cache
- $HOME/.drush/cache
+ - tests/behat/vendor
+before_install:
+ - # start your web application and listen on `localhost`
+ - google-chrome-stable --headless --disable-gpu --remote-debugging-address=0.0.0.0 --remote-debugging-port=9222 &
install:
+ # Remove xdebug for the moment. We aren't generating code coverage, and it slows us down.
+ - rm /home/travis/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini
+
+ # Create database.
- "mysql -e 'create database drupal;'"
# Install latest Drush 6.
@@ -95,16 +103,6 @@ install:
# Setup files
- chmod -R 777 drupal/sites/all
- # Setup display for Selenium
- - export DISPLAY=:99.0
- - sh -e /etc/init.d/xvfb start
- - sleep 5
-
- # Get Selenium
- - wget http://selenium-release.storage.googleapis.com/2.42/selenium-server-standalone-2.42.1.jar
- - java -jar selenium-server-standalone-2.42.1.jar > /dev/null 2>&1 &
- - nc -zvv localhost 4444; out=$?; while [[ $out -ne 0 ]]; do echo "Retry hit port 4444..."; nc -zvv localhost 4444; out=$?; sleep 5; done
-
# Disable sendmail
- echo sendmail_path=`which true` >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
@@ -112,6 +110,10 @@ install:
- echo "mysql.connect_timeout=3000" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
- echo "default_socket_timeout=3000" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
+ # Multibyte string input conversion in PHP is active and must be disabled for Drupal on PHP 5.6.
+ - echo "mbstring.http_input = pass" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
+ - echo "mbstring.http_output = pass" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
+
# Increase the MySQL server timetout and packet size.
- mysql -e "SET GLOBAL wait_timeout = 36000;"
- mysql -e "SET GLOBAL max_allowed_packet = 33554432;"
@@ -136,7 +138,9 @@ before_script:
- drush pm-disable dblog --yes
# If testing the override, enable it and revert feature it's overriding (because we didn't on the same install.)
- - if [[ "$TEST_FEATURES_OVERRIDES" == 1 ]]; then drush en -y commerce_kickstart_overrides_test && drush fr -y commerce_kickstart_blog; fi
+ # We need to download rc2, because rc3 requires a function in Features 2.7,
+ # breaking test.
+ - if [[ "$TEST_FEATURES_OVERRIDES" == 1 ]]; then drush dl features_override-7.x-2.0-rc2 && drush en -y commerce_kickstart_overrides_test && drush fr -y commerce_kickstart_blog; fi
- cd ../drupal
@@ -153,6 +157,9 @@ script:
# If this isn't an upgrade, we test if any features are overridden.
- if [[ "$UPGRADE" == none ]]; then ../../scripts/check-overridden.sh; fi
+ # Fix bad Commerce Migrate release for testing the demo.
+ - if [[ "$UPGRADE" == "7.x-2.34" || "$UPGRADE" == "7.x-2.33" || "$UPGRADE" == "7.x-2.32" || "$UPGRADE" == "7.x-2.31" || "$UPGRADE" == "7.x-2.30" || "$UPGRADE" == "7.x-2.29" || "$UPGRADE" == "7.x-2.28" || "$UPGRADE" == "7.x-2.27" ]]; then drush mi --all --update; fi
+
# Run Behat tests.
- if [[ "$TEST_FEATURES_OVERRIDES" != 1 ]]; then ./bin/behat --config behat.travis.yml --tags ~@overrides; fi
- if [[ "$TEST_FEATURES_OVERRIDES" == 1 ]]; then ./bin/behat --config behat.travis.yml --tags @overrides; fi
diff --git a/profiles/commerce_kickstart/commerce_kickstart.info b/profiles/commerce_kickstart/commerce_kickstart.info
index 3044e717..dfb1b9fc 100644
--- a/profiles/commerce_kickstart/commerce_kickstart.info
+++ b/profiles/commerce_kickstart/commerce_kickstart.info
@@ -78,7 +78,6 @@ dependencies[] = entityreference
dependencies[] = views_megarow
dependencies[] = commerce_addressbook
dependencies[] = commerce_discount
-dependencies[] = commerce_discount_date
dependencies[] = commerce_add_to_cart_confirmation
dependencies[] = commerce_message
dependencies[] = commerce_backoffice
@@ -118,9 +117,8 @@ dependencies[] = commerce_kickstart_migrate
; System Requirements.
php_memory_limit = 128M
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/commerce_kickstart.install b/profiles/commerce_kickstart/commerce_kickstart.install
index 00b34f3e..89b539a3 100644
--- a/profiles/commerce_kickstart/commerce_kickstart.install
+++ b/profiles/commerce_kickstart/commerce_kickstart.install
@@ -58,16 +58,18 @@ function commerce_kickstart_install_tasks_alter(&$tasks, $install_state) {
$tasks['install_select_locale']['run'] = INSTALL_TASK_SKIP;
$tasks['install_profile_modules']['display_name'] = st('Install Commerce Kickstart 2');
- // The "Welcome" screen needs to come after the first two steps
- // (profile and language selection), despite the fact that they are disabled.
- $new_task['install_welcome'] = array(
- 'display' => TRUE,
- 'display_name' => st('Welcome'),
- 'type' => 'form',
- 'run' => isset($install_state['parameters']['welcome']) ? INSTALL_TASK_SKIP : INSTALL_TASK_RUN_IF_REACHED,
- );
- $old_tasks = $tasks;
- $tasks = array_slice($old_tasks, 0, 2) + $new_task + array_slice($old_tasks, 2);
+ if (PHP_SAPI !== 'cli') {
+ // The "Welcome" screen needs to come after the first two steps
+ // (profile and language selection), despite the fact that they are disabled.
+ $new_task['install_welcome'] = array(
+ 'display' => TRUE,
+ 'display_name' => st('Welcome'),
+ 'type' => 'form',
+ 'run' => isset($install_state['parameters']['welcome']) ? INSTALL_TASK_SKIP : INSTALL_TASK_RUN_IF_REACHED,
+ );
+ $old_tasks = $tasks;
+ $tasks = array_slice($old_tasks, 0, 2) + $new_task + array_slice($old_tasks, 2);
+ }
// Set the installation theme.
_commerce_kickstart_set_theme('commerce_kickstart_admin');
@@ -1274,3 +1276,18 @@ function commerce_kickstart_update_7224() {
function commerce_kickstart_update_7225() {
module_enable(array('distro_update'));
}
+
+/**
+ * Disable the Distribution Update Status Manager module.
+ */
+function commerce_kickstart_update_7226() {
+ // Causing too much grief with security warnings about modules.
+ module_disable(array('distro_update'));
+}
+
+/**
+ * Re-enable the Distribution Update Status Manager module.
+ */
+function commerce_kickstart_update_7227() {
+ module_enable(array('distro_update'));
+}
diff --git a/profiles/commerce_kickstart/drupal-org-core.make b/profiles/commerce_kickstart/drupal-org-core.make
index 9bf25e49..db954bc0 100644
--- a/profiles/commerce_kickstart/drupal-org-core.make
+++ b/profiles/commerce_kickstart/drupal-org-core.make
@@ -1,6 +1,6 @@
api = 2
core = 7.x
-projects[drupal][version] = 7.39
+projects[drupal][version] = 7.60
; Patches for Core
projects[drupal][patch][] = "http://drupal.org/files/issues/install-redirect-on-empty-database-728702-36.patch"
diff --git a/profiles/commerce_kickstart/drupal-org.make b/profiles/commerce_kickstart/drupal-org.make
index 10a683c0..d144a226 100644
--- a/profiles/commerce_kickstart/drupal-org.make
+++ b/profiles/commerce_kickstart/drupal-org.make
@@ -5,91 +5,75 @@ api = 2
defaults[projects][subdir] = contrib
; Basic contributed modules.
-projects[ctools][version] = 1.9
-projects[entity][version] = 1.6
-projects[entityreference][version] = 1.1
-projects[entityreference][patch][] = "http://drupal.org/files/1580348-universal-formatters-17.patch"
-projects[rules][version] = 2.9
-projects[views][version] = 3.11
-projects[views][patch][] = "http://drupal.org/files/2059555-reduce-formatter-form-state.patch"
-projects[views_bulk_operations][version] = 3.3
-projects[addressfield][version] = 1.1
-projects[features][version] = "2.6"
+projects[ctools][version] = 1.13
+projects[entity][version] = 1.9
+projects[entityreference][version] = 1.5
+projects[rules][version] = 2.10
+projects[views][version] = 3.18
+projects[views_bulk_operations][version] = 3.4
+projects[addressfield][version] = 1.2
+projects[features][version] = 2.10
projects[features][patch][2143765] = "http://drupal.org/files/issues/features-fix-modules-enabled-2143765-1.patch"
projects[features][patch][2479803] = "https://www.drupal.org/files/issues/ignore_hidden_modules-2479803-1.patch"
-projects[features][patch][2534138] = "https://www.drupal.org/files/issues/2534138-field-base-exception-catch-1.patch"
-projects[features_override][version] = 2.0-rc2
+projects[features_override][version] = 2.0-rc3
projects[strongarm][version] = 2.0
projects[taxonomy_menu][version] = 1.5
-projects[libraries][version] = 2.2
-projects[views_megarow][version] = 1.4
+projects[libraries][version] = 2.3
+projects[views_megarow][version] = 1.7
; Drupal Commerce and Commerce contribs.
-projects[commerce][version] = 1.11
-projects[commerce_features][version] = 1.1
-projects[commerce_addressbook][version] = 2.0-rc8
-projects[commerce_shipping][version] = 2.2
+projects[commerce][version] = 1.14
+projects[commerce_features][version] = 1.3
+projects[commerce_addressbook][version] = 2.0-rc9
+projects[commerce_shipping][version] = 2.3
projects[commerce_flat_rate][version] = 1.0-beta2
projects[commerce_fancy_attributes][version] = 1.0
-projects[commerce_autosku][version] = 1.x-dev
-projects[commerce_autosku][download][type] = git
-projects[commerce_autosku][download][revision] = 32e86f4
-projects[commerce_autosku][download][branch] = 7.x-1.x
-projects[commerce_migrate][version] = 1.1
-projects[commerce_migrate][patch][1931302] = https://www.drupal.org/files/commerce_products_source_migration-1931302-2.patch
-projects[commerce_discount][version] = 1.x-dev
-projects[commerce_discount][download][type] = git
-projects[commerce_discount][download][revision] = 7a78225
-projects[commerce_discount][download][branch] = 7.x-1.x
-projects[commerce_checkout_progress][version] = 1.3
+projects[commerce_autosku][version] = 1.2
+projects[commerce_migrate][version] = 1.2
+projects[commerce_migrate][patch][2701333] = https://www.drupal.org/files/issues/reference_fields_should-2701333-3.patch
+projects[commerce_discount][version] = 1.0-beta5
+projects[commerce_checkout_progress][version] = 1.5
projects[commerce_extra_price_formatters][version] = 1.x-dev
projects[commerce_extra_price_formatters][download][type] = git
projects[commerce_extra_price_formatters][download][revision] = 1371336
projects[commerce_extra_price_formatters][download][branch] = 7.x-1.x
-projects[commerce_checkout_redirect][version] = 2.0-rc1
+projects[commerce_checkout_redirect][version] = 2.0
projects[commerce_hosted_pci][version] = 1.0-rc2
projects[commerce_payleap][version] = 1.1
projects[commerce_moneybookers][version] = 1.2
projects[commerce_moneybookers][patch][] = "http://drupal.org/files/commerce_moneybookers-disable_payment_method_by_default-1962226-3.patch"
-projects[commerce_paypal][version] = 2.3
-projects[commerce_backoffice][version] = 1.4
-projects[commerce_message][version] = 1.0-rc3
-projects[commerce_search_api][version] = 1.3
-projects[commerce_add_to_cart_confirmation][version] = 1.0-rc2
+projects[commerce_paypal][version] = 2.4
+projects[commerce_backoffice][version] = 1.5
+projects[commerce_message][version] = 1.0
+projects[commerce_search_api][version] = 1.6
+projects[commerce_add_to_cart_confirmation][version] = 1.0-rc3
projects[commerce_kiala][version] = 1.0-rc1
projects[commerce_physical][version] = 1.x-dev
projects[commerce_physical][download][type] = git
-projects[commerce_physical][download][revision] = e2a8866
+projects[commerce_physical][download][revision] = 477aaee
projects[commerce_physical][download][branch] = 7.x-1.x
projects[commerce_amex][version] = 1.1
projects[commerce_cba][version] = 1.0-beta1
-projects[commerce_authnet][version] = 1.1
+projects[commerce_authnet][version] = 1.4
projects[commerce_exactor][version] = 1.3
projects[commerce_paymill][version] = 2.4
-projects[commerce_nosto_tagging][version] = 1.0
-projects[commerce_nosto_tagging][patch][] = https://drupal.org/files/issues/issue-2225883.patch
-projects[commerce_yotpo][download][type] = "git"
-projects[commerce_yotpo][download][revision] = "ecc41f9"
-projects[commerce_yotpo][download][branch] = 7.x-1.x
-projects[commerce_firstdata_gge4][version] = 1.0
+projects[commerce_nosto_tagging][version] = 1.1
+projects[commerce_yotpo][version] = 1.2
+projects[commerce_firstdata_gge4][version] = 1.1
+projects[commerce_amazon_lpa][version] = 1.3
; Other contribs.
projects[countries][version] = 2.3
projects[remote_stream_wrapper][version] = 1.0-rc1
-projects[colorbox][version] = 2.7
-projects[colorbox][patch][] = https://www.drupal.org/files/issues/plugin_version_detection-2360375-9.patch
-projects[physical][version] = 1.x-dev
-projects[physical][download][type] = git
-projects[physical][download][revision] = 32e1a38
-projects[physical][download][branch] = 7.x-1.x
+projects[colorbox][version] = 2.13
+projects[physical][version] = 1.0
projects[crumbs][version] = 1.10
projects[http_client][version] = 2.4
-projects[oauth][version] = 3.2
-projects[oauth][patch][] = "http://drupal.org/files/980340-d7.patch"
+projects[oauth][version] = 3.4
projects[connector][version] = 1.0-beta2
projects[oauthconnector][version] = 1.0-beta2
-projects[inline_entity_form][version] = 1.6
-projects[inline_conditions][version] = 1.0-alpha5
+projects[inline_entity_form][version] = 1.8
+projects[inline_conditions][version] = 1.0-rc1
projects[field_extractor][version] = 1.3
projects[service_links][version] = 2.x-dev
projects[service_links][download][type] = "git"
@@ -97,64 +81,63 @@ projects[service_links][download][revision] = "6f63b84"
projects[service_links]download][branch] = 7.x-2.x
projects[advanced_help][version] = 1.3
projects[mailsystem][version] = 2.34
-projects[mimemail][version] = 1.0-beta3
-projects[token][version] = 1.6
+projects[mailsystem][patch][1534706] = "https://www.drupal.org/files/mailsystem.1534706.6.patch"
+projects[mimemail][version] = 1.1
+projects[token][version] = 1.7
projects[token][patch][] = "http://drupal.org/files/token-token_asort_tokens-1712336_0.patch"
-projects[eva][version] = 1.2
-projects[message][version] = 1.10
+projects[eva][version] = 1.3
+projects[message][version] = 1.12
projects[message_notify][version] = 2.5
projects[migrate][version] = 2.8
projects[migrate_extras][version] = 2.5
projects[migrate_extras][patch][] = "http://drupal.org/files/migrate_extras-fix-destid2-array-1951904-4.patch"
-projects[date][version] = 2.8
+projects[date][version] = 2.10
projects[yottaa][version] = 1.2
-projects[menu_attributes][version] = 1.0-rc3
-projects[fences][version] = "1.0"
-projects[fences][patch][] = "http://drupal.org/files/undefined-index-1561244-7.patch"
-projects[fences][patch][] = "http://drupal.org/files/fences-default_markup_option-1857230-2.patch"
-projects[title][version] = "1.0-alpha7"
-projects[title][patch][] = "http://drupal.org/files/title-translation_overwrite-1269076-35.patch"
-projects[kameleoon][version] = "1.1"
-projects[mailup][version] = "1.1"
-projects[mailjet][version] = "2.3"
+projects[menu_attributes][version] = 1.0
+projects[fences][version] = 1.2
+projects[title][version] = 1.0-alpha9
+projects[title][patch][] = "https://www.drupal.org/files/issues/title-fix_description_empty_on_submit-2075041-7.patch"
+projects[kameleoon][version] = 1.1
+projects[mailup][version] = 1.4
+projects[mailjet][version] = 2.14
; Search related modules.
-projects[search_api][version] = 1.15
-projects[search_api_db][version] = 1.4
+projects[search_api][version] = 1.22
+projects[search_api_db][version] = 1.6
projects[search_api_ranges][version] = 1.5
projects[search_api_ranges][patch][] = "https://drupal.org/files/issues/search_api_ranges-rewrite-data-alteration-callback-2001846-4.patch"
projects[facetapi][version] = 1.5
projects[facetapi][patch][] = "https://drupal.org/files/1616518-term_remove_link-24.patch"
projects[facetapi][patch][2378693] = "https://www.drupal.org/files/issues/notice_undefined-2378693-3.patch"
-projects[search_api_sorts][version] = 1.5
+projects[search_api_sorts][version] = 1.7
; UI improvement modules.
-projects[module_filter][version] = 2.0
+projects[module_filter][version] = 2.1
projects[image_delta_formatter][version] = 1.0-rc1
-projects[link][version] = 1.3
-projects[pathauto][version] = 1.2
-projects[cloud_zoom][version] = 1.x-dev
+projects[link][version] = 1.4
+projects[pathauto][version] = 1.3
+; projects[cloud_zoom][version] = 1.x-dev
projects[cloud_zoom][download][type] = git
projects[cloud_zoom][download][revision] = 3cff30f
projects[cloud_zoom][download][branch] = 7.x-1.x
projects[special_menu_items][version] = 2.0
-projects[chosen][version] = 2.x-dev
-projects[chosen][download][type] = git
-projects[chosen][download][revision] = e7a0d22
-projects[chosen][download][branch] = 7.x-2.x
-projects[admin_views][version] = 1.5
+projects[chosen][version] = 2.1
+projects[admin_views][version] = 1.6
projects[distro_update][version] = 1.0-beta4
; Internationalization
projects[variable][version] = 2.5
-projects[i18n][version] = "1.12"
-projects[lingotek][version] = 6.02
+projects[i18n][version] = 1.17
+projects[lingotek][version] = 7.21
; Base theme.
projects[omega][version] = 3.1
projects[omega][patch][] = "http://drupal.org/files/relative-src-15.patch"
+projects[omega][type] = theme
projects[omega_kickstart][version] = 3.4
-projects[shiny][version] = 1.6
+projects[omega_kickstart][type] = theme
+projects[shiny][version] = 1.7
+projects[shiny][type] = theme
; Libraries.
libraries[colorbox][type] = "libraries"
@@ -185,7 +168,7 @@ libraries[selectnav.js][download][revision] = 538237c7c5e95736fc376f4efc3e40f5b9
libraries[selectnav.js][download][branch] = master
libraries[ie7-js][type] = "libraries"
libraries[ie7-js][download][type] = "file"
-libraries[ie7-js][download][url] = "https://ie7-js.googlecode.com/files/ie7-2.1%28beta4%29.zip"
+libraries[ie7-js][download][url] = "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/ie7-js/ie7-2.1(beta4).zip"
libraries[chosen][type] = "libraries"
libraries[chosen][download][type] = "get"
libraries[chosen][download][url] = "https://github.com/harvesthq/chosen/releases/download/v1.1.0/chosen_v1.1.0.zip"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_block/commerce_kickstart_block.features.menu_custom.inc b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_block/commerce_kickstart_block.features.menu_custom.inc
index dcaaf085..ade56d03 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_block/commerce_kickstart_block.features.menu_custom.inc
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_block/commerce_kickstart_block.features.menu_custom.inc
@@ -34,6 +34,5 @@ function commerce_kickstart_block_menu_default_menu_custom() {
t('Payment methods');
t('Secondary navigation');
-
return $menus;
}
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_block/commerce_kickstart_block.features.menu_links.inc b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_block/commerce_kickstart_block.features.menu_links.inc
index 55c765e0..34c94e47 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_block/commerce_kickstart_block.features.menu_links.inc
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_block/commerce_kickstart_block.features.menu_links.inc
@@ -10,7 +10,7 @@
function commerce_kickstart_block_menu_default_menu_links() {
$menu_links = array();
- // Exported menu link: menu-footer-navigation_about-us:node/2
+ // Exported menu link: menu-footer-navigation_about-us:node/2.
$menu_links['menu-footer-navigation_about-us:node/2'] = array(
'menu_name' => 'menu-footer-navigation',
'link_path' => 'node/2',
@@ -29,7 +29,7 @@ function commerce_kickstart_block_menu_default_menu_links() {
'customized' => 1,
'parent_identifier' => 'menu-footer-navigation_company-info:',
);
- // Exported menu link: menu-footer-navigation_company-info:
+ // Exported menu link: menu-footer-navigation_company-info:.
$menu_links['menu-footer-navigation_company-info:'] = array(
'menu_name' => 'menu-footer-navigation',
'link_path' => '',
@@ -49,7 +49,7 @@ function commerce_kickstart_block_menu_default_menu_links() {
'weight' => -50,
'customized' => 1,
);
- // Exported menu link: menu-footer-navigation_our-security-policy:node/8
+ // Exported menu link: menu-footer-navigation_our-security-policy:node/8.
$menu_links['menu-footer-navigation_our-security-policy:node/8'] = array(
'menu_name' => 'menu-footer-navigation',
'link_path' => 'node/8',
@@ -70,7 +70,7 @@ function commerce_kickstart_block_menu_default_menu_links() {
'customized' => 1,
'parent_identifier' => 'menu-footer-navigation_security--privacy:',
);
- // Exported menu link: menu-footer-navigation_press-links:node/6
+ // Exported menu link: menu-footer-navigation_press-links:node/6.
$menu_links['menu-footer-navigation_press-links:node/6'] = array(
'menu_name' => 'menu-footer-navigation',
'link_path' => 'node/6',
@@ -89,7 +89,7 @@ function commerce_kickstart_block_menu_default_menu_links() {
'customized' => 1,
'parent_identifier' => 'menu-footer-navigation_company-info:',
);
- // Exported menu link: menu-footer-navigation_security--privacy:
+ // Exported menu link: menu-footer-navigation_security--privacy:.
$menu_links['menu-footer-navigation_security--privacy:'] = array(
'menu_name' => 'menu-footer-navigation',
'link_path' => '',
@@ -109,7 +109,7 @@ function commerce_kickstart_block_menu_default_menu_links() {
'weight' => -48,
'customized' => 1,
);
- // Exported menu link: menu-footer-navigation_service--support:
+ // Exported menu link: menu-footer-navigation_service--support:.
$menu_links['menu-footer-navigation_service--support:'] = array(
'menu_name' => 'menu-footer-navigation',
'link_path' => '',
@@ -129,7 +129,7 @@ function commerce_kickstart_block_menu_default_menu_links() {
'weight' => -49,
'customized' => 1,
);
- // Exported menu link: menu-footer-navigation_service-agreements:node/7
+ // Exported menu link: menu-footer-navigation_service-agreements:node/7.
$menu_links['menu-footer-navigation_service-agreements:node/7'] = array(
'menu_name' => 'menu-footer-navigation',
'link_path' => 'node/7',
@@ -150,7 +150,7 @@ function commerce_kickstart_block_menu_default_menu_links() {
'customized' => 1,
'parent_identifier' => 'menu-footer-navigation_service--support:',
);
- // Exported menu link: menu-footer-navigation_shipping--returns:
+ // Exported menu link: menu-footer-navigation_shipping--returns:.
$menu_links['menu-footer-navigation_shipping--returns:'] = array(
'menu_name' => 'menu-footer-navigation',
'link_path' => '',
@@ -170,7 +170,7 @@ function commerce_kickstart_block_menu_default_menu_links() {
'weight' => -47,
'customized' => 1,
);
- // Exported menu link: menu-footer-navigation_shipping-fees:node/5
+ // Exported menu link: menu-footer-navigation_shipping-fees:node/5.
$menu_links['menu-footer-navigation_shipping-fees:node/5'] = array(
'menu_name' => 'menu-footer-navigation',
'link_path' => 'node/5',
@@ -191,7 +191,7 @@ function commerce_kickstart_block_menu_default_menu_links() {
'customized' => 1,
'parent_identifier' => 'menu-footer-navigation_shipping--returns:',
);
- // Exported menu link: menu-footer-navigation_terms-of-use:node/3
+ // Exported menu link: menu-footer-navigation_terms-of-use:node/3.
$menu_links['menu-footer-navigation_terms-of-use:node/3'] = array(
'menu_name' => 'menu-footer-navigation',
'link_path' => 'node/3',
@@ -210,7 +210,7 @@ function commerce_kickstart_block_menu_default_menu_links() {
'customized' => 1,
'parent_identifier' => 'menu-footer-navigation_security--privacy:',
);
- // Exported menu link: menu-payment-methods_american-express:
+ // Exported menu link: menu-payment-methods_american-express:.
$menu_links['menu-payment-methods_american-express:'] = array(
'menu_name' => 'menu-payment-methods',
'link_path' => '',
@@ -234,7 +234,7 @@ function commerce_kickstart_block_menu_default_menu_links() {
'weight' => -47,
'customized' => 1,
);
- // Exported menu link: menu-payment-methods_mastercard:
+ // Exported menu link: menu-payment-methods_mastercard:.
$menu_links['menu-payment-methods_mastercard:'] = array(
'menu_name' => 'menu-payment-methods',
'link_path' => '',
@@ -258,7 +258,7 @@ function commerce_kickstart_block_menu_default_menu_links() {
'weight' => -50,
'customized' => 1,
);
- // Exported menu link: menu-payment-methods_paypal:
+ // Exported menu link: menu-payment-methods_paypal:.
$menu_links['menu-payment-methods_paypal:'] = array(
'menu_name' => 'menu-payment-methods',
'link_path' => '',
@@ -282,7 +282,7 @@ function commerce_kickstart_block_menu_default_menu_links() {
'weight' => -49,
'customized' => 1,
);
- // Exported menu link: menu-payment-methods_visa:
+ // Exported menu link: menu-payment-methods_visa:.
$menu_links['menu-payment-methods_visa:'] = array(
'menu_name' => 'menu-payment-methods',
'link_path' => '',
@@ -306,7 +306,7 @@ function commerce_kickstart_block_menu_default_menu_links() {
'weight' => -48,
'customized' => 1,
);
- // Exported menu link: secondary-navigation_about:node/2
+ // Exported menu link: secondary-navigation_about:node/2.
$menu_links['secondary-navigation_about:node/2'] = array(
'menu_name' => 'secondary-navigation',
'link_path' => 'node/2',
@@ -323,7 +323,7 @@ function commerce_kickstart_block_menu_default_menu_links() {
'weight' => 2,
'customized' => 1,
);
- // Exported menu link: secondary-navigation_contact:node/1
+ // Exported menu link: secondary-navigation_contact:node/1.
$menu_links['secondary-navigation_contact:node/1'] = array(
'menu_name' => 'secondary-navigation',
'link_path' => 'node/1',
@@ -340,6 +340,7 @@ function commerce_kickstart_block_menu_default_menu_links() {
'weight' => 1,
'customized' => 1,
);
+
// Translatables
// Included for use with string extractors like potx.
t('About');
@@ -359,6 +360,5 @@ function commerce_kickstart_block_menu_default_menu_links() {
t('Terms of use');
t('Visa');
-
return $menu_links;
}
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_block/commerce_kickstart_block.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_block/commerce_kickstart_block.info
index 4549bef7..91071f64 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_block/commerce_kickstart_block.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_block/commerce_kickstart_block.info
@@ -32,9 +32,8 @@ features[menu_links][] = secondary-navigation_contact:node/1
features[variable][] = menu_secondary_links_source
files[] = commerce_kickstart_block.module
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_blog/commerce_kickstart_blog.features.field_base.inc b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_blog/commerce_kickstart_blog.features.field_base.inc
index 9cd1743b..a299c4f3 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_blog/commerce_kickstart_blog.features.field_base.inc
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_blog/commerce_kickstart_blog.features.field_base.inc
@@ -10,7 +10,7 @@
function commerce_kickstart_blog_field_default_field_bases() {
$field_bases = array();
- // Exported field_base: 'field_blog_category'
+ // Exported field_base: 'field_blog_category'.
$field_bases['field_blog_category'] = array(
'active' => 1,
'cardinality' => -1,
@@ -31,12 +31,13 @@ function commerce_kickstart_blog_field_default_field_bases() {
'parent' => 0,
),
),
+ 'options_list_callback' => 'title_taxonomy_allowed_values',
),
'translatable' => 0,
'type' => 'taxonomy_term_reference',
);
- // Exported field_base: 'field_tags'
+ // Exported field_base: 'field_tags'.
$field_bases['field_tags'] = array(
'active' => 1,
'cardinality' => -1,
@@ -57,6 +58,7 @@ function commerce_kickstart_blog_field_default_field_bases() {
'parent' => 0,
),
),
+ 'options_list_callback' => 'title_taxonomy_allowed_values',
),
'translatable' => 0,
'type' => 'taxonomy_term_reference',
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_blog/commerce_kickstart_blog.features.field_instance.inc b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_blog/commerce_kickstart_blog.features.field_instance.inc
index 653ec831..6c0f47df 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_blog/commerce_kickstart_blog.features.field_instance.inc
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_blog/commerce_kickstart_blog.features.field_instance.inc
@@ -10,7 +10,7 @@
function commerce_kickstart_blog_field_default_field_instances() {
$field_instances = array();
- // Exported field_instance: 'node-blog_post-body'
+ // Exported field_instance: 'node-blog_post-body'.
$field_instances['node-blog_post-body'] = array(
'bundle' => 'blog_post',
'default_value' => NULL,
@@ -68,7 +68,7 @@ function commerce_kickstart_blog_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-blog_post-field_blog_category'
+ // Exported field_instance: 'node-blog_post-field_blog_category'.
$field_instances['node-blog_post-field_blog_category'] = array(
'bundle' => 'blog_post',
'default_value' => NULL,
@@ -115,7 +115,7 @@ function commerce_kickstart_blog_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-blog_post-field_image'
+ // Exported field_instance: 'node-blog_post-field_image'.
$field_instances['node-blog_post-field_image'] = array(
'bundle' => 'blog_post',
'deleted' => 0,
@@ -181,7 +181,7 @@ function commerce_kickstart_blog_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-blog_post-field_tags'
+ // Exported field_instance: 'node-blog_post-field_tags'.
$field_instances['node-blog_post-field_tags'] = array(
'bundle' => 'blog_post',
'default_value' => NULL,
@@ -233,7 +233,7 @@ function commerce_kickstart_blog_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-blog_post-title_field'
+ // Exported field_instance: 'node-blog_post-title_field'.
$field_instances['node-blog_post-title_field'] = array(
'bundle' => 'blog_post',
'default_value' => NULL,
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_blog/commerce_kickstart_blog.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_blog/commerce_kickstart_blog.info
index e53d56f3..e22c8d45 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_blog/commerce_kickstart_blog.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_blog/commerce_kickstart_blog.info
@@ -51,9 +51,8 @@ features_exclude[field_base][field_image] = field_image
features_exclude[field_base][title_field] = title_field
files[] = commerce_kickstart_blog.migrate.inc
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_blog/commerce_kickstart_blog.module b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_blog/commerce_kickstart_blog.module
index 209301c8..4ef76046 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_blog/commerce_kickstart_blog.module
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_blog/commerce_kickstart_blog.module
@@ -19,6 +19,10 @@ function commerce_kickstart_blog_migrate_api() {
),
);
}
+
+ // Return a near empty array to avoid API warning.
+ // @link https://www.drupal.org/node/2544320
+ return array('api' => 2);
}
/**
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_comment/commerce_kickstart_comment.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_comment/commerce_kickstart_comment.info
index cecd3267..e168e687 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_comment/commerce_kickstart_comment.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_comment/commerce_kickstart_comment.info
@@ -4,9 +4,8 @@ package = Commerce Kickstart
core = 7.x
dependencies[] = comment
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_dfp/commerce_kickstart_dfp.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_dfp/commerce_kickstart_dfp.info
index 7467af23..1d1d77ca 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_dfp/commerce_kickstart_dfp.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_dfp/commerce_kickstart_dfp.info
@@ -3,9 +3,8 @@ description = Provides in-distribution content for Commerce Kickstart.
core = 7.x
package = Commerce Kickstart
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_help/commerce_kickstart_help.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_help/commerce_kickstart_help.info
index 1cf54841..17f322d9 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_help/commerce_kickstart_help.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_help/commerce_kickstart_help.info
@@ -4,9 +4,8 @@ core = 7.x
package = Commerce Kickstart
dependencies[] = advanced_help
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_help/commerce_kickstart_inline_help/commerce_kickstart_inline_help.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_help/commerce_kickstart_inline_help/commerce_kickstart_inline_help.info
index a2e35703..a505006f 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_help/commerce_kickstart_inline_help/commerce_kickstart_inline_help.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_help/commerce_kickstart_inline_help/commerce_kickstart_inline_help.info
@@ -5,9 +5,8 @@ package = Commerce Kickstart
dependencies[] = advanced_help
dependencies[] = commerce_kickstart_help
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_lite_product/commerce_kickstart_lite_product.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_lite_product/commerce_kickstart_lite_product.info
index 8b7e9316..141dea60 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_lite_product/commerce_kickstart_lite_product.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_lite_product/commerce_kickstart_lite_product.info
@@ -55,9 +55,8 @@ features[variable][] = pathauto_taxonomy_term_pattern
features_exclude[taxonomy][product_category] = product_category
files[] = commerce_kickstart_lite_product.migrate.inc
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_menus/commerce_kickstart_menus.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_menus/commerce_kickstart_menus.info
index 588dfa9e..96f70b5d 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_menus/commerce_kickstart_menus.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_menus/commerce_kickstart_menus.info
@@ -6,9 +6,8 @@ dependencies[] = toolbar_megamenu
stylesheets[all][] = commerce_kickstart_menus.css
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_menus/commerce_kickstart_menus.module b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_menus/commerce_kickstart_menus.module
index db9eab75..6b92cae7 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_menus/commerce_kickstart_menus.module
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_menus/commerce_kickstart_menus.module
@@ -370,8 +370,8 @@ function commerce_kickstart_menus_menu_alter(&$items) {
}
// Show the Discounts link under "Store settings".
- if (module_exists('commerce_discount') && isset($items['admin/commerce/store/discounts'])) {
- $items['admin/commerce/store/discounts']['parent'] = 'admin/commerce/config/promotions';
+ if (module_exists('commerce_discount') && isset($items['admin/commerce/discounts'])) {
+ $items['admin/commerce/discounts']['parent'] = 'admin/commerce/config/promotions';
}
$advanced_store_items = array(
'admin/commerce/customer-profiles',
@@ -492,26 +492,28 @@ function commerce_kickstart_menus_views_api() {
* Implements hook_menu_breadcrumb_alter().
*/
function commerce_kickstart_menus_menu_breadcrumb_alter(&$active_trail, $item) {
- // Home > Administration > Content > Settings > Content types
- if (drupal_match_path($item['path'], "admin/structure/types") || drupal_match_path($item['path'], "admin/structure/types/*")) {
- if (drupal_match_path($item['path'], "admin/structure/types/add")) {
- return;
+ if (isset($item['path'])) {
+ // Home > Administration > Content > Settings > Content types
+ if (drupal_match_path($item['path'], "admin/structure/types") || drupal_match_path($item['path'], "admin/structure/types/*")) {
+ if (drupal_match_path($item['path'], "admin/structure/types/add")) {
+ return;
+ }
+ $active_trail_end = array_slice($active_trail, 6);
+ $active_trail = array_slice($active_trail, 0, 1);
+ $active_trail[] = _commerce_kickstart_menus_get_item('admin');
+ $active_trail[] = _commerce_kickstart_menus_get_item('admin/commerce/manage-content');
+ $active_trail[] = _commerce_kickstart_menus_get_item('admin/commerce/manage-content/settings');
+ $active_trail[] = _commerce_kickstart_menus_get_item('admin/commerce/manage-content/settings/content-types');
+ $active_trail = array_merge($active_trail, $active_trail_end);
+ }
+ // Set the breadcrumb for the "Add content" tab of node/add.
+ else if (drupal_match_path($item['path'], 'node/add')) {
+ $active_trail = array_slice($active_trail, 0, 1);
+ $active_trail[] = _commerce_kickstart_menus_get_item('admin');
+ $active_trail[] = _commerce_kickstart_menus_get_item('admin/commerce/manage-content');
+ $active_trail[] = _commerce_kickstart_menus_get_item('admin/commerce/manage-content/actions');
+ $active_trail[] = _commerce_kickstart_menus_get_item('node/add/add-content');
}
- $active_trail_end = array_slice($active_trail, 6);
- $active_trail = array_slice($active_trail, 0, 1);
- $active_trail[] = _commerce_kickstart_menus_get_item('admin');
- $active_trail[] = _commerce_kickstart_menus_get_item('admin/commerce/manage-content');
- $active_trail[] = _commerce_kickstart_menus_get_item('admin/commerce/manage-content/settings');
- $active_trail[] = _commerce_kickstart_menus_get_item('admin/commerce/manage-content/settings/content-types');
- $active_trail = array_merge($active_trail, $active_trail_end);
- }
- // Set the breadcrumb for the "Add content" tab of node/add.
- else if (drupal_match_path($item['path'], 'node/add')) {
- $active_trail = array_slice($active_trail, 0, 1);
- $active_trail[] = _commerce_kickstart_menus_get_item('admin');
- $active_trail[] = _commerce_kickstart_menus_get_item('admin/commerce/manage-content');
- $active_trail[] = _commerce_kickstart_menus_get_item('admin/commerce/manage-content/actions');
- $active_trail[] = _commerce_kickstart_menus_get_item('node/add/add-content');
}
}
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_merchandising/commerce_kickstart_merchandising.features.field_base.inc b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_merchandising/commerce_kickstart_merchandising.features.field_base.inc
index 81359e38..16c1b297 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_merchandising/commerce_kickstart_merchandising.features.field_base.inc
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_merchandising/commerce_kickstart_merchandising.features.field_base.inc
@@ -10,7 +10,7 @@
function commerce_kickstart_merchandising_field_default_field_bases() {
$field_bases = array();
- // Exported field_base: 'field_link'
+ // Exported field_base: 'field_link'.
$field_bases['field_link'] = array(
'active' => 1,
'cardinality' => 1,
@@ -37,7 +37,7 @@ function commerce_kickstart_merchandising_field_default_field_bases() {
'type' => 'link_field',
);
- // Exported field_base: 'field_tagline'
+ // Exported field_base: 'field_tagline'.
$field_bases['field_tagline'] = array(
'active' => 1,
'cardinality' => 1,
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_merchandising/commerce_kickstart_merchandising.features.field_instance.inc b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_merchandising/commerce_kickstart_merchandising.features.field_instance.inc
index 7900c2be..737413be 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_merchandising/commerce_kickstart_merchandising.features.field_instance.inc
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_merchandising/commerce_kickstart_merchandising.features.field_instance.inc
@@ -10,7 +10,7 @@
function commerce_kickstart_merchandising_field_default_field_instances() {
$field_instances = array();
- // Exported field_instance: 'comment-comment_node_ad_push-comment_body'
+ // Exported field_instance: 'comment-comment_node_ad_push-comment_body'.
$field_instances['comment-comment_node_ad_push-comment_body'] = array(
'bundle' => 'comment_node_ad_push',
'default_value' => NULL,
@@ -43,7 +43,7 @@ function commerce_kickstart_merchandising_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-ad_push-field_image'
+ // Exported field_instance: 'node-ad_push-field_image'.
$field_instances['node-ad_push-field_image'] = array(
'bundle' => 'ad_push',
'deleted' => 0,
@@ -109,7 +109,7 @@ function commerce_kickstart_merchandising_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-ad_push-field_link'
+ // Exported field_instance: 'node-ad_push-field_link'.
$field_instances['node-ad_push-field_link'] = array(
'bundle' => 'ad_push',
'default_value' => NULL,
@@ -176,7 +176,7 @@ function commerce_kickstart_merchandising_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-ad_push-field_tagline'
+ // Exported field_instance: 'node-ad_push-field_tagline'.
$field_instances['node-ad_push-field_tagline'] = array(
'bundle' => 'ad_push',
'default_value' => NULL,
@@ -228,7 +228,7 @@ function commerce_kickstart_merchandising_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-ad_push-title_field'
+ // Exported field_instance: 'node-ad_push-title_field'.
$field_instances['node-ad_push-title_field'] = array(
'bundle' => 'ad_push',
'default_value' => NULL,
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_merchandising/commerce_kickstart_merchandising.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_merchandising/commerce_kickstart_merchandising.info
index b684195d..ae8c337a 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_merchandising/commerce_kickstart_merchandising.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_merchandising/commerce_kickstart_merchandising.info
@@ -41,9 +41,8 @@ features_exclude[field_base][field_image] = field_image
features_exclude[field_base][title_field] = title_field
files[] = commerce_kickstart_merchandising.migrate.inc
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_merchandising/commerce_kickstart_merchandising.module b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_merchandising/commerce_kickstart_merchandising.module
index 6f884ef6..f5b507cf 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_merchandising/commerce_kickstart_merchandising.module
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_merchandising/commerce_kickstart_merchandising.module
@@ -19,6 +19,10 @@ function commerce_kickstart_merchandising_migrate_api() {
),
);
}
+
+ // Return a near empty array to avoid API warning.
+ // @link https://www.drupal.org/node/2544320
+ return array('api' => 2);
}
/**
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_migrate/commerce_kickstart_migrate.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_migrate/commerce_kickstart_migrate.info
index 22e67f1d..e60fe365 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_migrate/commerce_kickstart_migrate.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_migrate/commerce_kickstart_migrate.info
@@ -8,9 +8,8 @@ dependencies[] = commerce_migrate
files[] = commerce_kickstart_migrate.migrate.inc
files[] = plugins/destinations/fields.inc
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_order/commerce_kickstart_order.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_order/commerce_kickstart_order.info
index 2ec1fab1..2a72cd96 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_order/commerce_kickstart_order.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_order/commerce_kickstart_order.info
@@ -8,9 +8,8 @@ dependencies[] = commerce_message
dependencies[] = commerce_cart
dependencies[] = ctools
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product/commerce_kickstart_product.features.field_base.inc b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product/commerce_kickstart_product.features.field_base.inc
index 29953c75..735b5e02 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product/commerce_kickstart_product.features.field_base.inc
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product/commerce_kickstart_product.features.field_base.inc
@@ -10,7 +10,7 @@
function commerce_kickstart_product_field_default_field_bases() {
$field_bases = array();
- // Exported field_base: 'commerce_price'
+ // Exported field_base: 'commerce_price'.
$field_bases['commerce_price'] = array(
'active' => 1,
'cardinality' => 1,
@@ -32,7 +32,7 @@ function commerce_kickstart_product_field_default_field_bases() {
'type' => 'commerce_price',
);
- // Exported field_base: 'field_bag_size'
+ // Exported field_base: 'field_bag_size'.
$field_bases['field_bag_size'] = array(
'active' => 1,
'cardinality' => 1,
@@ -53,12 +53,13 @@ function commerce_kickstart_product_field_default_field_bases() {
'parent' => 0,
),
),
+ 'options_list_callback' => 'title_taxonomy_allowed_values',
),
'translatable' => 0,
'type' => 'taxonomy_term_reference',
);
- // Exported field_base: 'field_brand'
+ // Exported field_base: 'field_brand'.
$field_bases['field_brand'] = array(
'active' => 1,
'cardinality' => 1,
@@ -79,12 +80,13 @@ function commerce_kickstart_product_field_default_field_bases() {
'parent' => 0,
),
),
+ 'options_list_callback' => 'title_taxonomy_allowed_values',
),
'translatable' => 0,
'type' => 'taxonomy_term_reference',
);
- // Exported field_base: 'field_category'
+ // Exported field_base: 'field_category'.
$field_bases['field_category'] = array(
'active' => 1,
'cardinality' => 1,
@@ -105,12 +107,13 @@ function commerce_kickstart_product_field_default_field_bases() {
'parent' => 0,
),
),
+ 'options_list_callback' => 'title_taxonomy_allowed_values',
),
'translatable' => 0,
'type' => 'taxonomy_term_reference',
);
- // Exported field_base: 'field_category_color'
+ // Exported field_base: 'field_category_color'.
$field_bases['field_category_color'] = array(
'active' => 1,
'cardinality' => 1,
@@ -131,7 +134,7 @@ function commerce_kickstart_product_field_default_field_bases() {
'type' => 'text',
);
- // Exported field_base: 'field_collection'
+ // Exported field_base: 'field_collection'.
$field_bases['field_collection'] = array(
'active' => 1,
'cardinality' => 1,
@@ -152,12 +155,13 @@ function commerce_kickstart_product_field_default_field_bases() {
'parent' => 0,
),
),
+ 'options_list_callback' => 'title_taxonomy_allowed_values',
),
'translatable' => 0,
'type' => 'taxonomy_term_reference',
);
- // Exported field_base: 'field_color'
+ // Exported field_base: 'field_color'.
$field_bases['field_color'] = array(
'active' => 1,
'cardinality' => 1,
@@ -178,12 +182,13 @@ function commerce_kickstart_product_field_default_field_bases() {
'parent' => 0,
),
),
+ 'options_list_callback' => 'title_taxonomy_allowed_values',
),
'translatable' => 0,
'type' => 'taxonomy_term_reference',
);
- // Exported field_base: 'field_gender'
+ // Exported field_base: 'field_gender'.
$field_bases['field_gender'] = array(
'active' => 1,
'cardinality' => 1,
@@ -204,12 +209,13 @@ function commerce_kickstart_product_field_default_field_bases() {
'parent' => 0,
),
),
+ 'options_list_callback' => 'title_taxonomy_allowed_values',
),
'translatable' => 0,
'type' => 'taxonomy_term_reference',
);
- // Exported field_base: 'field_hat_size'
+ // Exported field_base: 'field_hat_size'.
$field_bases['field_hat_size'] = array(
'active' => 1,
'cardinality' => 1,
@@ -230,12 +236,13 @@ function commerce_kickstart_product_field_default_field_bases() {
'parent' => 0,
),
),
+ 'options_list_callback' => 'title_taxonomy_allowed_values',
),
'translatable' => 0,
'type' => 'taxonomy_term_reference',
);
- // Exported field_base: 'field_images'
+ // Exported field_base: 'field_images'.
$field_bases['field_images'] = array(
'active' => 1,
'cardinality' => -1,
@@ -257,7 +264,7 @@ function commerce_kickstart_product_field_default_field_bases() {
'type' => 'image',
);
- // Exported field_base: 'field_product'
+ // Exported field_base: 'field_product'.
$field_bases['field_product'] = array(
'active' => 1,
'cardinality' => -1,
@@ -278,7 +285,7 @@ function commerce_kickstart_product_field_default_field_bases() {
'type' => 'commerce_product_reference',
);
- // Exported field_base: 'field_shoe_size'
+ // Exported field_base: 'field_shoe_size'.
$field_bases['field_shoe_size'] = array(
'active' => 1,
'cardinality' => 1,
@@ -299,12 +306,13 @@ function commerce_kickstart_product_field_default_field_bases() {
'parent' => 0,
),
),
+ 'options_list_callback' => 'title_taxonomy_allowed_values',
),
'translatable' => 0,
'type' => 'taxonomy_term_reference',
);
- // Exported field_base: 'field_storage_capacity'
+ // Exported field_base: 'field_storage_capacity'.
$field_bases['field_storage_capacity'] = array(
'active' => 1,
'cardinality' => 1,
@@ -325,12 +333,13 @@ function commerce_kickstart_product_field_default_field_bases() {
'parent' => 0,
),
),
+ 'options_list_callback' => 'title_taxonomy_allowed_values',
),
'translatable' => 0,
'type' => 'taxonomy_term_reference',
);
- // Exported field_base: 'field_top_size'
+ // Exported field_base: 'field_top_size'.
$field_bases['field_top_size'] = array(
'active' => 1,
'cardinality' => 1,
@@ -351,6 +360,7 @@ function commerce_kickstart_product_field_default_field_bases() {
'parent' => 0,
),
),
+ 'options_list_callback' => 'title_taxonomy_allowed_values',
),
'translatable' => 0,
'type' => 'taxonomy_term_reference',
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product/commerce_kickstart_product.features.field_instance.inc b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product/commerce_kickstart_product.features.field_instance.inc
index a21391d8..7532f383 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product/commerce_kickstart_product.features.field_instance.inc
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product/commerce_kickstart_product.features.field_instance.inc
@@ -10,7 +10,7 @@
function commerce_kickstart_product_field_default_field_instances() {
$field_instances = array();
- // Exported field_instance: 'commerce_product-bags_cases-commerce_price'
+ // Exported field_instance: 'commerce_product-bags_cases-commerce_price'.
$field_instances['commerce_product-bags_cases-commerce_price'] = array(
'bundle' => 'bags_cases',
'default_value' => NULL,
@@ -142,7 +142,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-bags_cases-field_bag_size'
+ // Exported field_instance: 'commerce_product-bags_cases-field_bag_size'.
$field_instances['commerce_product-bags_cases-field_bag_size'] = array(
'bundle' => 'bags_cases',
'commerce_cart_settings' => array(
@@ -218,7 +218,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-bags_cases-field_color'
+ // Exported field_instance: 'commerce_product-bags_cases-field_color'.
$field_instances['commerce_product-bags_cases-field_color'] = array(
'bundle' => 'bags_cases',
'commerce_cart_settings' => array(
@@ -294,7 +294,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-bags_cases-field_images'
+ // Exported field_instance: 'commerce_product-bags_cases-field_images'.
$field_instances['commerce_product-bags_cases-field_images'] = array(
'bundle' => 'bags_cases',
'deleted' => 0,
@@ -417,7 +417,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-bags_cases-title_field'
+ // Exported field_instance: 'commerce_product-bags_cases-title_field'.
$field_instances['commerce_product-bags_cases-title_field'] = array(
'bundle' => 'bags_cases',
'default_value' => NULL,
@@ -486,7 +486,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-drinks-commerce_price'
+ // Exported field_instance: 'commerce_product-drinks-commerce_price'.
$field_instances['commerce_product-drinks-commerce_price'] = array(
'bundle' => 'drinks',
'default_value' => NULL,
@@ -618,7 +618,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-drinks-field_color'
+ // Exported field_instance: 'commerce_product-drinks-field_color'.
$field_instances['commerce_product-drinks-field_color'] = array(
'bundle' => 'drinks',
'commerce_cart_settings' => array(
@@ -695,7 +695,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-drinks-field_images'
+ // Exported field_instance: 'commerce_product-drinks-field_images'.
$field_instances['commerce_product-drinks-field_images'] = array(
'bundle' => 'drinks',
'deleted' => 0,
@@ -818,7 +818,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-drinks-title_field'
+ // Exported field_instance: 'commerce_product-drinks-title_field'.
$field_instances['commerce_product-drinks-title_field'] = array(
'bundle' => 'drinks',
'default_value' => NULL,
@@ -887,7 +887,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-hats-commerce_price'
+ // Exported field_instance: 'commerce_product-hats-commerce_price'.
$field_instances['commerce_product-hats-commerce_price'] = array(
'bundle' => 'hats',
'default_value' => NULL,
@@ -1019,7 +1019,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-hats-field_color'
+ // Exported field_instance: 'commerce_product-hats-field_color'.
$field_instances['commerce_product-hats-field_color'] = array(
'bundle' => 'hats',
'commerce_cart_settings' => array(
@@ -1100,7 +1100,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-hats-field_hat_size'
+ // Exported field_instance: 'commerce_product-hats-field_hat_size'.
$field_instances['commerce_product-hats-field_hat_size'] = array(
'bundle' => 'hats',
'commerce_cart_settings' => array(
@@ -1180,7 +1180,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-hats-field_images'
+ // Exported field_instance: 'commerce_product-hats-field_images'.
$field_instances['commerce_product-hats-field_images'] = array(
'bundle' => 'hats',
'deleted' => 0,
@@ -1303,7 +1303,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-hats-title_field'
+ // Exported field_instance: 'commerce_product-hats-title_field'.
$field_instances['commerce_product-hats-title_field'] = array(
'bundle' => 'hats',
'default_value' => NULL,
@@ -1372,7 +1372,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-shoes-commerce_price'
+ // Exported field_instance: 'commerce_product-shoes-commerce_price'.
$field_instances['commerce_product-shoes-commerce_price'] = array(
'bundle' => 'shoes',
'default_value' => NULL,
@@ -1504,7 +1504,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-shoes-field_color'
+ // Exported field_instance: 'commerce_product-shoes-field_color'.
$field_instances['commerce_product-shoes-field_color'] = array(
'bundle' => 'shoes',
'commerce_cart_settings' => array(
@@ -1581,7 +1581,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-shoes-field_images'
+ // Exported field_instance: 'commerce_product-shoes-field_images'.
$field_instances['commerce_product-shoes-field_images'] = array(
'bundle' => 'shoes',
'deleted' => 0,
@@ -1704,7 +1704,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-shoes-field_shoe_size'
+ // Exported field_instance: 'commerce_product-shoes-field_shoe_size'.
$field_instances['commerce_product-shoes-field_shoe_size'] = array(
'bundle' => 'shoes',
'commerce_cart_settings' => array(
@@ -1780,7 +1780,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-shoes-title_field'
+ // Exported field_instance: 'commerce_product-shoes-title_field'.
$field_instances['commerce_product-shoes-title_field'] = array(
'bundle' => 'shoes',
'default_value' => NULL,
@@ -1849,7 +1849,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-storage_devices-commerce_price'
+ // Exported field_instance: 'commerce_product-storage_devices-commerce_price'.
$field_instances['commerce_product-storage_devices-commerce_price'] = array(
'bundle' => 'storage_devices',
'default_value' => NULL,
@@ -1981,7 +1981,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-storage_devices-field_images'
+ // Exported field_instance: 'commerce_product-storage_devices-field_images'.
$field_instances['commerce_product-storage_devices-field_images'] = array(
'bundle' => 'storage_devices',
'deleted' => 0,
@@ -2105,7 +2105,7 @@ function commerce_kickstart_product_field_default_field_instances() {
);
// Exported field_instance:
- // 'commerce_product-storage_devices-field_storage_capacity'
+ // 'commerce_product-storage_devices-field_storage_capacity'.
$field_instances['commerce_product-storage_devices-field_storage_capacity'] = array(
'bundle' => 'storage_devices',
'commerce_cart_settings' => array(
@@ -2180,7 +2180,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-storage_devices-title_field'
+ // Exported field_instance: 'commerce_product-storage_devices-title_field'.
$field_instances['commerce_product-storage_devices-title_field'] = array(
'bundle' => 'storage_devices',
'default_value' => NULL,
@@ -2249,7 +2249,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-tops-commerce_price'
+ // Exported field_instance: 'commerce_product-tops-commerce_price'.
$field_instances['commerce_product-tops-commerce_price'] = array(
'bundle' => 'tops',
'default_value' => NULL,
@@ -2381,7 +2381,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-tops-field_color'
+ // Exported field_instance: 'commerce_product-tops-field_color'.
$field_instances['commerce_product-tops-field_color'] = array(
'bundle' => 'tops',
'commerce_cart_settings' => array(
@@ -2457,7 +2457,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-tops-field_images'
+ // Exported field_instance: 'commerce_product-tops-field_images'.
$field_instances['commerce_product-tops-field_images'] = array(
'bundle' => 'tops',
'deleted' => 0,
@@ -2580,7 +2580,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-tops-field_top_size'
+ // Exported field_instance: 'commerce_product-tops-field_top_size'.
$field_instances['commerce_product-tops-field_top_size'] = array(
'bundle' => 'tops',
'commerce_cart_settings' => array(
@@ -2656,7 +2656,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'commerce_product-tops-title_field'
+ // Exported field_instance: 'commerce_product-tops-title_field'.
$field_instances['commerce_product-tops-title_field'] = array(
'bundle' => 'tops',
'default_value' => NULL,
@@ -2725,7 +2725,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-bags_cases-body'
+ // Exported field_instance: 'node-bags_cases-body'.
$field_instances['node-bags_cases-body'] = array(
'bundle' => 'bags_cases',
'default_value' => NULL,
@@ -2790,7 +2790,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-bags_cases-field_brand'
+ // Exported field_instance: 'node-bags_cases-field_brand'.
$field_instances['node-bags_cases-field_brand'] = array(
'bundle' => 'bags_cases',
'default_value' => NULL,
@@ -2848,7 +2848,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-bags_cases-field_category'
+ // Exported field_instance: 'node-bags_cases-field_category'.
$field_instances['node-bags_cases-field_category'] = array(
'bundle' => 'bags_cases',
'default_value' => NULL,
@@ -2905,7 +2905,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-bags_cases-field_collection'
+ // Exported field_instance: 'node-bags_cases-field_collection'.
$field_instances['node-bags_cases-field_collection'] = array(
'bundle' => 'bags_cases',
'default_value' => NULL,
@@ -2962,7 +2962,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-bags_cases-field_gender'
+ // Exported field_instance: 'node-bags_cases-field_gender'.
$field_instances['node-bags_cases-field_gender'] = array(
'bundle' => 'bags_cases',
'default_value' => NULL,
@@ -3019,7 +3019,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-bags_cases-field_product'
+ // Exported field_instance: 'node-bags_cases-field_product'.
$field_instances['node-bags_cases-field_product'] = array(
'bundle' => 'bags_cases',
'deleted' => 0,
@@ -3114,7 +3114,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-bags_cases-title_field'
+ // Exported field_instance: 'node-bags_cases-title_field'.
$field_instances['node-bags_cases-title_field'] = array(
'bundle' => 'bags_cases',
'default_value' => NULL,
@@ -3176,7 +3176,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-drinks-body'
+ // Exported field_instance: 'node-drinks-body'.
$field_instances['node-drinks-body'] = array(
'bundle' => 'drinks',
'default_value' => NULL,
@@ -3241,7 +3241,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-drinks-field_brand'
+ // Exported field_instance: 'node-drinks-field_brand'.
$field_instances['node-drinks-field_brand'] = array(
'bundle' => 'drinks',
'default_value' => NULL,
@@ -3299,7 +3299,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-drinks-field_category'
+ // Exported field_instance: 'node-drinks-field_category'.
$field_instances['node-drinks-field_category'] = array(
'bundle' => 'drinks',
'default_value' => NULL,
@@ -3356,7 +3356,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-drinks-field_collection'
+ // Exported field_instance: 'node-drinks-field_collection'.
$field_instances['node-drinks-field_collection'] = array(
'bundle' => 'drinks',
'default_value' => NULL,
@@ -3413,7 +3413,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-drinks-field_gender'
+ // Exported field_instance: 'node-drinks-field_gender'.
$field_instances['node-drinks-field_gender'] = array(
'bundle' => 'drinks',
'default_value' => NULL,
@@ -3469,7 +3469,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-drinks-field_product'
+ // Exported field_instance: 'node-drinks-field_product'.
$field_instances['node-drinks-field_product'] = array(
'bundle' => 'drinks',
'deleted' => 0,
@@ -3563,7 +3563,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-drinks-title_field'
+ // Exported field_instance: 'node-drinks-title_field'.
$field_instances['node-drinks-title_field'] = array(
'bundle' => 'drinks',
'default_value' => NULL,
@@ -3626,7 +3626,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-hats-body'
+ // Exported field_instance: 'node-hats-body'.
$field_instances['node-hats-body'] = array(
'bundle' => 'hats',
'default_value' => NULL,
@@ -3691,7 +3691,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-hats-field_brand'
+ // Exported field_instance: 'node-hats-field_brand'.
$field_instances['node-hats-field_brand'] = array(
'bundle' => 'hats',
'default_value' => NULL,
@@ -3749,7 +3749,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-hats-field_category'
+ // Exported field_instance: 'node-hats-field_category'.
$field_instances['node-hats-field_category'] = array(
'bundle' => 'hats',
'default_value' => NULL,
@@ -3806,7 +3806,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-hats-field_collection'
+ // Exported field_instance: 'node-hats-field_collection'.
$field_instances['node-hats-field_collection'] = array(
'bundle' => 'hats',
'default_value' => NULL,
@@ -3863,7 +3863,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-hats-field_gender'
+ // Exported field_instance: 'node-hats-field_gender'.
$field_instances['node-hats-field_gender'] = array(
'bundle' => 'hats',
'default_value' => NULL,
@@ -3920,7 +3920,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-hats-field_product'
+ // Exported field_instance: 'node-hats-field_product'.
$field_instances['node-hats-field_product'] = array(
'bundle' => 'hats',
'deleted' => 0,
@@ -4015,7 +4015,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-hats-title_field'
+ // Exported field_instance: 'node-hats-title_field'.
$field_instances['node-hats-title_field'] = array(
'bundle' => 'hats',
'default_value' => NULL,
@@ -4077,7 +4077,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-shoes-body'
+ // Exported field_instance: 'node-shoes-body'.
$field_instances['node-shoes-body'] = array(
'bundle' => 'shoes',
'default_value' => NULL,
@@ -4142,7 +4142,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-shoes-field_brand'
+ // Exported field_instance: 'node-shoes-field_brand'.
$field_instances['node-shoes-field_brand'] = array(
'bundle' => 'shoes',
'default_value' => NULL,
@@ -4200,7 +4200,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-shoes-field_category'
+ // Exported field_instance: 'node-shoes-field_category'.
$field_instances['node-shoes-field_category'] = array(
'bundle' => 'shoes',
'default_value' => NULL,
@@ -4257,7 +4257,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-shoes-field_collection'
+ // Exported field_instance: 'node-shoes-field_collection'.
$field_instances['node-shoes-field_collection'] = array(
'bundle' => 'shoes',
'default_value' => NULL,
@@ -4314,7 +4314,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-shoes-field_gender'
+ // Exported field_instance: 'node-shoes-field_gender'.
$field_instances['node-shoes-field_gender'] = array(
'bundle' => 'shoes',
'default_value' => NULL,
@@ -4371,7 +4371,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-shoes-field_product'
+ // Exported field_instance: 'node-shoes-field_product'.
$field_instances['node-shoes-field_product'] = array(
'bundle' => 'shoes',
'deleted' => 0,
@@ -4466,7 +4466,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-shoes-title_field'
+ // Exported field_instance: 'node-shoes-title_field'.
$field_instances['node-shoes-title_field'] = array(
'bundle' => 'shoes',
'default_value' => NULL,
@@ -4528,7 +4528,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-storage_devices-body'
+ // Exported field_instance: 'node-storage_devices-body'.
$field_instances['node-storage_devices-body'] = array(
'bundle' => 'storage_devices',
'default_value' => NULL,
@@ -4593,7 +4593,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-storage_devices-field_brand'
+ // Exported field_instance: 'node-storage_devices-field_brand'.
$field_instances['node-storage_devices-field_brand'] = array(
'bundle' => 'storage_devices',
'default_value' => NULL,
@@ -4651,7 +4651,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-storage_devices-field_category'
+ // Exported field_instance: 'node-storage_devices-field_category'.
$field_instances['node-storage_devices-field_category'] = array(
'bundle' => 'storage_devices',
'default_value' => NULL,
@@ -4708,7 +4708,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-storage_devices-field_collection'
+ // Exported field_instance: 'node-storage_devices-field_collection'.
$field_instances['node-storage_devices-field_collection'] = array(
'bundle' => 'storage_devices',
'default_value' => NULL,
@@ -4765,7 +4765,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-storage_devices-field_gender'
+ // Exported field_instance: 'node-storage_devices-field_gender'.
$field_instances['node-storage_devices-field_gender'] = array(
'bundle' => 'storage_devices',
'default_value' => NULL,
@@ -4822,7 +4822,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-storage_devices-field_product'
+ // Exported field_instance: 'node-storage_devices-field_product'.
$field_instances['node-storage_devices-field_product'] = array(
'bundle' => 'storage_devices',
'deleted' => 0,
@@ -4909,7 +4909,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-storage_devices-title_field'
+ // Exported field_instance: 'node-storage_devices-title_field'.
$field_instances['node-storage_devices-title_field'] = array(
'bundle' => 'storage_devices',
'default_value' => NULL,
@@ -4971,7 +4971,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-tops-body'
+ // Exported field_instance: 'node-tops-body'.
$field_instances['node-tops-body'] = array(
'bundle' => 'tops',
'default_value' => NULL,
@@ -5034,7 +5034,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-tops-field_brand'
+ // Exported field_instance: 'node-tops-field_brand'.
$field_instances['node-tops-field_brand'] = array(
'bundle' => 'tops',
'default_value' => NULL,
@@ -5092,7 +5092,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-tops-field_category'
+ // Exported field_instance: 'node-tops-field_category'.
$field_instances['node-tops-field_category'] = array(
'bundle' => 'tops',
'default_value' => NULL,
@@ -5149,7 +5149,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-tops-field_collection'
+ // Exported field_instance: 'node-tops-field_collection'.
$field_instances['node-tops-field_collection'] = array(
'bundle' => 'tops',
'default_value' => NULL,
@@ -5206,7 +5206,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-tops-field_gender'
+ // Exported field_instance: 'node-tops-field_gender'.
$field_instances['node-tops-field_gender'] = array(
'bundle' => 'tops',
'default_value' => NULL,
@@ -5263,7 +5263,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-tops-field_product'
+ // Exported field_instance: 'node-tops-field_product'.
$field_instances['node-tops-field_product'] = array(
'bundle' => 'tops',
'deleted' => 0,
@@ -5358,7 +5358,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-tops-title_field'
+ // Exported field_instance: 'node-tops-title_field'.
$field_instances['node-tops-title_field'] = array(
'bundle' => 'tops',
'default_value' => NULL,
@@ -5420,7 +5420,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'taxonomy_term-category-field_category_color'
+ // Exported field_instance: 'taxonomy_term-category-field_category_color'.
$field_instances['taxonomy_term-category-field_category_color'] = array(
'bundle' => 'category',
'default_value' => array(
@@ -5464,7 +5464,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'taxonomy_term-collection-field_image'
+ // Exported field_instance: 'taxonomy_term-collection-field_image'.
$field_instances['taxonomy_term-collection-field_image'] = array(
'bundle' => 'collection',
'deleted' => 0,
@@ -5523,7 +5523,7 @@ function commerce_kickstart_product_field_default_field_instances() {
),
);
- // Exported field_instance: 'taxonomy_term-color-field_category_color'
+ // Exported field_instance: 'taxonomy_term-color-field_category_color'.
$field_instances['taxonomy_term-color-field_category_color'] = array(
'bundle' => 'color',
'default_value' => NULL,
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product/commerce_kickstart_product.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product/commerce_kickstart_product.info
index f7f2b7a8..659f5215 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product/commerce_kickstart_product.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product/commerce_kickstart_product.info
@@ -230,9 +230,8 @@ features_exclude[field_base][field_image] = field_image
features_exclude[field_base][title_field] = title_field
files[] = commerce_kickstart_product.migrate.inc
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product_ui/commerce_kickstart_product_ui.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product_ui/commerce_kickstart_product_ui.info
index 023d2226..b6a2625b 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product_ui/commerce_kickstart_product_ui.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_product_ui/commerce_kickstart_product_ui.info
@@ -7,9 +7,8 @@ dependencies[] = commerce_product
dependencies[] = views
dependencies[] = libraries
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_reset/commerce_kickstart_reset.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_reset/commerce_kickstart_reset.info
index 92673c72..f3ad9bd1 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_reset/commerce_kickstart_reset.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_reset/commerce_kickstart_reset.info
@@ -2,9 +2,8 @@ name = Commerce Kickstart Reset
core = 7.x
package = Commerce Kickstart
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_search/commerce_kickstart_search.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_search/commerce_kickstart_search.info
index 5ca57242..21f04581 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_search/commerce_kickstart_search.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_search/commerce_kickstart_search.info
@@ -15,9 +15,8 @@ dependencies[] = search_api_views
dependencies[] = views
scripts[] = commerce_kickstart_search.js
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_slideshow/commerce_kickstart_slideshow.features.field_base.inc b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_slideshow/commerce_kickstart_slideshow.features.field_base.inc
index 07be029c..427e7fdb 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_slideshow/commerce_kickstart_slideshow.features.field_base.inc
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_slideshow/commerce_kickstart_slideshow.features.field_base.inc
@@ -10,7 +10,7 @@
function commerce_kickstart_slideshow_field_default_field_bases() {
$field_bases = array();
- // Exported field_base: 'comment_body'
+ // Exported field_base: 'comment_body'.
$field_bases['comment_body'] = array(
'active' => 1,
'cardinality' => 1,
@@ -31,7 +31,7 @@ function commerce_kickstart_slideshow_field_default_field_bases() {
'type' => 'text_long',
);
- // Exported field_base: 'field_headline'
+ // Exported field_base: 'field_headline'.
$field_bases['field_headline'] = array(
'active' => 1,
'cardinality' => 1,
@@ -52,7 +52,7 @@ function commerce_kickstart_slideshow_field_default_field_bases() {
'type' => 'text',
);
- // Exported field_base: 'field_link'
+ // Exported field_base: 'field_link'.
$field_bases['field_link'] = array(
'active' => 1,
'cardinality' => 1,
@@ -79,7 +79,7 @@ function commerce_kickstart_slideshow_field_default_field_bases() {
'type' => 'link_field',
);
- // Exported field_base: 'field_tagline'
+ // Exported field_base: 'field_tagline'.
$field_bases['field_tagline'] = array(
'active' => 1,
'cardinality' => 1,
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_slideshow/commerce_kickstart_slideshow.features.field_instance.inc b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_slideshow/commerce_kickstart_slideshow.features.field_instance.inc
index 0263556c..19ebe96c 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_slideshow/commerce_kickstart_slideshow.features.field_instance.inc
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_slideshow/commerce_kickstart_slideshow.features.field_instance.inc
@@ -10,7 +10,7 @@
function commerce_kickstart_slideshow_field_default_field_instances() {
$field_instances = array();
- // Exported field_instance: 'comment-comment_node_slideshow-comment_body'
+ // Exported field_instance: 'comment-comment_node_slideshow-comment_body'.
$field_instances['comment-comment_node_slideshow-comment_body'] = array(
'bundle' => 'comment_node_slideshow',
'default_value' => NULL,
@@ -43,7 +43,7 @@ function commerce_kickstart_slideshow_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-slideshow-field_headline'
+ // Exported field_instance: 'node-slideshow-field_headline'.
$field_instances['node-slideshow-field_headline'] = array(
'bundle' => 'slideshow',
'default_value' => NULL,
@@ -95,7 +95,7 @@ function commerce_kickstart_slideshow_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-slideshow-field_image'
+ // Exported field_instance: 'node-slideshow-field_image'.
$field_instances['node-slideshow-field_image'] = array(
'bundle' => 'slideshow',
'deleted' => 0,
@@ -161,7 +161,7 @@ function commerce_kickstart_slideshow_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-slideshow-field_link'
+ // Exported field_instance: 'node-slideshow-field_link'.
$field_instances['node-slideshow-field_link'] = array(
'bundle' => 'slideshow',
'default_value' => NULL,
@@ -228,7 +228,7 @@ function commerce_kickstart_slideshow_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-slideshow-field_tagline'
+ // Exported field_instance: 'node-slideshow-field_tagline'.
$field_instances['node-slideshow-field_tagline'] = array(
'bundle' => 'slideshow',
'default_value' => NULL,
@@ -280,7 +280,7 @@ function commerce_kickstart_slideshow_field_default_field_instances() {
),
);
- // Exported field_instance: 'node-slideshow-title_field'
+ // Exported field_instance: 'node-slideshow-title_field'.
$field_instances['node-slideshow-title_field'] = array(
'bundle' => 'slideshow',
'default_value' => NULL,
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_slideshow/commerce_kickstart_slideshow.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_slideshow/commerce_kickstart_slideshow.info
index 4914ac21..9ae7ab7f 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_slideshow/commerce_kickstart_slideshow.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_slideshow/commerce_kickstart_slideshow.info
@@ -50,9 +50,8 @@ features_exclude[field_base][field_image] = field_image
features_exclude[field_base][title_field] = title_field
files[] = commerce_kickstart_slideshow.migrate.inc
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_social/commerce_kickstart_social.features.menu_custom.inc b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_social/commerce_kickstart_social.features.menu_custom.inc
index 1e02ae6c..dc233c5f 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_social/commerce_kickstart_social.features.menu_custom.inc
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_social/commerce_kickstart_social.features.menu_custom.inc
@@ -21,6 +21,5 @@ function commerce_kickstart_social_menu_default_menu_custom() {
t('Connect with us');
t('The "Connect with us" menu.');
-
return $menus;
}
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_social/commerce_kickstart_social.features.menu_links.inc b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_social/commerce_kickstart_social.features.menu_links.inc
index 873af166..9f101930 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_social/commerce_kickstart_social.features.menu_links.inc
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_social/commerce_kickstart_social.features.menu_links.inc
@@ -10,7 +10,7 @@
function commerce_kickstart_social_menu_default_menu_links() {
$menu_links = array();
- // Exported menu link: menu-social-connection_follow-us-on-twitter:https://twitter.com/commerceguys
+ // Exported menu link: menu-social-connection_follow-us-on-twitter:https://twitter.com/commerceguys.
$menu_links['menu-social-connection_follow-us-on-twitter:https://twitter.com/commerceguys'] = array(
'menu_name' => 'menu-social-connection',
'link_path' => 'https://twitter.com/commerceguys',
@@ -34,7 +34,7 @@ function commerce_kickstart_social_menu_default_menu_links() {
'weight' => -49,
'customized' => 1,
);
- // Exported menu link: menu-social-connection_like-us-on-facebook:https://www.facebook.com/commerceguys
+ // Exported menu link: menu-social-connection_like-us-on-facebook:https://www.facebook.com/commerceguys.
$menu_links['menu-social-connection_like-us-on-facebook:https://www.facebook.com/commerceguys'] = array(
'menu_name' => 'menu-social-connection',
'link_path' => 'https://www.facebook.com/commerceguys',
@@ -58,7 +58,7 @@ function commerce_kickstart_social_menu_default_menu_links() {
'weight' => -50,
'customized' => 1,
);
- // Exported menu link: menu-social-connection_what-we-like-on-pinterest:http://pinterest.com/
+ // Exported menu link: menu-social-connection_what-we-like-on-pinterest:http://pinterest.com/.
$menu_links['menu-social-connection_what-we-like-on-pinterest:http://pinterest.com/'] = array(
'menu_name' => 'menu-social-connection',
'link_path' => 'http://pinterest.com/',
@@ -82,12 +82,12 @@ function commerce_kickstart_social_menu_default_menu_links() {
'weight' => -48,
'customized' => 1,
);
+
// Translatables
// Included for use with string extractors like potx.
t('Follow Us on Twitter');
t('Like us on Facebook');
t('What We Like on Pinterest');
-
return $menu_links;
}
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_social/commerce_kickstart_social.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_social/commerce_kickstart_social.info
index c41f6d69..513a0d0d 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_social/commerce_kickstart_social.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_social/commerce_kickstart_social.info
@@ -2,7 +2,6 @@ name = Commerce Kickstart Social
description = Social features for Commerce kickstart.
core = 7.x
package = Commerce Kickstart
-php = 5.2.4
dependencies[] = block
dependencies[] = connector_action_default_register_form
dependencies[] = ctools
@@ -33,9 +32,8 @@ features[variable][] = service_links_show
features[variable][] = service_links_style
features[variable][] = service_links_visibility_for_node
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_social/commerce_kickstart_social.strongarm.inc b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_social/commerce_kickstart_social.strongarm.inc
index 6cdaa0fa..356f7424 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_social/commerce_kickstart_social.strongarm.inc
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_social/commerce_kickstart_social.strongarm.inc
@@ -31,6 +31,33 @@ function commerce_kickstart_social_strongarm() {
$strongarm->value = '';
$export['service_links_label_in_node'] = $strongarm;
+ $strongarm = new stdClass();
+ $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+ $strongarm->api_version = 1;
+ $strongarm->name = 'service_links_node_types';
+ $strongarm->value = array(
+ 0 => 'bags_cases',
+ 1 => 'drinks',
+ 2 => 'hats',
+ 3 => 'shoes',
+ 4 => 'storage_devices',
+ 5 => 'tops',
+ );
+ $export['service_links_node_types'] = $strongarm;
+
+ $strongarm = new stdClass();
+ $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+ $strongarm->api_version = 1;
+ $strongarm->name = 'service_links_node_view_modes';
+ $strongarm->value = array(
+ 'full' => 'full',
+ 'teaser' => 0,
+ 'rss' => 0,
+ 'token' => 0,
+ 'product_list' => 0,
+ );
+ $export['service_links_node_view_modes'] = $strongarm;
+
$strongarm = new stdClass();
$strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
$strongarm->api_version = 1;
@@ -56,25 +83,5 @@ function commerce_kickstart_social_strongarm() {
$strongarm->value = '0';
$export['service_links_visibility_for_node'] = $strongarm;
- $strongarm = new stdClass();
- $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
- $strongarm->api_version = 1;
- $strongarm->name = 'service_links_node_types';
- $strongarm->value = array_keys(commerce_product_reference_node_types());
- $export['service_links_node_types'] = $strongarm;
-
- $strongarm = new stdClass();
- $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
- $strongarm->api_version = 1;
- $strongarm->name = 'service_links_node_view_modes';
- $strongarm->value = array(
- 'full' => 'full',
- 'teaser' => 0,
- 'rss' => 0,
- 'token' => 0,
- 'product_list' => 0,
- );
- $export['service_links_node_view_modes'] = $strongarm;
-
return $export;
}
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_taxonomy/commerce_kickstart_taxonomy.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_taxonomy/commerce_kickstart_taxonomy.info
index e3255ccb..aeb79ee9 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_taxonomy/commerce_kickstart_taxonomy.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_taxonomy/commerce_kickstart_taxonomy.info
@@ -9,9 +9,8 @@ dependencies[] = views
; Views files
files[] = includes/views/handlers/commerce_kickstart_taxonomy_handler_field_text.inc
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_taxonomy/commerce_kickstart_taxonomy.module b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_taxonomy/commerce_kickstart_taxonomy.module
index 5dfd0bb7..e04982af 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_taxonomy/commerce_kickstart_taxonomy.module
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_taxonomy/commerce_kickstart_taxonomy.module
@@ -98,7 +98,7 @@ function commerce_kickstart_taxonomy_term_path($vid, $tid) {
}
else {
$path = $vocabulary->machine_name . '/' . $tid;
- if (variable_get(_taxonomy_menu_build_variable('display_decendants', $vid), FALSE)) {
+ if (variable_get(_taxonomy_menu_build_variable('display_descendants', $vid), FALSE)) {
// Use 'all' at the end of the path
if (variable_get(_taxonomy_menu_build_variable('end_all', $vid), FALSE)) {
$path .= '/all';
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_taxonomy/includes/views/commerce_kickstart_taxonomy.views_default.inc b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_taxonomy/includes/views/commerce_kickstart_taxonomy.views_default.inc
index d6fde2f6..67cdea45 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_taxonomy/includes/views/commerce_kickstart_taxonomy.views_default.inc
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_taxonomy/includes/views/commerce_kickstart_taxonomy.views_default.inc
@@ -199,6 +199,10 @@ function commerce_kickstart_taxonomy_views_default_views() {
* Add specific overrides for the no demo store.
*/
function commerce_kickstart_taxonomy_views_default_views_alter(&$views) {
+ if (!isset($views['collection_products'])) {
+ return;
+ }
+
$install_demo_store = variable_get('commerce_kickstart_demo_store', FALSE);
if (empty($install_demo_store)) {
$view = &$views['collection_products'];
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_user/commerce_kickstart_user.features.menu_custom.inc b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_user/commerce_kickstart_user.features.menu_custom.inc
index ad83b5b6..91cb5a00 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_user/commerce_kickstart_user.features.menu_custom.inc
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_user/commerce_kickstart_user.features.menu_custom.inc
@@ -20,6 +20,5 @@ function commerce_kickstart_user_menu_default_menu_custom() {
// Included for use with string extractors like potx.
t('Kickstart User menu');
-
return $menus;
}
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_user/commerce_kickstart_user.features.menu_links.inc b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_user/commerce_kickstart_user.features.menu_links.inc
index 8ab65d91..709e757b 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_user/commerce_kickstart_user.features.menu_links.inc
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_user/commerce_kickstart_user.features.menu_links.inc
@@ -10,7 +10,7 @@
function commerce_kickstart_user_menu_default_menu_links() {
$menu_links = array();
- // Exported menu link: menu-user-menu_create-account:user/register
+ // Exported menu link: menu-user-menu_create-account:user/register.
$menu_links['menu-user-menu_create-account:user/register'] = array(
'menu_name' => 'menu-user-menu',
'link_path' => 'user/register',
@@ -28,7 +28,7 @@ function commerce_kickstart_user_menu_default_menu_links() {
'weight' => 2,
'customized' => 1,
);
- // Exported menu link: menu-user-menu_log-in:user/login
+ // Exported menu link: menu-user-menu_log-in:user/login.
$menu_links['menu-user-menu_log-in:user/login'] = array(
'menu_name' => 'menu-user-menu',
'link_path' => 'user/login',
@@ -46,7 +46,7 @@ function commerce_kickstart_user_menu_default_menu_links() {
'weight' => 1,
'customized' => 1,
);
- // Exported menu link: menu-user-menu_log-out:user/logout
+ // Exported menu link: menu-user-menu_log-out:user/logout.
$menu_links['menu-user-menu_log-out:user/logout'] = array(
'menu_name' => 'menu-user-menu',
'link_path' => 'user/logout',
@@ -64,7 +64,7 @@ function commerce_kickstart_user_menu_default_menu_links() {
'weight' => 4,
'customized' => 1,
);
- // Exported menu link: menu-user-menu_my-account:user
+ // Exported menu link: menu-user-menu_my-account:user.
$menu_links['menu-user-menu_my-account:user'] = array(
'menu_name' => 'menu-user-menu',
'link_path' => 'user',
@@ -83,6 +83,7 @@ function commerce_kickstart_user_menu_default_menu_links() {
'weight' => 3,
'customized' => 1,
);
+
// Translatables
// Included for use with string extractors like potx.
t('Create account');
@@ -90,6 +91,5 @@ function commerce_kickstart_user_menu_default_menu_links() {
t('Log out');
t('My account');
-
return $menu_links;
}
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_user/commerce_kickstart_user.info b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_user/commerce_kickstart_user.info
index 09446aed..b5de2b22 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_user/commerce_kickstart_user.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/commerce_kickstart_user/commerce_kickstart_user.info
@@ -39,9 +39,8 @@ features[variable][] = user_email_verification
features[variable][] = user_pictures
features[variable][] = user_register
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/commerce_kickstart/toolbar_megamenu/toolbar_megamenu.info b/profiles/commerce_kickstart/modules/commerce_kickstart/toolbar_megamenu/toolbar_megamenu.info
index 45ce985b..186aa679 100644
--- a/profiles/commerce_kickstart/modules/commerce_kickstart/toolbar_megamenu/toolbar_megamenu.info
+++ b/profiles/commerce_kickstart/modules/commerce_kickstart/toolbar_megamenu/toolbar_megamenu.info
@@ -3,9 +3,8 @@ description = "Extension of Toolbar to support dropdown megamenus."
core = 7.x
dependencies[] = toolbar
-; Information added by Drupal.org packaging script on 2015-08-20
-version = "7.x-2.28"
+; Information added by Drupal.org packaging script on 2018-10-18
+version = "7.x-2.55"
core = "7.x"
project = "commerce_kickstart"
-datestamp = "1440110572"
-
+datestamp = "1539873597"
diff --git a/profiles/commerce_kickstart/modules/contrib/addressfield/addresses.txt b/profiles/commerce_kickstart/modules/contrib/addressfield/addresses.txt
index e64b8202..1f11bd89 100644
--- a/profiles/commerce_kickstart/modules/contrib/addressfield/addresses.txt
+++ b/profiles/commerce_kickstart/modules/contrib/addressfield/addresses.txt
@@ -1,298 +1,298 @@
-AT NULL Feldkirch NULL 6800 Pater Grimm Weg 20
-AU NULL Melbourne NULL
-AU NULL Sydney NULL
-AU 04 NULL NORMANBY NULL 4059 30 Normanby Terrace
-BD NULL Dhaka NULL 1205 23, Subal Das Road, Chowdhury Bazar, Lalbagh
-BD NULL Dhaka NULL 1207 R-1,H-19,Kallaynpur,Mirpur,Dhaka
-BD NULL Dhaka NULL 1207 World Bank Office Dhaka, Plot E 32, Agargaon, Sher-E-Bangla Nagar
-BD NULL Dhaka NULL 1209 House# 66B, Flat# B2 Zigatola
-BD NULL Dhaka NULL 1219 390 West Rampura Dhaka
-BD NULL Dhaka NULL 1230 Uttara
-BD 81 NULL Dhaka NULL 1000 Institute of Water and Flood Management
-BD 81 NULL Dhaka NULL 1203 84/a maniknagar
-BD 81 NULL Dhaka NULL 1205 Dhaka Bangladesh
-BD 81 NULL Dhaka NULL 1207 BetterStories Limited 17 West Panthopath
-BD 81 NULL Dhaka NULL 1216 Mirpur, Dhaka
-BD 81 NULL Dhaka NULL 1230 830, Prembagan, Dhakshin Khan
-BD 82 NULL khulna NULL 9203
-BD NULL NULL Dhaka NULL 1000 Institute of Water and Flood Management
-BD NULL NULL Dhaka NULL 1207 World Bank Office Dhaka, Plot E 32, Agargaon, Sher-E-Bangla Nagar
-BE NULL Brussels NULL
-BE NULL Watermael-Boitsfort NULL 1170 Avenue des Staphylins
-BH NULL Manama NULL 00973 Manama Bahrain Manama Bahrain
-BR NULL Porto Alegre NULL
-BR NULL Recife NULL
-BR RJ NULL Rio de Janeiro NULL
-BW NULL Francistown NULL NULL
-BW NULL NULL Francistown NULL NULL
-CA NULL Montreal NULL
-CA NULL Toronto NULL
-CA BC NULL Vancouver NULL
-CA ON NULL Kitchener NULL
-CA ON NULL wterloo NULL n2l3g1 200 University Avenue West
-CH NULL Geneva NULL 1202 15, chemin Louis-Dunant
-CH 25 NULL Zurich NULL 8098 UBS Optimus Foundation Augustinerhof 1
-DE NULL Berlin NULL
-DE 05 NULL Frankfurt am Main NULL 60386 Johanna-Tesch-Platz 7
-DK NULL Aarhus NULL
-ES NULL Bilbao NULL
-ET 44 NULL ADDIS ABABA NULL 11945 ADDIS ABABA,P.O.BOX 11945
-FI NULL Espoo NULL 02130 Mahlarinne 3B
-FI NULL Helsinki NULL 00580 Hermannin rantatie 2 A Hermannin rantatie 2 A
-FI NULL Tampere NULL 33101 Tampere Univerity of Technology
-FI 13 NULL Espoo NULL 02150 Aalto Venture Garage Betonimiehenkuja 3
-GB NULL Exeter NULL
-GB NULL London NULL
-GB NULL London NULL N4 2DP 2 Myddleton Ave
-GB NULL London NULL N7 0AH 104 St George’s Avenue
-GB NULL London NULL SE16 3UL 25 Blue Anchor Lane
-GB NULL London NULL SW18 5SP Flat 1 150 Merton road
-GB NULL London NULL W1T 4BQ 13 Fitzroy Street
-GB NULL Oxford NULL
-GB NULL Southampton NULL
-GB C3 NULL NULL cb244qg 32 market street swavesey
-GB E7 NULL London NULL SE3 7TP
-GB F3 NULL Wood Green NULL N22 5RU 6 Cedar House
-GB H1 NULL London NULL SE11 5JD 47-49 Durham Street
-GB H6 NULL London NULL SE8 4DD 8 Harton St Deptford
-GB K2 NULL Oxford NULL OX2 6QY 3 The Villas, Rutherway
-GH 05 NULL NSAWAM NULL NULL P.O.BOX 455
-GH NULL NULL Accra NULL NULL
-ID NULL Bandung NULL 40134 Jalan Sadang Hegar 1 No. 12 RT04 RW13 Sadang Serang
-ID NULL Bekasi NULL 17411 Jl.Binadharma 1 No.62. Jatiwaringin
-ID NULL Jakarta NULL
-ID NULL Jakarta NULL 12440 Jl. H. Niin 7 Lebak Bulus, Cilandak
-ID NULL Jakarta NULL 13330 Otista
-ID NULL Jakarta selatan NULL 12000 jl. rawa jati timur 6 no. 10
-ID NULL Jakarta Timur NULL Jl.Mulia No.15B Kel.Bidara Cina, Kec.Jatinegara, Jakarta Timur
-ID NULL Pematang Siantar NULL 51511 Jl. Durian I 30
-ID 04 NULL Bogor NULL 16165
-ID 04 NULL jakarta NULL otista
-ID 04 NULL Jakarta NULL 12520 Jl. Pertanian Raya III No.42 Jakarta Selatan Pasar Minggu
-ID 04 NULL Jakarta NULL 13330 Jakarta
-ID 04 NULL Jakarta NULL 13330 Jl Sensus IIC Bidaracina Jaktim
-ID 04 NULL Jakarta NULL 13330 Jl. Bonasut 2 no.22
-ID 04 NULL Jakarta NULL 13330 Otista 64c
-ID 04 NULL jakarta NULL 13330 Otista jaktim
-ID 04 NULL Jakarta Timur NULL 13330 Kebon Sayur I no. 1 RT 10/15
-ID 04 NULL Jakarta Timur NULL 13460 Jl. Pondok Kopi Blok G4/5 RT. 005/08 Jakarta Timur
-ID 04 NULL Jakarta Timur NULL 13810 Jl. Raya Pondok Gede Rt03 Rw08 no.35 , Lubang Buaya, Jakarta Timur Jl. Raya Pondok Gede Rt03 Rw08 no.35 , Lubang Buaya, Jakarta Timur
-ID 07 NULL Brebes NULL 54321 Jl Kersem Blok D14 Perum Taman Indo Kaligangsa Wetan Brebes
-ID 07 NULL Semarang NULL 50143 Puspowarno Tengah 2/2
-ID 08 NULL Lumajang NULL 67373 Desa Tumpeng Kecamatan Candipuro Lumajang
-ID 30 NULL Bandung NULL 55241 Jl Pelesiran No 55A/56
-ID 30 NULL Bekasi NULL 17510 bekasi West Java Indonesia
-ID 30 NULL Depok NULL 16245 Jalan juragan sinda 2 no 10
-ID 30 NULL Depok NULL 16424 Jalan Margonda RayaJalan Kober Gang Mawar
-ID 30 NULL Depok NULL 16424 Jl. Haji Yahya Nuih no.24, Pondok Cina
-ID 30 NULL Depok NULL 16425 Kukusan Kelurahan
-ID 30 NULL Depok NULL 16518 Jl. Salak No.1/C.88 Durenseribu Bojongsari
-ID 30 NULL Depok NULL 16952 Jl. Merak No.34 -36 Rt.004/014 Jl. Merak No. 34 -36 Rt. 004/014
-ID 36 NULL biak numfor NULL 98111 jl. s. mamberamo no 6782 biak numfor
-IL NULL Tel Aviv NULL
-IN NULL Bangalore NULL
-IN NULL India NULL
-IN NULL new delhi NULL 110003 55 lodi estate
-IN 07 NULL NEW DELHI NULL 110018 15/11 A 1ST FLOOR TILAK NAGAR
-IN 07 NULL New Delhu NULL 110075 B 54 Hilansh Apartments Plot No 1, Sector 10, Dwarka
-IN 10 NULL Gurgaon NULL D- 201 Ivy Apartments Sushant Lok 1 Gurgaon Haryana
-IN 13 NULL Trivandrum NULL 695010 TC 9/1615, SRMH Road, Sasthamangalam, Trivandrum
-IN 16 NULL Mumbai NULL 400020 Bharat Mahal, Flat#55 Marine Drive
-IN 16 NULL Mumbai NULL 400028 303,Shree Parvati Co-Op Housing Society, D.L.Vaidya Road,Dadar
-IN 16 NULL Pune NULL
-IN 16 NULL Pune NULL Infosys Campus Hinjewadi Phase 2
-IN 16 NULL Pune NULL 400705 #22 Iris Garden Gokhale Road
-IN 16 NULL PUNE NULL 411043
-IN 16 NULL Pune NULL 411051
-IN 16 NULL Pune NULL 411057 Infosys Ltd. Rajiv gandhi infostech park Hinjewadi phase 2
-IN 16 NULL Pune NULL 412108 Pune Maharatshtra
-IN 16 NULL Pune NULL 433011 502 utkarsh vihar golande state pune
-IN 19 NULL Bangalore NULL 560080 Indian Institute for Human Settlements IIHS Bangalore City Campus, Sadashivanagar,
-IN 19 NULL Bangalore NULL 560100 electronic city
-IN 19 NULL Bhalki NULL 585411 bhalki,bidar ,karnataka karnataka
-IN 24 NULL Jaipur NULL 302011 Institute of Health Management Research 1, Prabhu Dayal Marg
-IR 26 NULL Tehran NULL 1118844454 Baharestan sq. mostafa khomeini str., javahery Ave., no. 11,
-IT NULL Trento NULL
-JM 08 NULL Kingston NULL Kgn 7 MOna Campus UWI
-KE NULL Nairobi NULL
-KE 05 NULL Nairobi NULL 30300 212,kapsabet
-KH NULL NULL Phnom Penh NULL
-LR NULL Monrovia NULL 00000
-NG 11 NULL Abuja NULL 930001 17 Bechar street Wuse zone 2
-PE 15 NULL Lima NULL 18 Lima Lima
-PE 15 NULL Lima NULL Lima 18 123 Miraflores
-PE NULL NULL Lima NULL 03 Calle Granada 104
-PE NULL NULL Lima NULL 18 Lima Lima
-PH NULL Manila NULL Globe Telepark 111 Valero Street
-PH NULL Quezon Coty NULL 1109 86 Harvard Street, Cubao, Quezon City, Philippines 84 Harvard Street, Cubao, Quezon City,hilippines
-PH 20 NULL Silang NULL 4118 370 Bayungan Kaong Silang Cavite
-PH 57 NULL Kidapawan NULL 9400 Kidapawan City Kidapawan City
-PH 66 NULL zamboanga NULL 7000 29-tripplet rd san jose 29-tripplet rd san jose
-PH D9 NULL Pasig City NULL World Bank Office Manila, 20/F Taipan Place F. Ortigas Jr. Road, Ortigas Center
-PK NULL Lahore NULL 54000 17-R Model Town Lahore
-PK NULL Lahore NULL 54000 53- chamber lane road Lahore
-PK NULL Lahore NULL 54000 85 E block Model Town
-PK NULL Lahore NULL 54000 House no 227, street no 5, Imamia Colony Shahadra Lahore
-PK NULL LAHORE NULL 54000 room no.6 khalid bim waleed hall, near New Anarkali, LAHORE room no.6 khalid bim waleed hall, near New Anarkali, LAHORE
-PK NULL Lahore NULL pk097 LUMS, Lahore,
-PK NULL Sheikhupura NULL 03935 D.H.Q.Hospital Sheikhupura House number 08. Room no 109 Khalid bin waleed haal, punjab University lahore old campus.
-PK 02 NULL Quetta NULL 87000 Postal Address 87000, Kuchlak, Quetta, Balochistan. H#24 Peer Abul Khair road Quetta, Balochistan.
-PK 02 NULL Quetta NULL 87300 block no-1 falt no. 7 New Crime Branch Abbas Ali Road Cantt
-PK 02 NULL Quetta NULL 87300 Flat no. 3 Shafeen Centre Jinnah Town ,Near I.T university , Quetta
-PK 02 NULL Quetta NULL 87300 H-no. C-220 Zarghoonabad Phase-2 , Nawa Killi ,Quetta
-PK 04 NULL burewala NULL 60101 Fatima Fayyaz Hazrat Sakina hall girls hostel number 9 Punjab university Lahore Pakistan Sardar Wajid Azim Azeem abad Burewala dist Vehari Pakistan
-PK 04 NULL Faisalabad NULL 38000 P 101/1, Green Town, Millat Road, Faisalabad
-PK 04 NULL Islamabad NULL 44000 P.O Tarlai kalan chappar Islamabad
-PK 04 NULL lahore NULL
-PK 04 NULL Lahore NULL 54000
-PK 04 NULL lahore NULL 54000 Street No.63 House 36/A Al-madad Pak Colony Ravi Road, Lahore. Street No.63 House 36/A Al-madad Pak Colony Ravi Road, Lahore.
-PK 04 NULL Lahore NULL 54000 1149-1-D2 Green Town Lahore
-PK 04 NULL Lahore NULL 54000 124, street# 2, karim block Allama Iqbal Town lahore. 124, street# 2, karim block Allama Iqbal Town lahore.
-PK 04 NULL Lahore NULL 54000 150 A Qila Lachman Singh Ravi Road lahore
-PK 04 NULL Lahore NULL 54000 166/1L DHA Lahore
-PK 04 NULL Lahore NULL 54000 172 A2 Township Lahore
-PK 04 NULL Lahore NULL 54000 183,S/Block, Model Town, Lhr
-PK 04 NULL lahore NULL 54000 19- A block ,Eden Lane Villas Raiwind Road ,Lahore
-PK 04 NULL lahore NULL 54000 3-c kaliyar road opposite kids lyceum, rustam park near mor samnabad
-PK 04 NULL Lahore NULL 54000 31 Saeed Block, Canal Bank Scheme
-PK 04 NULL Lahore NULL 54000 31c DHA Lahore
-PK 04 NULL Lahore NULL 54000 387 E1 wapda town, Lahore
-PK 04 NULL Lahore NULL 54000 45-D dha eme sector multan road,lahore
-PK 04 NULL Lahore NULL 54000 5 Zafar Ali Road
-PK 04 NULL Lahore NULL 54000 54-R PGECHS
-PK 04 NULL lahore NULL 54000 566 E-1 johar town lahore 566 E-1 johar town lahore
-PK 04 NULL Lahore NULL 54000 82/1 Z Block, Phase 3 DHA
-PK 04 NULL Lahore NULL 54000 A-1 VRI Zarrar shaheed road lahore cantt A-1 VRI Zarrar shaheed road lahore cantt
-PK 04 NULL lahore NULL 54000 e5/39D street 6 zaman colony cavalry ground ext
-PK 04 NULL Lahore NULL 54000 Ho # 61, Block G3, Johar Town Lahore
-PK 04 NULL LAhore NULL 54000 House #19-A street #5 Usman nagr Ghaziabad Lahore
-PK 04 NULL lahore NULL 54000 House no 692 street no 67 sadar bazar
-PK 04 NULL Lahore NULL 54000 Khosa Law Chamber 1 Turner Road
-PK 04 NULL Lahore NULL 54000 Lahore,Pakistan Lahore,Pakistan
-PK 04 NULL Lahore NULL 54000 room no 69, khalid bin waleed hall, anarkali
-PK 04 NULL Lahore NULL 54000 Suite # 8, Al-Hafeez Suites, Gulberg II
-PK 04 NULL Lahore NULL 54085 199 Shadman 2
-PK 04 NULL Lahore NULL 54300 Mughalpura Lahore Pakistan
-PK 04 NULL Lahore NULL 54660 SD 69 falcon complex gulberg III lahore
-PK 04 NULL lahore NULL 54800 764-G4 johar town ,lahore
-PK 04 NULL Rawalpindi NULL 44000 House 522, F-Block Sattellite Town, Rawalpindi
-PK 04 NULL Rawalpindi NULL 46000 1950/c, Indusroad 2, Tariqabad, Rawalpindi Cantt
-PK 04 NULL Rawalpindi NULL 46000 House 54-E Lane 9 Sector 4, AECHS Chaklala Rawalpindi
-PK 04 NULL Rawalpindi NULL 46000 House B-1343, Sattellite town Rawalpindi
-PK 04 NULL Rawalpindi NULL 46000 House CB-299F, Street 1, Lane 4 Peshawar Road Rawalpindi
-PK 04 NULL Rawalpindi NULL 46300 House No 1518 Umer Block phase 8 BehriaTown
-PK 04 NULL sialkot NULL 51310 The National Model School, Ismaiealabad, Pacca Garah Sialkot
-PK 08 NULL Islamabad NULL CIomsats Institute of Information Technology Islamabad
-PK 08 NULL Islamabad NULL 38700 COMSATS tarlai boys hostel Islamabad. COMSATS tarlai boys hostel Islamabad (Room 30)
-PK 08 NULL Islamabad NULL 44000
-PK 08 NULL Islamabad NULL 44000 House # 256, Street # 9, Shahzad Town, Islamabad.
-PK 08 NULL Islamabad NULL 44000 Islamabad , Comsats University Islamabd ,Pakistan
-PK 08 NULL Islamabad NULL 44000 World Bank Building Sector G 5
-PK 08 NULL lahore NULL 54000 3c zafar ali road gulburg 5 3c zafar ali road gulburg 5
-PK 08 NULL lahore NULL 54000 49-a bilal park, chaburgy 49-a bilal park, chaburgy
-PK NULL NULL Lahore NULL 54000
-PK NULL NULL Lahore NULL 54000 85 E block Model Town
-SN 01 NULL NULL ouakam cité comico en face 217
-SN 01 NULL Dakar NULL
-SN 01 NULL Dakar NULL IDEV-ic Patte d'oie Builder's Villa B11
-SN 01 NULL Dakar NULL liberte 6/ dakar
-SN 01 NULL Dakar NULL ngor
-SN 01 NULL Dakar NULL 4027 ZAC Mbao Cité Fadia
-SN NULL NULL Dakar NULL IDEV-ic Patte d'oie Builder's Villa B11
-TZ NULL Dar es Salaam NULL NULL
-TZ NULL Dar es salaam NULL NULL 76021 Dar es salaam 1507 Morogoro
-TZ NULL Dar es salaam NULL NULL dar es salaam nassoro.ahmedy@yahoo.com
-TZ NULL DAR ES SALAAM NULL NULL dar es salaam UDSM
-TZ NULL Dar es salaam NULL NULL NA
-TZ NULL DAR ES SALAAM NULL NULL P O BOX 23409
-TZ NULL dar es salaam NULL NULL p. o. box 104994
-TZ NULL Dar es Salaam NULL NULL P.o. BOX 71415 Dar es Salaam
-TZ NULL Dar es Salaam NULL NULL P.O.BOx 66675 DSM
-TZ NULL Dar es salaam NULL NULL Tz Tz
-TZ NULL dsm NULL NULL
-TZ 02 NULL Bagamoyo NULL NULL PO.Box 393
-TZ 02 NULL Dar es salaam NULL NULL 22548
-TZ 03 NULL Dar-es-salaam NULL NULL Dodoma Municipal Kimara, Dar-es-salaa,
-TZ 23 NULL Dar es Salaam NULL NULL
-TZ 23 NULL dar es salaam NULL NULL 35074
-TZ 23 NULL dar es salaam NULL NULL 67389
-TZ 23 NULL Dar es Salaam NULL NULL COSTECH, Dar es Salaam, Tanzania
-TZ 23 NULL Dar es salaam NULL NULL na
-TZ 23 NULL dar es salaam NULL NULL p o box 60164
-TZ 23 NULL dar es salaam NULL NULL P. O. Box 77588
-TZ 23 NULL dar es salaam NULL NULL P.O BOX 78144
-TZ 23 NULL Dar es Salaam NULL NULL P.O.BOX 78373
-TZ 23 NULL Dar es salaam NULL NULL UDSM Dar es Salaam
-TZ 23 NULL Dar es salaam NULL NULL udsm udsm
-TZ 23 NULL Temeke NULL NULL P.O. Box 50127
-TZ NULL NULL Dar es Salaam NULL NULL
-TZ NULL NULL Dar es Salaam NULL NULL Kigoma
-TZ NULL NULL Dar es Salaam NULL NULL Mwanza
-UG NULL Kampala NULL NULL
-UG NULL Kampala NULL NULL Kampala Uganda East Africa
-US NULL London NULL SE1 8RT Capital Tower 91 Waterloo Road
-US CA NULL Los Angeles NULL
-US CA NULL Pleasanton NULL 94588 3412 Pickens Lane
-US CA NULL Sacramento NULL
-US CA NULL San Francisco NULL
-US CA NULL seattle NULL 98113 1234 1st st
-US CO NULL Denver NULL 80235 6666 West Quincy Ave
-US CT NULL Greenwich NULL 06830 140 Milbank
-US CT NULL Hartford NULL 06106 Center for Urban and Global Studies at Trinity College, 70 Vernon Street
-US DC NULL Washington NULL
-US DC NULL Washington NULL 20007 World Bank Headquarters 1818 H Street NW
-US DC NULL Washington NULL 20010
-US DC NULL Washington NULL 20036
-US DC NULL Washington NULL 20405 1889 F St NW
-US DC NULL Washington NULL 20433
-US DC NULL Washington NULL 20433 1818 H Street NW
-US DC NULL Washington NULL 20433 1818H St
-US DC NULL Washington NULL 20433 1818 H Street NW
-US DC NULL Washington DC NULL 20005 1424, K Street, NW Suite 600
-US DC NULL Washington DC NULL 20010 1818 H Street, NW
-US DC NULL Washington, DC NULL 20003 1818 H Street NW
-US DE NULL Virgin Islands|Charlotte Amalie,Cruz Bay,Christiansted NULL Morocco|Tafraout,Rabat,Tangier,Tetouan,Casablanca,Marrakesh,Fez,Oujda,Meknes,Agadir United Arab Emirates|Garhoud,Dubai,Bur Dubai,Ras al Khaymah,Abu Dhabi,Ajman,Al Fujayrah,Sharjah
-US FL NULL Falmouth NULL Falmouth Falmouth
-US FL NULL Lilongwe NULL Lilongwe Lilongwe
-US GA NULL Atlanta NULL
-US GU NULL Herndon NULL 15642 Ht USA
-US GU NULL Miami NULL Miami Miami
-US MD NULL Gaithersburg NULL 20877 554 N Frederick Avenue Suite 216
-US MD NULL Potomac NULL 20854 14 Sandalfoot Court
-US MD NULL Silver Spring NULL 20901 9202 Whitney St.
-US MI NULL Traverse City NULL 49685 PO Box 792
-US ND NULL Pirassununga NULL Pirassununga Pirassununga
-US NJ NULL Princeton NULL
-US NY NULL Brooklyn NULL 11206-1980 25 Montrose Ave. Apt 304
-US NY NULL Brooklyn NULL 11225 975 washington ave 2d
-US NY NULL Brooklyn NULL 11217 150 4TH AVE APT 9E
-US NY NULL New York NULL
-US NY NULL New York NULL 10013 148 Lafayette St. PH
-US NY NULL New York NULL 10017 UNICEF 3 UN Plaza
-US NY NULL New York NULL 10019 25 Columbus Circle Suite 52E
-US NY NULL New York NULL 10024 65 West 85th Street 3A
-US NY NULL New York NULL 10027 606 W. 116th Street #22
-US NY NULL New York NULL 10037
-US NY NULL Rochester NULL
-US NY NULL Scarsdale NULL 10583-1423 54 Walworth Avenue
-US OR NULL Portland NULL
-US PA NULL Philadelphia NULL
-US PA NULL Philadelphia NULL
-US PR NULL Colonel Hill NULL Colonel Hill Colonel Hill
-US SD NULL Banjul NULL Banjul Banjul
-US SD NULL London NULL London London
-US TX NULL Aledo NULL 76008 1588 Hunterglenn Dr
-US TX NULL Keller NULL 76248 810 Placid View Ct.
-US WA NULL Seattle NULL
-ZA NULL Cape Town NULL
-ZA NULL Cape Town NULL 7945 Alexander Road Muizenberg
-ZA NULL Pretoria NULL
-ZA 11 NULL Cape Town NULL
-ZA 11 NULL Cape Town NULL 7435 PostNet Suite #57, Private Bag X18 Milnerton
-ZA 11 NULL Cape town NULL 7508 24 Solyet Court, Lansdowne Road Claremont
-ZA 11 NULL Cape Town NULL 7701
-ZA 11 NULL Cape Town NULL 7785 10 Nyamakazi Road Luzuko Park Phillipi East
-ZA 11 NULL Cape Town NULL 7915 66 Albert Rd
-ZA 11 NULL Cape Town NULL 8001 210 Long Street
-ZM NULL Lusaka NULL
-ZM 09 NULL LUSAKA NULL 10101 P.O. BOX FW 174
+AT NULL Feldkirch NULL 6800 Pater Grimm Weg 20 NULL
+AU NULL Melbourne NULL NULL
+AU NULL Sydney NULL NULL
+AU 4 NULL NORMANBY NULL 4059 30 Normanby Terrace NULL
+BD NULL Dhaka NULL 1205 23, Subal Das Road, Chowdhury Bazar, Lalbagh NULL
+BD NULL Dhaka NULL 1207 R-1,H-19,Kallaynpur,Mirpur,Dhaka NULL
+BD NULL Dhaka NULL 1207 World Bank Office Dhaka, Plot E 32, Agargaon, Sher-E-Bangla Nagar NULL
+BD NULL Dhaka NULL 1209 House# 66B, Flat# B2 Zigatola NULL
+BD NULL Dhaka NULL 1219 390 West Rampura Dhaka NULL
+BD NULL Dhaka NULL 1230 Uttara NULL
+BD 81 NULL Dhaka NULL 1000 Institute of Water and Flood Management NULL
+BD 81 NULL Dhaka NULL 1203 84/a maniknagar NULL
+BD 81 NULL Dhaka NULL 1205 Dhaka Bangladesh NULL
+BD 81 NULL Dhaka NULL 1207 BetterStories Limited 17 West Panthopath NULL
+BD 81 NULL Dhaka NULL 1216 Mirpur, Dhaka NULL
+BD 81 NULL Dhaka NULL 1230 830, Prembagan, Dhakshin Khan NULL
+BD 82 NULL khulna NULL 9203 NULL
+BD NULL NULL Dhaka NULL 1000 Institute of Water and Flood Management NULL
+BD NULL NULL Dhaka NULL 1207 World Bank Office Dhaka, Plot E 32, Agargaon, Sher-E-Bangla Nagar NULL
+BE NULL Brussels NULL NULL
+BE NULL Watermael-Boitsfort NULL 1170 Avenue des Staphylins NULL
+BH NULL Manama NULL 973 Manama Bahrain Manama Bahrain NULL
+BR NULL Porto Alegre NULL NULL
+BR NULL Recife NULL NULL
+BR RJ NULL Rio de Janeiro NULL NULL
+BW NULL Francistown NULL NULL NULL
+BW NULL NULL Francistown NULL NULL NULL
+CA NULL Montreal NULL NULL
+CA NULL Toronto NULL NULL
+CA BC NULL Vancouver NULL NULL
+CA ON NULL Kitchener NULL NULL
+CA ON NULL wterloo NULL n2l3g1 200 University Avenue West NULL
+CH NULL Geneva NULL 1202 15, chemin Louis-Dunant NULL
+CH 25 NULL Zurich NULL 8098 UBS Optimus Foundation Augustinerhof 1 NULL
+DE NULL Berlin NULL NULL
+DE 5 NULL Frankfurt am Main NULL 60386 Johanna-Tesch-Platz 7 NULL
+DK NULL Aarhus NULL NULL
+ES NULL Bilbao NULL NULL
+ET 44 NULL ADDIS ABABA NULL 11945 ADDIS ABABA,P.O.BOX 11945 NULL
+FI NULL Espoo NULL 2130 Mahlarinne 3B NULL
+FI NULL Helsinki NULL 580 Hermannin rantatie 2 A Hermannin rantatie 2 A NULL
+FI NULL Tampere NULL 33101 Tampere University of Technology NULL
+FI 13 NULL Espoo NULL 2150 Aalto Venture Garage Betonimiehenkuja 3 NULL
+GB NULL Exeter NULL NULL
+GB NULL London NULL NULL
+GB NULL London NULL N4 2DP 2 Myddleton Ave NULL
+GB NULL London NULL N7 0AH 104 St George’s Avenue NULL
+GB NULL London NULL SE16 3UL 25 Blue Anchor Lane NULL
+GB NULL London NULL SW18 5SP Flat 1 150 Merton road NULL
+GB NULL London NULL W1T 4BQ 13 Fitzroy Street NULL
+GB NULL Oxford NULL NULL
+GB NULL Southampton NULL NULL
+GB C3 NULL NULL cb244qg 32 market street swavesey NULL
+GB E7 NULL London NULL SE3 7TP NULL
+GB F3 NULL Wood Green NULL N22 5RU 6 Cedar House NULL
+GB H1 NULL London NULL SE11 5JD 47-49 Durham Street NULL
+GB H6 NULL London NULL SE8 4DD 8 Harton St Deptford NULL
+GB K2 NULL Oxford NULL OX2 6QY 3 The Villas, Rutherway NULL
+GH 5 NULL NSAWAM NULL NULL P.O.BOX 455 NULL
+GH NULL NULL Accra NULL NULL NULL
+ID NULL Bandung NULL 40134 Jalan Sadang Hegar 1 No. 12 RT04 RW13 Sadang Serang NULL
+ID NULL Bekasi NULL 17411 Jl.Binadharma 1 No.62. Jatiwaringin NULL
+ID NULL Jakarta NULL NULL
+ID NULL Jakarta NULL 12440 Jl. H. Niin 7 Lebak Bulus, Cilandak NULL
+ID NULL Jakarta NULL 13330 Otista NULL
+ID NULL Jakarta selatan NULL 12000 jl. rawa jati timur 6 no. 10 NULL
+ID NULL Jakarta Timur NULL Jl.Mulia No.15B Kel.Bidara Cina, Kec.Jatinegara, Jakarta Timur NULL
+ID NULL Pematang Siantar NULL 51511 Jl. Durian I 30 NULL
+ID 4 NULL Bogor NULL 16165 NULL
+ID 4 NULL jakarta NULL otista NULL
+ID 4 NULL Jakarta NULL 12520 Jl. Pertanian Raya III No.42 Jakarta Selatan Pasar Minggu NULL
+ID 4 NULL Jakarta NULL 13330 Jakarta NULL
+ID 4 NULL Jakarta NULL 13330 Jl Sensus IIC Bidaracina Jaktim NULL
+ID 4 NULL Jakarta NULL 13330 Jl. Bonasut 2 no.22 NULL
+ID 4 NULL Jakarta NULL 13330 Otista 64c NULL
+ID 4 NULL jakarta NULL 13330 Otista jaktim NULL
+ID 4 NULL Jakarta Timur NULL 13330 Kebon Sayur I no. 1 RT 10/15 NULL
+ID 4 NULL Jakarta Timur NULL 13460 Jl. Pondok Kopi Blok G4/5 RT. 005/08 Jakarta Timur NULL
+ID 4 NULL Jakarta Timur NULL 13810 Jl. Raya Pondok Gede Rt03 Rw08 no.35 , Lubang Buaya, Jakarta Timur Jl. Raya Pondok Gede Rt03 Rw08 no.35 , Lubang Buaya, Jakarta Timur NULL
+ID 7 NULL Brebes NULL 54321 Jl Kersem Blok D14 Perum Taman Indo Kaligangsa Wetan Brebes NULL
+ID 7 NULL Semarang NULL 50143 Puspowarno Tengah 2/2 NULL
+ID 8 NULL Lumajang NULL 67373 Desa Tumpeng Kecamatan Candipuro Lumajang NULL
+ID 30 NULL Bandung NULL 55241 Jl Pelesiran No 55A/56 NULL
+ID 30 NULL Bekasi NULL 17510 bekasi West Java Indonesia NULL
+ID 30 NULL Depok NULL 16245 Jalan juragan sinda 2 no 10 NULL
+ID 30 NULL Depok NULL 16424 Jalan Margonda RayaJalan Kober Gang Mawar NULL
+ID 30 NULL Depok NULL 16424 Jl. Haji Yahya Nuih no.24, Pondok Cina NULL
+ID 30 NULL Depok NULL 16425 Kukusan Kelurahan NULL
+ID 30 NULL Depok NULL 16518 Jl. Salak No.1/C.88 Durenseribu Bojongsari NULL
+ID 30 NULL Depok NULL 16952 Jl. Merak No.34 -36 Rt.004/014 Jl. Merak No. 34 -36 Rt. 004/014 NULL
+ID 36 NULL biak numfor NULL 98111 jl. s. mamberamo no 6782 biak numfor NULL
+IL NULL Tel Aviv NULL NULL
+IN NULL Bangalore NULL NULL
+IN NULL India NULL NULL
+IN NULL new delhi NULL 110003 55 lodi estate NULL
+IN 7 NULL NEW DELHI NULL 110018 15/11 A 1ST FLOOR TILAK NAGAR NULL
+IN 7 NULL New Delhu NULL 110075 B 54 Hilansh Apartments Plot No 1, Sector 10, Dwarka NULL
+IN 10 NULL Gurgaon NULL D- 201 Ivy Apartments Sushant Lok 1 Gurgaon Haryana NULL
+IN 13 NULL Trivandrum NULL 695010 TC 9/1615, SRMH Road, Sasthamangalam, Trivandrum NULL
+IN 16 NULL Mumbai NULL 400020 Bharat Mahal, Flat#55 Marine Drive NULL
+IN 16 NULL Mumbai NULL 400028 303,Shree Parvati Co-Op Housing Society, D.L.Vaidya Road,Dadar NULL
+IN 16 NULL Pune NULL NULL
+IN 16 NULL Pune NULL Infosys Campus Hinjewadi Phase 2 NULL
+IN 16 NULL Pune NULL 400705 #22 Iris Garden Gokhale Road NULL
+IN 16 NULL PUNE NULL 411043 NULL
+IN 16 NULL Pune NULL 411051 NULL
+IN 16 NULL Pune NULL 411057 Infosys Ltd. Rajiv gandhi infostech park Hinjewadi phase 2 NULL
+IN 16 NULL Pune NULL 412108 Pune Maharatshtra NULL
+IN 16 NULL Pune NULL 433011 502 utkarsh vihar golande state pune NULL
+IN 19 NULL Bangalore NULL 560080 Indian Institute for Human Settlements IIHS Bangalore City Campus, Sadashivanagar, NULL
+IN 19 NULL Bangalore NULL 560100 electronic city NULL
+IN 19 NULL Bhalki NULL 585411 bhalki,bidar ,karnataka karnataka NULL
+IN 24 NULL Jaipur NULL 302011 Institute of Health Management Research 1, Prabhu Dayal Marg NULL
+IR 26 NULL Tehran NULL 1118844454 Baharestan sq. mostafa khomeini str., javahery Ave., no. 11, NULL
+IT NULL Trento NULL NULL
+JM 8 NULL Kingston NULL Kgn 7 MOna Campus UWI NULL
+KE NULL Nairobi NULL NULL
+KE 5 NULL Nairobi NULL 30300 212,kapsabet NULL
+KH NULL NULL Phnom Penh NULL NULL
+LR NULL Monrovia NULL 0 NULL
+NG 11 NULL Abuja NULL 930001 17 Bechar street Wuse zone 2 NULL
+PE 15 NULL Lima NULL 18 Lima Lima NULL
+PE 15 NULL Lima NULL Lima 18 123 Miraflores NULL
+PE NULL NULL Lima NULL 3 Calle Granada 104 NULL
+PE NULL NULL Lima NULL 18 Lima Lima NULL
+PH NULL Manila NULL Globe Telepark 111 Valero Street NULL
+PH NULL Quezon Coty NULL 1109 86 Harvard Street, Cubao, Quezon City, Philippines 84 Harvard Street, Cubao, Quezon City,hilippines NULL
+PH 20 NULL Silang NULL 4118 370 Bayungan Kaong Silang Cavite NULL
+PH 57 NULL Kidapawan NULL 9400 Kidapawan City Kidapawan City NULL
+PH 66 NULL zamboanga NULL 7000 29-tripplet rd san jose 29-tripplet rd san jose NULL
+PH D9 NULL Pasig City NULL World Bank Office Manila, 20/F Taipan Place F. Ortigas Jr. Road, Ortigas Center NULL
+PK NULL Lahore NULL 54000 17-R Model Town Lahore NULL
+PK NULL Lahore NULL 54000 53- chamber lane road Lahore NULL
+PK NULL Lahore NULL 54000 85 E block Model Town NULL
+PK NULL Lahore NULL 54000 House no 227, street no 5, Imamia Colony Shahadra Lahore NULL
+PK NULL LAHORE NULL 54000 room no.6 khalid bim waleed hall, near New Anarkali, LAHORE room no.6 khalid bim waleed hall, near New Anarkali, LAHORE NULL
+PK NULL Lahore NULL pk097 LUMS, Lahore, NULL
+PK NULL Sheikhupura NULL 3935 D.H.Q.Hospital Sheikhupura House number 08. Room no 109 Khalid bin waleed haal, punjab University lahore old campus. NULL
+PK 2 NULL Quetta NULL 87000 Postal Address 87000, Kuchlak, Quetta, Balochistan. H#24 Peer Abul Khair road Quetta, Balochistan. NULL
+PK 2 NULL Quetta NULL 87300 block no-1 falt no. 7 New Crime Branch Abbas Ali Road Cantt NULL
+PK 2 NULL Quetta NULL 87300 Flat no. 3 Shafeen Centre Jinnah Town ,Near I.T university , Quetta NULL
+PK 2 NULL Quetta NULL 87300 H-no. C-220 Zarghoonabad Phase-2 , Nawa Killi ,Quetta NULL
+PK 4 NULL burewala NULL 60101 Fatima Fayyaz Hazrat Sakina hall girls hostel number 9 Punjab university Lahore Pakistan Sardar Wajid Azim Azeem abad Burewala dist Vehari Pakistan NULL
+PK 4 NULL Faisalabad NULL 38000 P 101/1, Green Town, Millat Road, Faisalabad NULL
+PK 4 NULL Islamabad NULL 44000 P.O Tarlai kalan chappar Islamabad NULL
+PK 4 NULL lahore NULL NULL
+PK 4 NULL Lahore NULL 54000 NULL
+PK 4 NULL lahore NULL 54000 Street No.63 House 36/A Al-madad Pak Colony Ravi Road, Lahore. Street No.63 House 36/A Al-madad Pak Colony Ravi Road, Lahore. NULL
+PK 4 NULL Lahore NULL 54000 1149-1-D2 Green Town Lahore NULL
+PK 4 NULL Lahore NULL 54000 124, street# 2, karim block Allama Iqbal Town lahore. 124, street# 2, karim block Allama Iqbal Town lahore. NULL
+PK 4 NULL Lahore NULL 54000 150 A Qila Lachman Singh Ravi Road lahore NULL
+PK 4 NULL Lahore NULL 54000 166/1L DHA Lahore NULL
+PK 4 NULL Lahore NULL 54000 172 A2 Township Lahore NULL
+PK 4 NULL Lahore NULL 54000 183,S/Block, Model Town, Lhr NULL
+PK 4 NULL lahore NULL 54000 19- A block ,Eden Lane Villas Raiwind Road ,Lahore NULL
+PK 4 NULL lahore NULL 54000 3-c kaliyar road opposite kids lyceum, rustam park near mor samnabad NULL
+PK 4 NULL Lahore NULL 54000 31 Saeed Block, Canal Bank Scheme NULL
+PK 4 NULL Lahore NULL 54000 31c DHA Lahore NULL
+PK 4 NULL Lahore NULL 54000 387 E1 wapda town, Lahore NULL
+PK 4 NULL Lahore NULL 54000 45-D dha eme sector multan road,lahore NULL
+PK 4 NULL Lahore NULL 54000 5 Zafar Ali Road NULL
+PK 4 NULL Lahore NULL 54000 54-R PGECHS NULL
+PK 4 NULL lahore NULL 54000 566 E-1 johar town lahore 566 E-1 johar town lahore NULL
+PK 4 NULL Lahore NULL 54000 82/1 Z Block, Phase 3 DHA NULL
+PK 4 NULL Lahore NULL 54000 A-1 VRI Zarrar shaheed road lahore cantt A-1 VRI Zarrar shaheed road lahore cantt NULL
+PK 4 NULL lahore NULL 54000 e5/39D street 6 zaman colony cavalry ground ext NULL
+PK 4 NULL Lahore NULL 54000 Ho # 61, Block G3, Johar Town Lahore NULL
+PK 4 NULL LAhore NULL 54000 House #19-A street #5 Usman nagr Ghaziabad Lahore NULL
+PK 4 NULL lahore NULL 54000 House no 692 street no 67 sadar bazar NULL
+PK 4 NULL Lahore NULL 54000 Khosa Law Chamber 1 Turner Road NULL
+PK 4 NULL Lahore NULL 54000 Lahore,Pakistan Lahore,Pakistan NULL
+PK 4 NULL Lahore NULL 54000 room no 69, khalid bin waleed hall, anarkali NULL
+PK 4 NULL Lahore NULL 54000 Suite # 8, Al-Hafeez Suites, Gulberg II NULL
+PK 4 NULL Lahore NULL 54085 199 Shadman 2 NULL
+PK 4 NULL Lahore NULL 54300 Mughalpura Lahore Pakistan NULL
+PK 4 NULL Lahore NULL 54660 SD 69 falcon complex gulberg III lahore NULL
+PK 4 NULL lahore NULL 54800 764-G4 johar town ,lahore NULL
+PK 4 NULL Rawalpindi NULL 44000 House 522, F-Block Sattellite Town, Rawalpindi NULL
+PK 4 NULL Rawalpindi NULL 46000 1950/c, Indusroad 2, Tariqabad, Rawalpindi Cantt NULL
+PK 4 NULL Rawalpindi NULL 46000 House 54-E Lane 9 Sector 4, AECHS Chaklala Rawalpindi NULL
+PK 4 NULL Rawalpindi NULL 46000 House B-1343, Sattellite town Rawalpindi NULL
+PK 4 NULL Rawalpindi NULL 46000 House CB-299F, Street 1, Lane 4 Peshawar Road Rawalpindi NULL
+PK 4 NULL Rawalpindi NULL 46300 House No 1518 Umer Block phase 8 BehriaTown NULL
+PK 4 NULL sialkot NULL 51310 The National Model School, Ismaiealabad, Pacca Garah Sialkot NULL
+PK 8 NULL Islamabad NULL CIomsats Institute of Information Technology Islamabad NULL
+PK 8 NULL Islamabad NULL 38700 COMSATS tarlai boys hostel Islamabad. COMSATS tarlai boys hostel Islamabad (Room 30) NULL
+PK 8 NULL Islamabad NULL 44000 NULL
+PK 8 NULL Islamabad NULL 44000 House # 256, Street # 9, Shahzad Town, Islamabad. NULL
+PK 8 NULL Islamabad NULL 44000 Islamabad , Comsats University Islamabd ,Pakistan NULL
+PK 8 NULL Islamabad NULL 44000 World Bank Building Sector G 5 NULL
+PK 8 NULL lahore NULL 54000 3c zafar ali road gulburg 5 3c zafar ali road gulburg 5 NULL
+PK 8 NULL lahore NULL 54000 49-a bilal park, chaburgy 49-a bilal park, chaburgy NULL
+PK NULL NULL Lahore NULL 54000 NULL
+PK NULL NULL Lahore NULL 54000 85 E block Model Town NULL
+SN 1 NULL NULL ouakam cité comico en face 217 NULL
+SN 1 NULL Dakar NULL NULL
+SN 1 NULL Dakar NULL IDEV-ic Patte d'oie Builder's Villa B11 NULL
+SN 1 NULL Dakar NULL liberte 6/ dakar NULL
+SN 1 NULL Dakar NULL ngor NULL
+SN 1 NULL Dakar NULL 4027 ZAC Mbao Cité Fadia NULL
+SN NULL NULL Dakar NULL IDEV-ic Patte d'oie Builder's Villa B11 NULL
+TZ NULL Dar es Salaam NULL NULL NULL
+TZ NULL Dar es salaam NULL NULL 76021 Dar es salaam 1507 Morogoro NULL
+TZ NULL Dar es salaam NULL NULL dar es salaam nassoro.ahmedy@yahoo.com NULL
+TZ NULL DAR ES SALAAM NULL NULL dar es salaam UDSM NULL
+TZ NULL Dar es salaam NULL NULL NA NULL
+TZ NULL DAR ES SALAAM NULL NULL P O BOX 23409 NULL
+TZ NULL dar es salaam NULL NULL p. o. box 104994 NULL
+TZ NULL Dar es Salaam NULL NULL P.o. BOX 71415 Dar es Salaam NULL
+TZ NULL Dar es Salaam NULL NULL P.O.BOx 66675 DSM NULL
+TZ NULL Dar es salaam NULL NULL Tz Tz NULL
+TZ NULL dsm NULL NULL NULL
+TZ 2 NULL Bagamoyo NULL NULL PO.Box 393 NULL
+TZ 2 NULL Dar es salaam NULL NULL 22548 NULL
+TZ 3 NULL Dar-es-salaam NULL NULL Dodoma Municipal Kimara, Dar-es-salaa, NULL
+TZ 23 NULL Dar es Salaam NULL NULL NULL
+TZ 23 NULL dar es salaam NULL NULL 35074 NULL
+TZ 23 NULL dar es salaam NULL NULL 67389 NULL
+TZ 23 NULL Dar es Salaam NULL NULL COSTECH, Dar es Salaam, Tanzania NULL
+TZ 23 NULL Dar es salaam NULL NULL na NULL
+TZ 23 NULL dar es salaam NULL NULL p o box 60164 NULL
+TZ 23 NULL dar es salaam NULL NULL P. O. Box 77588 NULL
+TZ 23 NULL dar es salaam NULL NULL P.O BOX 78144 NULL
+TZ 23 NULL Dar es Salaam NULL NULL P.O.BOX 78373 NULL
+TZ 23 NULL Dar es salaam NULL NULL UDSM Dar es Salaam NULL
+TZ 23 NULL Dar es salaam NULL NULL udsm udsm NULL
+TZ 23 NULL Temeke NULL NULL P.O. Box 50127 NULL
+TZ NULL NULL Dar es Salaam NULL NULL NULL
+TZ NULL NULL Dar es Salaam NULL NULL Kigoma NULL
+TZ NULL NULL Dar es Salaam NULL NULL Mwanza NULL
+UG NULL Kampala NULL NULL NULL
+UG NULL Kampala NULL NULL Kampala Uganda East Africa NULL
+US NULL London NULL SE1 8RT Capital Tower 91 Waterloo Road NULL
+US CA NULL Los Angeles NULL NULL
+US CA NULL Pleasanton NULL 94588 3412 Pickens Lane NULL
+US CA NULL Sacramento NULL NULL
+US CA NULL San Francisco NULL NULL
+US CA NULL seattle NULL 98113 1234 1st st NULL
+US CO NULL Denver NULL 80235 6666 West Quincy Ave NULL
+US CT NULL Greenwich NULL 6830 140 Milbank NULL
+US CT NULL Hartford NULL 6106 Center for Urban and Global Studies at Trinity College, 70 Vernon Street NULL
+US DC NULL Washington NULL NULL
+US DC NULL Washington NULL 20007 World Bank Headquarters 1818 H Street NW NULL
+US DC NULL Washington NULL 20010 NULL
+US DC NULL Washington NULL 20036 NULL
+US DC NULL Washington NULL 20405 1889 F St NW NULL
+US DC NULL Washington NULL 20433 NULL
+US DC NULL Washington NULL 20433 1818 H Street NW NULL
+US DC NULL Washington NULL 20433 1818H St NULL
+US DC NULL Washington NULL 20433 1818 H Street NW NULL
+US DC NULL Washington DC NULL 20005 1424, K Street, NW Suite 600 NULL
+US DC NULL Washington DC NULL 20010 1818 H Street, NW NULL
+US DC NULL Washington, DC NULL 20003 1818 H Street NW NULL
+US DE NULL Virgin Islands|Charlotte Amalie,Cruz Bay,Christiansted NULL Morocco|Tafraout,Rabat,Tangier,Tetouan,Casablanca,Marrakesh,Fez,Oujda,Meknes,Agadir United Arab Emirates|Garhoud,Dubai,Bur Dubai,Ras al Khaymah,Abu Dhabi,Ajman,Al Fujayrah,Sharjah NULL
+US FL NULL Falmouth NULL Falmouth Falmouth NULL
+US FL NULL Lilongwe NULL Lilongwe Lilongwe NULL
+US GA NULL Atlanta NULL NULL
+US GU NULL Herndon NULL 15642 Ht USA NULL
+US GU NULL Miami NULL Miami Miami NULL
+US MD NULL Gaithersburg NULL 20877 554 N Frederick Avenue Suite 216 NULL
+US MD NULL Potomac NULL 20854 14 Sandalfoot Court NULL
+US MD NULL Silver Spring NULL 20901 9202 Whitney St. NULL
+US MI NULL Traverse City NULL 49685 PO Box 792 NULL
+US ND NULL Pirassununga NULL Pirassununga Pirassununga NULL
+US NJ NULL Princeton NULL NULL
+US NY NULL Brooklyn NULL 11206-1980 25 Montrose Ave. Apt 304 NULL
+US NY NULL Brooklyn NULL 11225 975 washington ave 2d NULL
+US NY NULL Brooklyn NULL 11217 150 4TH AVE APT 9E NULL
+US NY NULL New York NULL NULL
+US NY NULL New York NULL 10013 148 Lafayette St. PH NULL
+US NY NULL New York NULL 10017 UNICEF 3 UN Plaza NULL
+US NY NULL New York NULL 10019 25 Columbus Circle Suite 52E NULL
+US NY NULL New York NULL 10024 65 West 85th Street 3A NULL
+US NY NULL New York NULL 10027 606 W. 116th Street #22 NULL
+US NY NULL New York NULL 10037 NULL
+US NY NULL Rochester NULL NULL
+US NY NULL Scarsdale NULL 10583-1423 54 Walworth Avenue NULL
+US OR NULL Portland NULL NULL
+US PA NULL Philadelphia NULL NULL
+US PA NULL Philadelphia NULL NULL
+US PR NULL Colonel Hill NULL Colonel Hill Colonel Hill NULL
+US SD NULL Banjul NULL Banjul Banjul NULL
+US SD NULL London NULL London London NULL
+US TX NULL Aledo NULL 76008 1588 Hunterglenn Dr NULL
+US TX NULL Keller NULL 76248 810 Placid View Ct. NULL
+US WA NULL Seattle NULL NULL
+ZA NULL Cape Town NULL NULL
+ZA NULL Cape Town NULL 7945 Alexander Road Muizenberg NULL
+ZA NULL Pretoria NULL NULL
+ZA 11 NULL Cape Town NULL NULL
+ZA 11 NULL Cape Town NULL 7435 PostNet Suite #57, Private Bag X18 Milnerton NULL
+ZA 11 NULL Cape town NULL 7508 24 Solyet Court, Lansdowne Road Claremont NULL
+ZA 11 NULL Cape Town NULL 7701 NULL
+ZA 11 NULL Cape Town NULL 7785 10 Nyamakazi Road Luzuko Park Phillipi East NULL
+ZA 11 NULL Cape Town NULL 7915 66 Albert Rd NULL
+ZA 11 NULL Cape Town NULL 8001 210 Long Street NULL
+ZM NULL Lusaka NULL NULL
+ZM 9 NULL LUSAKA NULL 10101 P.O. BOX FW 174 NULL
diff --git a/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.address_formats.inc b/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.address_formats.inc
index 793e2f1e..19e7958b 100644
--- a/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.address_formats.inc
+++ b/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.address_formats.inc
@@ -41,11 +41,11 @@ function addressfield_get_address_format($country_code) {
// postal code in 'used_fields'.
$countries_with_optional_postal_code = array(
'AC', 'AD', 'AL', 'AZ', 'BA', 'BB', 'BD', 'BG', 'BH', 'BM', 'BN', 'BT',
- 'CR', 'CY', 'CZ', 'DO', 'DZ', 'EC', 'EH', 'ET', 'FO', 'GE', 'GN', 'GT',
+ 'CR', 'CY', 'DO', 'DZ', 'EC', 'EH', 'ET', 'FO', 'GE', 'GN', 'GT',
'GW', 'HR', 'HT', 'IL', 'IS', 'JO', 'KE', 'KG', 'KH', 'KW', 'LA',
'LA', 'LB', 'LK', 'LR', 'LS', 'MA', 'MC', 'MD', 'ME', 'MG', 'MK', 'MM',
'MT', 'MU', 'MV', 'NE', 'NP', 'OM', 'PK', 'PY', 'RO', 'RS', 'SA', 'SI',
- 'SK', 'SN', 'SZ', 'TA', 'TJ', 'TM', 'TN', 'VA', 'VC', 'VG', 'XK', 'ZM',
+ 'SN', 'SZ', 'TA', 'TJ', 'TM', 'TN', 'VA', 'VC', 'VG', 'XK', 'ZM',
);
foreach ($countries_with_optional_postal_code as $code) {
$address_formats[$code] = array(
@@ -56,9 +56,9 @@ function addressfield_get_address_format($country_code) {
// These formats differ from the default only by the presence of the
// postal code in 'used_fields' and 'required_fields'.
$countries_with_required_postal_code = array(
- 'AT', 'AX', 'BE', 'BL', 'CH', 'DE', 'DK', 'FI', 'FK', 'FR', 'GF', 'GG',
+ 'AT', 'AX', 'BE', 'BL', 'CH', 'CZ', 'DE', 'DK', 'FI', 'FK', 'FR', 'GF', 'GG',
'GL', 'GP', 'GR', 'GS', 'HU', 'IM', 'IO', 'JE', 'LI', 'LU', 'MF', 'MQ', 'NC',
- 'NL', 'NO', 'PL', 'PM', 'PN', 'PT', 'RE', 'SE', 'SH', 'SJ', 'TC', 'WF',
+ 'NL', 'NO', 'PL', 'PM', 'PN', 'PT', 'RE', 'SE', 'SH', 'SJ', 'SK', 'TC', 'WF',
'YT',
);
foreach ($countries_with_required_postal_code as $code) {
@@ -114,7 +114,7 @@ function addressfield_get_address_format($country_code) {
'used_fields' => array('locality', 'administrative_area', 'postal_code'),
);
$address_formats['CL'] = array(
- 'used_fields' => array('locality', 'administrative_area', 'postal_code'),
+ 'used_fields' => array('dependent_locality', 'locality', 'administrative_area', 'postal_code'),
'administrative_area_label' => t('State', array(), array('context' => 'Territory of a country')),
'render_administrative_area_value' => TRUE,
);
@@ -124,7 +124,7 @@ function addressfield_get_address_format($country_code) {
'dependent_locality_label' => t('District'),
);
$address_formats['CO'] = array(
- 'used_fields' => array('locality', 'administrative_area'),
+ 'used_fields' => array('locality', 'administrative_area', 'postal_code'),
'administrative_area_label' => t('Department', array(), array('context' => 'Territory of a country')),
);
$address_formats['CV'] = array(
@@ -235,6 +235,7 @@ function addressfield_get_address_format($country_code) {
'used_fields' => array('dependent_locality', 'locality', 'administrative_area', 'postal_code'),
'required_fields' => array('locality', 'administrative_area', 'postal_code'),
'dependent_locality_label' => t('District'),
+ 'render_administrative_area_value' => TRUE,
);
$address_formats['KY'] = array(
'used_fields' => array('administrative_area', 'postal_code'),
diff --git a/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.administrative_areas.inc b/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.administrative_areas.inc
index 88343de9..aa6ebad6 100644
--- a/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.administrative_areas.inc
+++ b/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.administrative_areas.inc
@@ -11,6 +11,29 @@
* NULL if not found.
*/
function addressfield_get_administrative_areas($country_code) {
+ // Maintain a static cache to avoid passing the administrative areas through
+ // t() more than once per request.
+ $administrative_areas = &drupal_static(__FUNCTION__, array());
+ if (empty($administrative_areas)) {
+ // Get the default administrative areas.
+ $administrative_areas = _addressfield_get_administrative_areas_defaults();
+
+ // Allow other modules to alter the administrative areas.
+ drupal_alter('addressfield_administrative_areas', $administrative_areas);
+ }
+
+ return isset($administrative_areas[$country_code]) ? $administrative_areas[$country_code] : NULL;
+}
+
+/**
+ * Provides the default administrative areas.
+ */
+function _addressfield_get_administrative_areas_defaults() {
+ // To avoid needless pollution of the strings list we only pass to t()
+ // those administrative areas that are in English (or a latin transcription),
+ // and belong to a country that either has multiple official languages (CA)
+ // or uses a non-latin script (AE, CN, JP, KR, UA, RU, etc).
+ // No translation is expected in other cases.
$administrative_areas = array();
$administrative_areas['AE'] = array(
'AZ' => t('Abu Dhabi'),
@@ -22,69 +45,69 @@ function addressfield_get_administrative_areas($country_code) {
'AJ' => t('Ajmān'),
);
$administrative_areas['AR'] = array(
- 'B' => t('Buenos Aires'),
- 'K' => t('Catamarca'),
- 'H' => t('Chaco'),
- 'U' => t('Chubut'),
- 'C' => t('Ciudad de Buenos Aires'),
- 'X' => t('Córdoba'),
- 'W' => t('Corrientes'),
- 'E' => t('Entre Ríos'),
- 'P' => t('Formosa'),
- 'Y' => t('Jujuy'),
- 'L' => t('La Pampa'),
- 'F' => t('La Rioja'),
- 'M' => t('Mendoza'),
- 'N' => t('Misiones'),
- 'Q' => t('Neuquén'),
- 'R' => t('Río Negro'),
- 'A' => t('Salta'),
- 'J' => t('San Juan'),
- 'D' => t('San Luis'),
- 'Z' => t('Santa Cruz'),
- 'S' => t('Santa Fe'),
- 'G' => t('Santiago del Estero'),
- 'V' => t('Tierra del Fuego'),
- 'T' => t('Tucumán'),
+ 'B' => 'Buenos Aires',
+ 'K' => 'Catamarca',
+ 'H' => 'Chaco',
+ 'U' => 'Chubut',
+ 'C' => 'Ciudad de Buenos Aires',
+ 'X' => 'Córdoba',
+ 'W' => 'Corrientes',
+ 'E' => 'Entre Ríos',
+ 'P' => 'Formosa',
+ 'Y' => 'Jujuy',
+ 'L' => 'La Pampa',
+ 'F' => 'La Rioja',
+ 'M' => 'Mendoza',
+ 'N' => 'Misiones',
+ 'Q' => 'Neuquén',
+ 'R' => 'Río Negro',
+ 'A' => 'Salta',
+ 'J' => 'San Juan',
+ 'D' => 'San Luis',
+ 'Z' => 'Santa Cruz',
+ 'S' => 'Santa Fe',
+ 'G' => 'Santiago del Estero',
+ 'V' => 'Tierra del Fuego',
+ 'T' => 'Tucumán',
);
$administrative_areas['AU'] = array(
- 'ACT' => t('Australian Capital Territory'),
- 'NSW' => t('New South Wales'),
- 'NT' => t('Northern Territory'),
- 'QLD' => t('Queensland'),
- 'SA' => t('South Australia'),
- 'TAS' => t('Tasmania'),
- 'VIC' => t('Victoria'),
- 'WA' => t('Western Australia'),
+ 'ACT' => 'Australian Capital Territory',
+ 'NSW' => 'New South Wales',
+ 'NT' => 'Northern Territory',
+ 'QLD' => 'Queensland',
+ 'SA' => 'South Australia',
+ 'TAS' => 'Tasmania',
+ 'VIC' => 'Victoria',
+ 'WA' => 'Western Australia',
);
$administrative_areas['BR'] = array(
- 'AC' => t('Acre'),
- 'AL' => t('Alagoas'),
- 'AM' => t('Amazonas'),
- 'AP' => t('Amapá'),
- 'BA' => t('Bahia'),
- 'CE' => t('Ceará'),
- 'DF' => t('Distrito Federal'),
- 'ES' => t('Espírito Santo'),
- 'GO' => t('Goiás'),
- 'MA' => t('Maranhão'),
- 'MG' => t('Minas Gerais'),
- 'MS' => t('Mato Grosso do Sul'),
- 'MT' => t('Mato Grosso'),
- 'PA' => t('Pará'),
- 'PB' => t('Paraíba'),
- 'PE' => t('Pernambuco'),
- 'PI' => t('Piauí'),
- 'PR' => t('Paraná'),
- 'RJ' => t('Rio de Janeiro'),
- 'RN' => t('Rio Grande do Norte'),
- 'RO' => t('Rondônia'),
- 'RR' => t('Roraima'),
- 'RS' => t('Rio Grande do Sul'),
- 'SC' => t('Santa Catarina'),
- 'SE' => t('Sergipe'),
- 'SP' => t('São Paulo'),
- 'TO' => t('Tocantins'),
+ 'AC' => 'Acre',
+ 'AL' => 'Alagoas',
+ 'AM' => 'Amazonas',
+ 'AP' => 'Amapá',
+ 'BA' => 'Bahia',
+ 'CE' => 'Ceará',
+ 'DF' => 'Distrito Federal',
+ 'ES' => 'Espírito Santo',
+ 'GO' => 'Goiás',
+ 'MA' => 'Maranhão',
+ 'MG' => 'Minas Gerais',
+ 'MS' => 'Mato Grosso do Sul',
+ 'MT' => 'Mato Grosso',
+ 'PA' => 'Pará',
+ 'PB' => 'Paraíba',
+ 'PE' => 'Pernambuco',
+ 'PI' => 'Piauí',
+ 'PR' => 'Paraná',
+ 'RJ' => 'Rio de Janeiro',
+ 'RN' => 'Rio Grande do Norte',
+ 'RO' => 'Rondônia',
+ 'RR' => 'Roraima',
+ 'RS' => 'Rio Grande do Sul',
+ 'SC' => 'Santa Catarina',
+ 'SE' => 'Sergipe',
+ 'SP' => 'São Paulo',
+ 'TO' => 'Tocantins',
);
$administrative_areas['CA'] = array(
'AB' => t('Alberta'),
@@ -102,21 +125,21 @@ function addressfield_get_administrative_areas($country_code) {
'YT' => t('Yukon Territory'),
);
$administrative_areas['CL'] = array(
- 'AI' => t('Aysén del General Carlos Ibáñez del Campo'),
- 'AN' => t('Antofagasta'),
- 'AR' => t('Araucanía'),
- 'AP' => t('Arica y Parinacota'),
- 'AT' => t('Atacama'),
- 'BI' => t('Biobío'),
- 'CO' => t('Coquimbo'),
- 'LI' => t('Libertador General Bernardo O\'Higgins'),
- 'LL' => t('Los Lagos'),
- 'LR' => t('Los Ríos'),
- 'MA' => t('Magallanes y de la Antártica Chilena'),
- 'ML' => t('Maule'),
- 'RM' => t('Metropolitana de Santiago'),
- 'TA' => t('Tarapacá'),
- 'VS' => t('Valparaíso'),
+ 'AI' => 'Aysén del General Carlos Ibáñez del Campo',
+ 'AN' => 'Antofagasta',
+ 'AR' => 'Araucanía',
+ 'AP' => 'Arica y Parinacota',
+ 'AT' => 'Atacama',
+ 'BI' => 'Biobío',
+ 'CO' => 'Coquimbo',
+ 'LI' => 'Libertador General Bernardo O\'Higgins',
+ 'LL' => 'Los Lagos',
+ 'LR' => 'Los Ríos',
+ 'MA' => 'Magallanes y de la Antártica Chilena',
+ 'ML' => 'Maule',
+ 'RM' => 'Metropolitana de Santiago',
+ 'TA' => 'Tarapacá',
+ 'VS' => 'Valparaíso',
);
$administrative_areas['CN'] = array(
'34' => t('Anhui Sheng'),
@@ -155,55 +178,55 @@ function addressfield_get_administrative_areas($country_code) {
'33' => t('Zhejiang Sheng'),
);
$administrative_areas['CO'] = array(
- 'AMA' => t('Amazonas'),
- 'ANT' => t('Antioquia'),
- 'ARA' => t('Arauca'),
- 'ATL' => t('Atlántico'),
- 'BOL' => t('Bolívar'),
- 'BOY' => t('Boyacá'),
- 'CAL' => t('Caldas'),
- 'CAQ' => t('Caquetá'),
- 'CAS' => t('Casanare'),
- 'CAU' => t('Cauca'),
- 'CES' => t('Cesar'),
- 'COR' => t('Córdoba'),
- 'CUN' => t('Cundinamarca'),
- 'CHO' => t('Chocó'),
- 'GUA' => t('Guainía'),
- 'GUV' => t('Guaviare'),
- 'HUI' => t('Huila'),
- 'LAG' => t('La Guajira'),
- 'MAG' => t('Magdalena'),
- 'MET' => t('Meta'),
- 'NAR' => t('Nariño'),
- 'NSA' => t('Norte de Santander'),
- 'PUT' => t('Putumayo'),
- 'QUI' => t('Quindío'),
- 'RIS' => t('Risaralda'),
- 'SAP' => t('San Andrés, Providencia y Santa Catalina'),
- 'SAN' => t('Santander'),
- 'SUC' => t('Sucre'),
- 'TOL' => t('Tolima'),
- 'VAC' => t('Valle del Cauca'),
- 'VAU' => t('Vaupés'),
- 'VID' => t('Vichada'),
+ 'AMA' => 'Amazonas',
+ 'ANT' => 'Antioquia',
+ 'ARA' => 'Arauca',
+ 'ATL' => 'Atlántico',
+ 'BOL' => 'Bolívar',
+ 'BOY' => 'Boyacá',
+ 'CAL' => 'Caldas',
+ 'CAQ' => 'Caquetá',
+ 'CAS' => 'Casanare',
+ 'CAU' => 'Cauca',
+ 'CES' => 'Cesar',
+ 'COR' => 'Córdoba',
+ 'CUN' => 'Cundinamarca',
+ 'CHO' => 'Chocó',
+ 'GUA' => 'Guainía',
+ 'GUV' => 'Guaviare',
+ 'HUI' => 'Huila',
+ 'LAG' => 'La Guajira',
+ 'MAG' => 'Magdalena',
+ 'MET' => 'Meta',
+ 'NAR' => 'Nariño',
+ 'NSA' => 'Norte de Santander',
+ 'PUT' => 'Putumayo',
+ 'QUI' => 'Quindío',
+ 'RIS' => 'Risaralda',
+ 'SAP' => 'San Andrés, Providencia y Santa Catalina',
+ 'SAN' => 'Santander',
+ 'SUC' => 'Sucre',
+ 'TOL' => 'Tolima',
+ 'VAC' => 'Valle del Cauca',
+ 'VAU' => 'Vaupés',
+ 'VID' => 'Vichada',
);
$administrative_areas['EE'] = array(
- '37' => t('Harjumaa'),
- '39' => t('Hiiumaa'),
- '44' => t('Ida-Virumaa'),
- '49' => t('Jõgevamaa'),
- '51' => t('Järvamaa'),
- '57' => t('Läänemaa'),
- '59' => t('Lääne-Virumaa'),
- '65' => t('Põlvamaa'),
- '67' => t('Pärnumaa'),
- '70' => t('Raplamaa'),
- '74' => t('Saaremaa'),
- '78' => t('Tartumaa'),
- '82' => t('Valgamaa'),
- '84' => t('Viljandimaa'),
- '86' => t('Võrumaa'),
+ '37' => 'Harjumaa',
+ '39' => 'Hiiumaa',
+ '44' => 'Ida-Virumaa',
+ '49' => 'Jõgevamaa',
+ '51' => 'Järvamaa',
+ '57' => 'Läänemaa',
+ '59' => 'Lääne-Virumaa',
+ '65' => 'Põlvamaa',
+ '67' => 'Pärnumaa',
+ '70' => 'Raplamaa',
+ '74' => 'Saaremaa',
+ '78' => 'Tartumaa',
+ '82' => 'Valgamaa',
+ '84' => 'Viljandimaa',
+ '86' => 'Võrumaa',
);
$administrative_areas['EG'] = array(
'ALX' => t('Alexandria'),
@@ -235,58 +258,58 @@ function addressfield_get_administrative_areas($country_code) {
'LX' => t('Luxor'),
);
$administrative_areas['ES'] = array(
- 'C' => t("A Coruña"),
- 'VI' => t('Alava'),
- 'AB' => t('Albacete'),
- 'A' => t('Alicante'),
- 'AL' => t("Almería"),
- 'O' => t('Asturias'),
- 'AV' => t("Ávila"),
- 'BA' => t('Badajoz'),
- 'PM' => t('Baleares'),
- 'B' => t('Barcelona'),
- 'BU' => t('Burgos'),
- 'CC' => t("Cáceres"),
- 'CA' => t("Cádiz"),
- 'S' => t('Cantabria'),
- 'CS' => t("Castellón"),
- 'CE' => t('Ceuta'),
- 'CR' => t('Ciudad Real'),
- 'CO' => t("Córdoba"),
- 'CU' => t('Cuenca'),
- 'GI' => t('Gerona'),
- 'GR' => t('Granada'),
- 'GU' => t('Guadalajara'),
- 'SS' => t("Guipúzcoa"),
- 'H' => t('Huelva'),
- 'HU' => t('Huesca'),
- 'J' => t("Jaén"),
- 'LO' => t('La Rioja'),
- 'GC' => t('Las Palmas'),
- 'LE' => t("León"),
- 'L' => t("Lérida"),
- 'LU' => t('Lugo'),
- 'M' => t('Madrid'),
- 'MA' => t("Málaga"),
- 'ML' => t('Melilla'),
- 'MU' => t('Murcia'),
- 'NA' => t('Navarra'),
- 'OR' => t('Ourense'),
- 'P' => t('Palencia'),
- 'PO' => t('Pontevedra'),
- 'SA' => t('Salamanca'),
- 'TF' => t('Santa Cruz de Tenerife'),
- 'SG' => t('Segovia'),
- 'SE' => t('Sevilla'),
- 'SO' => t('Soria'),
- 'T' => t('Tarragona'),
- 'TE' => t('Teruel'),
- 'TO' => t('Toledo'),
- 'V' => t('Valencia'),
- 'VA' => t('Valladolid'),
- 'BI' => t('Vizcaya'),
- 'ZA' => t('Zamora'),
- 'Z' => t('Zaragoza'),
+ 'C' => "A Coruña",
+ 'VI' => 'Alava',
+ 'AB' => 'Albacete',
+ 'A' => 'Alicante',
+ 'AL' => "Almería",
+ 'O' => 'Asturias',
+ 'AV' => "Ávila",
+ 'BA' => 'Badajoz',
+ 'PM' => 'Baleares',
+ 'B' => 'Barcelona',
+ 'BU' => 'Burgos',
+ 'CC' => "Cáceres",
+ 'CA' => "Cádiz",
+ 'S' => 'Cantabria',
+ 'CS' => "Castellón",
+ 'CE' => 'Ceuta',
+ 'CR' => 'Ciudad Real',
+ 'CO' => "Córdoba",
+ 'CU' => 'Cuenca',
+ 'GI' => 'Girona',
+ 'GR' => 'Granada',
+ 'GU' => 'Guadalajara',
+ 'SS' => "Guipúzcoa",
+ 'H' => 'Huelva',
+ 'HU' => 'Huesca',
+ 'J' => "Jaén",
+ 'LO' => 'La Rioja',
+ 'GC' => 'Las Palmas',
+ 'LE' => "León",
+ 'L' => "Lleida",
+ 'LU' => 'Lugo',
+ 'M' => 'Madrid',
+ 'MA' => "Málaga",
+ 'ML' => 'Melilla',
+ 'MU' => 'Murcia',
+ 'NA' => 'Navarra',
+ 'OR' => 'Ourense',
+ 'P' => 'Palencia',
+ 'PO' => 'Pontevedra',
+ 'SA' => 'Salamanca',
+ 'TF' => 'Santa Cruz de Tenerife',
+ 'SG' => 'Segovia',
+ 'SE' => 'Sevilla',
+ 'SO' => 'Soria',
+ 'T' => 'Tarragona',
+ 'TE' => 'Teruel',
+ 'TO' => 'Toledo',
+ 'V' => 'Valencia',
+ 'VA' => 'Valladolid',
+ 'BI' => 'Vizcaya',
+ 'ZA' => 'Zamora',
+ 'Z' => 'Zaragoza',
);
$administrative_areas['HK'] = array(
// HK subdivisions have no ISO codes assigned.
@@ -330,57 +353,57 @@ function addressfield_get_administrative_areas($country_code) {
'SU' => t('Sumatera Utara'),
);
$administrative_areas['IE'] = array(
- 'CW' => t('Co Carlow'),
- 'CN' => t('Co Cavan'),
- 'CE' => t('Co Clare'),
- 'CO' => t('Co Cork'),
- 'DL' => t('Co Donegal'),
- 'D' => t('Co Dublin'),
- 'D1' => t('Dublin 1'),
- 'D2' => t('Dublin 2'),
- 'D3' => t('Dublin 3'),
- 'D4' => t('Dublin 4'),
- 'D5' => t('Dublin 5'),
- 'D6' => t('Dublin 6'),
- 'D6W' => t('Dublin 6w'),
- 'D7' => t('Dublin 7'),
- 'D8' => t('Dublin 8'),
- 'D9' => t('Dublin 9'),
- 'D10' => t('Dublin 10'),
- 'D11' => t('Dublin 11'),
- 'D12' => t('Dublin 12'),
- 'D13' => t('Dublin 13'),
- 'D14' => t('Dublin 14'),
- 'D15' => t('Dublin 15'),
- 'D16' => t('Dublin 16'),
- 'D17' => t('Dublin 17'),
- 'D18' => t('Dublin 18'),
- 'D19' => t('Dublin 19'),
- 'D20' => t('Dublin 20'),
- 'D21' => t('Dublin 21'),
- 'D22' => t('Dublin 22'),
- 'D23' => t('Dublin 23'),
- 'D24' => t('Dublin 24'),
- 'G' => t('Co Galway'),
- 'KY' => t('Co Kerry'),
- 'KE' => t('Co Kildare'),
- 'KK' => t('Co Kilkenny'),
- 'LS' => t('Co Laois'),
- 'LM' => t('Co Leitrim'),
- 'LK' => t('Co Limerick'),
- 'LD' => t('Co Longford'),
- 'LH' => t('Co Louth'),
- 'MO' => t('Co Mayo'),
- 'MH' => t('Co Meath'),
- 'MN' => t('Co Monaghan'),
- 'OY' => t('Co Offaly'),
- 'RN' => t('Co Roscommon'),
- 'SO' => t('Co Sligo'),
- 'TA' => t('Co Tipperary'),
- 'WD' => t('Co Waterford'),
- 'WH' => t('Co Westmeath'),
- 'WX' => t('Co Wexford'),
- 'WW' => t('Co Wicklow'),
+ 'CW' => 'Co Carlow',
+ 'CN' => 'Co Cavan',
+ 'CE' => 'Co Clare',
+ 'CO' => 'Co Cork',
+ 'DL' => 'Co Donegal',
+ 'D' => 'Co Dublin',
+ 'D1' => 'Dublin 1',
+ 'D2' => 'Dublin 2',
+ 'D3' => 'Dublin 3',
+ 'D4' => 'Dublin 4',
+ 'D5' => 'Dublin 5',
+ 'D6' => 'Dublin 6',
+ 'D6W' => 'Dublin 6w',
+ 'D7' => 'Dublin 7',
+ 'D8' => 'Dublin 8',
+ 'D9' => 'Dublin 9',
+ 'D10' => 'Dublin 10',
+ 'D11' => 'Dublin 11',
+ 'D12' => 'Dublin 12',
+ 'D13' => 'Dublin 13',
+ 'D14' => 'Dublin 14',
+ 'D15' => 'Dublin 15',
+ 'D16' => 'Dublin 16',
+ 'D17' => 'Dublin 17',
+ 'D18' => 'Dublin 18',
+ 'D19' => 'Dublin 19',
+ 'D20' => 'Dublin 20',
+ 'D21' => 'Dublin 21',
+ 'D22' => 'Dublin 22',
+ 'D23' => 'Dublin 23',
+ 'D24' => 'Dublin 24',
+ 'G' => 'Co Galway',
+ 'KY' => 'Co Kerry',
+ 'KE' => 'Co Kildare',
+ 'KK' => 'Co Kilkenny',
+ 'LS' => 'Co Laois',
+ 'LM' => 'Co Leitrim',
+ 'LK' => 'Co Limerick',
+ 'LD' => 'Co Longford',
+ 'LH' => 'Co Louth',
+ 'MO' => 'Co Mayo',
+ 'MH' => 'Co Meath',
+ 'MN' => 'Co Monaghan',
+ 'OY' => 'Co Offaly',
+ 'RN' => 'Co Roscommon',
+ 'SO' => 'Co Sligo',
+ 'TA' => 'Co Tipperary',
+ 'WD' => 'Co Waterford',
+ 'WH' => 'Co Westmeath',
+ 'WX' => 'Co Wexford',
+ 'WW' => 'Co Wicklow',
);
$administrative_areas['IN'] = array(
'AP' => t('Andhra Pradesh'),
@@ -388,8 +411,6 @@ function addressfield_get_administrative_areas($country_code) {
'AS' => t('Assam'),
'BR' => t('Bihar'),
'CT' => t('Chhattisgarh'),
- 'DD' => t('Daman & Diu'),
- 'DN' => t('Dadra & Nagar Haveli'),
'GA' => t('Goa'),
'GJ' => t('Gujarat'),
'HP' => t('Himachal Pradesh'),
@@ -424,116 +445,116 @@ function addressfield_get_administrative_areas($country_code) {
'PY' => t('Puducherry'),
);
$administrative_areas['IT'] = array(
- 'AG' => t('Agrigento'),
- 'AL' => t('Alessandria'),
- 'AN' => t('Ancona'),
- 'AO' => t('Aosta'),
- 'AP' => t('Ascoli Piceno'),
- 'AQ' => t("L'Aquila"),
- 'AR' => t('Arezzo'),
- 'AT' => t('Asti'),
- 'AV' => t('Avellino'),
- 'BA' => t('Bari'),
- 'BG' => t('Bergamo'),
- 'BI' => t('Biella'),
- 'BL' => t('Belluno'),
- 'BN' => t('Benevento'),
- 'BO' => t('Bologna'),
- 'BR' => t('Brindisi'),
- 'BS' => t('Brescia'),
- 'BT' => t('Barletta-Andria-Trani'),
- 'BZ' => t('Bolzano/Bozen'),
- 'CA' => t('Cagliari'),
- 'CB' => t('Campobasso'),
- 'CE' => t('Caserta'),
- 'CH' => t('Chieti'),
- 'CI' => t('Carbonia-Iglesias'),
- 'CL' => t('Caltanissetta'),
- 'CN' => t('Cuneo'),
- 'CO' => t('Como'),
- 'CR' => t('Cremona'),
- 'CS' => t('Cosenza'),
- 'CT' => t('Catania'),
- 'CZ' => t('Catanzaro'),
- 'EN' => t('Enna'),
- 'FC' => t('Forlì-Cesena'),
- 'FE' => t('Ferrara'),
- 'FG' => t('Foggia'),
- 'FI' => t('Firenze'),
- 'FM' => t('Fermo'),
- 'FR' => t('Frosinone'),
- 'GE' => t('Genova'),
- 'GO' => t('Gorizia'),
- 'GR' => t('Grosseto'),
- 'IM' => t('Imperia'),
- 'IS' => t('Isernia'),
- 'KR' => t('Crotone'),
- 'LC' => t('Lecco'),
- 'LE' => t('Lecce'),
- 'LI' => t('Livorno'),
- 'LO' => t('Lodi'),
- 'LT' => t('Latina'),
- 'LU' => t('Lucca'),
- 'MB' => t('Monza e Brianza'),
- 'MC' => t('Macerata'),
- 'ME' => t('Messina'),
- 'MI' => t('Milano'),
- 'MN' => t('Mantova'),
- 'MO' => t('Modena'),
- 'MS' => t('Massa-Carrara'),
- 'MT' => t('Matera'),
- 'NA' => t('Napoli'),
- 'NO' => t('Novara'),
- 'NU' => t('Nuoro'),
- 'OG' => t('Ogliastra'),
- 'OR' => t('Oristano'),
- 'OT' => t('Olbia-Tempio'),
- 'PA' => t('Palermo'),
- 'PC' => t('Piacenza'),
- 'PD' => t('Padova'),
- 'PE' => t('Pescara'),
- 'PG' => t('Perugia'),
- 'PI' => t('Pisa'),
- 'PN' => t('Pordenone'),
- 'PO' => t('Prato'),
- 'PR' => t('Parma'),
- 'PT' => t('Pistoia'),
- 'PU' => t('Pesaro e Urbino'),
- 'PV' => t('Pavia'),
- 'PZ' => t('Potenza'),
- 'RA' => t('Ravenna'),
- 'RC' => t('Reggio Calabria'),
- 'RE' => t('Reggio Emilia'),
- 'RG' => t('Ragusa'),
- 'RI' => t('Rieti'),
- 'RM' => t('Roma'),
- 'RN' => t('Rimini'),
- 'RO' => t('Rovigo'),
- 'SA' => t('Salerno'),
- 'SI' => t('Siena'),
- 'SO' => t('Sondrio'),
- 'SP' => t('La Spezia'),
- 'SR' => t('Siracusa'),
- 'SS' => t('Sassari'),
- 'SV' => t('Savona'),
- 'TA' => t('Taranto'),
- 'TE' => t('Teramo'),
- 'TN' => t('Trento'),
- 'TO' => t('Torino'),
- 'TP' => t('Trapani'),
- 'TR' => t('Terni'),
- 'TS' => t('Trieste'),
- 'TV' => t('Treviso'),
- 'UD' => t('Udine'),
- 'VA' => t('Varese'),
- 'VB' => t('Verbano-Cusio-Ossola'),
- 'VC' => t('Vercelli'),
- 'VE' => t('Venezia'),
- 'VI' => t('Vicenza'),
- 'VR' => t('Verona'),
- 'VS' => t('Medio Campidano'),
- 'VT' => t('Viterbo'),
- 'VV' => t('Vibo Valentia'),
+ 'AG' => 'Agrigento',
+ 'AL' => 'Alessandria',
+ 'AN' => 'Ancona',
+ 'AO' => 'Aosta',
+ 'AP' => 'Ascoli Piceno',
+ 'AQ' => "L'Aquila",
+ 'AR' => 'Arezzo',
+ 'AT' => 'Asti',
+ 'AV' => 'Avellino',
+ 'BA' => 'Bari',
+ 'BG' => 'Bergamo',
+ 'BI' => 'Biella',
+ 'BL' => 'Belluno',
+ 'BN' => 'Benevento',
+ 'BO' => 'Bologna',
+ 'BR' => 'Brindisi',
+ 'BS' => 'Brescia',
+ 'BT' => 'Barletta-Andria-Trani',
+ 'BZ' => 'Bolzano/Bozen',
+ 'CA' => 'Cagliari',
+ 'CB' => 'Campobasso',
+ 'CE' => 'Caserta',
+ 'CH' => 'Chieti',
+ 'CI' => 'Carbonia-Iglesias',
+ 'CL' => 'Caltanissetta',
+ 'CN' => 'Cuneo',
+ 'CO' => 'Como',
+ 'CR' => 'Cremona',
+ 'CS' => 'Cosenza',
+ 'CT' => 'Catania',
+ 'CZ' => 'Catanzaro',
+ 'EN' => 'Enna',
+ 'FC' => 'Forlì-Cesena',
+ 'FE' => 'Ferrara',
+ 'FG' => 'Foggia',
+ 'FI' => 'Firenze',
+ 'FM' => 'Fermo',
+ 'FR' => 'Frosinone',
+ 'GE' => 'Genova',
+ 'GO' => 'Gorizia',
+ 'GR' => 'Grosseto',
+ 'IM' => 'Imperia',
+ 'IS' => 'Isernia',
+ 'KR' => 'Crotone',
+ 'LC' => 'Lecco',
+ 'LE' => 'Lecce',
+ 'LI' => 'Livorno',
+ 'LO' => 'Lodi',
+ 'LT' => 'Latina',
+ 'LU' => 'Lucca',
+ 'MB' => 'Monza e Brianza',
+ 'MC' => 'Macerata',
+ 'ME' => 'Messina',
+ 'MI' => 'Milano',
+ 'MN' => 'Mantova',
+ 'MO' => 'Modena',
+ 'MS' => 'Massa-Carrara',
+ 'MT' => 'Matera',
+ 'NA' => 'Napoli',
+ 'NO' => 'Novara',
+ 'NU' => 'Nuoro',
+ 'OG' => 'Ogliastra',
+ 'OR' => 'Oristano',
+ 'OT' => 'Olbia-Tempio',
+ 'PA' => 'Palermo',
+ 'PC' => 'Piacenza',
+ 'PD' => 'Padova',
+ 'PE' => 'Pescara',
+ 'PG' => 'Perugia',
+ 'PI' => 'Pisa',
+ 'PN' => 'Pordenone',
+ 'PO' => 'Prato',
+ 'PR' => 'Parma',
+ 'PT' => 'Pistoia',
+ 'PU' => 'Pesaro e Urbino',
+ 'PV' => 'Pavia',
+ 'PZ' => 'Potenza',
+ 'RA' => 'Ravenna',
+ 'RC' => 'Reggio Calabria',
+ 'RE' => 'Reggio Emilia',
+ 'RG' => 'Ragusa',
+ 'RI' => 'Rieti',
+ 'RM' => 'Roma',
+ 'RN' => 'Rimini',
+ 'RO' => 'Rovigo',
+ 'SA' => 'Salerno',
+ 'SI' => 'Siena',
+ 'SO' => 'Sondrio',
+ 'SP' => 'La Spezia',
+ 'SR' => 'Siracusa',
+ 'SS' => 'Sassari',
+ 'SV' => 'Savona',
+ 'TA' => 'Taranto',
+ 'TE' => 'Teramo',
+ 'TN' => 'Trento',
+ 'TO' => 'Torino',
+ 'TP' => 'Trapani',
+ 'TR' => 'Terni',
+ 'TS' => 'Trieste',
+ 'TV' => 'Treviso',
+ 'UD' => 'Udine',
+ 'VA' => 'Varese',
+ 'VB' => 'Verbano-Cusio-Ossola',
+ 'VC' => 'Vercelli',
+ 'VE' => 'Venezia',
+ 'VI' => 'Vicenza',
+ 'VR' => 'Verona',
+ 'VS' => 'Medio Campidano',
+ 'VT' => 'Viterbo',
+ 'VV' => 'Vibo Valentia',
);
$administrative_areas['JM'] = array(
'13' => 'Clarendon',
@@ -638,38 +659,38 @@ function addressfield_get_administrative_areas($country_code) {
'ZHA' => t('Zhambyl region'),
);
$administrative_areas['MX'] = array(
- 'AGU' => t('Aguascalientes'),
- 'BCN' => t('Baja California'),
- 'BCS' => t('Baja California Sur'),
- 'CAM' => t('Campeche'),
- 'COA' => t('Coahuila'),
- 'COL' => t('Colima'),
- 'CHP' => t('Chiapas'),
- 'CHH' => t('Chihuahua'),
- 'DIF' => t('Distrito Federal'),
- 'DUG' => t('Durango'),
- 'MEX' => t('Estado de México'),
- 'GUA' => t('Guanajuato'),
- 'GRO' => t('Guerrero'),
- 'HID' => t('Hidalgo'),
- 'JAL' => t('Jalisco'),
- 'MIC' => t('Michoacán'),
- 'MOR' => t('Morelos'),
- 'NAY' => t('Nayarit'),
- 'NLE' => t('Nuevo León'),
- 'OAX' => t('Oaxaca'),
- 'PUE' => t('Puebla'),
- 'QUE' => t('Queretaro'),
- 'ROO' => t('Quintana Roo'),
- 'SLP' => t('San Luis Potosí'),
- 'SIN' => t('Sinaloa'),
- 'SON' => t('Sonora'),
- 'TAB' => t('Tabasco'),
- 'TAM' => t('Tamaulipas'),
- 'TLA' => t('Tlaxcala'),
- 'VER' => t('Veracruz'),
- 'YUC' => t('Yucatán'),
- 'ZAC' => t('Zacatecas'),
+ 'AGU' => 'Aguascalientes',
+ 'BCN' => 'Baja California',
+ 'BCS' => 'Baja California Sur',
+ 'CAM' => 'Campeche',
+ 'COA' => 'Coahuila',
+ 'COL' => 'Colima',
+ 'CHP' => 'Chiapas',
+ 'CHH' => 'Chihuahua',
+ 'DIF' => 'Distrito Federal',
+ 'DUG' => 'Durango',
+ 'MEX' => 'Estado de México',
+ 'GUA' => 'Guanajuato',
+ 'GRO' => 'Guerrero',
+ 'HID' => 'Hidalgo',
+ 'JAL' => 'Jalisco',
+ 'MIC' => 'Michoacán',
+ 'MOR' => 'Morelos',
+ 'NAY' => 'Nayarit',
+ 'NLE' => 'Nuevo León',
+ 'OAX' => 'Oaxaca',
+ 'PUE' => 'Puebla',
+ 'QUE' => 'Queretaro',
+ 'ROO' => 'Quintana Roo',
+ 'SLP' => 'San Luis Potosí',
+ 'SIN' => 'Sinaloa',
+ 'SON' => 'Sonora',
+ 'TAB' => 'Tabasco',
+ 'TAM' => 'Tamaulipas',
+ 'TLA' => 'Tlaxcala',
+ 'VER' => 'Veracruz',
+ 'YUC' => 'Yucatán',
+ 'ZAC' => 'Zacatecas',
);
$administrative_areas['MY'] = array(
'01' => t('Johor'),
@@ -690,31 +711,31 @@ function addressfield_get_administrative_areas($country_code) {
'11' => t('Terengganu'),
);
$administrative_areas['PE'] = array(
- 'AMA' => t('Amazonas'),
- 'ANC' => t('Ancash'),
- 'APU' => t('Apurimac'),
- 'ARE' => t('Arequipa'),
- 'AYA' => t('Ayacucho'),
- 'CAJ' => t('Cajamarca'),
- 'CAL' => t('Callao'),
- 'CUS' => t('Cusco'),
- 'HUV' => t('Huancavelica'),
- 'HUC' => t('Huanuco'),
- 'ICA' => t('Ica'),
- 'JUN' => t('Junin'),
- 'LAL' => t('La Libertad'),
- 'LAM' => t('Lambayeque'),
- 'LIM' => t('Lima'),
- 'LOR' => t('Loreto'),
- 'MDD' => t('Madre de Dios'),
- 'MOQ' => t('Moquegua'),
- 'PAS' => t('Pasco'),
- 'PIU' => t('Piura'),
- 'PUN' => t('Puno'),
- 'SAM' => t('San Martin'),
- 'TAC' => t('Tacna'),
- 'TUM' => t('Tumbes'),
- 'UCA' => t('Ucayali'),
+ 'AMA' => 'Amazonas',
+ 'ANC' => 'Ancash',
+ 'APU' => 'Apurimac',
+ 'ARE' => 'Arequipa',
+ 'AYA' => 'Ayacucho',
+ 'CAJ' => 'Cajamarca',
+ 'CAL' => 'Callao',
+ 'CUS' => 'Cusco',
+ 'HUV' => 'Huancavelica',
+ 'HUC' => 'Huanuco',
+ 'ICA' => 'Ica',
+ 'JUN' => 'Junin',
+ 'LAL' => 'La Libertad',
+ 'LAM' => 'Lambayeque',
+ 'LIM' => 'Lima',
+ 'LOR' => 'Loreto',
+ 'MDD' => 'Madre de Dios',
+ 'MOQ' => 'Moquegua',
+ 'PAS' => 'Pasco',
+ 'PIU' => 'Piura',
+ 'PUN' => 'Puno',
+ 'SAM' => 'San Martin',
+ 'TAC' => 'Tacna',
+ 'TUM' => 'Tumbes',
+ 'UCA' => 'Ucayali',
);
$administrative_areas['RU'] = array(
'MOW' => t('Moskva'),
@@ -918,7 +939,6 @@ function addressfield_get_administrative_areas($country_code) {
'21' => t('Zakarpats\'ka oblast'),
'23' => t('Zaporiz\'ka oblast'),
'26' => t('Ivano-Frankivs\'ka oblast'),
- '30' => t('Kyiv city'),
'30' => t('Kiev Oblast'),
'35' => t('Kirovohrads\'ka oblast'),
'09' => t('Luhans\'ka oblast'),
@@ -1003,35 +1023,32 @@ function addressfield_get_administrative_areas($country_code) {
'VI' => t('Virgin Islands'),
);
$administrative_areas['VE'] = array(
- 'Z' => t('Amazonas'),
- 'B' => t('Anzoátegui'),
- 'C' => t('Apure'),
- 'D' => t('Aragua'),
- 'E' => t('Barinas'),
- 'F' => t('Bolívar'),
- 'G' => t('Carabobo'),
- 'H' => t('Cojedes'),
- 'Y' => t('Delta Amacuro'),
- 'W' => t('Dependencias Federales'),
- 'A' => t('Distrito Federal'),
- 'I' => t('Falcón'),
- 'J' => t('Guárico'),
- 'K' => t('Lara'),
- 'L' => t('Mérida'),
- 'M' => t('Miranda'),
- 'N' => t('Monagas'),
- 'O' => t('Nueva Esparta'),
- 'P' => t('Portuguesa'),
- 'R' => t('Sucre'),
- 'S' => t('Táchira'),
- 'T' => t('Trujillo'),
- 'X' => t('Vargas'),
- 'U' => t('Yaracuy'),
- 'V' => t('Zulia'),
+ 'Z' => 'Amazonas',
+ 'B' => 'Anzoátegui',
+ 'C' => 'Apure',
+ 'D' => 'Aragua',
+ 'E' => 'Barinas',
+ 'F' => 'Bolívar',
+ 'G' => 'Carabobo',
+ 'H' => 'Cojedes',
+ 'Y' => 'Delta Amacuro',
+ 'W' => 'Dependencias Federales',
+ 'A' => 'Distrito Federal',
+ 'I' => 'Falcón',
+ 'J' => 'Guárico',
+ 'K' => 'Lara',
+ 'L' => 'Mérida',
+ 'M' => 'Miranda',
+ 'N' => 'Monagas',
+ 'O' => 'Nueva Esparta',
+ 'P' => 'Portuguesa',
+ 'R' => 'Sucre',
+ 'S' => 'Táchira',
+ 'T' => 'Trujillo',
+ 'X' => 'Vargas',
+ 'U' => 'Yaracuy',
+ 'V' => 'Zulia',
);
- // Allow other modules to alter the administrative areas.
- drupal_alter('addressfield_administrative_areas', $administrative_areas);
-
- return isset($administrative_areas[$country_code]) ? $administrative_areas[$country_code] : null;
+ return $administrative_areas;
}
diff --git a/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.devel_generate.inc b/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.devel_generate.inc
index e14c8885..2eb9c41a 100644
--- a/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.devel_generate.inc
+++ b/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.devel_generate.inc
@@ -43,7 +43,6 @@ function _addressfield_sample_addresses() {
$fields = array();
if ($handle = @fopen("$filepath/addresses.txt",'r')) {
if (is_resource($handle)) {
- $addresses = array();
while (($buffer = fgets($handle)) !== false) {
list($country, $administrative_area, $sub_administrative_area, $locality, $dependent_locality, $postal_code, $thoroughfare, $premise, $sub_premise) = explode("\t", $buffer);
$fields[] = array(
diff --git a/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.feeds.inc b/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.feeds.inc
index 2b8537ad..062b221f 100644
--- a/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.feeds.inc
+++ b/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.feeds.inc
@@ -6,10 +6,10 @@
*/
/**
- * Implements hook_feeds_node_processor_targets_alter().
+ * Implements hook_feeds_processor_targets_alter().
*/
-function addressfield_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
- foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
+function addressfield_feeds_processor_targets_alter(&$targets, $entity_type, $bundle) {
+ foreach (field_info_instances($entity_type, $bundle) as $name => $instance) {
$info = field_info_field($name);
if ($info['type'] == 'addressfield') {
foreach ($info['columns'] as $sub_field => $schema_info) {
@@ -34,7 +34,7 @@ function addressfield_feeds_processor_targets_alter(&$targets, $entity_type, $bu
* An entity object, for instance a node object.
* @param $target
* A string identifying the target on the node.
- * @param $value
+ * @param $values
* The value to populate the target with.
*/
function addressfield_set_target($source, $entity, $target, $values) {
diff --git a/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.info b/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.info
index 991621bb..89e95157 100644
--- a/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.info
+++ b/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.info
@@ -6,12 +6,13 @@ package = Fields
dependencies[] = ctools
files[] = addressfield.migrate.inc
+files[] = views/addressfield_views_handler_field_administrative_area.inc
files[] = views/addressfield_views_handler_field_country.inc
files[] = views/addressfield_views_handler_filter_country.inc
-; Information added by Drupal.org packaging script on 2015-04-23
-version = "7.x-1.1"
+; Information added by Drupal.org packaging script on 2015-10-07
+version = "7.x-1.2"
core = "7.x"
project = "addressfield"
-datestamp = "1429819382"
+datestamp = "1444254070"
diff --git a/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.migrate.inc b/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.migrate.inc
index 6e74d63f..cc98911c 100644
--- a/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.migrate.inc
+++ b/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.migrate.inc
@@ -152,7 +152,7 @@ class MigrateAddressFieldHandler extends MigrateFieldHandler {
if ($value) {
if (isset($field_info['columns'][$column_key])) {
- // Store the data in a seperate column.
+ // Store the data in a separate column.
$result[$column_key] = $value;
}
else {
diff --git a/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.module b/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.module
index db7e0236..25b277dc 100644
--- a/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.module
+++ b/profiles/commerce_kickstart/modules/contrib/addressfield/addressfield.module
@@ -534,7 +534,9 @@ function addressfield_field_widget_form(&$form, &$form_state, $field, $instance,
// $form_state['values'] is empty because of #limit_validation_errors, so
// $form_state['input'] needs to be used instead.
$parents = array_merge($element['#field_parents'], array($element['#field_name'], $langcode, $delta));
- $input_address = drupal_array_get_nested_value($form_state['input'], $parents);
+ if (!empty($form_state['input'])) {
+ $input_address = drupal_array_get_nested_value($form_state['input'], $parents);
+ }
if (!empty($input_address)) {
$address = $input_address;
}
@@ -728,8 +730,6 @@ function addressfield_field_formatter_settings_summary($field, $instance, $view_
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
- $summary = '';
-
if ($settings['use_widget_handlers']) {
return t('Use widget configuration');
}
diff --git a/profiles/commerce_kickstart/modules/contrib/addressfield/example/addressfield_example.info b/profiles/commerce_kickstart/modules/contrib/addressfield/example/addressfield_example.info
index c7120e3b..b0f19829 100644
--- a/profiles/commerce_kickstart/modules/contrib/addressfield/example/addressfield_example.info
+++ b/profiles/commerce_kickstart/modules/contrib/addressfield/example/addressfield_example.info
@@ -7,9 +7,9 @@ hidden = TRUE
dependencies[] = ctools
dependencies[] = addressfield
-; Information added by Drupal.org packaging script on 2015-04-23
-version = "7.x-1.1"
+; Information added by Drupal.org packaging script on 2015-10-07
+version = "7.x-1.2"
core = "7.x"
project = "addressfield"
-datestamp = "1429819382"
+datestamp = "1444254070"
diff --git a/profiles/commerce_kickstart/modules/contrib/addressfield/example/plugins/format/address-ch-example.inc b/profiles/commerce_kickstart/modules/contrib/addressfield/example/plugins/format/address-ch-example.inc
index db3a98e2..4f92daa5 100644
--- a/profiles/commerce_kickstart/modules/contrib/addressfield/example/plugins/format/address-ch-example.inc
+++ b/profiles/commerce_kickstart/modules/contrib/addressfield/example/plugins/format/address-ch-example.inc
@@ -3552,8 +3552,6 @@ function addressfield_form_ch_postal_code_validation($element, &$form_state, &$f
if (!empty($element['#value']) && (isset($data[$element['#value']]))) {
// Get the base #parents for this address form.
$base_parents = array_slice($element['#parents'], 0, -1);
- $base_array_parents = array_slice($element['#array_parents'], 0, -2);
-
$city = $data[$element['#value']];
// Set the new values in the form.
diff --git a/profiles/commerce_kickstart/modules/contrib/addressfield/plugins/format/address-optional.inc b/profiles/commerce_kickstart/modules/contrib/addressfield/plugins/format/address-optional.inc
index 201e40ea..bb4408be 100644
--- a/profiles/commerce_kickstart/modules/contrib/addressfield/plugins/format/address-optional.inc
+++ b/profiles/commerce_kickstart/modules/contrib/addressfield/plugins/format/address-optional.inc
@@ -7,7 +7,7 @@
*/
$plugin = array(
- 'title' => t('Make all fields optional (Not recommended)'),
+ 'title' => t('Make all fields optional (No validation - unsuitable for postal purposes)'),
'format callback' => 'addressfield_format_address_optional',
'type' => 'address',
'weight' => 100,
diff --git a/profiles/commerce_kickstart/modules/contrib/addressfield/plugins/format/address.inc b/profiles/commerce_kickstart/modules/contrib/addressfield/plugins/format/address.inc
index 0523ffe1..e9b801f1 100644
--- a/profiles/commerce_kickstart/modules/contrib/addressfield/plugins/format/address.inc
+++ b/profiles/commerce_kickstart/modules/contrib/addressfield/plugins/format/address.inc
@@ -83,7 +83,7 @@ function addressfield_format_address_generate(&$format, $address, $context = arr
'#tag' => 'div',
'#attributes' => array(
'class' => array('dependent-locality'),
- 'autocomplete' => '"address-level3',
+ 'autocomplete' => 'address-level3',
),
// Most formats place this field in its own row.
'#suffix' => $clearfix,
@@ -97,7 +97,7 @@ function addressfield_format_address_generate(&$format, $address, $context = arr
'#prefix' => ' ',
'#attributes' => array(
'class' => array('locality'),
- 'autocomplete' => '"address-level2',
+ 'autocomplete' => 'address-level2',
),
);
$format['locality_block']['administrative_area'] = array(
diff --git a/profiles/commerce_kickstart/modules/contrib/addressfield/plugins/format/organisation.inc b/profiles/commerce_kickstart/modules/contrib/addressfield/plugins/format/organisation.inc
index 5cef00e3..3cec0f7f 100644
--- a/profiles/commerce_kickstart/modules/contrib/addressfield/plugins/format/organisation.inc
+++ b/profiles/commerce_kickstart/modules/contrib/addressfield/plugins/format/organisation.inc
@@ -20,7 +20,7 @@ $plugin = array(
function addressfield_format_organisation_generate(&$format, $address) {
$format['organisation_block'] = array(
'#type' => 'addressfield_container',
- '#attributes' => array('class' => array('addressfield-container-inline', 'name-block')),
+ '#attributes' => array('class' => array('addressfield-container-inline', 'organisation-block')),
'#weight' => -50,
// The addressfield is considered empty without a country, hide all fields
// until one is selected.
diff --git a/profiles/commerce_kickstart/modules/contrib/addressfield/views/addressfield.views.inc b/profiles/commerce_kickstart/modules/contrib/addressfield/views/addressfield.views.inc
index 9be1637e..f059da34 100644
--- a/profiles/commerce_kickstart/modules/contrib/addressfield/views/addressfield.views.inc
+++ b/profiles/commerce_kickstart/modules/contrib/addressfield/views/addressfield.views.inc
@@ -26,7 +26,7 @@ function addressfield_field_views_data($field) {
// Only expose these components as Views field handlers.
$implemented = array(
'country' => 'addressfield_views_handler_field_country',
- 'administrative_area' => 'views_handler_field',
+ 'administrative_area' => 'addressfield_views_handler_field_administrative_area',
'sub_administrative_area' => 'views_handler_field',
'dependent_locality' => 'views_handler_field',
'locality' => 'views_handler_field',
diff --git a/profiles/commerce_kickstart/modules/contrib/addressfield/views/addressfield_views_handler_field_administrative_area.inc b/profiles/commerce_kickstart/modules/contrib/addressfield/views/addressfield_views_handler_field_administrative_area.inc
new file mode 100644
index 00000000..daeae662
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/addressfield/views/addressfield_views_handler_field_administrative_area.inc
@@ -0,0 +1,48 @@
+country_alias = $this->query->add_field($this->table_alias, $this->definition['field_name'] . '_country');
+ }
+
+ function option_definition() {
+ $options = parent::option_definition();
+ $options['display_name'] = array('default' => TRUE);
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+
+ $form['display_name'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Display the name of administrative area instead of the code.'),
+ '#default_value' => $this->options['display_name'],
+ );
+ }
+
+ function get_value($values, $field = NULL) {
+ $value = parent::get_value($values, $field);
+
+ // If we have a value for the field, look for the administrative area name in the
+ // Address Field options list array if specified.
+ if (!empty($value) && !empty($this->options['display_name'])) {
+ module_load_include('inc', 'addressfield', 'addressfield.administrative_areas');
+ $country = $values->{$this->country_alias};
+ $areas = addressfield_get_administrative_areas($country);
+
+ if (!empty($areas[$value])) {
+ $value = $areas[$value];
+ }
+ }
+
+ return $value;
+ }
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/admin_views/admin_views.info b/profiles/commerce_kickstart/modules/contrib/admin_views/admin_views.info
index 3bce29f5..2dc00a58 100644
--- a/profiles/commerce_kickstart/modules/contrib/admin_views/admin_views.info
+++ b/profiles/commerce_kickstart/modules/contrib/admin_views/admin_views.info
@@ -10,9 +10,9 @@ files[] = plugins/views_plugin_access_menu.inc
files[] = tests/admin_views.test
-; Information added by Drupal.org packaging script on 2015-07-08
-version = "7.x-1.5"
+; Information added by Drupal.org packaging script on 2016-08-02
+version = "7.x-1.6"
core = "7.x"
project = "admin_views"
-datestamp = "1436376676"
+datestamp = "1470165840"
diff --git a/profiles/commerce_kickstart/modules/contrib/admin_views/plugins/views_plugin_access_menu.inc b/profiles/commerce_kickstart/modules/contrib/admin_views/plugins/views_plugin_access_menu.inc
index 82c9ceaa..79a2e93f 100644
--- a/profiles/commerce_kickstart/modules/contrib/admin_views/plugins/views_plugin_access_menu.inc
+++ b/profiles/commerce_kickstart/modules/contrib/admin_views/plugins/views_plugin_access_menu.inc
@@ -24,6 +24,11 @@ class views_plugin_access_menu extends views_plugin_access {
// view itself. The 'current display' could be set to something else, like
// default.
$path = $this->display->handler->get_option('path');
+
+ if (empty($path)) {
+ return FALSE;
+ }
+
$item = menu_get_item($path);
// If we are on the original router path, the menu system has checked access already.
diff --git a/profiles/commerce_kickstart/modules/contrib/admin_views/tests/admin_views.test b/profiles/commerce_kickstart/modules/contrib/admin_views/tests/admin_views.test
index 727bded3..22d4e2bd 100644
--- a/profiles/commerce_kickstart/modules/contrib/admin_views/tests/admin_views.test
+++ b/profiles/commerce_kickstart/modules/contrib/admin_views/tests/admin_views.test
@@ -199,6 +199,7 @@ class AdminViewsPageDisplayTestCase extends AdminViewsWebTestCase {
* Returns a test page view with a path under "admin/content".
*/
protected function normalPageView() {
+ views_include('view');
$view = new view();
$view->name = 'admin_views_test_normal';
$view->description = '';
@@ -283,5 +284,17 @@ class AdminViewsAccessHandlerTestCase extends AdminViewsWebTestCase {
// The next item in the AJAX data will be the insert command containing the
// rendered view.
$this->assertTrue(empty($response_data[1]));
+
+ // Test the access again with the default display.
+ $params['views_display_id'] = 'default';
+
+ $response_data = $this->drupalGetAJAX('views/ajax', array('query' => $params));
+
+ $this->assertResponse(200);
+ // Check no views settings are returned.
+ $this->assertTrue(empty($response_data[0]['settings']['views']));
+ // The next item in the AJAX data will be the insert command containing the
+ // rendered view.
+ $this->assertTrue(empty($response_data[1]));
}
}
diff --git a/profiles/commerce_kickstart/modules/contrib/admin_views/tests/admin_views_test/admin_views_test.info b/profiles/commerce_kickstart/modules/contrib/admin_views/tests/admin_views_test/admin_views_test.info
index 80f2f406..ff8fdfc8 100644
--- a/profiles/commerce_kickstart/modules/contrib/admin_views/tests/admin_views_test/admin_views_test.info
+++ b/profiles/commerce_kickstart/modules/contrib/admin_views/tests/admin_views_test/admin_views_test.info
@@ -6,9 +6,9 @@ hidden = TRUE
dependencies[] admin_views
-; Information added by Drupal.org packaging script on 2015-07-08
-version = "7.x-1.5"
+; Information added by Drupal.org packaging script on 2016-08-02
+version = "7.x-1.6"
core = "7.x"
project = "admin_views"
-datestamp = "1436376676"
+datestamp = "1470165840"
diff --git a/profiles/commerce_kickstart/modules/contrib/chosen/LICENSE.txt b/profiles/commerce_kickstart/modules/contrib/chosen/LICENSE.txt
new file mode 100644
index 00000000..d159169d
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/chosen/LICENSE.txt
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/profiles/commerce_kickstart/modules/contrib/chosen/README.txt b/profiles/commerce_kickstart/modules/contrib/chosen/README.txt
index 658c4e0c..619533e2 100644
--- a/profiles/commerce_kickstart/modules/contrib/chosen/README.txt
+++ b/profiles/commerce_kickstart/modules/contrib/chosen/README.txt
@@ -1,13 +1,17 @@
-- SUMMARY --
-Chosen uses the Chosen jQuery plugin to make your
',
'#tree' => TRUE,
'#parents' => array('commerce_discount_fields'),
+ '#pre_render' => array('commerce_discount_form_pre_render'),
+ );
+ // Vertical tabs container.
+ $form['commerce_discount_fields']['additional_settings'] = array(
+ '#type' => 'vertical_tabs',
+ '#weight' => 99,
+ 'discount_options' => array(
+ '#type' => 'fieldset',
+ '#title' => t('Discount options'),
+ '#collapsible' => TRUE,
+ '#weight' => -10,
+ ),
+ 'commerce_discount_compatibility' => array(
+ '#type' => 'fieldset',
+ '#title' => t('Discount compatibility'),
+ '#collapsible' => TRUE,
+ ),
+ );
+
+ // Add radios for enabling or disabling this discount.
+ $form['commerce_discount_fields']['additional_settings']['discount_options']['status'] = array(
+ '#title' => t('Discount status'),
+ '#type' => 'radios',
+ '#parents' => array('status'),
+ '#options' => array(
+ TRUE => t('Active'),
+ FALSE => t('Disabled'),
+ ),
+ '#required' => FALSE,
+ '#default_value' => $commerce_discount->status,
+ );
+
+ // Add the sort order select list.
+ $form['commerce_discount_fields']['additional_settings']['discount_options']['sort_order'] = array(
+ '#type' => 'select',
+ '#parents' => array('sort_order'),
+ '#title' => t('Sort order'),
+ '#description' => t('Discounts will be sorted by this value to be evaluated in that order.'),
+ '#options' => drupal_map_assoc(range(1, 21)),
+ '#default_value' => !empty($commerce_discount->sort_order) ? $commerce_discount->sort_order : 10,
);
field_attach_form('commerce_discount', $commerce_discount, $form['commerce_discount_fields'], $form_state);
@@ -213,9 +247,10 @@ function commerce_discount_form($form, &$form_state, CommerceDiscount $commerce_
// Add a class to custom fields for easier styling.
// Ignore the offer reference field and any date fields. Date fields are
// ignored because their markup makes them hard to style generically.
+ $date_field_types = array('date', 'datestamp', 'datetime');
foreach (element_get_visible_children($form['commerce_discount_fields']) as $field_name) {
$field = field_info_field($field_name);
- if ($field_name == 'commerce_discount_offer' || in_array($field['type'], array('date', 'datestamp', 'datetime'))) {
+ if ($field_name == 'commerce_discount_offer' || in_array($field['type'], $date_field_types)) {
continue;
}
@@ -226,13 +261,61 @@ function commerce_discount_form($form, &$form_state, CommerceDiscount $commerce_
$field_form['#attributes']['class'][] = 'commerce-discount-box';
}
+ // Give the compatibility strategy field a title and a description linking to
+ // the compatibility documentation based on the discount type.
+ switch ($form['commerce_discount_fields']['commerce_compatibility_strategy'][LANGUAGE_NONE]['#bundle']) {
+ case 'product_discount':
+ $discount_type_name = t('Product discounts');
+ $description = t('This setting determines which product discounts this discount can be applied after or that can be applied to the same product line item after this one.');
+ break;
+ case 'order_discount':
+ $discount_type_name = t('Order discounts');
+ $description = t('This setting determines which order discounts this discount can be applied after or that can be applied to the same order after this one.');
+ break;
+ default:
+ $discount_type_name = t('discounts of the same type');
+ $description = t('This setting determines which discounts of the same type this discount can be applied after or that can be applied to the same item after this one.');
+ break;
+ }
+
+ $title = t('Compatibility with other %name', array('%name' => $discount_type_name));
+ $form['commerce_discount_fields']['commerce_compatibility_strategy'][LANGUAGE_NONE]['#title'] = $title;
+ $form['commerce_discount_fields']['commerce_compatibility_strategy'][LANGUAGE_NONE]['#description'] = $description . ' ' . t('For more information, refer to the discount compatibility !link on drupal.org.', array('!link' => '' . t('documentation page') . ''));;
+
+ // Ensure the compatibility strategy field has a default value.
+ if (empty($form['commerce_discount_fields']['commerce_compatibility_strategy'][LANGUAGE_NONE]['#default_value'])) {
+ $form['commerce_discount_fields']['commerce_compatibility_strategy'][LANGUAGE_NONE]['#default_value'] = 'any';
+ }
+
+ // Add visibility states to the discount compatibility selection field.
+ $form['commerce_discount_fields']['commerce_compatibility_selection']['#states'] = array(
+ 'visible' => array(
+ ':input[name="commerce_discount_fields[commerce_compatibility_strategy][' . LANGUAGE_NONE . ']"]' => array(
+ array('value' => 'except'),
+ array('value' => 'only'),
+ ),
+ ),
+ );
+
+ // We have to do some extra adjustments to move compatibility fields into
+ // the vertical tabs.
+ $form['commerce_discount_fields']['additional_settings']['commerce_discount_compatibility']['commerce_compatibility_strategy'] = $form['commerce_discount_fields']['commerce_compatibility_strategy'];
+ $form['commerce_discount_fields']['additional_settings']['commerce_discount_compatibility']['commerce_compatibility_strategy']['#parents'] = array(
+ 'commerce_discount_fields', 'commerce_compatibility_strategy',
+ );
+ $form['commerce_discount_fields']['additional_settings']['commerce_discount_compatibility']['commerce_compatibility_selection'] = $form['commerce_discount_fields']['commerce_compatibility_selection'];
+ $form['commerce_discount_fields']['additional_settings']['commerce_discount_compatibility']['commerce_compatibility_selection']['#parents'] = array(
+ 'commerce_discount_fields', 'commerce_compatibility_selection',
+ );
+ unset($form['commerce_discount_fields']['commerce_compatibility_strategy'], $form['commerce_discount_fields']['commerce_compatibility_selection']);
+
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save discount'),
'#weight' => 40,
'#ief_submit_all' => TRUE,
- '#submit' => null,
+ '#submit' => NULL,
);
if (!$commerce_discount->hasStatus(ENTITY_IN_CODE) && $op != 'add') {
@@ -242,17 +325,30 @@ function commerce_discount_form($form, &$form_state, CommerceDiscount $commerce_
'#weight' => 45,
'#limit_validation_errors' => array(),
'#submit' => array('commerce_discount_form_submit_delete'),
+ '#suffix' => l(t('Cancel'), 'admin/commerce/discounts'),
);
}
+ else {
+ $form['actions']['submit']['#suffix'] = l(t('Cancel'), 'admin/commerce/discounts');
+ }
+
+ $form['commerce_discount_fields']['additional_settings']['commerce_discount_usage'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Maximum usage'),
+ '#collapsible' => TRUE,
+ );
+ $form['commerce_discount_fields']['additional_settings']['discount_date'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Discount dates'),
+ '#collapsible' => TRUE,
+ '#weight' => -1,
+ );
// Add assets.
$form['#attached']['js'][] = drupal_get_path('module', 'commerce_discount') . '/js/commerce_discount.js';
$form['#attached']['css'][] = drupal_get_path('module', 'commerce_discount') . '/css/commerce_discount.css';
- // Load rtl.css file if needed.
- if ($GLOBALS['language']->direction == 1) {
- $form['#attached']['css'][] = drupal_get_path('module', 'commerce_discount') . '/css/commerce_discount-rtl.css';
- }
$form['#attributes']['class'][] = 'commerce-discount-form';
+
return $form;
}
@@ -275,6 +371,14 @@ function commerce_discount_form_validate($form, &$form_state) {
if (!empty($form_state['values']['name'])) {
form_set_value($form['name'], 'discount_' . $form_state['values']['name'], $form_state);
}
+
+ // Check if this is a percentage offer.
+ if (isset($form_state['values']['commerce_discount_fields']['commerce_discount_offer'][LANGUAGE_NONE]['form']['commerce_percentage'])) {
+ $percentage = $form_state['values']['commerce_discount_fields']['commerce_discount_offer'][LANGUAGE_NONE]['form']['commerce_percentage'][LANGUAGE_NONE][0]['value'];
+ if (!empty($percentage) && $percentage <= 0) {
+ form_set_error('commerce_discount_fields][commerce_discount_offer][' . LANGUAGE_NONE . '][form][commerce_percentage', t('Percentage should be a positive, non-zero number.'));
+ }
+ }
}
/**
@@ -283,23 +387,30 @@ function commerce_discount_form_validate($form, &$form_state) {
function commerce_discount_form_submit(&$form, &$form_state) {
$commerce_discount = entity_ui_form_submit_build_entity($form, $form_state);
$commerce_discount->save();
- $form_state['redirect'] = 'admin/commerce/store/discounts';
+
+ // Set the redirect based on the type of the discount.
+ if ($commerce_discount->type == 'order_discount') {
+ $form_state['redirect'] = array('admin/commerce/discounts', array('query' => array('type' => 'order_discount')));
+ }
+ else {
+ $form_state['redirect'] = 'admin/commerce/discounts';
+ }
}
/**
* Form API submit callback for the delete button.
*/
function commerce_discount_form_submit_delete(&$form, &$form_state) {
- $form_state['redirect'] = 'admin/commerce/store/discounts/manage/' . $form_state['commerce_discount']->name . '/delete';
+ $form_state['redirect'] = 'admin/commerce/discounts/manage/' . $form_state['commerce_discount']->name . '/delete';
}
/**
* Checks if a Discount machine name is taken.
*
- * @param $value
+ * @param string $value
* The machine name, not prefixed with 'discount_'.
*
- * @return
+ * @return object|bool
* Whether or not the field machine name is taken.
*/
function _commerce_discount_name_exists($value) {
@@ -318,9 +429,67 @@ function commerce_discount_settings() {
$form['commerce_discount_line_item_types'] = array(
'#type' => 'checkboxes',
'#title' => t('Line item types to use for discounts'),
- '#default_value' => variable_get('commerce_discount_line_item_types', array('product')),
+ '#default_value' => variable_get('commerce_discount_line_item_types', array_diff(commerce_product_line_item_types(), array('product_discount'))),
'#options' => $types,
'#description' => t('Select the line item types that will be taken into account for calculating the discount amounts in percentage offers.'),
);
return system_settings_form($form);
}
+
+/**
+ * Add fields to the additional_settings vertical tabs container.
+ */
+function commerce_discount_form_pre_render($fields) {
+ $fields['additional_settings']['commerce_discount_usage']['discount_usage_per_person'] = $fields['discount_usage_per_person'];
+ $fields['additional_settings']['commerce_discount_usage']['discount_usage_limit'] = $fields['discount_usage_limit'];
+ $fields['additional_settings']['discount_date']['commerce_discount_date'] = $fields['commerce_discount_date'];
+
+ unset($fields['discount_usage_per_person']);
+ unset($fields['discount_usage_limit']);
+ unset($fields['commerce_discount_date']);
+
+ return $fields;
+}
+
+/**
+ * Implements hook_date_combo_process_alter().
+ */
+function commerce_discount_date_combo_process_alter(&$element, &$form_state, $context) {
+ if ($element['#field_name'] == 'commerce_discount_date') {
+ $element['#attributes'] = 'container-inline';
+
+ // Hide the checkbox for showing the end date.
+ $element['show_todate']['#type'] = 'value';
+ $element['show_todate']['#default_value'] = TRUE;
+ unset($element['show_todate']['#prefix']);
+ unset($element['show_todate']['#suffix']);
+
+ // Ignore the "Show end date" checkbox.
+ unset($element['value2']['#states']);
+
+ // Remove fieldset description.
+ $element['#fieldset_description'] = '';
+ }
+}
+
+/**
+ * Implements hook_date_popup_process_alter().
+ */
+function commerce_discount_date_popup_process_alter(&$element, &$form_state, $context) {
+ if ($element['#field']['field_name'] == 'commerce_discount_date') {
+ // Date-clear.
+ unset($element['#attributes']['class']);
+ array_shift($element['#wrapper_attributes']['class']);
+ // Reset the titles and descriptions of the start and end date fields.
+ $field_name = end($element['#parents']);
+ if ($field_name == 'value') {
+ $element['date']['#title'] = t('Start date');
+ $element['date']['#description'] = t('Starts at 12:00:00 AM');
+ }
+ else {
+ $element['date']['#title'] = t('End date');
+ $element['date']['#description'] = t('Ends after 11:59:59 PM');
+ }
+ $element['#title'] = '';
+ }
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/commerce_discount.class.inc b/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/commerce_discount.class.inc
index c1a1351b..e27724e8 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/commerce_discount.class.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/commerce_discount.class.inc
@@ -1,5 +1,10 @@
component_title = $this->getTranslation('component_title');
}
+ /**
+ * {@inheritdoc}
+ */
protected function defaultUri() {
$entity_info = entity_get_info('commerce_discount');
$path = $entity_info['admin ui']['path'] . '/manage';
return array('path' => $path . '/' . $this->name);
}
+
+ /**
+ * Overridden, to introduce the method for old entity API versions (BC).
+ *
+ * @todo Remove once we bump the required entity API version.
+ */
+ public function getTranslation($property, $langcode = NULL) {
+ if (module_exists('i18n_string')) {
+ return parent::getTranslation($property, $langcode);
+ }
+ return $this->$property;
+ }
+
}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/commerce_discount.controller.inc b/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/commerce_discount.controller.inc
index f53a62db..ec2e6a91 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/commerce_discount.controller.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/commerce_discount.controller.inc
@@ -11,13 +11,15 @@
class CommerceDiscountControllerExportable extends EntityAPIControllerExportable {
/**
- * Override export, to allow embedding the commerce discount offer
- * inside the export of the comemrce discount.
+ * {@inheritdoc}
+ *
+ * Override export, to allow embedding the commerce discount offer inside the
+ * export of the commerce discount.
*/
public function export($entity, $prefix = '') {
$vars = get_object_vars($entity);
- // Add commerce_discout_offer full entity export.
+ // Add commerce_discount_offer full entity export.
$wrapper = entity_metadata_wrapper('commerce_discount', $entity);
$discount_offer = $wrapper->commerce_discount_offer->value();
if (!empty($discount_offer)) {
@@ -38,7 +40,7 @@ class CommerceDiscountControllerExportable extends EntityAPIControllerExportable
* @param string $export
* An exported entity as serialized string.
*
- * @return
+ * @return object
* An entity object not yet saved.
*/
public function import($export) {
@@ -52,7 +54,7 @@ class CommerceDiscountControllerExportable extends EntityAPIControllerExportable
}
/**
- * Overridden to handle embedded dicount_offer update.
+ * Overridden to handle embedded discount_offer update.
*/
public function save($entity, DatabaseTransaction $transaction = NULL) {
// If overwriting an existing discount, delete the referenced
@@ -75,7 +77,9 @@ class CommerceDiscountControllerExportable extends EntityAPIControllerExportable
*/
public function delete($ids, DatabaseTransaction $transaction = NULL) {
parent::delete($ids, $transaction);
- // Rebuild entities.
+
+ // Rebuild rules config.
entity_defaults_rebuild(array('rules_config'));
}
+
}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/commerce_discount_offer.class.inc b/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/commerce_discount_offer.class.inc
index c0c8a2f8..7da6c5a6 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/commerce_discount_offer.class.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/commerce_discount_offer.class.inc
@@ -1,5 +1,10 @@
type = $form_state['commerce_dicount_offer_selection_' . $entity_form['#ief_id']];
+ if (isset($form_state['commerce_discount_offer_selection_' . $entity_form['#ief_id']])) {
+ $offer->type = $form_state['commerce_discount_offer_selection_' . $entity_form['#ief_id']];
}
// Get discount type.
$discount_type = commerce_discount_type($form_state['commerce_discount']->type);
- $options = array();
+ $offer_types = array();
foreach (commerce_discount_offer_types() as $type => $info) {
if (in_array($discount_type['entity type'], $info['entity types'])) {
- $options[$type] = $info['label'];
+ $offer_types[$type] = $info['label'];
}
}
// Ensures the discount type includes the passed offer type. If not, set the
// offer type to the first found valid offer.
- if (!in_array($offer->type, array_keys($options))) {
- $offer->type = reset(array_keys($options));
+ if (!in_array($offer->type, array_keys($offer_types))) {
+ $offer->type = reset(array_keys($offer_types));
+ }
+
+ $ief_id = $entity_form['#ief_id'];
+ field_attach_form('commerce_discount_offer', $offer, $entity_form, $form_state, LANGUAGE_NONE);
+
+ $fields_wrapper = array(
+ '#type' => 'container',
+ '#attributes' => array(
+ 'class' => array('commerce-offer-fields-wrapper'),
+ ),
+ '#weight' => 2,
+ '#parents' => array(
+ 'commerce_discount_fields',
+ 'commerce_discount_offer',
+ LANGUAGE_NONE,
+ 'form',
+ ),
+ );
+
+ // Transfer field elements onto fields container.
+ foreach (element_children($entity_form) as $key) {
+ $fields_wrapper[$key] = $entity_form[$key];
+ unset($entity_form[$key]);
}
+ // Set the fields container back to the form.
+ $entity_form['commerce_discount_offer_fields'] = $fields_wrapper;
+ // Add offer type options.
$entity_form['type'] = array(
- '#title' => t('Choose offer type'),
'#type' => 'radios',
- '#options' => $options,
+ '#title' => t('Choose offer type'),
+ '#title_display' => 'invisible',
+ '#options' => $offer_types,
'#required' => FALSE,
'#default_value' => $offer->type,
'#ajax' => array(
- 'callback' => 'inline_entity_form_get_element',
- 'wrapper' => 'inline-entity-form-' . $entity_form['#ief_id'],
+ 'callback' => 'inline_entity_form_get_element',
+ 'wrapper' => 'inline-entity-form-' . $ief_id,
),
+ '#weight' => 1,
);
- field_attach_form('commerce_discount_offer', $offer, $entity_form, $form_state, LANGUAGE_NONE);
+ // Add wrapper class for CSS to avoid form item collisions.
+ $entity_form['#attributes']['class'][] = 'commerce-offer-type-wrapper';
+ $entity_form['#type'] = 'fieldset';
+ $entity_form['#title'] = t('Choose offer type');
return $entity_form;
}
+
}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/views/commerce_discount.views.inc b/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/views/commerce_discount.views.inc
index 5fd510fb..0d3273d0 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/views/commerce_discount.views.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/views/commerce_discount.views.inc
@@ -16,26 +16,26 @@ class CommerceDiscountViewsController extends EntityDefaultViewsController {
public function views_data() {
$data = parent::views_data();
- // Expose the product status.
- $data['commerce_discount']['status'] = array(
- 'title' => t('Status'),
- 'help' => t('Whether or not the discount is active.'),
- 'field' => array(
- 'handler' => 'views_handler_field_boolean',
- 'click sortable' => TRUE,
- 'output formats' => array(
- 'active-disabled' => array(t('Active'), t('Disabled')),
+ // Expose the product status.
+ $data['commerce_discount']['status'] = array(
+ 'title' => t('Status'),
+ 'help' => t('Whether or not the discount is active.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field_boolean',
+ 'click sortable' => TRUE,
+ 'output formats' => array(
+ 'active-disabled' => array(t('Active'), t('Disabled')),
+ ),
),
- ),
- 'filter' => array(
- 'handler' => 'views_handler_filter_boolean_operator',
- 'label' => t('Active'),
- 'type' => 'yes-no',
- ),
- 'sort' => array(
- 'handler' => 'views_handler_sort',
- ),
- );
+ 'filter' => array(
+ 'handler' => 'views_handler_filter_boolean_operator',
+ 'label' => t('Active'),
+ 'type' => 'yes-no',
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort',
+ ),
+ );
// Show the operations using CTools dropbutton menu.
$data['commerce_discount']['operations_dropbutton'] = array(
@@ -52,3 +52,163 @@ class CommerceDiscountViewsController extends EntityDefaultViewsController {
}
}
+
+/**
+ * Implements hook_views_data_alter().
+ */
+function commerce_discount_views_data_alter(&$data) {
+ if (isset($data['commerce_discount'])) {
+
+ // Usage analytics field.
+ $data['commerce_discount']['commerce_discount_usage'] = array(
+ 'title' => t('Analytics'),
+ 'help' => t('Show discount usage and usage limit.'),
+ 'field' => array(
+ 'handler' => 'commerce_discount_handler_field_commerce_discount_analytics',
+ ),
+ 'real field' => 'discount_id',
+ );
+
+ // Usage relationship.
+ $data['commerce_discount']['discount_usage'] = array(
+ 'relationship' => array(
+ 'title' => t('Discount usage'),
+ 'label' => t('Discount usage'),
+ 'help' => t('Relate this discount to its usage statistics.'),
+ 'handler' => 'views_handler_relationship',
+ 'base' => 'commerce_discount_usage',
+ 'base field' => 'discount',
+ 'field' => 'name',
+ ),
+ );
+ }
+
+ // Order table: discount usage relationship.
+ if (isset($data['commerce_order'])) {
+ $data['commerce_order']['discount_usage'] = array(
+ 'relationship' => array(
+ 'title' => t('Discount usage'),
+ 'label' => t('Discount usage'),
+ 'help' => t('Relate this order to its discount usage statistics.'),
+ 'handler' => 'views_handler_relationship',
+ 'base' => 'commerce_discount_usage',
+ 'base field' => 'order_id',
+ 'field' => 'order_id',
+ ),
+ );
+ }
+
+ // User table: discount usage relationship.
+ $data['users']['discount_usage'] = array(
+ 'relationship' => array(
+ 'title' => t('Discount usage'),
+ 'label' => t('Discount usage'),
+ 'help' => t('Relate this user to its discount usage statistics.'),
+ 'handler' => 'views_handler_relationship',
+ 'base' => 'commerce_discount_usage',
+ 'base field' => 'mail',
+ 'field' => 'mail',
+ ),
+ );
+}
+
+/**
+ * Implements hook_views_data().
+ */
+function commerce_discount_usage_views_data() {
+ $data = array();
+ $data['commerce_discount_usage']['table']['group'] = t('Commerce discount usage');
+
+ // Base table.
+ $data['commerce_discount_usage']['table']['base'] = array(
+ 'field' => 'mail',
+ 'title' => t('Commerce Discount Usage'),
+ 'help' => t('Usage statistics about discounts.'),
+ );
+
+ // Discount name.
+ $data['commerce_discount_usage']['discount'] = array(
+ 'title' => t('Discount'),
+ 'help' => t('The unique human-readable identifier of the discount.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field',
+ 'click sortable' => TRUE,
+ ),
+ 'filter' => array(
+ 'handler' => 'views_handler_filter_string',
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort',
+ ),
+ 'argument' => array(
+ 'handler' => 'views_handler_argument_string',
+ ),
+ 'relationship' => array(
+ 'title' => t('Discount'),
+ 'label' => t('Discount'),
+ 'help' => t('Relate a usage statistics record to its discount.'),
+ 'handler' => 'views_handler_relationship',
+ 'base' => 'commerce_discount',
+ 'base field' => 'name',
+ 'field' => 'discount',
+ ),
+ );
+
+ // Customer mail.
+ $data['commerce_discount_usage']['mail'] = array(
+ 'title' => t('User'),
+ 'help' => t('The email address of the customer who used the discount.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field',
+ 'click sortable' => TRUE,
+ ),
+ 'filter' => array(
+ 'handler' => 'views_handler_filter_string',
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort',
+ ),
+ 'argument' => array(
+ 'handler' => 'views_handler_argument_string',
+ ),
+ 'relationship' => array(
+ 'title' => t('Customer email'),
+ 'label' => t('Customer email'),
+ 'help' => t('Relate a usage statistics record to its user.'),
+ 'handler' => 'views_handler_relationship',
+ 'base' => 'users',
+ 'base field' => 'mail',
+ 'field' => 'mail',
+ ),
+ );
+
+ // Order ID.
+ $data['commerce_discount_usage']['order_id'] = array(
+ 'title' => t('Order ID'),
+ 'help' => t('The unique internal identifier of the order where the discount was used.'),
+ 'field' => array(
+ 'handler' => 'commerce_order_handler_field_order',
+ 'click sortable' => TRUE,
+ ),
+ 'filter' => array(
+ 'handler' => 'views_handler_filter_numeric',
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort',
+ ),
+ 'argument' => array(
+ 'handler' => 'commerce_order_handler_argument_order_order_id',
+ ),
+ 'relationship' => array(
+ 'title' => t('Order'),
+ 'label' => t('Order'),
+ 'help' => t('Relate a usage statistics record to its order.'),
+ 'handler' => 'views_handler_relationship',
+ 'base' => 'commerce_order',
+ 'base field' => 'order_id',
+ 'field' => 'order_id',
+ ),
+ );
+
+ return $data;
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/views/commerce_discount.views_default.inc b/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/views/commerce_discount.views_default.inc
index cd77219f..09638c1b 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/views/commerce_discount.views_default.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/views/commerce_discount.views_default.inc
@@ -30,15 +30,29 @@ function commerce_discount_views_default_views() {
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['query']['options']['query_comment'] = FALSE;
$handler->display->display_options['exposed_form']['type'] = 'basic';
+ $handler->display->display_options['exposed_form']['options']['reset_button'] = TRUE;
+ $handler->display->display_options['exposed_form']['options']['autosubmit'] = TRUE;
$handler->display->display_options['pager']['type'] = 'full';
+ $handler->display->display_options['pager']['options']['items_per_page'] = '25';
+ $handler->display->display_options['pager']['options']['offset'] = '0';
+ $handler->display->display_options['pager']['options']['id'] = '0';
+ $handler->display->display_options['pager']['options']['quantity'] = '9';
$handler->display->display_options['style_plugin'] = 'table';
+ $handler->display->display_options['style_options']['grouping'] = array(
+ 0 => array(
+ 'field' => 'status',
+ 'rendered' => 1,
+ 'rendered_strip' => 0,
+ ),
+ );
$handler->display->display_options['style_options']['columns'] = array(
'label' => 'label',
'type_1' => 'type_1',
'type' => 'type',
- 'status' => 'status',
+ 'commerce_discount_usage' => 'commerce_discount_usage',
'commerce_discount_date' => 'commerce_discount_date',
'commerce_discount_date_1' => 'commerce_discount_date_1',
+ 'status' => 'status',
'operations_dropbutton' => 'operations_dropbutton',
);
$handler->display->display_options['style_options']['default'] = '-1';
@@ -69,23 +83,23 @@ function commerce_discount_views_default_views() {
'separator' => '',
'empty_column' => 0,
),
- 'status' => array(
+ 'commerce_discount_date' => array(
'sortable' => 1,
- 'default_sort_order' => 'desc',
+ 'default_sort_order' => 'asc',
'align' => '',
'separator' => '',
'empty_column' => 0,
),
- 'commerce_discount_date' => array(
+ 'commerce_discount_date_1' => array(
'sortable' => 1,
'default_sort_order' => 'asc',
'align' => '',
'separator' => '',
'empty_column' => 0,
),
- 'commerce_discount_date_1' => array(
+ 'status' => array(
'sortable' => 1,
- 'default_sort_order' => 'asc',
+ 'default_sort_order' => 'desc',
'align' => '',
'separator' => '',
'empty_column' => 0,
@@ -97,56 +111,88 @@ function commerce_discount_views_default_views() {
),
);
$handler->display->display_options['style_options']['empty_table'] = TRUE;
-
/* No results behavior: Global: Text area */
$handler->display->display_options['empty']['area']['id'] = 'area';
$handler->display->display_options['empty']['area']['table'] = 'views';
$handler->display->display_options['empty']['area']['field'] = 'area';
$handler->display->display_options['empty']['area']['content'] = 'No discounts found.';
-
/* Relationship: Entity Reference: Referenced Entity */
$handler->display->display_options['relationships']['commerce_discount_offer_target_id']['id'] = 'commerce_discount_offer_target_id';
$handler->display->display_options['relationships']['commerce_discount_offer_target_id']['table'] = 'field_data_commerce_discount_offer';
$handler->display->display_options['relationships']['commerce_discount_offer_target_id']['field'] = 'commerce_discount_offer_target_id';
$handler->display->display_options['relationships']['commerce_discount_offer_target_id']['required'] = TRUE;
- /* Field: Commerce Discount: Label */
+ /* Field: Commerce Discount: Admin title */
$handler->display->display_options['fields']['label']['id'] = 'label';
$handler->display->display_options['fields']['label']['table'] = 'commerce_discount';
$handler->display->display_options['fields']['label']['field'] = 'label';
- $handler->display->display_options['fields']['label']['label'] = 'Name';
/* Field: Commerce Discount Offer: Type */
$handler->display->display_options['fields']['type_1']['id'] = 'type_1';
$handler->display->display_options['fields']['type_1']['table'] = 'commerce_discount_offer';
$handler->display->display_options['fields']['type_1']['field'] = 'type';
$handler->display->display_options['fields']['type_1']['relationship'] = 'commerce_discount_offer_target_id';
- $handler->display->display_options['fields']['type_1']['label'] = 'Offer';
- /* Field: Commerce Discount: Type */
- $handler->display->display_options['fields']['type']['id'] = 'type';
- $handler->display->display_options['fields']['type']['table'] = 'commerce_discount';
- $handler->display->display_options['fields']['type']['field'] = 'type';
- $handler->display->display_options['fields']['type']['alter']['alter_text'] = TRUE;
- $handler->display->display_options['fields']['type']['alter']['text'] = '[type]';
+ $handler->display->display_options['fields']['type_1']['label'] = 'Offer type';
+ /* Field: Commerce Discount: Discount dates */
+ $handler->display->display_options['fields']['commerce_discount_date']['id'] = 'commerce_discount_date';
+ $handler->display->display_options['fields']['commerce_discount_date']['table'] = 'field_data_commerce_discount_date';
+ $handler->display->display_options['fields']['commerce_discount_date']['field'] = 'commerce_discount_date';
+ $handler->display->display_options['fields']['commerce_discount_date']['label'] = 'Valid dates';
+ $handler->display->display_options['fields']['commerce_discount_date']['empty'] = 'Any';
+ $handler->display->display_options['fields']['commerce_discount_date']['settings'] = array(
+ 'format_type' => 'short',
+ 'custom_date_format' => '',
+ 'fromto' => 'both',
+ 'multiple_number' => '',
+ 'multiple_from' => '',
+ 'multiple_to' => '',
+ 'show_remaining_days' => 0,
+ );
+ /* Field: Commerce Discount: Analytics */
+ $handler->display->display_options['fields']['commerce_discount_usage']['id'] = 'commerce_discount_usage';
+ $handler->display->display_options['fields']['commerce_discount_usage']['table'] = 'commerce_discount';
+ $handler->display->display_options['fields']['commerce_discount_usage']['field'] = 'commerce_discount_usage';
/* Field: Commerce Discount: Status */
$handler->display->display_options['fields']['status']['id'] = 'status';
$handler->display->display_options['fields']['status']['table'] = 'commerce_discount';
$handler->display->display_options['fields']['status']['field'] = 'status';
+ $handler->display->display_options['fields']['status']['exclude'] = TRUE;
$handler->display->display_options['fields']['status']['type'] = 'active-disabled';
$handler->display->display_options['fields']['status']['not'] = 0;
+ /* Field: Commerce Discount: Sort order */
+ $handler->display->display_options['fields']['sort_order']['id'] = 'sort_order';
+ $handler->display->display_options['fields']['sort_order']['table'] = 'commerce_discount';
+ $handler->display->display_options['fields']['sort_order']['field'] = 'sort_order';
/* Field: Commerce Discount: Operations */
$handler->display->display_options['fields']['operations_dropbutton']['id'] = 'operations_dropbutton';
$handler->display->display_options['fields']['operations_dropbutton']['table'] = 'commerce_discount';
$handler->display->display_options['fields']['operations_dropbutton']['field'] = 'operations_dropbutton';
- /* Filter criterion: Commerce Discount: Label */
- $handler->display->display_options['filters']['label']['id'] = 'label';
- $handler->display->display_options['filters']['label']['table'] = 'commerce_discount';
- $handler->display->display_options['filters']['label']['field'] = 'label';
- $handler->display->display_options['filters']['label']['operator'] = 'contains';
- $handler->display->display_options['filters']['label']['group'] = 1;
- $handler->display->display_options['filters']['label']['exposed'] = TRUE;
- $handler->display->display_options['filters']['label']['expose']['operator_id'] = 'label_op';
- $handler->display->display_options['filters']['label']['expose']['label'] = 'Name';
- $handler->display->display_options['filters']['label']['expose']['operator'] = 'label_op';
- $handler->display->display_options['filters']['label']['expose']['identifier'] = 'label';
+ /* Sort criterion: Commerce Discount: Status */
+ $handler->display->display_options['sorts']['status']['id'] = 'status';
+ $handler->display->display_options['sorts']['status']['table'] = 'commerce_discount';
+ $handler->display->display_options['sorts']['status']['field'] = 'status';
+ $handler->display->display_options['sorts']['status']['order'] = 'DESC';
+ /* Sort criterion: Commerce Discount: Sort order */
+ $handler->display->display_options['sorts']['sort_order']['id'] = 'sort_order';
+ $handler->display->display_options['sorts']['sort_order']['table'] = 'commerce_discount';
+ $handler->display->display_options['sorts']['sort_order']['field'] = 'sort_order';
+ /* Filter criterion: Commerce Discount: Type */
+ $handler->display->display_options['filters']['type']['id'] = 'type';
+ $handler->display->display_options['filters']['type']['table'] = 'commerce_discount';
+ $handler->display->display_options['filters']['type']['field'] = 'type';
+ $handler->display->display_options['filters']['type']['value'] = array(
+ 'product_discount' => 'product_discount',
+ );
+ $handler->display->display_options['filters']['type']['group'] = 1;
+ $handler->display->display_options['filters']['type']['exposed'] = TRUE;
+ $handler->display->display_options['filters']['type']['expose']['operator_id'] = 'type_op';
+ $handler->display->display_options['filters']['type']['expose']['label'] = 'Discount type';
+ $handler->display->display_options['filters']['type']['expose']['operator'] = 'type_op';
+ $handler->display->display_options['filters']['type']['expose']['identifier'] = 'type';
+ $handler->display->display_options['filters']['type']['expose']['required'] = TRUE;
+ $handler->display->display_options['filters']['type']['expose']['remember_roles'] = array(
+ 2 => '2',
+ 1 => 0,
+ 3 => 0,
+ );
/* Filter criterion: Commerce Discount Offer: Type */
$handler->display->display_options['filters']['type_1']['id'] = 'type_1';
$handler->display->display_options['filters']['type_1']['table'] = 'commerce_discount_offer';
@@ -155,54 +201,13 @@ function commerce_discount_views_default_views() {
$handler->display->display_options['filters']['type_1']['group'] = 1;
$handler->display->display_options['filters']['type_1']['exposed'] = TRUE;
$handler->display->display_options['filters']['type_1']['expose']['operator_id'] = 'type_1_op';
- $handler->display->display_options['filters']['type_1']['expose']['label'] = 'Offer';
+ $handler->display->display_options['filters']['type_1']['expose']['label'] = 'Offer type';
$handler->display->display_options['filters']['type_1']['expose']['operator'] = 'type_1_op';
$handler->display->display_options['filters']['type_1']['expose']['identifier'] = 'type_1';
- /* Filter criterion: Commerce Discount: Type */
- $handler->display->display_options['filters']['type']['id'] = 'type';
- $handler->display->display_options['filters']['type']['table'] = 'commerce_discount';
- $handler->display->display_options['filters']['type']['field'] = 'type';
- $handler->display->display_options['filters']['type']['group'] = 1;
- $handler->display->display_options['filters']['type']['exposed'] = TRUE;
- $handler->display->display_options['filters']['type']['expose']['operator_id'] = 'type_op';
- $handler->display->display_options['filters']['type']['expose']['label'] = 'Type';
- $handler->display->display_options['filters']['type']['expose']['operator'] = 'type_op';
- $handler->display->display_options['filters']['type']['expose']['identifier'] = 'type';
- /* Filter criterion: Commerce Discount: Status */
- $handler->display->display_options['filters']['status']['id'] = 'status';
- $handler->display->display_options['filters']['status']['table'] = 'commerce_discount';
- $handler->display->display_options['filters']['status']['field'] = 'status';
- $handler->display->display_options['filters']['status']['value'] = 'All';
- $handler->display->display_options['filters']['status']['exposed'] = TRUE;
- $handler->display->display_options['filters']['status']['expose']['operator_id'] = '';
- $handler->display->display_options['filters']['status']['expose']['label'] = 'Active';
- $handler->display->display_options['filters']['status']['expose']['operator'] = 'status_op';
- $handler->display->display_options['filters']['status']['expose']['identifier'] = 'status';
- $translatables['commerce_discount_overview'] = array(
- t('Master'),
- t('more'),
- t('Apply'),
- t('Reset'),
- t('Sort by'),
- t('Asc'),
- t('Desc'),
- t('Items per page'),
- t('- All -'),
- t('Offset'),
- t('« first'),
- t('‹ previous'),
- t('next ›'),
- t('last »'),
- t('No discounts found.'),
- t('Commerce Discount Offer entity referenced from commerce_discount_offer'),
- t('Name'),
- t('Offer'),
- t('Type'),
- t('[type]'),
- t('Status'),
- t('Operations'),
- t('Name'),
- t('Active'),
+ $handler->display->display_options['filters']['type_1']['expose']['remember_roles'] = array(
+ 2 => '2',
+ 1 => 0,
+ 3 => 0,
);
$views['commerce_discount_overview'] = $view;
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/includes/views/handlers/commerce_discount_usage_handler_field_commerce_discount_analytics.inc b/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/views/handlers/commerce_discount_handler_field_commerce_discount_analytics.inc
similarity index 71%
rename from profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/includes/views/handlers/commerce_discount_usage_handler_field_commerce_discount_analytics.inc
rename to profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/views/handlers/commerce_discount_handler_field_commerce_discount_analytics.inc
index 48a5adb6..7521ec71 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/includes/views/handlers/commerce_discount_usage_handler_field_commerce_discount_analytics.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/views/handlers/commerce_discount_handler_field_commerce_discount_analytics.inc
@@ -1,11 +1,19 @@
additional_fields['discount_id'] = 'discount_id';
@@ -13,7 +21,10 @@ class commerce_discount_usage_handler_field_commerce_discount_analytics extends
$this->real_field = 'discount_id';
}
- function render($values) {
+ /**
+ * {@inheritdoc}
+ */
+ public function render($values) {
// Wrap the discount entity found.
$wrapper = entity_metadata_wrapper('commerce_discount', entity_load_single('commerce_discount', $this->get_value($values, 'discount_id')));
@@ -23,9 +34,10 @@ class commerce_discount_usage_handler_field_commerce_discount_analytics extends
'items' => array(
$wrapper->discount_usage_limit->value() ? t('@max available', array('@max' => $wrapper->discount_usage_limit->value())) : t('Unlimited'),
$wrapper->discount_usage_per_person->value() ? t('Limit @max per customer', array('@max' => $wrapper->discount_usage_per_person->value())) : t('Unlimited usage per customer'),
- t('Used @used times', array('@used' => commerce_discount_usage_get_usage($wrapper->name->value())))
- )
+ t('Used @used times', array('@used' => commerce_discount_usage_get_usage($wrapper->name->value()))),
+ ),
)
);
}
+
}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/views/handlers/commerce_discount_handler_field_operations_dropbutton.inc b/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/views/handlers/commerce_discount_handler_field_operations_dropbutton.inc
index 8d290692..0009c437 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/views/handlers/commerce_discount_handler_field_operations_dropbutton.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/includes/views/handlers/commerce_discount_handler_field_operations_dropbutton.inc
@@ -1,11 +1,19 @@
additional_fields['discount_id'] = 'discount_id';
@@ -13,7 +21,10 @@ class commerce_discount_handler_field_operations_dropbutton extends views_handle
$this->real_field = 'discount_id';
}
- function render($values) {
+ /**
+ * {@inheritdoc}
+ */
+ public function render($values) {
// Load the line item and return its title.
$discount_id = $this->get_value($values, 'discount_id');
$commerce_discount = entity_load_single('commerce_discount', $discount_id);
@@ -21,7 +32,7 @@ class commerce_discount_handler_field_operations_dropbutton extends views_handle
$entity_info = entity_get_info('commerce_discount');
$path = $entity_info['admin ui']['path'] . '/manage';
- // Preapre the links.
+ // Prepare the links.
$links = array();
$links[] = array(
'href' => $path . '/' . $commerce_discount->name,
@@ -53,6 +64,14 @@ class commerce_discount_handler_field_operations_dropbutton extends views_handle
'title' => t('export'),
);
+ if (module_exists('i18n_string')) {
+ $links[] = array(
+ 'href' => $path . '/' . $commerce_discount->name . '/translate',
+ 'title' => t('translate'),
+ );
+ }
+
return theme('links__ctools_dropbutton', array('links' => $links));
}
+
}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/js/commerce_discount.js b/profiles/commerce_kickstart/modules/contrib/commerce_discount/js/commerce_discount.js
index a9e069df..3a083150 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/js/commerce_discount.js
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/js/commerce_discount.js
@@ -1,12 +1,108 @@
-(function ($) {
-
-Drupal.behaviors.commerceDiscount = {};
-Drupal.behaviors.commerceDiscount.attach = function(context) {
- $('input:radio').change(function() {
- $('input:radio:not(:checked)').closest('div').removeClass('selected');
- $(this).closest('div').addClass('selected');
- })
- .filter(':checked').closest('div').addClass('selected');
-};
-
-})(jQuery);
+/**
+ * @file
+ * Commerce discount admin helper.
+ */
+
+(function ($, Drupal) {
+ Drupal.behaviors.commerceDiscount = {};
+ Drupal.behaviors.commerceDiscount.attach = function(context) {
+ $('input:radio').change(function() {
+ $('input:radio:not(:checked)').closest('div').removeClass('selected');
+ $(this).closest('div').addClass('selected');
+ }).filter(':checked').closest('div').addClass('selected');
+
+ // Provide the vertical tab summaries.
+ $('fieldset#edit-commerce-discount-fields-additional-settings-discount-options', context).drupalSetSummary(function(context) {
+ var values = [];
+ $("input[name^='status']:checked", context).parent().each(function() {
+ values.push(Drupal.checkPlain($(this).text().trim()));
+ });
+ values.push(Drupal.t("Sort order: @Sort order", {'@Sort order': $("select[name^='sort_order'] option:selected").val()}));
+ return values.join(', ');
+ });
+ $('fieldset#edit-commerce-discount-fields-additional-settings-commerce-discount-compatibility', context).drupalSetSummary(function(context) {
+ var values = [],
+ value;
+
+ value = $('input[name="commerce_discount_fields[commerce_compatibility_strategy][und]"]:checked', context).val();
+ if (value == 'any') {
+ return Drupal.t('Compatible with all');
+ }
+ else if (value == 'only' || value == 'except') {
+ selected = $('input[name^="commerce_discount_fields[commerce_compatibility_selection]"][name$="[target_id]"]', context).each(function (context) {
+ var ruleName = Drupal.checkPlain($(this).val().replace(/ \(\d+\)/, '').trim());
+ if (ruleName != '') {
+ values.push(ruleName);
+ }
+ });
+ if (value == 'only') {
+ if (values.length == 0) {
+ return Drupal.t('Incompatible with all');
+ }
+ else if (values.length == 1) {
+ return Drupal.t('Only with @selected', {'@selected': values.shift()});
+ }
+ else {
+ return Drupal.t('Only with @selected and @remaining more...', {'@selected': values.shift(), '@remaining': values.length});
+ }
+ }
+ else {
+ if (values.length == 0) {
+ return Drupal.t('Compatible with all');
+ }
+ else if (values.length == 1) {
+ return Drupal.t('All except @selected', {'@selected': values.shift()});
+ }
+ else {
+ return Drupal.t('All except @selected and @remaining more...', {'@selected': values.shift(), '@remaining': values.length});
+ }
+ }
+ }
+ else if (value == 'none') {
+ return Drupal.t('Incompatible with all');
+ }
+ });
+ $('fieldset#edit-commerce-discount-fields-additional-settings-discount-date', context).drupalSetSummary(function(context) {
+ var fromDate,
+ toDate,
+ fromDateTS,
+ toDateTS;
+
+ fromDate = $('input[name="commerce_discount_fields[commerce_discount_date][und][0][value][date]"]').val();
+ fromDateTS = fromDate ? new Date(fromDate) : 0;
+ toDate = $('input[name="commerce_discount_fields[commerce_discount_date][und][0][value2][date]"]').val();
+ toDateTS = toDate ? new Date(toDate) : 0;
+
+ options = {
+ '!from': fromDateTS < Date.now() ? Drupal.t('Started') : Drupal.t('Starts'),
+ '!to': toDateTS < Date.now() ? Drupal.t('Ended') : Drupal.t('Ends'),
+ '@fromDate': fromDate,
+ '@toDate': toDate
+ };
+
+ if (fromDate && toDate) {
+ options['!to'] = options['!to'].toLowerCase();
+ return Drupal.t('!from @fromDate and !to @toDate', options);
+ }
+ else if (fromDate && !toDate) {
+ return Drupal.t('!from @fromDate', options);
+ }
+ else if (!fromDate && toDate) {
+ return Drupal.t('!to @toDate', options);
+ }
+ else {
+ return Drupal.t('Always active');
+ }
+ });
+ $('fieldset#edit-commerce-discount-fields-additional-settings-commerce-discount-usage', context).drupalSetSummary(function(context) {
+ var usagePerPerson = $('input[name="commerce_discount_fields[discount_usage_per_person][und][0][value]"]').val(),
+ overallUsage = $('input[name="commerce_discount_fields[discount_usage_limit][und][0][value]"]').val(),
+ values = [];
+
+ values.push(Drupal.t('!usagePerPerson per person', {'!usagePerPerson': usagePerPerson > 0 ? Drupal.checkPlain(usagePerPerson) : '∞'}));
+ values.push(Drupal.t('!overallUsage total', {'!overallUsage': overallUsage > 0 ? Drupal.checkPlain(overallUsage) : '∞'}));
+
+ return values.join(', ');
+ });
+ };
+}(jQuery, Drupal));
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/commerce_discount_date.info b/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/commerce_discount_date.info
deleted file mode 100644
index fc121f8a..00000000
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/commerce_discount_date.info
+++ /dev/null
@@ -1,19 +0,0 @@
-name = Commerce Discount Date
-description = Provides date fields for the Commerce discount entity.
-core = 7.x
-package = Commerce (contrib)
-
-dependencies[] = commerce_discount
-dependencies[] = date
-dependencies[] = date_popup
-
-; Simple tests
-files[] = commerce_discount_date.test
-
-
-; Information added by drush on 2015-08-20
-version = "7.x-1.0-alpha5+0-dev"
-core = "7.x"
-project = "commerce_discount"
-datestamp = "1440110608"
-
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/commerce_discount_date.install b/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/commerce_discount_date.install
deleted file mode 100644
index e4b7e89b..00000000
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/commerce_discount_date.install
+++ /dev/null
@@ -1,43 +0,0 @@
- array('commerce_discount'),
- 'settings' => array(
- 'granularity' => array(
- 'month' => 'month',
- 'day' => 'day',
- 'year' => 'year',
- ),
- 'tz_handling' => 'none',
- 'timezone_db' => '',
- 'todate' => 'optional',
- 'handler' => 'base',
- 'target_type' => 'commerce_discount',
- 'handler_settings' => array(
- 'target_bundles' => array(),
- ),
- ),
- 'field_name' => 'commerce_discount_date',
- 'type' => 'datestamp',
- 'locked' => TRUE,
- );
- field_create_field($field);
-}
-
-/**
- * Implements hook_uninstall().
- */
-function commerce_discount_date_uninstall() {
- field_delete_field('commerce_discount_date');
-}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/commerce_discount_date.module b/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/commerce_discount_date.module
deleted file mode 100644
index 7c3ae6fa..00000000
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/commerce_discount_date.module
+++ /dev/null
@@ -1,99 +0,0 @@
- $value) {
- if (!field_info_instance('commerce_discount', 'commerce_discount_date', $type)) {
- $instance = array(
- 'field_name' => 'commerce_discount_date',
- 'entity_type' => 'commerce_discount',
- 'bundle' => $type,
- 'label' => t('Discount dates'),
- 'widget' => array(
- 'module' => 'date',
- 'type' => 'date_popup',
- 'weight' => -11,
- ),
- 'settings' => array(
- 'default_value' => 'blank',
- 'default_value2' => 'blank',
- ),
- );
- field_create_instance($instance);
- }
- }
-}
-
-/**
- * Implements hook_views_api().
- */
-function commerce_discount_date_views_api($module, $api) {
- if ($module == 'views') {
- return array(
- 'version' => 2,
- 'path' => drupal_get_path('module', 'commerce_discount_date') . '/includes/views',
- );
- }
-}
-
-/**
- * Implements hook_form_FORM_ID_alter().
- */
-function commerce_discount_date_form_commerce_discount_form_alter(&$form, $form_state) {
- $form['commerce_discount_fields']['commerce_discount_date']['#after_build'][] = 'commerce_discount_date_after_build';
-}
-
-/**
- * After-build callback for altering the date field.
- *
- * @param $element
- * The date field.
- *
- * @return
- * The altered date field.
- */
-function commerce_discount_date_after_build($element, $form_state) {
- // Reset the titles.
- $element[LANGUAGE_NONE][0]['value']['#title'] = t('Start date');
- $element[LANGUAGE_NONE][0]['value2']['#title'] = t('End date');
- $element[LANGUAGE_NONE][0]['value']['date']['#title'] = '';
- $element[LANGUAGE_NONE][0]['value']['time']['#title'] = '';
- $element[LANGUAGE_NONE][0]['value2']['date']['#title'] = '';
- $element[LANGUAGE_NONE][0]['value2']['time']['#title'] = '';
- $element[LANGUAGE_NONE][0]['#fieldset_description'] = '';
-
- // Ignore the "Show end date" checkbox.
- unset($element[LANGUAGE_NONE][0]['value2']['#states']);
-
- // Check the "show end date" checkbox.
- $element[LANGUAGE_NONE][0]['show_todate']['#checked'] = TRUE;
-
- return $element;
-}
-
-/**
- * Implements hook_commerce_discount_rule_build().
- */
-function commerce_discount_date_commerce_discount_rule_build($rule, $discount) {
- $wrapper = entity_metadata_wrapper('commerce_discount', $discount);
- if (!$wrapper->commerce_discount_date->value()) {
- // No need to add a condition.
- return;
- }
-
- // Add condition to check usage didn't reach max uses.
- $rule->condition('commerce_discount_date_condition', array(
- 'commerce_discount' => $discount->name,
- ));
-}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/commerce_discount_date.rules.inc b/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/commerce_discount_date.rules.inc
deleted file mode 100644
index bed6296b..00000000
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/commerce_discount_date.rules.inc
+++ /dev/null
@@ -1,38 +0,0 @@
- t('Check discount dates'),
- 'group' => t('Commerce Discount'),
- 'parameter' => array(
- 'commerce_discount' => array(
- 'label' => t('Commerce Discount'),
- 'type' => 'token',
- 'options list' => 'commerce_discount_entity_list',
- ),
- ),
- 'base' => 'commerce_discount_date_condition',
- );
-
- return $items;
-}
-
-/**
- * Rules condition: Check discount can be applied.
- */
-function commerce_discount_date_condition($discount_name) {
- $wrapper = entity_metadata_wrapper('commerce_discount', $discount_name);
- $time = time();
- return $time >= $wrapper->commerce_discount_date->value->value() && $time <= $wrapper->commerce_discount_date->value2->value();
-}
-
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/commerce_discount_date.test b/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/commerce_discount_date.test
deleted file mode 100644
index 00e5d9fc..00000000
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/commerce_discount_date.test
+++ /dev/null
@@ -1,254 +0,0 @@
- 'Discounts date',
- 'description' => 'Test discounts date UI and functionality',
- 'group' => 'Commerce discounts',
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function setUp() {
- parent::setUp();
- }
-
- /**
- * Test date specific elements in the add discount UI.
- */
- public function testDiscountDateUIAddDiscount() {
- // Login with store admin.
- $this->drupalLogin($this->store_admin);
-
- // Access to the admin discount creation page.
- $this->drupalGet('admin/commerce/store/discounts/add');
-
- // Check the integrity of the add form.
- $this->assertFieldByName('commerce_discount_fields[commerce_discount_date][und][0][value][date]', NULL, t('Start date field is present'));
- $this->assertFieldByName('commerce_discount_fields[commerce_discount_date][und][0][value2][date]', NULL, t('End date field is present'));
-
- // Create a discount valid from yesterday until tomorrow.
- $date_format = 'm/d/Y';
- $start_time = time() - 86400;
- $start_date = date($date_format, $start_time);
- $end_time = time() + 86400;
- $end_date = date($date_format, $end_time);
-
- $values = array(
- 'label' => 'Order discount - fixed',
- 'name' => 'order_discount_fixed',
- 'component_title' => 'Order discount',
- 'commerce_discount_fields[commerce_discount_offer][und][form][commerce_fixed_amount][und][0][amount]' => 12.77,
- 'commerce_discount_fields[commerce_discount_date][und][0][value][date]' => $start_date,
- 'commerce_discount_fields[commerce_discount_date][und][0][value2][date]' => $end_date,
- );
- $this->drupalPost(NULL, $values, t('Save discount'));
-
- // Load the discount and wrap it.
- $discount = entity_load_single('commerce_discount', 1);
- $wrapper = entity_metadata_wrapper('commerce_discount', $discount);
-
- // Check the usage fields of the stored discount.
- $this->assertTrue(date($date_format, $wrapper->commerce_discount_date->value->value()) == $start_date, t('Start date is stored correctly.'));
- $this->assertTrue(date($date_format, $wrapper->commerce_discount_date->value2->value()) == $end_date, t('End date is stored correctly.'));
-
- // // Check the discounts listing
- // $this->assertText($start_date, t('Start date is shown'));
- // $this->assertText($end_date, t('End date is shown'));
- }
-
- /**
- * Test the Edit discount UI.
- */
- public function testDiscountDateUIEditDiscount() {
- // Create a discount valid from yesterday until tomorrow.
- $start_time = time() - 86400;
- $end_time = time() + 86400;
- $discount = $this->createDateDiscount('order_discount', 'fixed_amount', 300, $start_time, $end_time);
-
- // Login with store admin.
- $this->drupalLogin($this->store_admin);
-
- // Access to the admin discount edit page.
- $this->drupalGet('admin/commerce/store/discounts/manage/' . $discount->name);
-
- // Check the integrity of the add form.
- $this->assertFieldByName('commerce_discount_fields[commerce_discount_date][und][0][value][date]', NULL, t('Start date field is present'));
- $this->assertFieldByName('commerce_discount_fields[commerce_discount_date][und][0][value2][date]', NULL, t('End date field is present'));
-
- // Try to save the product and check validation messages.
- $this->drupalPost(NULL, array(), t('Save discount'));
-
- // Change the discount date, to be valid from tomorrow.
- $date_format = 'm/d/Y';
- $start_time = time() + 86400;
- $start_date = date($date_format, $start_time);
- $end_time = time() + 2 * 86400;
- $end_date = date($date_format, $end_time);
-
- $values = array(
- 'label' => 'Order discount - fixed',
- 'name' => 'order_discount_fixed',
- 'component_title' => 'Order discount',
- 'commerce_discount_fields[commerce_discount_offer][und][form][commerce_fixed_amount][und][0][amount]' => 12.77,
- 'commerce_discount_fields[commerce_discount_date][und][0][value][date]' => $start_date,
- 'commerce_discount_fields[commerce_discount_date][und][0][value2][date]' => $end_date,
- );
-
- // $this->drupalPost(NULL, $values, t('Save discount'));
-
- // Load the discount and wrap it.
- $discount = entity_load_single('commerce_discount', 1);
- $wrapper = entity_metadata_wrapper('commerce_discount', $discount);
-
- // // Check the usage fields of the stored discount.
- // $this->assertTrue(date($date_format, $wrapper->commerce_discount_date->value->value()) == $start_date, t('Start date is stored correctly.'));
- // $this->assertTrue(date($date_format, $wrapper->commerce_discount_date->value2->value()) == $end_date, t('End date is stored correctly.'));
-
- // // Check the discounts listing
- // $this->assertText($start_date, t('Start date is shown'));
- // $this->assertText($end_date, t('End date is shown'));
- }
-
- /**
- * Test order discount in timespan.
- */
- public function testDiscountDateOrderDiscountInTime() {
- // Create a discount valid from yesterday until tomorrow.
- $start_time = time() - 86400;
- $end_time = time() + 86400;
-
- // Testing fixed discount.
- $discount = $this->createDateDiscount('order_discount', 'fixed_amount', 300, $start_time, $end_time);
-
- // Create an order.
- $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'complete');
- $wrapper = entity_metadata_wrapper('commerce_order', $order);
-
- // Recalculate discounts.
- commerce_cart_order_refresh($order);
-
- // Check if the discount was applied on the order total price.
- $this->assertTrue($wrapper->commerce_order_total->amount->value() == 700, t('Order discount is deducted when in time frame.'));
- }
-
- /**
- * Test order discount out of timespan.
- */
- public function testDiscountDateOrderDiscountOutOfTime() {
-
- // Create a discount valid from tomorrow.
- $start_time = time() + 86400;
- $end_time = time() + 2 * 86400;
-
- // Testing fixed discount.
- // Create a fixed order discount of $3 limited to one use.
- $discount = $this->createDateDiscount('order_discount', 'fixed_amount', 300, $start_time, $end_time);
-
- // Create an order.
- $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'complete');
- $wrapper = entity_metadata_wrapper('commerce_order', $order);
- // Check if the discount was applied on the order total price.
- $this->assertTrue($wrapper->commerce_order_total->amount->value() == 1000, t('Order discount is ignored when out of time frame.'));
- }
-
- /**
- * Test product discount in timespan.
- */
- public function testDiscountDateProductDiscountInTime() {
- // Create a discount valid from yesterday until tomorrow.
- $start_time = time() - 86400;
- $end_time = time() + 86400;
-
- $discount = $this->createDateDiscount('product_discount', 'fixed_amount', 300, $start_time, $end_time);
-
- // Create an order.
- $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'complete');
- $wrapper = entity_metadata_wrapper('commerce_order', $order);
- // Invoke line item price re-calculation.
- $line_item = $wrapper->commerce_line_items->get(0)->value();
- rules_invoke_event('commerce_product_calculate_sell_price', $line_item);
- // Check if the discount was added as a component to the line item.
- $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
- $price_data = $line_item_wrapper->commerce_unit_price->data->value();
- $this->assertTrue($price_data['components'][1]['price']['amount'] == -300, t('Product discount is applied when discount is in time frame.'));
- }
-
- /**
- * Test product discount out of timespan.
- */
- public function testDiscountDateProductDiscountOutOfTime() {
- // Create a discount valid from tomorrow.
- $start_time = time() + 86400;
- $end_time = time() + 2 * 86400;
-
- $discount = $this->createDateDiscount('product_discount', 'fixed_amount', 300, $start_time, $end_time);
-
- // Create an order.
- $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'complete');
- $wrapper = entity_metadata_wrapper('commerce_order', $order);
- // Invoke line item price re-calculation.
- $line_item = $wrapper->commerce_line_items->get(0)->value();
- rules_invoke_event('commerce_product_calculate_sell_price', $line_item);
- // Check if the discount was added as a component to the line item.
- $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
- $price_data = $line_item_wrapper->commerce_unit_price->data->value();
- $this->assertTrue(count($price_data['components']) == 1, t('Product discount is ignored when discount is out of time frame.'));
- }
-
- /**
- * Create a date discount.
- *
- * @param string $discount_type
- * The discount type; Either 'order_discount' or 'product_discount'.
- * @param string $offer_type
- * The discount offer type; Either 'fixed_amount' or 'percentage'.
- * @param integer $amount
- * The discount offer amount.
- * @param $start_time
- * Discount valid from.
- * @param $end_time
- * Discount valid until.
- *
- * @return object
- * The newly created commerce_discount entity.
- */
- protected function createDateDiscount($discount_type, $offer_type, $amount, $start_time, $end_time) {
- // Use the base class to create a discount.
- $discount = parent::createDiscount($discount_type, $offer_type, $amount);
-
- // Populate the date fields.
- $wrapper = entity_metadata_wrapper('commerce_discount', $discount);
-
- $date_data = array(
- 'value' => $start_time,
- 'value2' => $end_time,
- 'date_type' => 'datestamp',
- );
-
- $wrapper->commerce_discount_date->set($date_data);
- $wrapper->save();
-
- return $wrapper->value();
- }
-}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/includes/views/commerce_discount_date.views_default.inc b/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/includes/views/commerce_discount_date.views_default.inc
deleted file mode 100644
index 9c4f770e..00000000
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_date/includes/views/commerce_discount_date.views_default.inc
+++ /dev/null
@@ -1,111 +0,0 @@
-display['default']->handler;
-
- // In order to insert the date fields in the middle of the fields array,
- // rebuild it while inserting the date fields after the 'rendered_entity'
- // field.
- if (empty($handler->display->display_options['fields']) || !is_array($handler->display->display_options['fields'])) {
- return;
- }
- foreach ($handler->display->display_options['fields'] as $field_id => $field) {
- $fields[$field_id] = $field;
-
- if ($field_id == 'rendered_entity') {
- $fields += $date_fields;
- }
- }
-
- // Overwrite the original fields array.
- $handler->display->display_options['fields'] = $fields;
-}
-
-/**
- * Helper function to get the Views import.
- */
-function _commerce_discount_date_views_get_view_delta() {
- $handler = new stdClass();
-
- /* Field: Commerce Discount: Discount dates */
- $handler->display->display_options['fields']['commerce_discount_date']['id'] = 'commerce_discount_date';
- $handler->display->display_options['fields']['commerce_discount_date']['table'] = 'field_data_commerce_discount_date';
- $handler->display->display_options['fields']['commerce_discount_date']['field'] = 'commerce_discount_date';
- $handler->display->display_options['fields']['commerce_discount_date']['label'] = 'Start date';
- $handler->display->display_options['fields']['commerce_discount_date']['alter']['alter_text'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date']['alter']['make_link'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date']['alter']['absolute'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date']['alter']['external'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date']['alter']['replace_spaces'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date']['alter']['trim_whitespace'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date']['alter']['nl2br'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date']['alter']['word_boundary'] = 1;
- $handler->display->display_options['fields']['commerce_discount_date']['alter']['ellipsis'] = 1;
- $handler->display->display_options['fields']['commerce_discount_date']['alter']['more_link'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date']['alter']['strip_tags'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date']['alter']['trim'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date']['alter']['html'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date']['element_label_colon'] = 1;
- $handler->display->display_options['fields']['commerce_discount_date']['element_default_classes'] = 1;
- $handler->display->display_options['fields']['commerce_discount_date']['hide_empty'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date']['empty_zero'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date']['hide_alter_empty'] = 1;
- $handler->display->display_options['fields']['commerce_discount_date']['settings'] = array(
- 'format_type' => 'short',
- 'fromto' => 'value',
- 'multiple_number' => '',
- 'multiple_from' => '',
- 'multiple_to' => '',
- );
- $handler->display->display_options['fields']['commerce_discount_date']['field_api_classes'] = 0;
- /* Field: Commerce Discount: Discount dates */
- $handler->display->display_options['fields']['commerce_discount_date_1']['id'] = 'commerce_discount_date_1';
- $handler->display->display_options['fields']['commerce_discount_date_1']['table'] = 'field_data_commerce_discount_date';
- $handler->display->display_options['fields']['commerce_discount_date_1']['field'] = 'commerce_discount_date';
- $handler->display->display_options['fields']['commerce_discount_date_1']['label'] = 'End date';
- $handler->display->display_options['fields']['commerce_discount_date_1']['alter']['alter_text'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date_1']['alter']['make_link'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date_1']['alter']['absolute'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date_1']['alter']['external'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date_1']['alter']['replace_spaces'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date_1']['alter']['trim_whitespace'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date_1']['alter']['nl2br'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date_1']['alter']['word_boundary'] = 1;
- $handler->display->display_options['fields']['commerce_discount_date_1']['alter']['ellipsis'] = 1;
- $handler->display->display_options['fields']['commerce_discount_date_1']['alter']['more_link'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date_1']['alter']['strip_tags'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date_1']['alter']['trim'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date_1']['alter']['html'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date_1']['element_label_colon'] = 1;
- $handler->display->display_options['fields']['commerce_discount_date_1']['element_default_classes'] = 1;
- $handler->display->display_options['fields']['commerce_discount_date_1']['hide_empty'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date_1']['empty_zero'] = 0;
- $handler->display->display_options['fields']['commerce_discount_date_1']['hide_alter_empty'] = 1;
- $handler->display->display_options['fields']['commerce_discount_date_1']['settings'] = array(
- 'format_type' => 'short',
- 'fromto' => 'value2',
- 'multiple_number' => '',
- 'multiple_from' => '',
- 'multiple_to' => '',
- );
- $handler->display->display_options['fields']['commerce_discount_date_1']['field_api_classes'] = 0;
-
- return $handler->display->display_options['fields'];
-}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/commerce_discount_usage.info b/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/commerce_discount_usage.info
deleted file mode 100644
index 5f886b3d..00000000
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/commerce_discount_usage.info
+++ /dev/null
@@ -1,21 +0,0 @@
-name = Commerce Discount Usage
-description = Provide usage tracking and limits for Commerce Discounts
-package = Commerce (contrib)
-core = 7.x
-
-; Dependencies
-dependencies[] = commerce_discount
-
-; Views handlers
-files[] = includes/views/handlers/commerce_discount_usage_handler_field_commerce_discount_analytics.inc
-
-; Simple tests
-files[] = commerce_discount_usage.test
-
-
-; Information added by drush on 2015-08-20
-version = "7.x-1.0-alpha5+0-dev"
-core = "7.x"
-project = "commerce_discount"
-datestamp = "1440110608"
-
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/commerce_discount_usage.install b/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/commerce_discount_usage.install
deleted file mode 100644
index f7b3b07f..00000000
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/commerce_discount_usage.install
+++ /dev/null
@@ -1,158 +0,0 @@
- array('commerce_discount'),
- 'field_name' => 'discount_usage_per_person',
- 'type' => 'number_integer',
- 'locked' => TRUE,
- );
- field_create_field($field);
- }
- foreach (commerce_discount_types() as $type => $info) {
- if (empty($instances['commerce_discount'][$type]['discount_usage_per_person'])) {
- $instance = array(
- 'field_name' => 'discount_usage_per_person',
- 'entity_type' => 'commerce_discount',
- 'bundle' => $type,
- 'label' => t('Maximum usage per customer'),
- 'description' => t('Enter the maximum number of times a specific person (as identified by email) may use this discount. Leave blank for unlimited.'),
- 'required' => FALSE,
- 'widget' => array(
- 'weight' => 100,
- ),
- 'settings' => array(
- 'min' => 0
- )
- );
- field_create_instance($instance);
- }
- }
-
- // Discount usage.
- if (empty($fields['discount_usage_limit'])) {
- // Create entity reference field.
- $field = array(
- 'entity_types' => array('commerce_discount'),
- 'field_name' => 'discount_usage_limit',
- 'type' => 'number_integer',
- 'locked' => TRUE,
- );
- field_create_field($field);
- }
- foreach (commerce_discount_types() as $type => $info) {
- if (empty($instances['commerce_discount'][$type]['discount_usage_limit'])) {
- $instance = array(
- 'field_name' => 'discount_usage_limit',
- 'entity_type' => 'commerce_discount',
- 'bundle' => $type,
- 'label' => t('Maximum overall usage'),
- 'description' => t('Enter the maximum number of times this discount may be used on the site, by anyone. Leave blank for unlimited.'),
- 'required' => FALSE,
- 'widget' => array(
- 'weight' => 100,
- ),
- 'settings' => array(
- 'min' => 0
- )
- );
- field_create_instance($instance);
- }
- }
-}
-
-/**
- * Implements hook_schema().
- */
-function commerce_discount_usage_schema() {
- $schema['commerce_discount_usage'] = array(
- 'fields' => array(
- 'discount' => array(
- 'type' => 'varchar',
- 'length' => 64,
- 'not null' => TRUE,
- 'description' => 'Discount name.',
- ),
- 'mail' => array(
- 'type' => 'varchar',
- 'length' => 255,
- 'not null' => TRUE,
- 'default' => '',
- 'description' => 'The email of the customer that used this discount.',
- ),
- 'order_id' => array(
- 'type' => 'int',
- 'not null' => TRUE,
- 'description' => 'The order id that this discount was used with.',
- ),
- ),
- 'unique keys' => array(
- 'discount_mail_order_id' => array('discount', 'mail', 'order_id'),
- ),
- 'foreign keys' => array(
- 'discount' => array(
- 'table' => 'commerce_discount',
- 'column' => array('discount' => 'name')
- ),
- 'order_id' => array(
- 'table' => 'commerce_order',
- 'column' => array('order_id' => 'order_id')
- ),
- 'mail' => array(
- 'table' => 'users',
- 'column' => array('mail' => 'mail')
- )
- ),
- 'indexes' => array(
- 'mail' => array('mail'),
- 'discount' => array('discount'),
- 'order_id' => array('order_id')
- )
- );
-
- return $schema;
-}
-
-/**
- * Create usage table
- */
-function commerce_discount_usage_update_7001() {
- // Add usage table.
- if (!db_table_exists('commerce_discount_usage')) {
- db_create_table('commerce_discount_usage', drupal_get_schema_unprocessed('commerce_discount_usage', 'commerce_discount_usage'));
- }
-}
-
-/**
- * Migrate from commerce_discount_max_uses to discount_usage_limit.
- */
-function commerce_discount_usage_update_7002() {
- foreach (entity_load('commerce_discount') as $discount) {
- $wrapper = entity_metadata_wrapper('commerce_discount', $discount);
- if (!isset($wrapper->discount_usage_limit) || $wrapper->discount_usage_limit->value() == FALSE
- && isset($wrapper->commerce_discount_max_uses) && $wrapper->commerce_discount_max_uses->value()) {
- $wrapper->discount_usage_limit = $wrapper->commerce_discount_max_uses->value();
- entity_save('commerce_discount', $discount);
- }
- }
-
- field_delete_field('commerce_discount_max_uses');
-}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/commerce_discount_usage.module b/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/commerce_discount_usage.module
deleted file mode 100644
index 6833c71b..00000000
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/commerce_discount_usage.module
+++ /dev/null
@@ -1,216 +0,0 @@
- 'commerce-order',
- 'product_discount' => 'commerce-line-item:order'
- );
-
- if (isset($map[$discount->type])) {
- // Add condition for per-person usage
- if ($wrapper->discount_usage_per_person->value()) {
- $rule->condition(
- 'commerce_discount_usage_max_usage_per_person',
- array(
- 'commerce_discount' => $discount->name,
- 'order:select' => $map[$discount->type],
- 'usage' => $wrapper->discount_usage_per_person->value(),
- )
- );
- }
- // For normal usage
- if ($wrapper->discount_usage_limit->value()) {
- $rule->condition(
- 'commerce_discount_usage_max_usage',
- array(
- 'commerce_discount' => $discount->name,
- 'order:select' => $map[$discount->type],
- 'usage' => $wrapper->discount_usage_limit->value(),
- )
- );
- }
- }
-}
-
-/*
- * Implements hook_commerce_discount_usages().
- */
-function commerce_discount_usage_flush_caches() {
- module_load_install('commerce_discount_usage');
- _commerce_discount_usage_install_helper();
-}
-
-/**
- * Get usage of a discount for a user, excluding a certain order id.
- *
- * @param string $discount_name
- * The discount name.
- * @param string $mail
- * The user mail.
- * @param bool $exclude_order_id
- * If TRUE, the order id will be excluded from the SQL request.
- *
- * @return int
- * Return the number of usage by mail.
- */
-function commerce_discount_usage_get_usage_by_mail($discount_name, $mail, $exclude_order_id = FALSE) {
- $query = db_select('commerce_discount_usage', 'g')
- ->fields('g')
- ->condition('g.mail', $mail)
- ->condition('g.discount', $discount_name);
-
- if ($exclude_order_id) {
- $query->condition('g.order_id', $exclude_order_id, '<>');
- }
-
- return $query->execute()->rowCount();
-}
-
-/**
- * Get usage of a discount, excluding a certain order id.
- *
- * @param string $discount_name
- * The discount name.
- * @param bool $exclude_order_id
- * If TRUE, the order id will be excluded from the SQL request.
- *
- * @return int
- * Return the number of usage.
- */
-function commerce_discount_usage_get_usage($discount_name, $exclude_order_id = FALSE) {
- $query = db_select('commerce_discount_usage', 'g')
- ->fields('g')
- ->condition('g.discount', $discount_name);
-
- if ($exclude_order_id) {
- $query->condition('g.order_id', $exclude_order_id, '<>');
- }
-
- return $query->execute()->rowCount();
-}
-
-/**
- * Reset usage statistics for an entire order
- *
- * @param object $order
- * A fully qualified order object.
- *
- * @return DeleteQuery
- * Return a new DeleteQuery object.
- */
-function commerce_discount_usage_reset_order_usage($order) {
- return db_delete('commerce_discount_usage')
- ->condition('order_id', $order->order_id)
- ->execute();
-}
-
-/**
- * Record order usage
- *
- * @param object $order
- * A fully qualified order object.
- *
- * @return void
- */
-function commerce_discount_usage_record_order_usage($order) {
- // Reset usage for this order first.
- commerce_discount_usage_reset_order_usage($order);
-
- // Only record discount usage if the order has an email.
- $discount_names = commerce_discount_usage_order_discounts($order);
-
- foreach ($discount_names as $discount_name) {
- $record = array(
- 'discount' => $discount_name,
- 'mail' => $order->mail ? $order->mail : '',
- 'order_id' => $order->order_id
- );
- drupal_write_record('commerce_discount_usage', $record);
- }
-}
-
-/**
- * Load all discounts connected to an order, including line item level discounts
- * traced through line item unit price components.
- *
- * @param object $order
- * A fully qualified order object.
- *
- * @return array
- *
- */
-function commerce_discount_usage_order_discounts($order) {
- $order_wrapper = entity_metadata_wrapper('commerce_order', $order);
- $order_discounts = array();
-
- foreach ($order_wrapper->commerce_line_items as $line_item_wrapper) {
- $data = $line_item_wrapper->commerce_unit_price->data->value();
-
- foreach ($data['components'] as $key => $component) {
- if ($component['name'] == 'discount' || !empty($component['price']['data']['discount_name'])) {
- $order_discount_name = $component['price']['data']['discount_name'];
- $order_discount_wrapper = entity_metadata_wrapper('commerce_discount', $order_discount_name);
- // Make a list of discounts present via the order's line item price
- // components.
- if ($order_discount_wrapper->value()) {
- $order_discounts[] = $order_discount_wrapper->name->value();
- }
- }
- }
- }
-
- // Add the set of discounts directly referenced on the order.
- if (!empty($order->commerce_discounts)) {
- foreach ($order_wrapper->commerce_discounts->value() as $discount) {
- $order_discounts[] = $discount->name;
- }
- }
-
- $order_discounts = array_unique($order_discounts);
-
- return $order_discounts;
-}
-
-/*
- * Implements hook_commerce_order_update().
- */
-function commerce_discount_usage_commerce_order_update($order) {
- commerce_discount_usage_record_order_usage($order);
-}
-
-/*
- * Implements hook_commerce_order_insert().
- */
-function commerce_discount_usage_commerce_order_insert($order) {
- commerce_discount_usage_record_order_usage($order);
-}
-
-/*
- * Implements hook_commerce_order_delete().
- */
-function commerce_discount_usage_commerce_order_delete($order) {
- commerce_discount_usage_reset_order_usage($order);
-}
-
-/**
- * Implements hook_form_FORM_ID_alter().
- */
-function commerce_discount_usage_form_commerce_discount_form_alter(&$form, $form_state) {
- $form['#attached']['css'][] = drupal_get_path('module', 'commerce_discount_usage') . '/css/commerce_discount_usage.css';
-}
-
-/*
- * Implements hook_views_api().
- */
-function commerce_discount_usage_views_api() {
- return array(
- 'version' => 2,
- 'path' => drupal_get_path('module', 'commerce_discount_usage') . '/includes/views'
- );
-}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/commerce_discount_usage.rules.inc b/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/commerce_discount_usage.rules.inc
deleted file mode 100644
index 52655204..00000000
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/commerce_discount_usage.rules.inc
+++ /dev/null
@@ -1,88 +0,0 @@
- t('Max usage per person'),
- 'parameter' => array(
- 'order' => array(
- 'type' => 'commerce_order',
- 'label' => t('Order')
- ),
- 'commerce_discount' => array(
- 'label' => t('Commerce Discount'),
- 'type' => 'token',
- 'options list' => 'commerce_discount_entity_list',
- ),
- 'usage' => array(
- 'type' => 'integer',
- 'label' => t('Maximum usage per customer'),
- 'description' => t('Enter the maximum number of times a specific person (as identified by email) may use this discount. Leave blank for unlimited.'),
- ),
- ),
- 'group' => t('Commerce Discount'),
- );
-
- // Max usage
- $conditions['commerce_discount_usage_max_usage'] = array(
- 'label' => t('Max usage'),
- 'parameter' => array(
- 'order' => array(
- 'type' => 'commerce_order',
- 'label' => t('Order')
- ),
- 'commerce_discount' => array(
- 'label' => t('Commerce Discount'),
- 'type' => 'token',
- 'options list' => 'commerce_discount_entity_list',
- ),
- 'usage' => array(
- 'type' => 'integer',
- 'label' => t('Maximum overall usage'),
- 'description' => t('Enter the maximum number of times this discount may be used on the site, by anyone. Leave blank for unlimited.'),
- ),
- ),
- 'group' => t('Commerce Discount'),
- );
-
- return $conditions;
-}
-
-/*
- * Rules condition callback: evaluate maximum usage per-person of a discount.
- */
-function commerce_discount_usage_max_usage_per_person($order, $discount_name) {
- $discount_wrapper = entity_metadata_wrapper('commerce_discount', $discount_name);
- $per_person_limit = $discount_wrapper->discount_usage_per_person->value();
-
- // Nothing to count if the order does not have an email.
- if (!$per_person_limit || !$order->mail) {
- return TRUE;
- }
-
- // Find other orders owned by same person that have same discount.
- $usage = commerce_discount_usage_get_usage_by_mail($discount_name, $order->mail, $order->order_id);
-
- return $usage < $per_person_limit;
-}
-
-/*
- * Rules condition callback: evaluate maximum usage of a discount.
- */
-function commerce_discount_usage_max_usage($order, $discount_name) {
- $discount_wrapper = entity_metadata_wrapper('commerce_discount', $discount_name);
- $limit = $discount_wrapper->discount_usage_limit->value();
-
- if (!$limit) {
- return TRUE;
- }
-
- // Find other orders that have same discount.
- $usage = commerce_discount_usage_get_usage($discount_name, $order->order_id);
-
- return $usage < $limit;
-}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/commerce_discount_usage.test b/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/commerce_discount_usage.test
deleted file mode 100644
index 57365f16..00000000
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/commerce_discount_usage.test
+++ /dev/null
@@ -1,271 +0,0 @@
- 'Discounts usage',
- 'description' => 'Test discounts usage UI and functionality',
- 'group' => 'Commerce discounts',
- );
- }
-
- /**
- * {@inheritdoc}
- */
- public function setUp() {
- parent::setUp();
- $this->store_customer2 = $this->createStoreCustomer();
- }
-
- /**
- * Test usage specific elements in the add discount UI.
- */
- public function testCommerceDiscountUsageUIAddDiscount() {
- // Login with store admin.
- $this->drupalLogin($this->store_admin);
-
- // Access to the admin discount creation page.
- $this->drupalGet('admin/commerce/store/discounts/add');
-
- // Check the integrity of the add form.
- // $this->assertFieldByName('commerce_discount_fields[discount_usage_limit][limit_uses]', NULL, t('Quantity field is present'));
- $this->assertFieldByName('commerce_discount_fields[discount_usage_limit][und][0][value]', NULL, t('Amount field is present'));
-
- // Create a discount.
- $values = array(
- 'label' => 'Order discount - fixed',
- 'name' => 'order_discount_fixed',
- 'component_title' => 'Order discount',
- 'commerce_discount_fields[commerce_discount_offer][und][form][commerce_fixed_amount][und][0][amount]' => 12.77,
- 'commerce_discount_fields[discount_usage_limit][und][0][value]' => 5,
- );
- $this->drupalPost(NULL, $values, t('Save discount'));
-
- // Load the discount and wrap it.
- $discount = entity_load_single('commerce_discount', 1);
- $wrapper = entity_metadata_wrapper('commerce_discount', $discount);
-
- // Check the usage fields of the stored discount.
- $this->assertTrue($wrapper->discount_usage_per_person->value() == 0, t('Discount uses field is empty.'));
- $this->assertTrue($wrapper->discount_usage_limit->value() == 5, t('Discount max uses stored correctly.'));
-
- // Check the discounts listing
- $this->assertText(t('@amount available', array('@amount' => 5)), t('Analytics - Max usage is shown.'));
- $this->assertText(t('Used @amount times', array('@amount' => 0)), t('Analytics - Usage is shown.'));
- }
-
- /**
- * Test usage specific elements in the edit discount UI.
- */
- public function testCommerceDiscountUsageUIEditDiscount() {
- // Testing fixed discount.
- // Create a fixed order discount of $3 limited to one use.
- $discount = $this->createUsageDiscount('order_discount', 'fixed_amount', 300, 1);
-
- // Login with store admin.
- $this->drupalLogin($this->store_admin);
-
- // Access to the admin discount edit page.
- $this->drupalGet('admin/commerce/store/discounts/manage/' . $discount->name);
-
- // Check the integrity of the add form.
- // $this->assertFieldByName('commerce_discount_fields[discount_usage_limit][limit_uses]', NULL, t('Quantity field is present'));
- $this->assertFieldByName('commerce_discount_fields[discount_usage_limit][und][0][value]', NULL, t('Amount field is present'));
-
- // Change the discount values.
- $values = array(
- 'label' => 'Order discount - fixed',
- 'name' => 'order_discount_fixed',
- 'component_title' => 'Order discount',
- 'commerce_discount_fields[commerce_discount_offer][und][form][commerce_fixed_amount][und][0][amount]' => 12.77,
- 'commerce_discount_fields[discount_usage_limit][und][0][value]' => 5,
- );
- $this->drupalPost(NULL, $values, t('Save discount'));
-
- // Load the discount and wrap it.
- $discount = entity_load_single('commerce_discount', 1);
- $discount_wrapper = entity_metadata_wrapper('commerce_discount', $discount);
-
- // Check the usage fields of the stored discount.
- $this->assertTrue($discount_wrapper->discount_usage_per_person->value() == 0, t('Discount uses field is empty.'));
- // $this->assertTrue($discount_wrapper->discount_usage_limit->value() == 5, t('Discount max uses stored correctly.'));
-
- // Check the discounts listing
- $this->assertText(t('@amount available', array('@amount' => 5)), t('Analytics - Max usage is shown.'));
- $this->assertText(t('Used @amount times', array('@amount' => 0)), t('Analytics - Usage is shown.'));
- }
-
- /**
- * Test fixed order discounts.
- */
- public function testCommerceDiscountUsageFixedOrderDiscount() {
- // Testing fixed discount.
- // Create a fixed order discount of $3 limited to one use.
- $discount = $this->createUsageDiscount('order_discount', 'fixed_amount', 300, 1);
-
- // Create an order.
- $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'complete');
- $wrapper = entity_metadata_wrapper('commerce_order', $order);
-
- // Recalculate discounts.
- commerce_cart_order_refresh($order);
-
- // Check if the discount was applied on the order total price.
- $this->assertTrue($wrapper->commerce_order_total->amount->value() == 700, t('Fixed order discount is deducted correctly on the first use.'));
-
- // Create another order to make sure the discount isn't applied again.
- $order = $this->createDummyOrder($this->store_customer2->uid, array($this->product->product_id => 1), 'complete');
- $wrapper = entity_metadata_wrapper('commerce_order', $order);
-
- // Recalculate discounts.
- commerce_cart_order_refresh($order);
-
- // Check if the discount was applied on the order total price.
- $this->assertTrue($wrapper->commerce_order_total->amount->value() == 1000, t('Fixed order discount is ignored after maximal usage.'));
- }
-
- /**
- * Test percentage order discounts.
- */
- public function testCommerceDiscountUsagePercentageOrderDiscount() {
- // Testing percentage discount.
- // Create a percentage order discount of 5% limited to one use.
- $discount = $this->createUsageDiscount('order_discount', 'percentage', 5, 1);
- // Create a completed order.
- $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'complete');
- $wrapper = entity_metadata_wrapper('commerce_order', $order);
-
- // Recalculate discounts.
- commerce_cart_order_refresh($order);
-
- // Check if the discount was applied on the order total price.
- $this->assertTrue($wrapper->commerce_order_total->amount->value() == 950, t('Percentage order discount is deducted correctly.'));
-
- // Create another order to make sure the discount isn't applied again.
- $order = $this->createDummyOrder($this->store_customer2->uid, array($this->product->product_id => 1), 'complete');
- $wrapper = entity_metadata_wrapper('commerce_order', $order);
-
- // Recalculate discounts.
- commerce_cart_order_refresh($order);
-
- // Check if the discount was applied on the order total price.
- $this->assertTrue($wrapper->commerce_order_total->amount->value() == 1000, t('Percentage order discount is ignored after maximal usage.'));
- }
-
- /**
- * Test fixed product discounts.
- */
- public function testCommerceDiscountUsageFixedProductDiscount() {
- $discount = $this->createUsageDiscount('product_discount', 'fixed_amount', 300, 1);
-
- // Create an order.
- $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'complete');
- $wrapper = entity_metadata_wrapper('commerce_order', $order);
- // Invoke line item price re-calculation.
- $line_item = $wrapper->commerce_line_items->get(0)->value();
- rules_invoke_event('commerce_product_calculate_sell_price', $line_item);
- // Check if the discount was added as a component to the line item.
- $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
- $price_data = $line_item_wrapper->commerce_unit_price->data->value();
- $this->assertTrue($price_data['components'][1]['price']['amount'] == -300, t('Fixed product discount is added as a price compoennt to the line item.'));
-
- // Create another order to make sure the discount isn't applied again.
- $order = $this->createDummyOrder($this->store_customer2->uid, array($this->product->product_id => 1), 'complete');
- $wrapper = entity_metadata_wrapper('commerce_order', $order);
-
- // Recalculate discounts.
- commerce_cart_order_refresh($order);
-
- // Invoke line item price re-calculation.
- $line_item = $wrapper->commerce_line_items->get(0)->value();
- rules_invoke_event('commerce_product_calculate_sell_price', $line_item);
- // Check if the discount was added as a component to the line item.
- $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
- $price_data = $line_item_wrapper->commerce_unit_price->data->value();
- // $this->assertTrue(count($price_data['components']) === 1, t('Fixed product discount is ignored after maximal usage.'));
- }
-
- /**
- * Test percentage product discounts.
- */
- public function testCommerceDiscountUsagePercentageProductDiscount() {
- $discount = $this->createUsageDiscount('product_discount', 'percentage', 5, 1);
-
- // Create an order.
- $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'complete');
- $wrapper = entity_metadata_wrapper('commerce_order', $order);
-
- // Recalculate discounts.
- commerce_cart_order_refresh($order);
-
- // Invoke line item price re-calculation.
- $line_item = $wrapper->commerce_line_items->get(0)->value();
- rules_invoke_event('commerce_product_calculate_sell_price', $line_item);
- // Check if the discount was added as a component to the line item.
- $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
- $price_data = $line_item_wrapper->commerce_unit_price->data->value();
- // $this->assertTrue($price_data['components'][1]['price']['amount'] == -500, t('Percentage product discount is added as a price compoennt to the line item.'));
-
- // Create another order to make sure the discount isn't applied again.
- $order = $this->createDummyOrder($this->store_customer2->uid, array($this->product->product_id => 1), 'complete');
- $wrapper = entity_metadata_wrapper('commerce_order', $order);
-
- // Recalculate discounts.
- commerce_cart_order_refresh($order);
-
- // Invoke line item price re-calculation.
- $line_item = $wrapper->commerce_line_items->get(0)->value();
- rules_invoke_event('commerce_product_calculate_sell_price', $line_item);
- // Check if the discount was added as a component to the line item.
- $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
- $price_data = $line_item_wrapper->commerce_unit_price->data->value();
- $this->assertTrue(count($price_data['components']) == 1, t('Percentage product discount is ignored after maximal usage.'));
- }
-
- /**
- * Create a discount.
- *
- * @param string $discount_type
- * The discount type; Either 'order_discount' or 'product_discount'.
- * @param string $offer_type
- * The discount offer type; Either 'fixed_amount' or 'percentage'.
- * @param integer $amount
- * The discount offer amount.
- * @param integer $max_usage
- * Maximal uses for the discount.
- *
- * @return object
- * The newly created commerce_discount entity.
- */
- protected function createUsageDiscount($discount_type, $offer_type, $amount, $max_usage) {
- // Use the base class to create a discount.
- $discount = parent::createDiscount($discount_type, $offer_type, $amount);
-
- // Populate the max usage field.
- $wrapper = entity_metadata_wrapper('commerce_discount', $discount);
- $wrapper->discount_usage_limit = $max_usage;
- $wrapper->save();
-
- return $wrapper->value();
- }
-
-}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/css/commerce_discount_usage.css b/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/css/commerce_discount_usage.css
deleted file mode 100644
index d0b9f383..00000000
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/css/commerce_discount_usage.css
+++ /dev/null
@@ -1,5 +0,0 @@
-#commerce-discount-fields-wrapper .field-name-discount-usage-limit,
-#commerce-discount-fields-wrapper .field-name-discount-usage-per-person{
- float:none;
- clear:both;
-}
\ No newline at end of file
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/includes/views/commerce_discount_usage.views.inc b/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/includes/views/commerce_discount_usage.views.inc
deleted file mode 100644
index 1a66e8e1..00000000
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/includes/views/commerce_discount_usage.views.inc
+++ /dev/null
@@ -1,161 +0,0 @@
- t('Analytics'),
- 'help' => t('Show discount usage and usage limit.'),
- 'field' => array(
- 'handler' => 'commerce_discount_usage_handler_field_commerce_discount_analytics',
- ),
- 'real field' => 'discount_id',
- );
-
- // Usage relationship
- $data['commerce_discount']['discount_usage'] = array(
- 'relationship' => array(
- 'title' => t('Discount usage'),
- 'label' => t('Discount usage'),
- 'help' => t('Relate this discount to its usage statistics.'),
- 'handler' => 'views_handler_relationship',
- 'base' => 'commerce_discount_usage',
- 'base field' => 'discount',
- 'field' => 'name',
- ),
- );
- }
-
- // Order table: discount usage relationship
- if (isset($data['commerce_order'])) {
- $data['commerce_order']['discount_usage'] = array(
- 'relationship' => array(
- 'title' => t('Discount usage'),
- 'label' => t('Discount usage'),
- 'help' => t('Relate this order to its discount usage statistics.'),
- 'handler' => 'views_handler_relationship',
- 'base' => 'commerce_discount_usage',
- 'base field' => 'order_id',
- 'field' => 'order_id',
- ),
- );
- }
-
- // User table: discount usage relationship
- $data['users']['discount_usage'] = array(
- 'relationship' => array(
- 'title' => t('Discount usage'),
- 'label' => t('Discount usage'),
- 'help' => t('Relate this user to its discount usage statistics.'),
- 'handler' => 'views_handler_relationship',
- 'base' => 'commerce_discount_usage',
- 'base field' => 'mail',
- 'field' => 'mail',
- ),
- );
-}
-
-/*
- * Implements hook_views_data().
- */
-function commerce_discount_usage_views_data() {
- $data = array();
- $data['commerce_discount_usage']['table']['group'] = t('Commerce discount usage');
-
- // Base table
- $data['commerce_discount_usage']['table']['base'] = array(
- 'field' => 'mail',
- 'title' => t('Commerce Discount Usage'),
- 'help' => t('Usage statistics about discounts.'),
- );
-
- // Discount name.
- $data['commerce_discount_usage']['discount'] = array(
- 'title' => t('Discount'),
- 'help' => t('The unique human-readable identifier of the discount.'),
- 'field' => array(
- 'handler' => 'views_handler_field',
- 'click sortable' => TRUE,
- ),
- 'filter' => array(
- 'handler' => 'views_handler_filter_string',
- ),
- 'sort' => array(
- 'handler' => 'views_handler_sort',
- ),
- 'argument' => array(
- 'handler' => 'views_handler_argument_string',
- ),
- 'relationship' => array(
- 'title' => t('Discount'),
- 'label' => t('Discount'),
- 'help' => t('Relate a usage statistics record to its discount.'),
- 'handler' => 'views_handler_relationship',
- 'base' => 'commerce_discount',
- 'base field' => 'name',
- 'field' => 'discount',
- )
- );
-
- // Customer mail.
- $data['commerce_discount_usage']['mail'] = array(
- 'title' => t('User'),
- 'help' => t('The email address of the customer who used the discount.'),
- 'field' => array(
- 'handler' => 'views_handler_field',
- 'click sortable' => TRUE,
- ),
- 'filter' => array(
- 'handler' => 'views_handler_filter_string',
- ),
- 'sort' => array(
- 'handler' => 'views_handler_sort',
- ),
- 'argument' => array(
- 'handler' => 'views_handler_argument_string',
- ),
- 'relationship' => array(
- 'title' => t('Customer email'),
- 'label' => t('Customer email'),
- 'help' => t('Relate a usage statistics record to its user.'),
- 'handler' => 'views_handler_relationship',
- 'base' => 'users',
- 'base field' => 'mail',
- 'field' => 'mail',
- )
- );
-
- // Order ID.
- $data['commerce_discount_usage']['order_id'] = array(
- 'title' => t('Order ID'),
- 'help' => t('The unique internal identifier of the order where the discount was used.'),
- 'field' => array(
- 'handler' => 'commerce_order_handler_field_order',
- 'click sortable' => TRUE,
- ),
- 'filter' => array(
- 'handler' => 'views_handler_filter_numeric',
- ),
- 'sort' => array(
- 'handler' => 'views_handler_sort',
- ),
- 'argument' => array(
- 'handler' => 'commerce_order_handler_argument_order_order_id',
- ),
- 'relationship' => array(
- 'title' => t('Order'),
- 'label' => t('Order'),
- 'help' => t('Relate a usage statistics record to its order.'),
- 'handler' => 'views_handler_relationship',
- 'base' => 'commerce_order',
- 'base field' => 'order_id',
- 'field' => 'order_id',
- )
- );
-
- return $data;
-}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/includes/views/commerce_discount_usage.views_default.inc b/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/includes/views/commerce_discount_usage.views_default.inc
deleted file mode 100644
index 6f271ad5..00000000
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/modules/commerce_discount_usage/includes/views/commerce_discount_usage.views_default.inc
+++ /dev/null
@@ -1,66 +0,0 @@
-display['default']->handler;
-
- if (empty($handler->display->display_options['fields']) || !is_array($handler->display->display_options['fields'])) {
- return;
- }
-
- $fields = array();
- foreach ($handler->display->display_options['fields'] as $field_id => $field) {
- // Add the usage column after the status column.
- if ($field_id == 'status') {
- $fields += $usage_field;
- }
- $fields[$field_id] = $field;
- }
-
- // Overwrite the original fields array.
- $handler->display->display_options['fields'] = $fields;
-}
-
-/**
- * Helper function to get the Views import.
- */
-function _commerce_discount_usage_views_get_view_delta() {
- $handler = new stdClass();
-
- /* Field: Commerce Discount: Analytics */
- $handler->display->display_options['fields']['commerce_discount_usage']['id'] = 'commerce_discount_usage';
- $handler->display->display_options['fields']['commerce_discount_usage']['table'] = 'commerce_discount';
- $handler->display->display_options['fields']['commerce_discount_usage']['field'] = 'commerce_discount_usage';
- $handler->display->display_options['fields']['commerce_discount_usage']['alter']['alter_text'] = 0;
- $handler->display->display_options['fields']['commerce_discount_usage']['alter']['make_link'] = 0;
- $handler->display->display_options['fields']['commerce_discount_usage']['alter']['absolute'] = 0;
- $handler->display->display_options['fields']['commerce_discount_usage']['alter']['external'] = 0;
- $handler->display->display_options['fields']['commerce_discount_usage']['alter']['replace_spaces'] = 0;
- $handler->display->display_options['fields']['commerce_discount_usage']['alter']['trim_whitespace'] = 0;
- $handler->display->display_options['fields']['commerce_discount_usage']['alter']['nl2br'] = 0;
- $handler->display->display_options['fields']['commerce_discount_usage']['alter']['word_boundary'] = 1;
- $handler->display->display_options['fields']['commerce_discount_usage']['alter']['ellipsis'] = 1;
- $handler->display->display_options['fields']['commerce_discount_usage']['alter']['more_link'] = 0;
- $handler->display->display_options['fields']['commerce_discount_usage']['alter']['strip_tags'] = 0;
- $handler->display->display_options['fields']['commerce_discount_usage']['alter']['trim'] = 0;
- $handler->display->display_options['fields']['commerce_discount_usage']['alter']['html'] = 0;
- $handler->display->display_options['fields']['commerce_discount_usage']['element_label_colon'] = 1;
- $handler->display->display_options['fields']['commerce_discount_usage']['element_default_classes'] = 1;
- $handler->display->display_options['fields']['commerce_discount_usage']['hide_empty'] = 0;
- $handler->display->display_options['fields']['commerce_discount_usage']['empty_zero'] = 0;
- $handler->display->display_options['fields']['commerce_discount_usage']['hide_alter_empty'] = 1;
-
- return $handler->display->display_options['fields'];
-}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/sass/_mixins.scss b/profiles/commerce_kickstart/modules/contrib/commerce_discount/sass/_mixins.scss
new file mode 100644
index 00000000..7374cf0d
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/sass/_mixins.scss
@@ -0,0 +1,85 @@
+$gray: #f0f0f0;
+$gray2: #ccc;
+$gray3: #e7e8e3;
+$gray4: #4d4e49;
+$grayLight: #f6f6f6;
+$grayDark: #6d6d6d;
+$blue: #0089c9;
+$green: #7cae20;
+$azure: #d2eeff;
+
+@mixin gradient {
+ // http://caniuse.com/#search=linear-gradient
+ background-image: -webkit-linear-gradient(top, rgb(252, 253, 252) 36%, rgb(240, 240, 240) 68%);
+ background-image: linear-gradient(top, rgb(252, 253, 252) 36%, rgb(240, 240, 240) 68%);
+}
+
+@mixin box {
+ padding: 0;
+}
+
+// https://css-tricks.com/snippets/css/clear-fix/
+@mixin clearfix {
+ &:after {
+ content: "";
+ display: table;
+ clear: both;
+ }
+}
+
+@mixin btn {
+ color: black;
+ border-radius: 5px;
+ [dir="ltr"] & {
+ margin-right: 20px;
+ }
+ [dir="rtl"] & {
+ margin-left: 20px;
+ }
+
+ margin-bottom: 5px;
+ padding: 5px;
+ &:hover {
+ background-color: $grayLight;
+ cursor: pointer;
+ label {
+ cursor: pointer;
+ }
+ }
+}
+
+@mixin radio-buttons {
+ clear: both;
+
+ .form-item {
+ @include btn;
+
+ input {
+ display: inline;
+ }
+ }
+}
+
+@mixin fieldset-title {
+ fieldset.form-wrapper {
+ border: none;
+
+ legend {
+ width: 100%;
+ }
+ .fieldset-legend {
+ border-bottom: 1px solid $gray2;
+ display: block;
+ margin-top: 0;
+ [dir="ltr"] & {
+ padding-left: 0;
+ }
+ [dir="rtl"] & {
+ padding-right: 0;
+ }
+
+ text-transform: none;
+ width: 100%;
+ }
+ }
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/scss/commerce_discount.scss b/profiles/commerce_kickstart/modules/contrib/commerce_discount/sass/commerce_discount.scss
similarity index 51%
rename from profiles/commerce_kickstart/modules/contrib/commerce_discount/scss/commerce_discount.scss
rename to profiles/commerce_kickstart/modules/contrib/commerce_discount/sass/commerce_discount.scss
index da2295fe..b81aee5e 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/scss/commerce_discount.scss
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/sass/commerce_discount.scss
@@ -1,4 +1,4 @@
-@import "_mixins.scss";
+@import "mixins";
/**
* Discount form.
@@ -6,37 +6,41 @@
.commerce-discount-form {
// Position the discount status block on top right region.
position: relative;
- .form-item-status {
- background-color: #eee;
- padding: 10px 10px 20px 10px;
- position: absolute;
- top: 0;
- right: 0; // LTR
- width: 180px;
- }
- // Reset
+
+ // Reset.
.form-item-label {
clear: both;
+
.form-item {
@include box;
}
}
+
.form-item.form-type-radio {
position: relative;
+
.ajax-progress-throbber {
position: absolute;
right: -10px;
+
.message {
display: none;
}
}
}
- // general block margins
+
+ // General block margins.
#commerce-discount-fields-wrapper {
- & > .form-wrapper {
+ .form-wrapper {
margin-bottom: 15px;
}
+
+ .field-name-discount-usage-limit, .field-name-discount-usage-per-person {
+ float: none;
+ clear: both;
+ }
}
+
#edit-actions {
clear: both;
}
@@ -48,24 +52,46 @@
.form-item-commerce-discount-type {
.form-radios {
margin-top: 5px;
+
.form-item {
@include btn;
- float: left;
+
+ [dir="ltr"] & {
+ float: left;
+ }
+
+ [dir="rtl"] & {
+ float: right;
+ }
&.selected {
background-color: #eee;
}
+
.ajax-progress {
display: none;
}
- #edit-commerce-discount-type {
- @include radio-buttons;
- clear: none;
+ }
+ }
+}
- .form-item {
- float: left; // LTR
- }
- }
+#edit-commerce-discount-type {
+ padding: 0;
+
+ @include radio-buttons;
+
+ margin-top: 10px;
+ clear: none;
+
+ .form-item {
+ [dir="ltr"] & {
+ float: left;
+ margin-right: 20px;
+ }
+
+ [dir="rtl"] & {
+ float: right;
+ margin-left: 20px;
}
}
}
@@ -85,55 +111,93 @@
* Choose offer type block.
*/
.field-name-commerce-discount-offer {
- border: none;
+ // Help with floaties inside.
+ @include clearfix;
+
+ border: 0;
margin: 0;
padding: 0;
- .form-wrapper .form-wrapper {
- .form-item {
- margin-bottom: 2px;
+ // Offer type options.
+ .form-item-commerce-discount-fields-commerce-discount-offer-und-form-type.form-type-radios {
+ padding-left: 0;
+ padding-right: 0;
+ [dir="ltr"] & {
+ float: left;
+ margin-right: 20px;
+ padding-right: 20px;
+ border-right: 1px dotted $gray2;
+ }
+
+ [dir="rtl"] & {
+ float: right;
+ margin-left: 20px;
+ padding-left: 20px;
+ border-left: 1px dotted $gray2;
+ }
+
+ .form-radios {
+ @include radio-buttons;
+ margin: 10px;
padding: 0;
- label {
- border-bottom: 1px solid $gray2;
- padding-left: 5px; // LTR
- }
- div.form-radios {
- @include radio-buttons;
-
- background-color: transparent;
- border-right: 1px dotted $gray2; /* LTR */
- float: left; /* LTR */
- margin: 10px;
- padding: 4px;
- padding-right: 20px; /* LTR */
-
- .form-item {
- &.selected {
- background-color: #eee;
- }
- .ajax-progress {
- display: none;
- }
+ .form-item {
+ &.selected {
+ background-color: #eee;
+ }
+
+ .ajax-progress {
+ display: none;
}
+ }
+
+ label {
+ border-bottom: 0;
- label {
- border-bottom: 0;
+ [dir="ltr"] & {
padding-left: 0;
}
+
+ [dir="rtl"] & {
+ padding-right: 0;
+ }
}
}
+ }
+
+ // Avoid collision with fields below.
+ .commerce-offer-type-wrapper > .fieldset-wrapper {
+ @include clearfix;
+ }
+
+ // The two columns for the offer type.
+ .commerce-offer-fields-wrapper {
+ padding: 0;
+ [dir="ltr"] & {
+ float: left;
+ }
+
+ [dir="rtl"] & {
+ float: right;
+ }
+ }
+
+ .form-wrapper .form-wrapper {
+ .form-item {
+ margin-bottom: 2px;
+ }
+
.form-wrapper {
label {
border-bottom: 0;
- padding-left: 0;
- }
- &.form-item {
- background-color: transparent;
- float: left; /* LTR */
- margin: 10px;
- padding: 4px;
+ [dir="ltr"] & {
+ padding-left: 0;
+ }
+
+ [dir="rtl"] & {
+ padding-right: 0;
+ }
}
}
}
@@ -144,19 +208,56 @@
*/
.field-name-commerce-discount-date {
clear: both;
- @include fieldset-title;
+
.form-wrapper fieldset.form-wrapper {
margin: 0;
}
- .fieldset-wrapper {
- @include fieldset-content;
+ .fieldset-wrapper {
background-color: transparent;
display: inline-block;
margin: 10px;
padding: 4px;
width: auto;
}
+
+ .container-inline-date {
+ clear: none;
+
+ [dir="ltr"] & {
+ float: left;
+ }
+
+ [dir="rtl"] & {
+ float: right;
+ }
+
+ .date-padding {
+ [dir="ltr"] & {
+ float: left;
+ }
+
+ [dir="rtl"] & {
+ float: right;
+ }
+ }
+
+ .form-text {
+ background-image: url(../images/calendar.svg);
+ background-repeat: no-repeat;
+ background-position: calc(100% - 0.25em) center;
+ background-size: 1.25em;
+ }
+ }
+
+ // Date.css override.
+ fieldset.date-combo .container-inline-date .date-padding {
+ padding: 0;
+ }
+ // Vertical tab fix.
+ fieldset.date-combo .fieldset-wrapper > .container-inline-date {
+ padding-top: 0;
+ }
}
/**
@@ -172,40 +273,76 @@
border-bottom: 1px solid $gray2;
}
}
+
.form-item .form-select {
- float: left; // LTR
+ [dir="ltr"] & {
+ float: left;
+ }
+
+ [dir="rtl"] & {
+ float: right;
+ }
+
margin: 10px;
}
+
.field-name-commerce-discount-max-uses {
@include box;
& > div {
- float: left; // LTR
- margin-left: 30px; // LTR
+ [dir="ltr"] & {
+ float: left;
+ margin-left: 30px;
+
+ &:first-child {
+ margin-left: 0;
+ }
+ }
+
+ [dir="rtl"] & {
+ float: right;
+ margin-right: 30px;
- &:first-child {
- margin-left: 0;
+ &:first-child {
+ margin-right: 0;
+ }
}
input[disabled] {
- background: #eeeeee;
+ background: #eee;
}
}
}
+
.field-type-number-integer {
- float: left; // LTR
+ [dir="ltr"] & {
+ float: left;
+ }
+
+ [dir="rtl"] & {
+ float: right;
+ }
.form-item {
padding: 0;
}
+
label {
display: inline;
font-weight: normal;
- margin-left: 10px; // LTR
+
+ [dir="ltr"] & {
+ margin-left: 10px;
+ }
+
+ [dir="rtl"] & {
+ margin-right: 10px;
+ }
}
+
.form-disabled input {
- border: none;
- background: none;
+ border: 0;
+ background-color: transparent;
}
}
}
@@ -215,22 +352,24 @@
*/
.view-commerce-discount-overview {
.views-table {
- border: none;
+ border: 0;
tr, td {
- border: none;
+ border: 0;
}
+
th {
text-transform: none;
- .views-field-enable-disable {}
.views-field-operations-dropbutton {
width: 70px;
}
}
+
td {
.views-field-type {
padding: 10px 20px;
}
+
.views-field-commerce-discount-usage li {
list-style-type: none;
@@ -239,6 +378,7 @@
font-style: italic;
}
}
+
.views-field-enable-disable .item-list ul {
width: 140px;
border: 2px solid $grayDark;
@@ -248,7 +388,15 @@
li {
display: block;
width: 50%;
- float: left; // LTR
+
+ [dir="ltr"] & {
+ float: left;
+ }
+
+ [dir="rtl"] & {
+ float: right;
+ }
+
text-transform: uppercase;
padding: 5px 0;
font-weight: bold;
@@ -270,6 +418,7 @@
}
}
}
+
.views-field-operations-dropbutton {
position: relative;
@@ -287,3 +436,7 @@
}
}
}
+
+.field-name-commerce-compatibility-strategy .field-widget-options-buttons .form-wrapper {
+ clear: both;
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/scss/_mixins.scss b/profiles/commerce_kickstart/modules/contrib/commerce_discount/scss/_mixins.scss
deleted file mode 100644
index cad8a772..00000000
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/scss/_mixins.scss
+++ /dev/null
@@ -1,114 +0,0 @@
-$gray: #f0f0f0;
-$gray2: #cccccc;
-$gray3: #e7e8e3;
-$gray4: #4d4e49;
-$grayLight: #f6f6f6;
-$grayDark: #6d6d6d;
-$blue: #0089c9;
-$green: #7cae20;
-$azure: #d2eeff;
-
-@mixin gradient {
- background-image: linear-gradient(top, rgb(252,253,252) 36%, rgb(240,240,240) 68%);
- background-image: -o-linear-gradient(top, rgb(252,253,252) 36%, rgb(240,240,240) 68%);
- background-image: -moz-linear-gradient(top, rgb(252,253,252) 36%, rgb(240,240,240) 68%);
- background-image: -webkit-linear-gradient(top, rgb(252,253,252) 36%, rgb(240,240,240) 68%);
- background-image: -ms-linear-gradient(top, rgb(252,253,252) 36%, rgb(240,240,240) 68%);
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0.36, rgb(252,253,252)), color-stop(0.68, rgb(240,240,240)));
-}
-
-@mixin box {
- padding: 0px;
-}
-
-@mixin btn {
- color: black;
- border-radius: 5px;
- margin-right: 20px; // LTR
- margin-bottom: 5px;
- padding: 5px;
- &:hover {
- background-color: $grayLight;
- cursor: pointer;
- label {
- cursor: pointer;
- }
- }
-}
-
-@mixin radio-buttons {
- @include box;
- clear: both;
- margin-top: 10px;
-
- .form-item {
- @include btn;
-
- input {
- display: inline;
- }
- }
-}
-
-@mixin fieldset-title {
- fieldset.form-wrapper {
- border: none;
-
- legend {
- width: 100%;
- }
- .fieldset-legend {
- border-bottom: 1px solid $gray2;
- display: block;
- margin-top: 0;
- padding-left: 0;
- text-transform: none;
- width: 100%;
- }
- }
-}
-
-@mixin fieldset-content {
- @include box;
-
- .form-type-checkbox {
- // Hide Show end date checkbox.
- display: none;
- }
- .container-inline-date {
- clear: none;
- float: left; // LTR
- width: auto;
-
- .description {
- display: none;
- }
- .form-item {
- padding: 0;
- }
- .date-padding {
- float: left; // LTR
- padding: 0;
-
- input.form-text {
- width: 55px;
- }
- & > .form-item:first-child input.form-text {
- // TODO: For some reason this icon isn't added.
- background: white url('../images/calendar.png') no-repeat 86px 0px; // LTR
- width: 100px;
- }
- }
- & > .form-item {
- border: none;
- }
- label {
- display: block;
- float: left; // LTR
- padding-right: 10px; // LTR
- }
- &.end-date-wrapper {
- margin-left: 20px; // LTR
- }
- }
-}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/scss/commerce_discount-rtl.scss b/profiles/commerce_kickstart/modules/contrib/commerce_discount/scss/commerce_discount-rtl.scss
deleted file mode 100644
index 8c810909..00000000
--- a/profiles/commerce_kickstart/modules/contrib/commerce_discount/scss/commerce_discount-rtl.scss
+++ /dev/null
@@ -1,200 +0,0 @@
-@import "_mixins.scss";
-
-@mixin btn {
- margin-left: 20px;
- margin-right: 0; // RTL
-}
-.form-item.form-type-radio {
- position: relative;
- .progress-disabled {
- float: none;
- }
- .ajax-progress-throbber {
- position: absolute;
- right: -10px;
- }
-}
-
-@mixin radio-buttons {
- .form-item {
- @include btn;
- }
-}
-
-@mixin fieldset-content {
- .container-inline-date {
- float: right;
-
- .date-padding {
- float: left; // LTR
-
-
- & > .form-item:first-child input.form-text {
- // TODO: For some reason this icon isn't added.
- background: white url('../images/calendar.png') no-repeat 2px 0px;
- }
- }
- label {
- float: right;
- padding-right: 0px;
- padding-left: 10px; // RTL
- }
- &.end-date-wrapper {
- margin-left: 0; // RTL
- margin-right: 20px;
- }
- }
-}
-
-html.js input.form-autocomplete {
- background-position: 0% 2px; // RTL
-}
-
-/**
- * Discount form.
- */
-.commerce-discount-form {
- // Position the discount status block on top right region.
- position: relative;
- .form-item-status {
- background-color: #eee;
- padding: 10px 10px 20px 10px;
- position: absolute;
- top: 0;
- left: 0;
- right: auto; // RTL
- width: 180px;
- }
- // Reset
- .form-item-label {
- clear: both;
- .form-item {
- @include box;
- }
- }
- .form-item.form-type-radio {
- position: relative;
- .ajax-progress-throbber {
- position: absolute;
- right: -10px;
-
- }
- }
- // general block margins
- #commerce-discount-fields-wrapper .form-wrapper {
- & > #inline-conditions-inline_conditions .form-wrapper .ajax-progress {
- display: block; /* RTL */
- margin-top: 10px; /* RTL */
- width: 180px; /* RTL */
- }
- & > #inline-conditions-inline_conditions .form-wrapper .condition-wrapper .form-item {
- .ajax-progress {
- display: inline-block;
- margin-top: 0;
- width: auto;
- }
- }
- }
-}
-/**
- * Choose discount type block.
- */
-.form-item-commerce-discount-type {
- .form-radios {
- .form-item {
- float: right;
-
- #edit-commerce-discount-type {
- @include radio-buttons;
-
- .form-item {
- float: right;
- }
- }
- }
- }
-}
-/**
- * Choose offer type block.
- */
-.field-name-commerce-discount-offer {
- clear: both; // RTL
-
- .form-wrapper .form-wrapper {
- .form-item {
- label {
- padding-right: 5px;
- padding-left: 0; // RTL
- }
- div.form-radios {
- @include radio-buttons;
-
- border-right: 0; // RTL
- border-left: 1px dotted $gray2;
- float: right;
- padding-right: 0; // RTL
- padding-left: 20px;
-
- label {
- padding-right: 5px;
- padding-left: 0; // RTL
- }
- }
- }
- .form-wrapper {
- label {
- padding-right: 5px;
- padding-left: 0; // RTL
- }
- &.form-item {
- float: right;
- }
- }
- }
-}
-
-/**
- * Discount dates block.
- */
-.field-name-commerce-discount-date {
- .fieldset-wrapper {
- @include fieldset-content;
- }
-}
-
-/**
- * Usage block.
- */
-.commerce-discount-usage {
- .form-item.form-type-select {
- margin: 0;
-
- label {
- border-bottom: 1px solid $gray2;
- }
- }
- .form-item .form-select {
- float: right;
- }
- .field-name-commerce-discount-max-uses {
- @include box;
-
- & > div {
- float: left; // LTR
- margin-left: 30px; // LTR
-
- &:first-child {
- margin-left: 0;
- }
-
- }
- }
- .field-type-number-integer {
- float: right;
-
- label {
- margin-left: 0px;
- margin-right: 10px; // RTL
- }
- }
-}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount.test b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount.test
new file mode 100644
index 00000000..02e0288f
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount.test
@@ -0,0 +1,587 @@
+ 'Discounts',
+ 'description' => 'Test discounts functionality',
+ 'group' => 'Commerce Discount',
+ );
+ }
+
+ /**
+ * Test the importing of commerce discounts.
+ */
+ public function testCommerceDiscountImport() {
+ $exported_discount = '{
+ "name" : "pf",
+ "label" : "PF",
+ "type" : "product_discount",
+ "status" : "1",
+ "component_title" : "pf",
+ "sort_order" : "10",
+ "commerce_discount_offer" : {
+ "type" : "fixed_amount",
+ "commerce_fixed_amount" : { "und" : [
+ {
+ "amount" : "1200",
+ "currency_code" : "USD",
+ "data" : { "components" : [] }
+ }
+ ]
+ }
+ },
+ "commerce_compatibility_strategy" : { "und" : [ { "value" : "any" } ] },
+ "commerce_compatibility_selection" : [],
+ "commerce_discount_date" : [],
+ "inline_conditions" : [],
+ "discount_usage_per_person" : [],
+ "discount_usage_limit" : []
+}';
+
+ // Import the discount.
+ $import = entity_import('commerce_discount', $exported_discount);
+ $this->assertNotNull($import, 'Entity export JSON imported successfully.');
+ entity_save('commerce_discount', $import);
+
+ // Export the discount to make sure it's identical to the import string.
+ $discount = entity_load_single('commerce_discount', $import->discount_id);
+ $export = entity_export('commerce_discount', $discount);
+ $this->assertTrue($exported_discount == $export, 'Exported discount is identical to its origin.');
+ }
+
+ /**
+ * Test order wrapper cache from order refresh.
+ */
+ public function testCommerceDiscountOrderRefreshWrapper() {
+ // Create a 'free bonus products' product discount.
+ $discount = $this->createDiscount('order_discount', 'free_products', array($this->product->product_id));
+ // Create a completed order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ $line_items = $order_wrapper->value()->commerce_line_items[LANGUAGE_NONE];
+ $this->assertEqual($order_wrapper->commerce_line_items->count(), count($line_items), 'Number of line items matched');
+
+ // Disable the discount.
+ $discount->status = FALSE;
+ entity_save('commerce_discount', $discount);
+
+ $order_wrapper = commerce_cart_order_refresh($order);
+ $line_items = $order_wrapper->value()->commerce_line_items[LANGUAGE_NONE];
+ $this->assertEqual($order_wrapper->commerce_line_items->count(), count($line_items), 'Number of line items matched');
+ }
+
+ /**
+ * Test fixed order discounts.
+ */
+ public function testCommerceDiscountFixedOrderDiscount() {
+ // Testing fixed discount.
+ // Create a fixed order discount of $3.
+ $discount = $this->createDiscount('order_discount', 'fixed_amount', 300);
+
+ // Create an order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+
+ // Check if the discount was applied on the order total price.
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 700, 'Fixed order discount is deducted correctly.');
+
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+
+ // Check if the discount was applied on the order total price.
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 700, 'Fixed order discount is deducted correctly even after order refresh.');
+
+ // Disable the discount.
+ $discount->status = FALSE;
+ entity_save('commerce_discount', $discount);
+
+ // Re-save the order.
+ // Check if the discount was applied on the order total price.
+ $order_wrapper = entity_metadata_wrapper('commerce_order', $order);
+ $order_wrapper->save();
+
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 1000, "Fixed order discount is removed when it's not applicable.");
+ }
+
+ /**
+ * Test percentage order discounts.
+ */
+ public function testCommerceDiscountPercentageOrderDiscount() {
+ // Testing percentage discount.
+ // Create a percentage order discount of 5%.
+ $discount = $this->createDiscount('order_discount', 'percentage', 5);
+ // Create a completed order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+
+ // Check if the discount was applied on the order total price.
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 950, 'Percentage order discount is deducted correctly.');
+
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+
+ // Check if the discount was applied on the order total price.
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 950, 'Percentage order discount is deducted correctly even after refresh.');
+
+ // Disable the discount.
+ $discount->status = FALSE;
+ entity_save('commerce_discount', $discount);
+
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 1000, "Percentage order discount is removed when it's not applicable.");
+ }
+
+ /**
+ * Test a 100% off product percentage discount.
+ *
+ * A 100% off product-level discount differs from the "Free product" discount
+ * offer type since those are normally used as an "add-on" that is added
+ * without the user's interaction (maybe as part of a package, or bonus);
+ * whereas a 100% off discount should be used for any product purposely added
+ * to a cart order.
+ */
+ public function testCommerceDiscountOneHundredPercentOff() {
+ // Login as the store admin.
+ $this->drupalLogin($this->store_admin);
+
+ // Create a 100% off discount and create a test product.
+ $discount = $this->createDiscount('product_discount', 'percentage', 100, 'freebie');
+
+ $product = $this->createDummyProduct('TEST-PRODUCT', 'Test Product', 999);
+
+ // Create the order and apply the freebie discount.
+ $order = $this->createDummyOrder($this->store_admin->uid, array($product->product_id => 1));
+ $order_wrapper = commerce_cart_order_refresh($order);
+
+ $properly_applied = $this->discountAppliedToOrder('freebie', $order);
+ $this->assertTrue($properly_applied, t('100% off discount applied to a product.'));
+
+ // Verify that the product is now free.
+ $unit_price = $order_wrapper->commerce_line_items->get(0)->commerce_unit_price->value();
+
+ $this->assertEqual($unit_price['amount'], 0, 'Product line item unit price amount is properly set to 0.');
+ $this->assertEqual($unit_price['data']['components'][1]['price']['amount'], -999, 'Product line item unit price discount component properly set to 100% of the product price.');
+
+ $order_wrapper = commerce_cart_order_refresh($order);
+
+ $properly_applied = $this->discountAppliedToOrder('freebie', $order);
+ $this->assertTrue($properly_applied, t('100% off discount applied to a product even after refresh.'));
+
+ // Verify that the product is now free.
+ $unit_price = $order_wrapper->commerce_line_items->get(0)->commerce_unit_price->value();
+
+ $this->assertEqual($unit_price['amount'], 0, 'Product line item unit price amount is properly set to 0 even after refresh.');
+ $this->assertEqual($unit_price['data']['components'][1]['price']['amount'], -999, 'Product line item unit price discount component properly set to 100% of the product price even after refresh.');
+
+ // Disable the discount.
+ $discount->status = FALSE;
+ entity_save('commerce_discount', $discount);
+
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ $unit_price = $order_wrapper->commerce_line_items->get(0)->commerce_unit_price->value();
+
+ $properly_applied = $this->discountAppliedToOrder('freebie', $order);
+ $this->assertFalse($properly_applied, t('100% off discount not applied to a product.'));
+
+ $this->assertEqual($unit_price['amount'], 999, 'Product line item unit price amount is 999.');
+ }
+
+ /**
+ * Test free bonus products order discounts.
+ */
+ public function testCommerceDiscountFreeProductsOrderDiscount() {
+ // Create 'free bonus products' product discount.
+ $discount = $this->createDiscount('order_discount', 'free_products', array($this->product->product_id));
+ // Create a completed order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+
+ // Check if the discount was applied on the order total price.
+ $this->assertEqual($order_wrapper->commerce_order_total->amount->value(), 1000, 'Free Bonus Products order discount has the price of only one product.');
+ $this->assertEqual($order_wrapper->commerce_line_items->count(), 2, 'Free Bonus Products order discount is added as a line item.');
+
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+
+ // Check if the discount was applied on the order total price.
+ $this->assertEqual($order_wrapper->commerce_order_total->amount->value(), 1000, 'Free Bonus Products order discount has the price of only one product even after refresh.');
+ $this->assertEqual($order_wrapper->commerce_line_items->count(), 2, 'Free Bonus Products order discount is added as a line item even after refresh.');
+
+ // Disable the discount.
+ $discount->status = FALSE;
+ entity_save('commerce_discount', $discount);
+
+ // Re-save the order.
+ // Check if the discount was applied on the order total price.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ $this->assertEqual($order_wrapper->commerce_order_total->amount->value(), 1000, "Free Bonus Products order discount is removed when it's not applicable and price is the same.");
+ $this->assertEqual($order_wrapper->commerce_line_items->count(), 1, "Free Bonus Products order discount is removed when it's not applicable and line item count is only 1");
+ }
+
+ /**
+ * Test fixed product discounts.
+ */
+ public function testCommerceDiscountFixedProductDiscount() {
+ $discount = $this->createDiscount('product_discount', 'fixed_amount', 300);
+
+ // Create an order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ $order_wrapper = commerce_cart_order_refresh($order);
+
+ // Check if the discount was added as a component to the line item.
+ $price = $order_wrapper->commerce_line_items->get(0)->commerce_unit_price->value();
+ $this->assertTrue($price['data']['components'][1]['price']['amount'] == -300, 'Fixed product discount is added as a price component to the line item.');
+ $this->assertEqual($price['amount'], 700, 'Line item price with fixed product discount is correct.');
+
+ $order_wrapper = commerce_cart_order_refresh($order);
+
+ // Check if the discount was added as a component to the line item.
+ $price = $order_wrapper->commerce_line_items->get(0)->commerce_unit_price->value();
+ $this->assertTrue($price['data']['components'][1]['price']['amount'] == -300, 'Fixed product discount is added as a price component to the line item even after refresh.');
+ $this->assertEqual($price['amount'], 700, 'Line item price with fixed product discount is correct even after refresh.');
+
+ // Disable the discount.
+ $discount->status = FALSE;
+ entity_save('commerce_discount', $discount);
+
+ $order_wrapper = commerce_cart_order_refresh($order);
+
+ // Check if the discount is not applied.
+ $price = $order_wrapper->commerce_line_items->get(0)->commerce_unit_price->value();
+ $this->assertEqual($price['amount'], 1000, 'Disabled fixed product discount is does not appear in the price.');
+ }
+
+ /**
+ * Test percentage product discounts.
+ */
+ public function testCommerceDiscountPercentageProductDiscount() {
+ $discount = $this->createDiscount('product_discount', 'percentage', 5);
+
+ // Create an order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ $order_wrapper = commerce_cart_order_refresh($order);
+
+ // Check if the discount was added as a component to the line item.
+ $price = $order_wrapper->commerce_line_items->get(0)->commerce_unit_price->value();
+ $this->assertEqual($price['data']['components'][1]['price']['amount'], -50, 'Percentage product discount is added as a price component to the line item.');
+ $this->assertEqual($price['amount'], 950, 'Line item amount with Percentage product discount is correct.');
+
+ $order_wrapper = commerce_cart_order_refresh($order);
+ // Check if the discount was added as a component to the line item.
+ $price = $order_wrapper->commerce_line_items->get(0)->commerce_unit_price->value();
+ $this->assertEqual($price['data']['components'][1]['price']['amount'], -50, 'Percentage product discount is added as a price component to the line item even after refresh.');
+ $this->assertEqual($price['amount'], 950, 'Line item amount with Percentage product discount is correct even after refresh.');
+
+ // Disable the discount.
+ $discount->status = FALSE;
+ entity_save('commerce_discount', $discount);
+
+ $order_wrapper = commerce_cart_order_refresh($order);
+
+ // Check if the discount was added as a component to the line item.
+ $price_data = $order_wrapper->commerce_line_items->get(0)->commerce_unit_price->value();
+ $this->assertEqual($price_data['amount'], 1000, 'Line item amount without Percentage product discount is correct.');
+ }
+
+ /**
+ * Test discounted product price display.
+ */
+ public function testCommerceDiscountDiscountedProductPriceDisplay() {
+ // Create a product discount.
+ $this->createDiscount('product_discount', 'fixed_amount', 300);
+ $formatted_discounted_price = '$7.00';
+
+ // Log in as a normal user.
+ $this->drupalLogin($this->store_customer);
+
+ $nid = $this->product_node->nid;
+ // View a product node.
+ $this->drupalGet("node/$nid");
+ $product_price = $this->xpath('//div[contains(@class, "field-name-commerce-price")]/div[contains(@class, "field-item")]');
+ $this->assertTrue(trim((string) $product_price[0]->div) == $formatted_discounted_price, 'Discounted product price is shown on product page.');
+
+ // Add a product to the cart.
+ $this->drupalPost('node/' . $this->product_node->nid, array(), t('Add to cart'));
+
+ // View the cart.
+ $this->drupalGet('cart');
+ $product_price = $this->xpath('//td[contains(@class, "views-field-commerce-unit-price")]');
+ $this->assertTrue(trim((string) $product_price[0]->{0}) == $formatted_discounted_price, 'Discounted product price is shown on the cart.');
+ }
+
+ /**
+ * Test multiple fixed order discounts.
+ */
+ public function testCommerceDiscountMultipleFixedOrderDiscounts() {
+ // Create two discounts.
+ $this->createDiscount('order_discount', 'fixed_amount', 300, 'of1');
+ $this->createDiscount('order_discount', 'fixed_amount', 200, 'of2');
+
+ // Create an order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+
+ $this->assertTrue($order_wrapper->commerce_discounts->count() == 2, '2 discounts are listed as applied on the order.');
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 500, 'Two fixed order discounts are applied on the total price.');
+ $this->assertTrue($order_wrapper->commerce_line_items->count() == 3, 'An order with one product and two fixed order discounts has three line items.');
+ $order_wrapper->save();
+ $this->assertTrue($order_wrapper->commerce_line_items->count() == 3, 'After updating the order it still has three line items.');
+ }
+
+ /**
+ * Test rounding in percentage based product discounts.
+ *
+ * To test the rounding used when adding discount price components to product
+ * line items, we use a 30% discount on a product that costs $10.25. When
+ * rounding was not working correctly, the unit price amount would be set to
+ * $7.18 even though the sum of the unit price's price components would in
+ * fact be $7.17. In reality, since the actual discount amount SHOULD be
+ * rounded up to $3.08 from $3.075, the unit price amount SHOULD be $7.17.
+ * This test ensures that is the case in conjunction with a patch from the
+ * linked issue below.
+ *
+ * @link https://www.drupal.org/node/2468943#comment-10476486
+ */
+ public function testCommerceProductPercentageDiscountRounding() {
+ // Create the 30% discount and $10.25 product.
+ $this->createDiscount('product_discount', 'percentage', 30, 'discount_30_off');
+ $product = $this->createDummyProduct('TEST-PRODUCT', 'Test Product', 1025);
+
+ // Create the order and apply discount.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($product->product_id => 1), 'completed');
+ $order_wrapper = commerce_cart_order_refresh($order);
+
+ // Verify rounding came out properly.
+ $line_item_wrapper = $order_wrapper->commerce_line_items->get(0);
+ $unit_price = $line_item_wrapper->commerce_unit_price->value();
+
+ $this->assertEqual($unit_price['amount'], 717, 'Product line item unit price amount rounded properly for a 30% discount.');
+ $this->assertEqual($unit_price['data']['components'][1]['price']['amount'], -308, 'Product line item unit price discount component properly rounded for a 30% discount.');
+ }
+
+ /**
+ * Test discount compatibility strategies.
+ *
+ * Currently implemented strategies include:
+ * - any: discount is compatible with any other discount.
+ * - except: discount is compatible with any discount except selected ones.
+ * - only: discount is only compatible with selected ones.
+ * - none: discount is not compatible with any other discount.
+ *
+ * Compatibility is checked first to ensure that discounts already on an order
+ * are not incompatible with the discount being added. It is then checked to
+ * ensure the discount being added is not incompatible with any discount that
+ * has already been added to the order.
+ */
+ public function testCommerceDiscountCompatibilityStrategies() {
+ // Create two discounts set to execute one after the other.
+ $discount_one = $this->createDiscount('order_discount', 'fixed_amount', 100, 'of1', 1);
+ $discount_one_wrapper = entity_metadata_wrapper('commerce_discount', $discount_one);
+ $discount_two = $this->createDiscount('order_discount', 'fixed_amount', 200, 'of2', 2);
+ $discount_two_wrapper = entity_metadata_wrapper('commerce_discount', $discount_two);
+
+ // Create an order and recalculate discounts.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+
+ // Test compatibility with both discounts using the "any" strategy. Both
+ // discounts should be applied.
+ commerce_cart_order_refresh($order);
+
+ $properly_applied = $this->discountAppliedToOrder('of1', $order) && $this->discountAppliedToOrder('of2', $order);
+ $this->assertTrue($properly_applied, t('Discount one and two applied when both are compatible with any discount.'));
+
+ // Test compatibility with only discount one using the "none" strategy. Only
+ // discount one should be applied.
+ $discount_one_wrapper->commerce_compatibility_strategy = 'none';
+ $discount_one_wrapper->save();
+ commerce_cart_order_refresh($order);
+
+ $properly_applied = $this->discountAppliedToOrder('of1', $order) && !$this->discountAppliedToOrder('of2', $order);
+ $this->assertTrue($properly_applied, t('Only discount one applied when it is not compatible with any other discount.'));
+
+ // Test compatibility with only discount two using the "none" strategy. Only
+ // discount one should be applied.
+ $discount_one_wrapper->commerce_compatibility_strategy = 'any';
+ $discount_one_wrapper->save();
+ $discount_two_wrapper->commerce_compatibility_strategy = 'none';
+ $discount_two_wrapper->save();
+ commerce_cart_order_refresh($order);
+
+ $properly_applied = $this->discountAppliedToOrder('of1', $order) && !$this->discountAppliedToOrder('of2', $order);
+ $this->assertTrue($properly_applied, t('Only discount one applied when discount two is not compatible with any other discount.'));
+
+ // Test compatibility with discount one compatible with any discount
+ // except discount two. Only discount one should be applied.
+ $discount_one_wrapper->commerce_compatibility_strategy = 'except';
+ $discount_one_wrapper->commerce_compatibility_selection = array($discount_two->discount_id);
+ $discount_one_wrapper->save();
+ $discount_two_wrapper->commerce_compatibility_strategy = 'any';
+ $discount_two_wrapper->save();
+ commerce_cart_order_refresh($order);
+
+ $properly_applied = $this->discountAppliedToOrder('of1', $order) && !$this->discountAppliedToOrder('of2', $order);
+ $this->assertTrue($properly_applied, t('Only discount one applied when it is compatible with any discount except discount two.'));
+
+ // Test compatibility with discount two compatible with any discount
+ // except discount one. Only discount one should be applied.
+ $discount_one_wrapper->commerce_compatibility_strategy = 'any';
+ $discount_one_wrapper->save();
+ $discount_two_wrapper->commerce_compatibility_strategy = 'except';
+ $discount_two_wrapper->commerce_compatibility_selection = array($discount_one->discount_id);
+ $discount_two_wrapper->save();
+ commerce_cart_order_refresh($order);
+
+ $properly_applied = $this->discountAppliedToOrder('of1', $order) && !$this->discountAppliedToOrder('of2', $order);
+ $this->assertTrue($properly_applied, t('Only discount one applied when it is compatible with any discount and discount two is compatible with any discount except discount one.'));
+
+ // Test compatibility with discount two compatible with only discount
+ // one. Both discounts should be applied.
+ $discount_two_wrapper->commerce_compatibility_strategy = 'only';
+ $discount_two_wrapper->save();
+ commerce_cart_order_refresh($order);
+
+ $properly_applied = $this->discountAppliedToOrder('of1', $order) && $this->discountAppliedToOrder('of2', $order);
+ $this->assertTrue($properly_applied, t('Both discounts applied when discount one is compatible with any discount and discount two is compatible only with discount one.'));
+
+ // Test compatibility with discount two compatible with only discount
+ // one. Both discounts should be applied.
+ $discount_one_wrapper->commerce_compatibility_strategy = 'only';
+ $discount_one_wrapper->save();
+ $discount_two_wrapper->commerce_compatibility_strategy = 'any';
+ $discount_two_wrapper->save();
+ commerce_cart_order_refresh($order);
+
+ $properly_applied = $this->discountAppliedToOrder('of1', $order) && $this->discountAppliedToOrder('of2', $order);
+ $this->assertTrue($properly_applied, t('Both discounts applied when discount one is only compatible with discount two and discount two is compatible with any discount.'));
+ }
+
+ /**
+ * Test discount deletion.
+ *
+ * Discount deletion should not cause fatal errors on cart refresh.
+ *
+ * @link https://www.drupal.org/node/2538812
+ */
+ public function testCartWithDiscountsDeleted() {
+ // Testing fixed discount.
+ // Create a fixed order discount of $3.
+ /** @var CommerceDiscount $discount */
+ $discount = $this->createDiscount('order_discount', 'fixed_amount', 300);
+
+ // Create an order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+
+ // Check if the discount was applied on the order total price.
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 700, 'Fixed order discount is deducted correctly.');
+
+ // Delete the discount.
+ $discount->delete();
+
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 1000, "Fixed order discount is removed when it's not applicable.");
+ }
+
+ /**
+ * Test discount compatibility regression https://www.drupal.org/node/2621526.
+ *
+ * Discount "toggles" when cart page is refreshed.
+ */
+ public function testCommerceDiscountCompatibilityStrategiesRefresh() {
+ // Create two discounts set to execute one after the other.
+ $discount_one = $this->createDiscount('product_discount', 'percentage', 10, 'of1');
+ $discount_one_wrapper = entity_metadata_wrapper('commerce_discount', $discount_one);
+ $discount_two = $this->createDiscount('product_discount', 'percentage', 20, 'of2', 2);
+ $discount_two_wrapper = entity_metadata_wrapper('commerce_discount', $discount_two);
+
+ // Create an order and recalculate discounts.
+ $order = $this->createDummyOrder($this->store_customer->uid, array(
+ $this->product->product_id => 1
+ ), 'completed');
+
+ // Test compatibility with discount one compatible only with discount two
+ // And discount two compatible with any discount. Both should be applied.
+ $discount_one_wrapper->commerce_compatibility_strategy = 'only';
+ $discount_one_wrapper->commerce_compatibility_selection = array(
+ $discount_two->discount_id
+ );
+ $discount_one_wrapper->save();
+ $discount_two_wrapper->commerce_compatibility_strategy = 'any';
+ $discount_two_wrapper->save();
+ commerce_cart_order_refresh($order);
+
+ $properly_applied = $this->discountAppliedToOrder('of1', $order) && $this->discountAppliedToOrder('of2', $order);
+ $this->assertTrue($properly_applied, t('Both discounts applied when discount one is compatible with any discount and discount two is compatible only with discount one.'));
+
+ // Regression test for discount compatibility with itself.
+ commerce_cart_order_refresh($order);
+
+ $properly_applied = $this->discountAppliedToOrder('of1', $order) && $this->discountAppliedToOrder('of2', $order);
+ $this->assertTrue($properly_applied, t('Both discounts applied when discount one is compatible with any discount, discount two is compatible only with discount one and the order refreshed one more time.'));
+ }
+
+ /**
+ * Test discount compatibility regression https://www.drupal.org/node/2621526.
+ *
+ * Two "none" compatible discounts "toggles" when cart page is refreshed.
+ */
+ public function testCommerceDiscountCompatibilityStrategiesRefreshNone() {
+ // Create two discounts set to execute one after the other.
+ $discount_one = $this->createDiscount('product_discount', 'percentage', 10, 'of1');
+ $discount_one_wrapper = entity_metadata_wrapper('commerce_discount', $discount_one);
+ $discount_two = $this->createDiscount('product_discount', 'percentage', 20, 'of2', 2);
+ $discount_two_wrapper = entity_metadata_wrapper('commerce_discount', $discount_two);
+
+ // Create an order and recalculate discounts.
+ $order = $this->createDummyOrder($this->store_customer->uid, array(
+ $this->product->product_id => 1
+ ), 'completed');
+
+ // Test compatibility with both discounts compatible with no other
+ // discounts.
+ // Only first discount should be applied.
+ $discount_one_wrapper->commerce_compatibility_strategy = 'none';
+ $discount_one_wrapper->save();
+ $discount_two_wrapper->commerce_compatibility_strategy = 'none';
+ $discount_two_wrapper->save();
+ commerce_cart_order_refresh($order);
+
+ $properly_applied = $this->discountAppliedToOrder('of1', $order) && ! $this->discountAppliedToOrder('of2', $order);
+ $this->assertTrue($this->discountAppliedToOrder('of1', $order), t('Discount 1.'));
+ $this->assertFalse($this->discountAppliedToOrder('of2', $order), t('Discount 2.'));
+ $this->assertTrue($properly_applied, t('Only first discount applied when both discounts are incompatible with any discounts.'));
+
+ // Regression test for discount compatibility with itself.
+ commerce_cart_order_refresh($order);
+
+ $properly_applied = $this->discountAppliedToOrder('of1', $order) && ! $this->discountAppliedToOrder('of2', $order);
+ $this->assertTrue($this->discountAppliedToOrder('of1', $order), t('Discount 1.'));
+ $this->assertFalse($this->discountAppliedToOrder('of2', $order), t('Discount 2.'));
+ $this->assertTrue($properly_applied, t('Only first discount applied when both discounts are incompatible with any discounts and order refreshed once again.'));
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_base.test b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_base.test
new file mode 100644
index 00000000..5c1570e1
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_base.test
@@ -0,0 +1,253 @@
+sub_module) {
+ $modules[] = $this->sub_module;
+ }
+ parent::setUp($modules);
+
+ // User creation for different operations.
+ $this->store_admin = $this->createStoreAdmin();
+ $this->store_customer = $this->createStoreCustomer();
+
+ // Create a dummy product.
+ $this->product = $this->createDummyProduct('PROD-01', 'Product One', 1000);
+
+ // Create a dummy product display content type.
+ $this->createDummyProductDisplayContentType();
+
+ // Create a product display node.
+ $this->product_node = $this->createDummyProductNode(array($this->product->product_id), 'Product One node');
+
+ // Set the default country to US.
+ variable_set('site_default_country', 'US');
+ }
+
+ /**
+ * Create a discount.
+ *
+ * @param string $discount_type
+ * The discount type; Either 'order_discount' or 'product_discount'.
+ * @param string $offer_type
+ * The discount offer type; One of 'fixed_amount', 'percentage',
+ * 'free_products', 'free_shipping', 'percent_off_shipping' or
+ * 'shipping_upgrade'.
+ * @param int|array $amount
+ * In case of 'fixed_amount' a number: the discount amount.
+ * In case of 'percentage' a number: the percentage (a number less than 1).
+ * In case of 'free_products' an array of the product ids.
+ * In case of 'free_shipping' a string of the free shipping service name.
+ * In case of 'percent_off_shipping' an array with the percentage amount
+ * (key: 'percent', should be < 100) and the shipping service name string
+ * (key: 'service').
+ * In case of 'shipping_upgrade' an array with the source service (key: '
+ * source') and the target service (key: 'target').
+ * @param string $name
+ * Discount name - Optional. If given, CANNOT start with a number.
+ * @param string $component_title
+ * Component title - Optional.
+ *
+ * @return object
+ * The newly created commerce_discount entity.
+ */
+ protected function createDiscount($discount_type, $offer_type, $amount, $name = '', $component_title = '', $sort_order = 10) {
+ // Create the discount offer.
+ $commerce_discount_offer = entity_create('commerce_discount_offer', array('type' => $offer_type));
+ $offer_wrapper = entity_metadata_wrapper('commerce_discount_offer', $commerce_discount_offer);
+ switch ($offer_type) {
+ case 'fixed_amount':
+ $offer_wrapper->commerce_fixed_amount->amount = $amount;
+ $offer_wrapper->commerce_fixed_amount->currency_code = 'USD';
+ break;
+
+ case 'percentage':
+ $offer_wrapper->commerce_percentage = $amount;
+ break;
+
+ case 'free_products':
+ // Product ids array should be provided for $amount.
+ $offer_wrapper->commerce_free_products = $amount;
+ break;
+
+ case 'free_shipping':
+ $offer_wrapper->commerce_free_shipping = $amount;
+ $offer_wrapper->commerce_free_shipping_strategy = 'only_selected';
+ break;
+
+ case 'percent_off_shipping':
+ $offer_wrapper->commerce_percent_off_shipping = $amount['percent'];
+ if (!empty($amount[1])) {
+ $offer_wrapper->commerce_percent_off_ship_serv = $amount['service'];
+ }
+ break;
+
+ case 'shipping_upgrade':
+ $offer_wrapper->commerce_shipping_upgrade_target = $amount['target'];
+ $offer_wrapper->commerce_shipping_upgrade_source = $amount['source'];
+ break;
+ }
+
+ $offer_wrapper->save();
+
+ // Provide default name.
+ $name = $name ? $name : $discount_type . '_' . $offer_type;
+ $component_title = $component_title ? $component_title : $name;
+
+ // Create the discount.
+ $values = array(
+ 'name' => $name,
+ 'label' => $name,
+ 'type' => $discount_type,
+ 'sort_order' => $sort_order,
+ 'component_title' => $component_title,
+ 'status' => TRUE,
+ 'export_status' => TRUE,
+ );
+ $commerce_discount = entity_create('commerce_discount', $values);
+ $discount_wrapper = entity_metadata_wrapper('commerce_discount', $commerce_discount);
+ $discount_wrapper->commerce_discount_offer = $commerce_discount_offer;
+ $discount_wrapper->save();
+
+ return $discount_wrapper->value();
+ }
+
+ /**
+ * Determines whether or not a discount has been applied to an order.
+ *
+ * @param string $discount_name
+ * The machine-name of the discount to look for.
+ * @param object $order
+ * The order object to inspect for the discount.
+ *
+ * @return bool
+ * Boolean indicating whether or not the discount is applied to the order.
+ */
+ public function discountAppliedToOrder($discount_name, $order) {
+ // Fetch the list of discounts applied to the order based on the price
+ // components in its order total array.
+ $order_wrapper = entity_metadata_wrapper('commerce_order', $order);
+ $order_total = $order_wrapper->commerce_order_total->value();
+ $applied_discounts = commerce_discount_get_discounts_applied_to_price($order_total);
+
+ // Look for the given discount in the list of applied discounts.
+ return in_array($discount_name, $applied_discounts);
+ }
+
+ /**
+ * Create a discount.
+ *
+ * @param string $discount_type
+ * The discount type; Either 'order_discount' or 'product_discount'.
+ * @param string $offer_type
+ * The discount offer type; Either 'fixed_amount' or 'percentage'.
+ * @param int $amount
+ * The discount offer amount.
+ * @param int $max_usage
+ * Maximal uses for the discount.
+ *
+ * @return object
+ * The newly created commerce_discount entity.
+ */
+ protected function createUsageDiscount($discount_type, $offer_type, $amount, $max_usage) {
+ // Use the base class to create a discount.
+ $discount = $this->createDiscount($discount_type, $offer_type, $amount);
+
+ // Populate the max usage field.
+ $wrapper = entity_metadata_wrapper('commerce_discount', $discount);
+ $wrapper->discount_usage_limit = $max_usage;
+ $wrapper->save();
+
+ return $wrapper->value();
+ }
+
+ /**
+ * Create a date discount.
+ *
+ * @param string $discount_type
+ * The discount type; Either 'order_discount' or 'product_discount'.
+ * @param string $offer_type
+ * The discount offer type; Either 'fixed_amount' or 'percentage'.
+ * @param int $amount
+ * The discount offer amount.
+ * @param int $start_time
+ * Discount valid from.
+ * @param int $end_time
+ * Discount valid until.
+ *
+ * @return object
+ * The newly created commerce_discount entity.
+ */
+ protected function createDateDiscount($discount_type, $offer_type, $amount, $start_time, $end_time) {
+ // Use the base class to create a discount.
+ $discount = $this->createDiscount($discount_type, $offer_type, $amount);
+
+ // Populate the date fields.
+ $discount_wrapper = entity_metadata_wrapper('commerce_discount', $discount);
+ $discount_wrapper->commerce_discount_date = array(
+ 'value' => $start_time,
+ 'value2' => $end_time,
+ 'date_type' => 'datestamp',
+ );
+ $discount_wrapper->save();
+
+ return $discount_wrapper->value();
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_conditions.test b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_conditions.test
new file mode 100644
index 00000000..bb7f90c7
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_conditions.test
@@ -0,0 +1,184 @@
+ 'Discounts inline conditions',
+ 'description' => 'Test discounts inline conditions',
+ 'group' => 'Commerce Discount',
+ );
+ }
+
+ /**
+ * Set up our tests by adding some additional products.
+ */
+ public function setUp() {
+ parent::setUp();
+
+ // We need a bunch of products.
+ $this->products['b'] = $this->createDummyProduct('PROD-B', 'Product B', 1000);
+ $this->products['c'] = $this->createDummyProduct('PROD-C', 'Product C', 1000);
+ $this->products['d'] = $this->createDummyProduct('PROD-D', 'Product D', 1000);
+ $this->products['e'] = $this->createDummyProduct('PROD-E', 'Product E', 1000);
+ $this->products['f'] = $this->createDummyProduct('PROD-F', 'Product F', 1000);
+ }
+
+ /**
+ * Tests the 'commerce_order_contains_products' rule.
+ */
+ public function testOrderContainsProductsCondition() {
+ // Build a test matrix.
+ // @see https://www.drupal.org/node/2398113
+ $test_matrix = array(
+ // All of the products, including other products.
+ 'all inclusive' => array(
+ 'products_in_order' => array('b', 'c', 'd', 'e', 'f'),
+ 'results' => array(
+ 'any' => TRUE,
+ 'all' => TRUE,
+ 'exactly' => FALSE,
+ 'only' => FALSE,
+ ),
+ ),
+ // All of the products, exclusive of other products.
+ 'all exclusive' => array(
+ 'products_in_order' => array('c', 'e', 'f'),
+ 'results' => array(
+ 'any' => TRUE,
+ 'all' => TRUE,
+ 'exactly' => TRUE,
+ 'only' => TRUE,
+ ),
+ ),
+ // Some of the products, including one other product.
+ 'some inclusive' => array(
+ 'products_in_order' => array('b', 'c'),
+ 'results' => array(
+ 'any' => TRUE,
+ 'all' => FALSE,
+ 'exactly' => FALSE,
+ 'only' => FALSE,
+ ),
+ ),
+ // Some of the products, exclusively.
+ 'some exclusive' => array(
+ 'products_in_order' => array('e', 'f'),
+ 'results' => array(
+ 'any' => TRUE,
+ 'all' => FALSE,
+ 'exactly' => FALSE,
+ 'only' => TRUE,
+ ),
+ ),
+ // None of the products.
+ 'none' => array(
+ 'products_in_order' => array('b', 'd'),
+ 'results' => array(
+ 'any' => FALSE,
+ 'all' => FALSE,
+ 'exactly' => FALSE,
+ 'only' => FALSE,
+ ),
+ ),
+ );
+
+ // Set up all of the discount rules.
+ foreach ($test_matrix['none']['results'] as $operator => $result) {
+ $discount = $this->createDiscount('order_discount', 'fixed_amount', 100, 'ic_' . $operator, 1);
+ $discount->inline_conditions[LANGUAGE_NONE][0] = array(
+ 'condition_name' => 'commerce_order_contains_products',
+ 'condition_settings' => array(
+ 'operator' => $operator,
+ 'products' => array(
+ array('product_id' => $this->products['c']->product_id),
+ array('product_id' => $this->products['e']->product_id),
+ array('product_id' => $this->products['f']->product_id),
+ ),
+ ),
+ );
+ entity_save('commerce_discount', $discount);
+ }
+
+ // Loop through each element of the test matrix and run the tests.
+ foreach ($test_matrix as $set => $test_details) {
+ $order_products = array();
+
+ // Only add products we want for our test.
+ foreach ($test_details['products_in_order'] as $product_letter) {
+ $order_products[$this->products[$product_letter]->product_id] = 1;
+ }
+
+ // Create a discount with our dummy products.
+ $order = $this->createDummyOrder($this->store_customer->uid, $order_products);
+
+ // Refresh the order to apply the discounts.
+ commerce_cart_order_refresh($order);
+
+ // Check if the discount was applied on the order total price.
+ foreach ($test_details['results'] as $operator => $result) {
+ $this->assertTrue(($this->discountAppliedToOrder('ic_' . $operator, $order) === $result), 'Order discount properly applies with "' . $operator . '" operator to product set: ' . $set . '.', 'Discount');
+ }
+
+ // Delete the order.
+ commerce_order_delete($order->order_id);
+ }
+ }
+
+ /**
+ * Test commerce_product_contains_products() condition.
+ */
+ public function testCommerceProductContainsProducts() {
+ $discount = $this->createDiscount('product_discount', 'fixed_amount', 100, 'product_sku_discount');
+ $discount->inline_conditions[LANGUAGE_NONE][0] = array(
+ 'condition_name' => 'commerce_product_contains_products',
+ 'condition_settings' => array(
+ 'sku' => array(
+ array('product_id' => $this->products['c']->product_id),
+ ),
+ ),
+ );
+ entity_save('commerce_discount', $discount);
+
+ // Calculated price has discount.
+ $calculated_data = commerce_product_calculate_sell_price($this->products['c']);
+ $discounts = commerce_discount_get_discounts_applied_to_price($calculated_data);
+ $this->assertTrue(!empty($discounts));
+
+ $calculated_data = commerce_product_calculate_sell_price($this->products['b']);
+ $discounts = commerce_discount_get_discounts_applied_to_price($calculated_data);
+ $this->assertTrue(empty($discounts));
+
+ // Orders have discount.
+ $order = $this->createDummyOrder($this->store_customer->uid, array(
+ $this->products['c']->product_id => 1,
+ ));
+ // Refresh the order to apply the discounts.
+ commerce_cart_order_refresh($order);
+ $this->assertTrue($this->discountAppliedToOrder('product_sku_discount', $order));
+
+ // Delete order createDummyOrder method uses commerce_cart_order_load.
+ commerce_order_delete($order->order_id);
+
+ $order2 = $this->createDummyOrder($this->store_customer->uid, array(
+ $this->products['b']->product_id => 1,
+ ));
+ // Refresh the order to apply the discounts.
+ commerce_cart_order_refresh($order2);
+ $this->assertFalse($this->discountAppliedToOrder('product_sku_discount', $order2));
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_date.test b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_date.test
new file mode 100644
index 00000000..418e3599
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_date.test
@@ -0,0 +1,144 @@
+ 'Discounts date',
+ 'description' => 'Test discounts date functionality',
+ 'group' => 'Commerce Discount',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setUp() {
+ parent::setUp();
+ }
+
+ /**
+ * Test order discount in timespan.
+ */
+ public function testDiscountDateOrderDiscountInTime() {
+ // Create a discount valid from yesterday until tomorrow.
+ $start_time = time() - $this->dayInSeconds;
+ $end_time = time() + $this->dayInSeconds;
+
+ // Testing fixed discount.
+ $this->createDateDiscount('order_discount', 'fixed_amount', 300, $start_time, $end_time);
+
+ // Create an order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ // Check if the discount was applied on the order total price.
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 700, 'Order discount is deducted when in time frame.');
+ }
+
+ /**
+ * Test order discount out of timespan.
+ */
+ public function testDiscountDateOrderDiscountOutOfTime() {
+ // Create a discount valid from tomorrow.
+ $start_time = time() + $this->dayInSeconds;
+ $end_time = time() + 2 * $this->dayInSeconds;
+
+ // Testing fixed discount.
+ // Create a fixed order discount of $3 limited to one use.
+ $this->createDateDiscount('order_discount', 'fixed_amount', 300, $start_time, $end_time);
+
+ // Create an order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ $order_wrapper = entity_metadata_wrapper('commerce_order', $order);
+ // Check if the discount was applied on the order total price.
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 1000, 'Order discount is ignored when out of time frame.');
+ }
+
+ /**
+ * Test product discount in timespan.
+ */
+ public function testDiscountDateProductDiscountInTime() {
+ // Create a discount valid from yesterday until tomorrow.
+ $start_time = time() - $this->dayInSeconds;
+ $end_time = time() + $this->dayInSeconds;
+
+ $this->createDateDiscount('product_discount', 'fixed_amount', 300, $start_time, $end_time);
+
+ // Create an order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ $order_wrapper = entity_metadata_wrapper('commerce_order', $order);
+ // Invoke line item price re-calculation.
+ $line_item = $order_wrapper->commerce_line_items->get(0)->value();
+ rules_invoke_event('commerce_product_calculate_sell_price', $line_item);
+ // Check if the discount was added as a component to the line item.
+ $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
+ $price_data = $line_item_wrapper->commerce_unit_price->data->value();
+ $this->assertEqual($price_data['components'][1]['price']['amount'], -300, 'Product discount is applied when discount is in time frame.');
+ }
+
+ /**
+ * Test product discount out of timespan.
+ */
+ public function testDiscountDateProductDiscountOutOfTime() {
+ // Create a discount valid from tomorrow.
+ $start_time = time() + $this->dayInSeconds;
+ $end_time = time() + (2 * $this->dayInSeconds);
+
+ $this->createDateDiscount('product_discount', 'fixed_amount', 300, $start_time, $end_time);
+
+ // Create an order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ $order_wrapper = entity_metadata_wrapper('commerce_order', $order);
+ // Invoke line item price re-calculation.
+ $line_item = $order_wrapper->commerce_line_items->get(0)->value();
+ rules_invoke_event('commerce_product_calculate_sell_price', $line_item);
+ // Check if the discount was added as a component to the line item.
+ $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
+ $price_data = $line_item_wrapper->commerce_unit_price->data->value();
+ $this->assertTrue(count($price_data['components']) == 1, 'Product discount is ignored when discount is out of time frame.');
+ }
+
+ /**
+ * Test product discount on the same day.
+ */
+ public function testDiscountSameDay() {
+ // Create a discount valid for today only.
+ $start_date = new DateTime();
+ $start_date->setTime(0, 0, 0);
+ $start_time = $start_date->getTimestamp();
+ $end_time = $start_time;
+
+ $this->createDateDiscount('product_discount', 'fixed_amount', 300, $start_time, $end_time);
+
+ // Create an order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ $order_wrapper = entity_metadata_wrapper('commerce_order', $order);
+ // Invoke line item price re-calculation.
+ $line_item = $order_wrapper->commerce_line_items->get(0)->value();
+ rules_invoke_event('commerce_product_calculate_sell_price', $line_item);
+ // Check if the discount was added as a component to the line item.
+ $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
+ $price_data = $line_item_wrapper->commerce_unit_price->data->value();
+ $this->assertEqual($price_data['components'][1]['price']['amount'], -300, 'Product discount is applied when discount is in time frame.');
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_date_ui.test b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_date_ui.test
new file mode 100644
index 00000000..a3ec38f2
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_date_ui.test
@@ -0,0 +1,141 @@
+ 'Discounts date UI',
+ 'description' => 'Test discounts date UI',
+ 'group' => 'Commerce Discount UI',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setUp() {
+ parent::setUp();
+ }
+
+ /**
+ * Test date specific elements in the add discount UI.
+ */
+ public function testDiscountDateUIAddDiscount() {
+ // Login with store admin.
+ $this->drupalLogin($this->store_admin);
+
+ // Access to the admin discount creation page.
+ $this->drupalGet('admin/commerce/discounts/add');
+
+ // Check the integrity of the add form.
+ $this->assertFieldByName('commerce_discount_fields[commerce_discount_date][und][0][value][date]', NULL, 'Start date field is present');
+ $this->assertFieldByName('commerce_discount_fields[commerce_discount_date][und][0][value2][date]', NULL, 'End date field is present');
+
+ // Create a discount valid from yesterday until tomorrow.
+ $start_time = time() - $this->dayInSeconds;
+ $start_date = date($this->dateFormat, $start_time);
+ $end_time = time() + $this->dayInSeconds;
+ $end_date = date($this->dateFormat, $end_time);
+
+ $values = array(
+ 'label' => 'Order discount - fixed',
+ 'name' => 'order_discount_fixed',
+ 'component_title' => 'Order discount',
+ 'commerce_discount_fields[commerce_discount_offer][und][form][commerce_fixed_amount][und][0][amount]' => 12.77,
+ 'commerce_discount_fields[commerce_discount_date][und][0][value][date]' => $start_date,
+ 'commerce_discount_fields[commerce_discount_date][und][0][value2][date]' => $end_date,
+ );
+ $this->drupalPost(NULL, $values, t('Save discount'));
+
+ // Load the discount and wrap it.
+ $discount = entity_load_single('commerce_discount', 1);
+ $wrapper = entity_metadata_wrapper('commerce_discount', $discount);
+
+ // Check the usage fields of the stored discount.
+ $result_start_date = date($this->dateFormat, $wrapper->commerce_discount_date->value->value());
+ $result_end_date = date($this->dateFormat, $wrapper->commerce_discount_date->value2->value());
+ $this->assertEqual($result_start_date, $start_date, 'Start date is stored correctly.');
+ $this->assertEqual($result_end_date, $end_date, 'End date is stored correctly.');
+
+ // Check the discounts listing.
+ $this->assertText($start_date, 'Start date is shown');
+ $this->assertText($end_date, 'End date is shown');
+ }
+
+ /**
+ * Test the Edit discount UI.
+ */
+ public function testDiscountDateUIEditDiscount() {
+ // Create a discount valid from yesterday until tomorrow.
+ $start_time = time() - $this->dayInSeconds;
+ $end_time = time() + $this->dayInSeconds;
+ $discount = $this->createDateDiscount('order_discount', 'fixed_amount', 300, $start_time, $end_time);
+
+ // Login with store admin.
+ $this->drupalLogin($this->store_admin);
+
+ // Access to the admin discount edit page.
+ $this->drupalGet('admin/commerce/discounts/manage/' . $discount->name);
+
+ // Check the integrity of the add form.
+ $this->assertFieldByName('commerce_discount_fields[commerce_discount_date][und][0][value][date]', NULL, 'Start date field is present');
+ $this->assertFieldByName('commerce_discount_fields[commerce_discount_date][und][0][value2][date]', NULL, 'End date field is present');
+
+ // Change the discount date, to be valid from tomorrow.
+ $start_time = time() + $this->dayInSeconds;
+ $end_time = time() + (2 * $this->dayInSeconds);
+ $start_date = date($this->dateFormat, $start_time);
+ $end_date = date($this->dateFormat, $end_time);
+
+ $values = array(
+ 'label' => 'Order discount - fixed',
+ 'name' => 'order_discount_fixed',
+ 'component_title' => 'Order discount',
+ 'commerce_discount_fields[commerce_discount_offer][und][form][commerce_fixed_amount][und][0][amount]' => 12.77,
+ 'commerce_discount_fields[commerce_discount_date][und][0][value][date]' => $start_date,
+ 'commerce_discount_fields[commerce_discount_date][und][0][value2][date]' => $end_date,
+ );
+
+ $this->drupalPost(NULL, $values, t('Save discount'));
+
+ // Load the discount from the database and wrap it.
+ $discounts = entity_load('commerce_discount', array($discount->discount_id), $conditions = array(), $reset = TRUE);
+ $wrapper = entity_metadata_wrapper('commerce_discount', reset($discounts));
+
+ // Check the usage fields of the stored discount.
+ $result_start_date = date($this->dateFormat, $wrapper->commerce_discount_date->value->value());
+ $result_end_date = date($this->dateFormat, $wrapper->commerce_discount_date->value2->value());
+ $this->assertEqual($result_start_date, $start_date, 'Start date is stored correctly.');
+ $this->assertEqual($result_end_date, $end_date, 'End date is stored correctly.');
+
+ // Check the discounts listing.
+ $this->assertText($start_date, 'Start date is shown');
+ $this->assertText($end_date, 'End date is shown');
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_shipping.test b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_shipping.test
new file mode 100644
index 00000000..1c099015
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_shipping.test
@@ -0,0 +1,229 @@
+ 'Shipping discounts',
+ 'description' => 'Test shipping discounts functionality',
+ 'group' => 'Commerce Discount',
+ );
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function setUp() {
+ parent::setUp();
+ module_enable(array('commerce_discount_shipping_test'));
+ $this->resetAll();
+ }
+
+ /**
+ * Test shipping discounts.
+ */
+ public function testCommerceDiscountShippingDiscounts() {
+ $shipping_service_name = 'commerce_discount_cheap_shipping';
+ $decent_shipping_service_name = 'commerce_discount_decent_shipping';
+ $expensive_shipping_service_name = 'commerce_discount_expensive_shipping';
+
+ // Create an order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'checkout_review', NULL);
+
+ // Check shipping prices shown in checkout.
+ $this->drupalLogin($this->store_customer);
+ $this->drupalGet('checkout/' . $order->order_id . '/shipping');
+ $this->assertText('Cheap shipping: $5.00', t('Cheap shipping price displayed correctly on checkout without a discount.'));
+ $this->assertText('Decent shipping: $15.00', t('Decent shipping price displayed correctly on checkout without a discount.'));
+ $this->assertText('Expensive shipping: $25.00', t('Expensive shipping price displayed correctly on checkout without a discount.'));
+ $this->assertText('Deluxe shipping: $55.00', t('Deluxe shipping price displayed correctly on checkout without a discount.'));
+
+ // Select cheap shipping.
+ $edit = array(
+ 'commerce_shipping[shipping_service]' => $shipping_service_name,
+ );
+ $this->drupalPostAJAX(NULL, $edit, 'commerce_shipping[shipping_service]');
+ // Go to next checkout step.
+ $this->drupalPost(NULL, $edit, t('Continue to next step'));
+ $this->assertText('Shipping$5.00', t('Cheap shipping price is correctly displayed on checkout review.'));
+ $this->assertText('Order total$15.00', t('Undiscounted order total with cheap shipping is correctly displayed on checkout review.'));
+
+ // Create a discount.
+ $discount = $this->createDiscount('order_discount', 'free_shipping', $shipping_service_name, 'free_shipping', 'Free cheap shipping');
+ // Go back to shipping checkout step.
+ $this->drupalPost(NULL, array(), t('Go back'));
+ $this->assertText('Cheap shipping: $0.00', t('Cheap shipping price displayed correctly on checkout shipping with a cheap discount.'));
+ $this->assertText('Decent shipping: $15.00', t('Decent shipping price displayed correctly on checkout shipping with a cheap discount.'));
+ $this->assertText('Expensive shipping: $25.00', t('Expensive shipping price displayed correctly on checkout shipping with a cheap discount.'));
+ $this->assertText('Deluxe shipping: $55.00', t('Deluxe shipping price displayed correctly on checkout shipping with a cheap discount.'));
+ // Go to next checkout step.
+ $this->drupalPost(NULL, $edit, t('Continue to next step'));
+ $this->assertText('Shipping$5.00', t('Cheap shipping price is correctly displayed on checkout review.'));
+ $this->assertText('Free cheap shipping-$5.00', t('Free cheap shipping discount amount is correctly displayed on checkout review.'));
+ $this->assertText('Order total$10.00', t('Order total with free cheap shipping discount is correctly displayed on checkout review.'));
+
+ $this->drupalPost(NULL, array(), t('Go back'));
+ // Select decent shipping.
+ $edit = array(
+ 'commerce_shipping[shipping_service]' => $decent_shipping_service_name,
+ );
+ $this->drupalPostAJAX(NULL, $edit, 'commerce_shipping[shipping_service]');
+ // Go to next checkout step.
+ $this->drupalPost(NULL, $edit, t('Continue to next step'));
+ $this->assertText('Shipping$15.00', t('Decent shipping price is correctly displayed.'));
+ $this->assertText('Order total$25.00', t('Undiscounted order total with decent shipping and with unapplied cheap shipping discount is correctly displayed.'));
+
+ // Update discount to have a 'discount_all' strategy.
+ $discount_wrapper = entity_metadata_wrapper('commerce_discount', $discount);
+ $discount_wrapper->commerce_discount_offer->commerce_free_shipping_strategy = 'discount_all';
+ $discount_wrapper->commerce_discount_offer->save();
+
+ $this->drupalPost(NULL, array(), t('Go back'));
+ $this->assertText('Cheap shipping: $0.00', t('Cheap shipping price displayed correctly on checkout shipping with a cheap discount with discount_all strategy.'));
+ $this->assertText('Decent shipping: $10.00', t('Decent shipping price displayed correctly on checkout shipping with a cheap discount with discount_all strategy.'));
+ $this->assertText('Expensive shipping: $20.00', t('Expensive shipping price displayed correctly on checkout shipping with a cheap discount with discount_all strategy.'));
+ $this->assertText('Deluxe shipping: $50.00', t('Deluxe shipping price displayed correctly on checkout shipping with a cheap discount with discount_all strategy.'));
+
+ // Select expensive shipping.
+ $edit = array(
+ 'commerce_shipping[shipping_service]' => $expensive_shipping_service_name,
+ );
+ $this->drupalPostAJAX(NULL, $edit, 'commerce_shipping[shipping_service]');
+ // Go to next checkout step.
+ $this->drupalPost(NULL, $edit, t('Continue to next step'));
+ $this->assertText('Shipping$25.00', t('Expensive shipping price is correctly displayed on checkout review.'));
+ $this->assertText('Free cheap shipping-$5.00', t('Discount amount on expensive shipping is correctly displayed in case of a discount_all cheap shipping on checkout review.'));
+ $this->assertText('Order total$30.00', t('Undiscounted order total with decent shipping and with unapplied discounted cheap shipping is correctly displayed on checkout review.'));
+
+ // Remove discount.
+ entity_delete('commerce_discount', $discount->discount_id);
+
+ // Create discount for the expensive shipping method with 'discount_all' strategy.
+ $discount = $this->createDiscount('order_discount', 'free_shipping', $expensive_shipping_service_name, 'free_shipping', 'Free expensive shipping');
+ $discount_wrapper = entity_metadata_wrapper('commerce_discount', $discount);
+ $discount_wrapper->commerce_discount_offer->commerce_free_shipping_strategy = 'discount_all';
+ $discount_wrapper->commerce_discount_offer->save();
+
+ $this->drupalPost(NULL, array(), t('Go back'));
+ $this->assertText('Cheap shipping: $0.00', t('Cheap shipping price displayed correctly on checkout shipping with an expensive discount with discount_all strategy.'));
+ $this->assertText('Decent shipping: $0.00', t('Decent shipping price displayed correctly on checkout shipping with an expensive discount with discount_all strategy.'));
+ $this->assertText('Expensive shipping: $0.00', t('Expensive shipping price displayed correctly on checkout shipping with an expensive discount with discount_all strategy.'));
+ $this->assertText('Deluxe shipping: $30.00', t('Deluxe shipping price displayed correctly on checkout shipping with an expensive discount with discount_all strategy.'));
+
+ // Select deluxe shipping.
+ $edit = array(
+ 'commerce_shipping[shipping_service]' => 'commerce_discount_deluxe_shipping',
+ );
+ $this->drupalPostAJAX(NULL, $edit, 'commerce_shipping[shipping_service]');
+ // Go to next checkout step.
+ $this->drupalPost(NULL, $edit, t('Continue to next step'));
+ $this->assertText('Shipping$55.00', t('Deluxe shipping price is correctly displayed on checkout review.'));
+ $this->assertText('Free expensive shipping-$25.00', t('Discount amount on deluxe shipping is correctly displayed in case of a discount_all expensive shipping on checkout review.'));
+ $this->assertText('Order total$40.00', t('Order total with deluxe shipping and with discounted expensive shipping discount is correctly displayed on checkout review.'));
+
+ // Remove discount.
+ entity_delete('commerce_discount', $discount->discount_id);
+
+ // Create a free cheap shipping discount with discount_all strategy.
+ $discount = $this->createDiscount('order_discount', 'free_shipping', $shipping_service_name, 'free_shipping', 'Free cheap shipping');
+ $discount_wrapper = entity_metadata_wrapper('commerce_discount', $discount);
+ $discount_wrapper->commerce_discount_offer->commerce_free_shipping_strategy = 'discount_all';
+ $discount_wrapper->commerce_discount_offer->save();
+
+ // Create a 20% percent off shipping discount.
+ $offer = array(
+ 'percent' => 20,
+ 'service' => '',
+ );
+ $percent_discount = $this->createDiscount('order_discount', 'percent_off_shipping', $offer, 'percent_off_shipping', '20% off shipping');
+ $percent_discount->sort_order = 9;
+ entity_save('commerce_discount', $percent_discount);
+
+ $this->drupalPost(NULL, array(), t('Go back'));
+ $this->assertText('Cheap shipping: $0.00', t('Cheap shipping price displayed correctly on checkout shipping with an expensive discount with discount_all strategy.'));
+ $this->assertText('Decent shipping: $7.00', t('Decent shipping price displayed correctly on checkout shipping with an expensive discount with discount_all strategy.'));
+ $this->assertText('Expensive shipping: $15.00', t('Expensive shipping price displayed correctly on checkout shipping with an expensive discount with discount_all strategy.'));
+ $this->assertText('Deluxe shipping: $39.00', t('Deluxe shipping price displayed correctly on checkout shipping with an expensive discount with discount_all strategy.'));
+
+ // Select deluxe shipping.
+ $edit = array(
+ 'commerce_shipping[shipping_service]' => 'commerce_discount_deluxe_shipping',
+ );
+ $this->drupalPostAJAX(NULL, $edit, 'commerce_shipping[shipping_service]');
+ // Go to next checkout step.
+ $this->drupalPost(NULL, $edit, t('Continue to next step'));
+ $this->assertText('Shipping$55.00', t('Deluxe shipping price is correctly displayed on checkout review.'));
+ $this->assertText('Free cheap shipping-$5.00', t('Discount amount on deluxe shipping is correctly displayed in case of a discount_all cheap shipping discount on checkout review.'));
+ $this->assertText('20% off shipping-$11.00', t('Discount amount on deluxe shipping is correctly displayed in case of an "all" 20% shipping discount on checkout review.'));
+ $this->assertText('Order total$49.00', t('Order total with deluxe shipping and with a discount_all cheap shipping discount and a 20% "all" shipping discount is correctly displayed on checkout review.'));
+
+ // Remove free shipping discount.
+ entity_delete('commerce_discount', $discount->discount_id);
+
+ // Create shipping upgrade discount.
+ $offer = array(
+ 'source' => $shipping_service_name,
+ 'target' => $expensive_shipping_service_name,
+ );
+ $this->createDiscount('order_discount', 'shipping_upgrade', $offer, 'shipping_upgrade', 'Shipping upgrade', 11);
+
+ $this->drupalPost(NULL, array(), t('Go back'));
+ $this->assertText('Cheap shipping: $4.00', t('Cheap shipping price displayed correctly on checkout shipping with a 20% "all" shipping discount and a cheap->expensive upgrade discount.'));
+ $this->assertText('Decent shipping: $12.00', t('Decent shipping price displayed correctly on checkout shipping with a 20% "all" shipping discount and a cheap->expensive upgrade discount.'));
+ $this->assertText('Expensive shipping: $4.00', t('Expensive shipping price displayed correctly on checkout shipping with a 20% "all" shipping discount and a cheap->expensive upgrade discount.'));
+ $this->assertText('Deluxe shipping: $44.00', t('Deluxe shipping price displayed correctly on checkout shipping with a 20% "all" shipping discount and a cheap->expensive upgrade discount.'));
+
+ // Select expensive shipping.
+ $edit = array(
+ 'commerce_shipping[shipping_service]' => $expensive_shipping_service_name,
+ );
+ $this->drupalPostAJAX(NULL, $edit, 'commerce_shipping[shipping_service]');
+ // Go to next checkout step.
+ $this->drupalPost(NULL, $edit, t('Continue to next step'));
+ $this->assertText('Shipping$25.00', t('Expensive shipping price is correctly displayed on checkout review with a 20% "all" shipping discount and a cheap->expensive upgrade discount.'));
+ $this->assertText('Shipping upgrade-$16.00', t('Discount amount on expensive shipping is correctly displayed in case of cheap->expensive upgrade discount on checkout review.'));
+ $this->assertText('20% off shipping-$5.00', t('20% off discount amount on expensive shipping is correctly displayed on checkout review.'));
+ $this->assertText('Order total$14.00', t('Order total with deluxe shipping and with a 20% "all" shipping discount and a cheap->expensive upgrade discount is correctly displayed on checkout review.'));
+ }
+
+ /**
+ * Test a free shipping discount combined with a fixed amount discount.
+ */
+ public function testCommerceDiscountShippingAndFixedAmount() {
+ $shipping_service_name = 'commerce_discount_cheap_shipping';
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed', NULL);
+ module_load_include('inc', 'commerce_shipping', 'commerce_shipping.rules');
+ commerce_shipping_rate_apply($order, $shipping_service_name);
+ commerce_order_save($order);
+ unset($order->shipping_rates);
+ $free_shipping_discount = $this->createDiscount('order_discount', 'free_shipping', $shipping_service_name, 'free_shipping', 'Free cheap shipping', 1);
+ $this->createDiscount('order_discount', 'fixed_amount', 1500, 'of1');
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ // Order total before discount is 1000, assert that applying both a shipping
+ // discount and a fixed amount discount isn't causing the order total to
+ // be negative (make sure order total is properly recalculated after the
+ // free shipping discount is applied).
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 0, 'Order total is correct when the free shipping discount has a lower weight than the fixed amount.');
+
+ // Update the free shipping discount weight to make sure the order total
+ // is correct when the shipping discount is evaluated after the fixed amount
+ // discount.
+ $free_shipping_discount->sort_order = 20;
+ $free_shipping_discount->save();
+ $order_wrapper = commerce_cart_order_refresh($order);
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 0, 'Order total is correct when the free shipping discount has a higher weight than the fixed amount.');
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_shipping_test/commerce_discount_shipping_test.info b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_shipping_test/commerce_discount_shipping_test.info
new file mode 100644
index 00000000..74eda69d
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_shipping_test/commerce_discount_shipping_test.info
@@ -0,0 +1,13 @@
+name = Commerce discount test shipping method
+description = Provides shipping methods for commerce discount tests.
+package = Commerce (shipping)
+dependencies[] = commerce
+dependencies[] = commerce_shipping
+core = 7.x
+
+; Information added by Drupal.org packaging script on 2017-12-19
+version = "7.x-1.0-beta5"
+core = "7.x"
+project = "commerce_discount"
+datestamp = "1513724288"
+
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_shipping_test/commerce_discount_shipping_test.module b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_shipping_test/commerce_discount_shipping_test.module
new file mode 100644
index 00000000..db34ecb9
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_shipping_test/commerce_discount_shipping_test.module
@@ -0,0 +1,110 @@
+ t('Discount test shipping method'),
+ 'description' => t('Defines 3 shipping services.'),
+ );
+
+ $shipping_methods['commerce_discount_test_other_method'] = array(
+ 'title' => t('Discount test other shipping method'),
+ 'description' => t('Defines a shipping service.'),
+ );
+
+ return $shipping_methods;
+}
+
+/**
+ * Implements hook_commerce_shipping_service_info().
+ */
+function commerce_discount_shipping_test_commerce_shipping_service_info() {
+ $shipping_services = array();
+
+ $shipping_services['commerce_discount_cheap_shipping'] = array(
+ 'title' => t('Cheap shipping service'),
+ 'description' => t('A cheap flat rate service.'),
+ 'display_title' => t('Cheap shipping'),
+ 'shipping_method' => 'commerce_discount_test_shipping_method',
+ 'price_component' => 'shipping',
+ 'callbacks' => array(
+ 'rate' => 'commerce_discount_test_shipping_service_rate',
+ ),
+ );
+
+ $shipping_services['commerce_discount_decent_shipping'] = array(
+ 'title' => t('Decent shipping service'),
+ 'description' => t('A decent flat rate service.'),
+ 'display_title' => t('Decent shipping'),
+ 'shipping_method' => 'commerce_discount_test_shipping_method',
+ 'price_component' => 'shipping',
+ 'callbacks' => array(
+ 'rate' => 'commerce_discount_test_shipping_service_rate',
+ ),
+ );
+
+ $shipping_services['commerce_discount_expensive_shipping'] = array(
+ 'title' => t('Expensive shipping service'),
+ 'description' => t('An expensive flat rate service.'),
+ 'display_title' => t('Expensive shipping'),
+ 'shipping_method' => 'commerce_discount_test_shipping_method',
+ 'price_component' => 'shipping',
+ 'callbacks' => array(
+ 'rate' => 'commerce_discount_test_shipping_service_rate',
+ ),
+ );
+
+ $shipping_services['commerce_discount_deluxe_shipping'] = array(
+ 'title' => t('Deluxe shipping service'),
+ 'description' => t('A deluxe flat rate service.'),
+ 'display_title' => t('Deluxe shipping'),
+ 'shipping_method' => 'commerce_discount_test_other_method',
+ 'price_component' => 'shipping',
+ 'callbacks' => array(
+ 'rate' => 'commerce_discount_test_shipping_service_rate',
+ ),
+ );
+
+ return $shipping_services;
+}
+
+/**
+ * Shipping service callback.
+ *
+ * Returns a base price array for a shipping service
+ * calculated for the given order.
+ */
+function commerce_discount_test_shipping_service_rate($shipping_service, $order) {
+ $order_wrapper = entity_metadata_wrapper('commerce_order', $order);
+ switch ($shipping_service['name']) {
+ case 'commerce_discount_cheap_shipping':
+ $amount = 500;
+ break;
+
+ case 'commerce_discount_decent_shipping':
+ $amount = 1500;
+ break;
+
+ case 'commerce_discount_expensive_shipping':
+ $amount = 2500;
+ break;
+
+ case 'commerce_discount_deluxe_shipping':
+ $amount = 5500;
+ break;
+ }
+ return array(
+ 'amount' => $amount,
+ 'currency_code' => $order_wrapper->commerce_order_total->currency_code->value(),
+ 'data' => array(),
+ );
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_ui.test b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_ui.test
new file mode 100644
index 00000000..dc436847
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_ui.test
@@ -0,0 +1,272 @@
+ 'Discounts',
+ 'description' => 'Test discounts UI and functionality',
+ 'group' => 'Commerce Discount UI',
+ );
+ }
+
+ /**
+ * Test the importing of commerce discounts.
+ */
+ public function testCommerceDiscountImportUI() {
+ // Login store admin.
+ $this->drupalLogin($this->store_admin);
+
+ // Access to the admin discount creation page.
+ $this->drupalGet('admin/commerce/discounts/import');
+ $this->assertResponse(200, 'Store admin is allowed in the discounts import page');
+ }
+
+ /**
+ * Access to commerce discounts admin.
+ */
+ public function testCommerceDiscountUIAccessDiscountsListing() {
+ // Login with customer.
+ $this->drupalLogin($this->store_customer);
+ // Check the access to the profiles listing.
+ $this->drupalGet('admin/commerce/discounts');
+ $this->assertResponse(403, 'The store customer has no access to discounts administration.');
+
+ // Login with store admin.
+ $this->drupalLogin($this->store_admin);
+ // Check the access to the profiles listing.
+ $this->drupalGet('admin/commerce/discounts');
+ $this->assertResponse(200, 'The store admin has access to discounts administration.');
+
+ // Check the message of no discounts available.
+ $this->assertText(t('No discounts found.'), "'No discounts found.' message is displayed");
+ // Check the add customer profile link.
+ $this->assertRaw(l(t('Add discount'), 'admin/commerce/discounts/add'), "'Add discount' link is present in the page");
+ }
+
+ /**
+ * Test the add discount UI.
+ */
+ public function testCommerceDiscountUIAddDiscount() {
+ // Login with normal user.
+ $this->drupalLogin($this->store_customer);
+
+ // Access to the admin discount creation page.
+ $this->drupalGet('admin/commerce/discounts/add');
+
+ $this->assertResponse(403, 'Normal user is not able to add a discount using the admin interface');
+
+ // Login with store admin.
+ $this->drupalLogin($this->store_admin);
+
+ // Access to the admin discount creation page.
+ $this->drupalGet('admin/commerce/discounts/add');
+
+ $this->assertResponse(200, 'Store admin user is allowed to add a discount using the admin interface');
+
+ // Check the integrity of the add form.
+ $this->assertFieldByName('commerce_discount_type', NULL, 'Discount type field is present');
+ $this->assertFieldByName('label', NULL, 'Label field is present');
+ $this->assertFieldByName('component_title', NULL, 'Name field is present');
+ $this->assertFieldByName('commerce_discount_fields[commerce_discount_offer][und][form][type]', NULL, 'Offer type field is present');
+ $this->assertFieldByName('commerce_discount_fields[commerce_discount_offer][und][form][commerce_fixed_amount][und][0][amount]', NULL, 'Amount field is present');
+ $this->assertFieldByName('status', NULL, 'Status field is present');
+ $this->assertFieldById('edit-submit', t('Save discount'), 'Save discount button is present');
+
+ // Try to save the product and check validation messages.
+ $this->drupalPost(NULL, array(), t('Save discount'));
+
+ $this->assertText(t('Admin title field is required.'), 'Validation message for missing label.');
+ $this->assertText(t('Machine-readable name field is required.'), 'Validation message for missing machine-name.');
+ $this->assertText(t('Fixed amount field is required.'), 'Validation message for missing amount.');
+
+ // Load a clean discount add form.
+ $this->drupalGet('admin/commerce/discounts/add');
+ // Create a discount.
+ $values = array(
+ 'label' => 'Order discount - fixed',
+ 'name' => 'order_discount_fixed',
+ 'component_title' => 'Order discount',
+ 'commerce_discount_fields[commerce_discount_offer][und][form][commerce_fixed_amount][und][0][amount]' => 12.77,
+ );
+ $this->drupalPost(NULL, $values, t('Save discount'));
+
+ // Load the discount and wrap it.
+ $discount = entity_load_single('commerce_discount', 1);
+ $discount_wrapper = entity_metadata_wrapper('commerce_discount', $discount);
+
+ // Check the stored discount.
+ $this->assertEqual($discount->label, $values['label'], 'Label stored correctly.');
+ $this->assertEqual($discount->name, 'discount_' . $values['name'], 'Name stored correctly.');
+ $this->assertEqual($discount->export_status, 1, 'Active stored correctly.');
+ $this->assertEqual($discount->component_title, $values['component_title'], 'Name for customer stored correctly.');
+ $this->assertEqual($discount->status, 1, 'Enabled stored correctly.');
+
+ $this->assertEqual($discount_wrapper->commerce_discount_offer->getBundle(), 'fixed_amount', 'Offer type stored correctly.');
+ $this->assertEqual($discount_wrapper->commerce_discount_offer->commerce_fixed_amount->amount->value(), 1277, 'Amount stored correctly.');
+
+ // Check the discounts listing.
+ $this->assertUrl('admin/commerce/discounts', array('query' => array('type' => 'order_discount')), 'Landing page after save is the order discounts list.');
+ $this->assertText($values['label'], 'Label of the discount is present.');
+ }
+
+ /**
+ * Test the Edit discount UI.
+ */
+ public function testCommerceDiscountUIEditDiscount() {
+ // Create a discount.
+ $discount = $this->createDiscount('order_discount', 'fixed_amount', 300);
+
+ // Login with normal user.
+ $this->drupalLogin($this->store_customer);
+
+ // Access to the admin discount edit page.
+ $this->drupalGet('admin/commerce/discounts/manage/' . $discount->name);
+ $this->assertResponse(403, 'Normal user is not able to edit a discount using the admin interface');
+
+ // Login with store admin.
+ $this->drupalLogin($this->store_admin);
+
+ // Access to the admin discount edit page.
+ $this->drupalGet('admin/commerce/discounts/manage/' . $discount->name);
+ $this->assertResponse(200, 'Store admin user is allowed to edit a discount using the admin interface');
+
+ // Check the integrity of the add form.
+ $this->assertFieldByName('commerce_discount_type', NULL, 'Discount type field is present');
+ $this->assertFieldByName('label', NULL, 'Label field is present');
+ $this->assertFieldByName('component_title', NULL, 'Name field is present');
+ $this->assertFieldByName('commerce_discount_fields[commerce_discount_offer][und][form][type]', NULL, 'Offer type field is present');
+ $this->assertFieldByName('commerce_discount_fields[commerce_discount_offer][und][form][commerce_fixed_amount][und][0][amount]', NULL, 'Amount field is present');
+ $this->assertFieldByName('status', NULL, 'Status field is present');
+ $this->assertFieldById('edit-submit', t('Save discount'), 'Save discount button is present');
+ $this->assertFieldById('edit-delete', t('Delete discount'), 'Delete discount button is present');
+
+ // Empty values for validation assertions.
+ $values = array(
+ 'label' => '',
+ 'name' => '',
+ 'component_title' => '',
+ 'commerce_discount_fields[commerce_discount_offer][und][form][commerce_fixed_amount][und][0][amount]' => '',
+ );
+
+ // Try to save the product and check validation messages.
+ $this->drupalPost(NULL, $values, t('Save discount'));
+
+ $this->assertText(t('Admin title field is required.'), 'Validation message for missing label.');
+ $this->assertText(t('Machine-readable name field is required.'), 'Validation message for missing machine-name.');
+ $this->assertText(t('Fixed amount field is required.'), 'Validation message for missing amount.');
+
+ // Discount new values.
+ $values = array(
+ 'label' => 'Order discount - fixed',
+ 'name' => 'order_discount_fixed',
+ 'component_title' => 'Order discount',
+ 'commerce_discount_fields[commerce_discount_offer][und][form][commerce_fixed_amount][und][0][amount]' => 12.77,
+ );
+ $this->drupalPost(NULL, $values, t('Save discount'));
+
+ // Load the discount and wrap it.
+ $discounts = entity_load('commerce_discount', array($discount->discount_id), $conditions = array(), $reset = TRUE);
+ $discount = reset($discounts);
+ $discount_wrapper = entity_metadata_wrapper('commerce_discount', $discount);
+
+ // Check the stored discount.
+ $this->assertEqual($discount->label, $values['label'], 'Label stored correctly.');
+ $this->assertEqual($discount->name, 'discount_' . $values['name'], 'Name stored correctly.');
+ $this->assertEqual($discount->component_title, $values['component_title'], 'Name for customer stored correctly.');
+ $this->assertEqual($discount->status, 1, 'Enabled stored correctly.');
+
+ $this->assertEqual($discount_wrapper->commerce_discount_offer->getBundle(), 'fixed_amount', 'Offer type stored correctly.');
+ $this->assertEqual($discount_wrapper->commerce_discount_offer->commerce_fixed_amount->amount->value(), 1277, 'Amount stored correctly.');
+
+ // Check the discounts listing.
+ $this->assertUrl('admin/commerce/discounts', array('query' => array('type' => 'order_discount')), 'Landing page after save is the order discounts list.');
+ $this->assertText($values['label'], 'Label of the discount is present.');
+ }
+
+ /**
+ * Test the delete discount UI.
+ */
+ public function testCommerceDiscountUIDeleteDiscount() {
+ // Create a discount.
+ $discount = $this->createDiscount('order_discount', 'fixed_amount', 300);
+
+ // Login with normal user.
+ $this->drupalLogin($this->store_customer);
+
+ // Access to the admin discount edit page.
+ $this->drupalGet('admin/commerce/discounts/manage/' . $discount->name . '/delete');
+
+ $this->assertResponse(403, 'Normal user is not able to delete a discount using the admin interface');
+
+ // Login with store admin.
+ $this->drupalLogin($this->store_admin);
+
+ // Access to the admin discount edit page.
+ $this->drupalGet('admin/commerce/discounts/manage/' . $discount->name . '/delete');
+
+ $this->assertResponse(200, 'Store admin user is allowed to delete a discount using the admin interface');
+
+ // Check the integrity of the add form.
+ $this->pass('Test the discount delete confirmation form:');
+ $this->assertTitle(t('Are you sure you want to delete the Commerce Discount !label?', array('!label' => $discount->label)) . ' | Drupal', 'The confirmation message is displayed');
+ $this->assertText(t('This action cannot be undone'), "A warning notifying the user about the action can't be undone is displayed.");
+ $this->assertFieldById('edit-submit', t('Confirm'), 'Delete button is present');
+ $this->assertText(t('Cancel'), 'Cancel is present');
+
+ // Try to save the product and check validation messages.
+ $this->drupalPost(NULL, array(), t('Confirm'));
+
+ // Check the url after deleting and if the discount has been deleted in
+ // database.
+ $this->assertUrl('admin/commerce/discounts', array(), 'Landing page after deleting a discount is the discounts listing page');
+ $this->assertRaw(t('Deleted %type %label.', array('%type' => 'Commerce Discount', '%label' => $discount->label)), "'Discount has been deleted' message is displayed");
+ $this->assertRaw(t('No discounts found.', array('@link' => url('admin/commerce/discounts/add'))), 'Empty discount listing message is displayed');
+ }
+
+ /**
+ * Test disabled line item types.
+ */
+ public function testCommerceDiscountUIDisabledLineItemTypes() {
+ // Create the 30% discount and $1 product.
+ $this->createDiscount('product_discount', 'percentage', 30, 'discount_30_off');
+ $product = $this->createDummyProduct('TEST-PRODUCT', 'Test Product', 100);
+
+ // Create the order and apply discount.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($product->product_id => 1));
+ $order_wrapper = commerce_cart_order_refresh($order);
+ commerce_order_calculate_total($order);
+
+ // Ensure discount applied.
+ $line_item_wrapper = $order_wrapper->commerce_line_items->get(0);
+ $unit_price = $line_item_wrapper->commerce_unit_price->value();
+ $this->assertEqual($unit_price['amount'], 70, 'Product line item unit price amount rounded properly for a 30% discount.');
+
+ // Login with store admin and turn off all line item types.
+ $this->drupalLogin($this->store_admin);
+ $this->drupalGet('admin/commerce/discounts/settings');
+ $values = array(
+ 'commerce_discount_line_item_types[product_discount]' => FALSE,
+ 'commerce_discount_line_item_types[product]' => FALSE,
+ );
+ $this->drupalPost(NULL, $values, t('Save configuration'));
+
+ // Refresh the order and ensure the discount is no longer applicable.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ $line_item_wrapper = $order_wrapper->commerce_line_items->get(0);
+ $unit_price = $line_item_wrapper->commerce_unit_price->value();
+ $this->assertEqual($unit_price['amount'], 100, 'Product line item unit price is the original amount');
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_usage.test b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_usage.test
new file mode 100644
index 00000000..77ea6a03
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_usage.test
@@ -0,0 +1,128 @@
+ 'Discounts usage',
+ 'description' => 'Test discounts usage functionality',
+ 'group' => 'Commerce Discount',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setUp() {
+ parent::setUp();
+ $this->store_customer2 = $this->createStoreCustomer();
+ }
+
+ /**
+ * Test fixed order discounts.
+ */
+ public function testCommerceDiscountUsageFixedOrderDiscount() {
+ // Testing fixed discount.
+ // Create a fixed order discount of $3 limited to one use.
+ $this->createUsageDiscount('order_discount', 'fixed_amount', 300, 1);
+
+ // Create an order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ // Check if the discount was applied on the order total price.
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 700, 'Fixed order discount is deducted correctly on the first use.');
+
+ // Create another order to make sure the discount isn't applied again.
+ $order = $this->createDummyOrder($this->store_customer2->uid, array($this->product->product_id => 1), 'completed');
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ // Check if the discount was applied on the order total price.
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 1000, 'Fixed order discount is ignored after maximal usage.');
+ }
+
+ /**
+ * Test percentage order discounts.
+ */
+ public function testCommerceDiscountUsagePercentageOrderDiscount() {
+ // Testing percentage discount.
+ // Create a percentage order discount of 5% limited to one use.
+ $this->createUsageDiscount('order_discount', 'percentage', 5, 1);
+
+ // Create a completed order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ // Check if the discount was applied on the order total price.
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 950, 'Percentage order discount is deducted correctly.');
+
+ // Create another order to make sure the discount isn't applied again.
+ $order = $this->createDummyOrder($this->store_customer2->uid, array($this->product->product_id => 1), 'completed');
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ // Check if the discount was applied on the order total price.
+ $this->assertTrue($order_wrapper->commerce_order_total->amount->value() == 1000, 'Percentage order discount is ignored after maximal usage.');
+ }
+
+ /**
+ * Test fixed product discounts.
+ */
+ public function testCommerceDiscountUsageFixedProductDiscount() {
+ $this->createUsageDiscount('product_discount', 'fixed_amount', 300, 1);
+
+ // Create an order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ // Check if the discount was added as a component to the line item.
+ $price = commerce_price_wrapper_value($order_wrapper->commerce_line_items->get(0), 'commerce_unit_price');
+ $this->assertTrue($price['data']['components'][1]['price']['amount'] == -300, 'Fixed product discount is added as a price component to the line item.');
+ commerce_order_save($order);
+
+ // Create another order to make sure the discount isn't applied again.
+ $order = $this->createDummyOrder($this->store_customer2->uid, array($this->product->product_id => 1), 'completed');
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ // Check if the discount was added as a component to the line item.
+ $price = commerce_price_wrapper_value($order_wrapper->commerce_line_items->get(0), 'commerce_unit_price');
+ $this->assertTrue(count($price['data']['components']) === 1, 'Fixed product discount is ignored after maximal usage.');
+ }
+
+ /**
+ * Test percentage product discounts.
+ */
+ public function testCommerceDiscountUsagePercentageProductDiscount() {
+ $this->createUsageDiscount('product_discount', 'percentage', 5, 1);
+
+ // Create an order.
+ $order = $this->createDummyOrder($this->store_customer->uid, array($this->product->product_id => 1), 'completed');
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ // Check if the discount was added as a component to the line item.
+ $price = commerce_price_wrapper_value($order_wrapper->commerce_line_items->get(0), 'commerce_unit_price');
+ $this->assertEqual($price['data']['components'][1]['price']['amount'], -50, 'Percentage product discount is added as a price component to the line item.');
+ commerce_order_save($order);
+
+ // Create another order to make sure the discount isn't applied again.
+ $order = $this->createDummyOrder($this->store_customer2->uid, array($this->product->product_id => 1), 'completed');
+ // Recalculate discounts.
+ $order_wrapper = commerce_cart_order_refresh($order);
+ // Check if the discount was added as a component to the line item.
+ $price = commerce_price_wrapper_value($order_wrapper->commerce_line_items->get(0), 'commerce_unit_price');
+ $this->assertTrue(count($price['data']['components']) === 1, 'Percentage product discount is ignored after maximal usage.');
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_usage_ui.test b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_usage_ui.test
new file mode 100644
index 00000000..f89db85b
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_discount/tests/commerce_discount_usage_ui.test
@@ -0,0 +1,109 @@
+ 'Discounts usage',
+ 'description' => 'Test discounts usage UI',
+ 'group' => 'Commerce Discount UI',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setUp() {
+ parent::setUp();
+ }
+
+ /**
+ * Test usage specific elements in the add discount UI.
+ */
+ public function testCommerceDiscountUsageUIAddDiscount() {
+ // Login with store admin.
+ $this->drupalLogin($this->store_admin);
+
+ // Access to the admin discount creation page.
+ $this->drupalGet('admin/commerce/discounts/add');
+
+ // Check the integrity of the add form.
+ $this->assertFieldByName('commerce_discount_fields[discount_usage_per_person][und][0][value]', NULL, 'Maximum usage per customer field is present');
+ $this->assertFieldByName('commerce_discount_fields[discount_usage_limit][und][0][value]', NULL, 'Maximum overall usage field is present');
+
+ // Create a discount.
+ $values = array(
+ 'label' => 'Order discount - fixed',
+ 'name' => 'order_discount_fixed',
+ 'component_title' => 'Order discount',
+ 'commerce_discount_fields[commerce_discount_offer][und][form][commerce_fixed_amount][und][0][amount]' => 12.77,
+ 'commerce_discount_fields[discount_usage_limit][und][0][value]' => 5,
+ );
+ $this->drupalPost(NULL, $values, t('Save discount'));
+
+ // Load the discount and wrap it.
+ $discount = entity_load_single('commerce_discount', 1);
+ $discount_wrapper = entity_metadata_wrapper('commerce_discount', $discount);
+
+ // Check the usage fields of the stored discount.
+ $this->assertTrue($discount_wrapper->discount_usage_per_person->value() == 0, 'Discount uses field is empty.');
+ $this->assertTrue($discount_wrapper->discount_usage_limit->value() == 5, 'Discount max uses stored correctly.');
+
+ // Check the discounts listing.
+ $this->assertText(t('@amount available', array('@amount' => 5)), 'Analytics - Max usage is shown.');
+ $this->assertText(t('Used @amount times', array('@amount' => 0)), 'Analytics - Usage is shown.');
+ }
+
+ /**
+ * Test usage specific elements in the edit discount UI.
+ */
+ public function testCommerceDiscountUsageUIEditDiscount() {
+ // Testing fixed discount.
+ // Create a fixed order discount of $3 limited to one use.
+ $discount = $this->createUsageDiscount('order_discount', 'fixed_amount', 300, 1);
+
+ // Login with store admin.
+ $this->drupalLogin($this->store_admin);
+
+ // Access to the admin discount edit page.
+ $this->drupalGet('admin/commerce/discounts/manage/' . $discount->name);
+
+ // Check the integrity of the add form.
+ $this->assertFieldByName('commerce_discount_fields[discount_usage_per_person][und][0][value]', NULL, 'Maximum usage per customer field is present');
+ $this->assertFieldByName('commerce_discount_fields[discount_usage_limit][und][0][value]', NULL, 'Maximum overall usage field is present');
+
+ // Change the discount values.
+ $values = array(
+ 'label' => 'Order discount - fixed',
+ 'name' => 'order_discount_fixed',
+ 'component_title' => 'Order discount',
+ 'commerce_discount_fields[commerce_discount_offer][und][form][commerce_fixed_amount][und][0][amount]' => 12.77,
+ 'commerce_discount_fields[discount_usage_limit][und][0][value]' => 5,
+ );
+ $this->drupalPost(NULL, $values, t('Save discount'));
+
+ // Load the discount from the database and wrap it.
+ $discounts = entity_load('commerce_discount', array($discount->discount_id), $conditions = array(), $reset = TRUE);
+ $discount_wrapper = entity_metadata_wrapper('commerce_discount', reset($discounts));
+
+ // Check the usage fields of the stored discount.
+ $this->assertEqual($discount_wrapper->discount_usage_per_person->value(), 0, 'Discount uses field is empty.');
+ $this->assertEqual($discount_wrapper->discount_usage_limit->value(), 5, 'Discount max uses stored correctly.');
+
+ // Check the discounts listing.
+ $this->assertText(t('@amount available', array('@amount' => 5)), 'Analytics - Max usage is shown.');
+ $this->assertText(t('Used @amount times', array('@amount' => 0)), 'Analytics - Usage is shown.');
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_extra_price_formatters/commerce_extra_price_formatters.info b/profiles/commerce_kickstart/modules/contrib/commerce_extra_price_formatters/commerce_extra_price_formatters.info
index 6ec0b566..4d173c0a 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_extra_price_formatters/commerce_extra_price_formatters.info
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_extra_price_formatters/commerce_extra_price_formatters.info
@@ -5,10 +5,7 @@ dependencies[] = commerce
dependencies[] = commerce_price
package = Commerce (contrib)
-
-; Information added by drush on 2015-08-20
+; Information added by drush on 2013-01-04
version = "7.x-1.1+7-dev"
-core = "7.x"
project = "commerce_extra_price_formatters"
-datestamp = "1440110607"
-
+datestamp = "1357314508"
\ No newline at end of file
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_checkout_panes.features.inc b/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_checkout_panes.features.inc
new file mode 100644
index 00000000..378f5b81
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_checkout_panes.features.inc
@@ -0,0 +1,103 @@
+ $pane) {
+ $options[$pane_id] = sprintf('%s (%s)', $pane['title'], $pane['name']);
+ }
+
+ return $options;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function commerce_checkout_panes_features_export(array $data, array &$export, $module) {
+ $panes = commerce_checkout_panes();
+
+ foreach ($data as $pane_id) {
+ $export['features'][COMMERCE_CHECKOUT_PANES_INTEGRATION_NAME][$pane_id] = $pane_id;
+ $export['dependencies'][] = $panes[$pane_id]['module'];
+ }
+
+ $export['dependencies'][] = 'commerce_checkout';
+
+ return array();
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function commerce_checkout_panes_features_export_render($module, array $data, $export = NULL) {
+ // Need to reset static cache, otherwise Features will not be able to check
+ // a state of components properly.
+ commerce_checkout_panes_reset();
+
+ $schema = drupal_get_schema('commerce_checkout_pane');
+ $fields = array_fill_keys(array_keys($schema['fields']), NULL);
+ $panes = commerce_checkout_panes();
+ $code = array();
+
+ $code[] = ' $panes = array();';
+
+ foreach ($data as $pane_id) {
+ if (isset($panes[$pane_id])) {
+ $code[] = '';
+ $code[] = sprintf(' $panes[%s] = %s;', "'$pane_id'", features_var_export(array_intersect_key($panes[$pane_id], $fields), ' '));
+ }
+ }
+
+ $code[] = '';
+ $code[] = ' return $panes;';
+
+ return array(COMMERCE_CHECKOUT_PANES_DEFAULT_HOOK => implode("\n", $code));
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function commerce_checkout_panes_features_revert($module) {
+ $defaults = module_invoke($module, COMMERCE_CHECKOUT_PANES_DEFAULT_HOOK);
+
+ if (!empty($defaults)) {
+ commerce_checkout_panes_reset();
+ $existing = commerce_checkout_panes();
+
+ foreach ($defaults as $pane_id => $pane) {
+ $pane['saved'] = isset($existing[$pane_id]['saved']) ? $existing[$pane_id]['saved'] : FALSE;
+
+ commerce_checkout_pane_save($pane);
+ }
+ }
+}
+
+/**
+ * Implements hook_features_rebuild().
+ */
+function commerce_checkout_panes_features_rebuild($module) {
+ commerce_checkout_panes_features_revert($module);
+}
+
+/**
+ * Implements hook_features_disable_feature().
+ */
+function commerce_checkout_panes_features_disable_feature($module) {
+ $defaults = module_invoke($module, COMMERCE_CHECKOUT_PANES_DEFAULT_HOOK);
+
+ if (!empty($defaults)) {
+ foreach ($defaults as $pane_id => $pane) {
+ commerce_checkout_pane_reset($pane_id);
+ }
+ }
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_customer.features.inc b/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_customer.features.inc
index 1b538c9c..34354bda 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_customer.features.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_customer.features.inc
@@ -20,7 +20,7 @@ function commerce_customer_features_export($data, &$export, $module_name = '') {
foreach ($data as $type) {
// Add module dependencies.
$export['dependencies'][$info[$type]['module']] = $info[$type]['module'];
- $export['features']['commerce_customer_type'][$type] = $type;
+ $export['features']['commerce_customer'][$type] = $type;
// Fetch fields of the profile type and add them as dependency.
$fields = field_info_instances('commerce_customer_profile', $type);
@@ -50,7 +50,22 @@ function commerce_customer_features_export_options() {
*/
function commerce_customer_features_export_render($module, $data) {
// Return nothing, since the appropriate code has to exist already.
- return array();
+ $info = commerce_customer_profile_types();
+ $output = array();
+ $output[] = ' $items = array(';
+ foreach ($data as $type) {
+ if (isset($info[$type]) && $item = $info[$type]) {
+ $output[] = " '{$type}' => array(";
+ foreach ($item as $key => $value) {
+ $output[] = " '{$key}' => " . features_var_export($value, ' ') . ",";
+ }
+ $output[] = " ),";
+ }
+ }
+ $output[] = ' );';
+ $output[] = ' return $items;';
+ $output = implode("\n", $output);
+ return array('commerce_customer_profile_type_info' => $output);
}
/**
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_features.info b/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_features.info
index 7ed7ab33..9d94a9d1 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_features.info
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_features.info
@@ -5,9 +5,9 @@ core = 7.x
dependencies[] = features
dependencies[] = commerce
-; Information added by Drupal.org packaging script on 2015-07-21
-version = "7.x-1.1"
+; Information added by Drupal.org packaging script on 2017-11-13
+version = "7.x-1.3"
core = "7.x"
project = "commerce_features"
-datestamp = "1437515562"
+datestamp = "1510599186"
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_features.module b/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_features.module
index a5addadf..f6635069 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_features.module
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_features.module
@@ -10,43 +10,34 @@
*/
function commerce_features_features_api() {
$features = array();
+ $path = drupal_get_path('module', 'commerce_features');
if (module_exists('commerce_product') && module_exists('commerce_product_ui')) {
$features['commerce_product_type'] = array(
'name' => t('Commerce product types'),
- 'feature_source' => TRUE,
'default_hook' => 'commerce_product_default_types',
- 'file' => drupal_get_path('module', 'commerce_features') . '/commerce_product_type.features.inc',
);
}
if (module_exists('commerce_tax')) {
$features['commerce_tax_type'] = array(
'name' => t('Commerce tax types'),
- 'feature_source' => TRUE,
'default_hook' => 'commerce_tax_default_types',
- 'file' => drupal_get_path('module', 'commerce_features') . '/commerce_tax_type.features.inc',
);
$features['commerce_tax_rate'] = array(
'name' => t('Commerce tax rates'),
- 'feature_source' => TRUE,
'default_hook' => 'commerce_tax_default_rates',
- 'file' => drupal_get_path('module', 'commerce_features') . '/commerce_tax_rate.features.inc',
);
}
if (module_exists('commerce_order') && module_exists('commerce_order_types')) {
$features['commerce_order_type'] = array(
'name' => t('Commerce order types'),
- 'features_source' => TRUE,
'default_hook' => 'commerce_order_default_types',
- 'file' => drupal_get_path('module', 'commerce_features') . '/commerce_order_type.features.inc',
);
}
if (module_exists('commerce_line_item') && module_exists('commerce_custom_product')) {
$features['commerce_line_item_type'] = array(
'name' => t('Commerce line item types'),
- 'feature_source' => TRUE,
'default_hook' => 'commerce_line_item_default_types',
- 'file' => drupal_get_path('module', 'commerce_features') . '/commerce_line_item_type.features.inc',
);
}
if (module_exists('commerce_coupon')) {
@@ -54,26 +45,50 @@ function commerce_features_features_api() {
if (version_compare($module_info['version'], '7.x-2', '<')) {
$features['commerce_coupon_type'] = array(
'name' => t('Commerce coupon types'),
- 'feature_source' => TRUE,
'default_hook' => 'commerce_coupon_default_types',
- 'file' => drupal_get_path('module', 'commerce_features') . '/commerce_coupon_type.features.inc',
);
}
}
if (module_exists('commerce_customer')) {
$features['commerce_customer'] = array(
'name' => t('Commerce customer profile types'),
- 'features_source' => TRUE,
'default_hook' => 'commerce_customer_default_types',
- 'file' => drupal_get_path('module', 'commerce_features') . '/commerce_customer.features.inc',
);
}
if (module_exists('commerce_flat_rate')) {
$features['commerce_flat_rate_services'] = array(
'name' => t('Commerce flat rate services'),
- 'features_source' => TRUE,
'default_hook' => 'commerce_flat_rate_default_services',
- 'file' => drupal_get_path('module', 'commerce_features') . '/commerce_flat_rate_services.features.inc',
+ );
+ }
+ if (module_exists('commerce_checkout')) {
+ $features['commerce_checkout_panes'] = array(
+ 'name' => t('Commerce checkout panes'),
+ 'default_hook' => 'commerce_checkout_panes_default',
+ 'default_file' => FEATURES_DEFAULTS_INCLUDED,
+ );
+ }
+
+ foreach ($features as $name => $integration) {
+ $features[$name] = $integration + array(
+ 'file' => "$path/$name.features.inc",
+ 'feature_source' => TRUE,
+ );
+ }
+ if (module_exists('commerce_payment')) {
+ $features['commerce_payment_method'] = array(
+ 'name' => t('Commerce payment methods'),
+ 'feature_source' => TRUE,
+ 'default_hook' => 'commerce_payment_default_methods',
+ 'file' => drupal_get_path('module', 'commerce_features') . '/commerce_payment_method.features.inc',
+ );
+ }
+ if (module_exists('commerce_fees')) {
+ $features['commerce_fees_type'] = array(
+ 'name' => t('Commerce fees types'),
+ 'feature_source' => TRUE,
+ 'default_hook' => 'commerce_fees_default_types',
+ 'file' => drupal_get_path('module', 'commerce_features') . '/commerce_fees.features.inc',
);
}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_fees.features.inc b/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_fees.features.inc
new file mode 100644
index 00000000..9391d3e3
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_fees.features.inc
@@ -0,0 +1,97 @@
+ $type) {
+ $feature_types[$key] = $type['display_title'];
+ }
+ }
+ return $feature_types;
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function commerce_fees_type_features_export_render($module, $data, $export = NULL) {
+ $info = commerce_fees_types();
+ $output = array();
+ $output[] = ' $items = array(';
+ foreach ($data as $type) {
+ if (isset($info[$type]) && $fees_type = $info[$type]) {
+ $output[] = " '{$type}' => " . features_var_export($fees_type, ' ') . ",";
+ }
+ }
+ $output[] = ' );';
+ $output[] = ' return $items;';
+ $output = implode("\n", $output);
+ return array('commerce_fees_default_types' => $output);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function commerce_fees_type_features_revert($module = NULL) {
+ // Get default fees types
+ if (module_hook($module, 'commerce_fees_default_types')) {
+ $default_types = module_invoke($module, 'commerce_fees_default_types');
+ // Read the fees types from the database instead of calling all
+ $existing_types = commerce_fees_types();
+ foreach ($default_types as $key => $type) {
+ // Add or update.
+ if (!isset($existing_types[$key])) {
+ $type['is_new'] = TRUE;
+ }
+ commerce_fees_save($type, TRUE, TRUE);
+ }
+ }
+ else {
+ drupal_set_message(t('Could not load default fees types.'), 'error');
+ return FALSE;
+ }
+
+ // Reset the static cache.
+ commerce_fees_reset();
+ // Schedule a menu rebuild.
+ variable_set('menu_rebuild_needed', TRUE);
+
+ return TRUE;
+}
+
+/**
+ * Implements hook_features_rebuild().
+ */
+function commerce_fees_type_features_rebuild($module) {
+ return commerce_fees_type_features_revert($module);
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_payment_method.features.inc b/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_payment_method.features.inc
new file mode 100644
index 00000000..ac4cc198
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_features/commerce_payment_method.features.inc
@@ -0,0 +1,38 @@
+ 1,
CURLOPT_POSTFIELDS => $request_content,
CURLOPT_RETURNTRANSFER => 1,
- CURLOPT_SSL_VERIFYPEER => 0,
+ CURLOPT_SSL_VERIFYPEER => 1,
CURLOPT_NOPROGRESS => 1,
CURLOPT_FOLLOWLOCATION => 0,
CURLOPT_FRESH_CONNECT => 1,
@@ -583,6 +583,19 @@ public function request(&$request_state) {
CURLOPT_HTTPHEADER => array_values($request_headers),
);
+ // Commerce First Data GGE4 requires SSL peer verification, which may prevent
+ // out of date servers from successfully processing API requests. If you get
+ // an error related to peer verification, you may need to download the CA
+ // certificate bundle file from http://curl.haxx.se/docs/caextract.html,
+ // place it in a safe location on your web server, and update your
+ // settings.php to set the commerce_firstdata_gge4_cacert variable to contain
+ // the absolute path of the file.
+ // Alternately, you may be able to update your php.ini to point to the file
+ // with the curl.cainfo setting.
+ if ($cert_path = variable_get('commerce_firstdata_gge4_cacert', FALSE)) {
+ $curl_options[CURLOPT_CAINFO] = $cert_path;
+ }
+
$ch = curl_init();
curl_setopt_array($ch, $curl_options);
$raw_response = curl_exec($ch);
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_message/LICENSE.txt b/profiles/commerce_kickstart/modules/contrib/commerce_message/LICENSE.txt
old mode 100755
new mode 100644
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_message/commerce_message.info b/profiles/commerce_kickstart/modules/contrib/commerce_message/commerce_message.info
index 1f252e36..e5aac410 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_message/commerce_message.info
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_message/commerce_message.info
@@ -12,10 +12,11 @@ dependencies[] = message
dependencies[] = message_notify
files[] = includes/views/handlers/commerce_message_handler_area_add_message.inc
+files[] = commerce_message.test
-; Information added by Drupal.org packaging script on 2014-06-11
-version = "7.x-1.0-rc3"
+; Information added by Drupal.org packaging script on 2017-06-26
+version = "7.x-1.0"
core = "7.x"
project = "commerce_message"
-datestamp = "1402495128"
+datestamp = "1498488844"
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_message/commerce_message.module b/profiles/commerce_kickstart/modules/contrib/commerce_message/commerce_message.module
index 892bbb5e..0b3a5ff1 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_message/commerce_message.module
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_message/commerce_message.module
@@ -25,6 +25,7 @@ function commerce_message_menu() {
'access callback' => 'commerce_order_access',
'access arguments' => array('view', 3),
'type' => MENU_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
'weight' => 11,
);
@@ -56,8 +57,10 @@ function commerce_message_module_implements_alter(&$implementations, $hook) {
*
* @link http://drupal.org/node/1272560
*/
-function commerce_message_message_presave($message) {
- if (!empty($message->mid) || $message->type != 'commerce_order_order_confirmation') {
+function commerce_message_message_presave(Message $message) {
+ // Only support unsaved messages that re-use our order reference field.
+ $wrapper = entity_metadata_wrapper('message', $message);
+ if (!empty($message->mid) || !isset($wrapper->message_commerce_order)) {
return;
}
@@ -70,14 +73,22 @@ function commerce_message_message_presave($message) {
/**
* Message callback; Show order summary.
*
- * @param $message
+ * @param Message $message
* The Message entity.
+ *
+ * @return string
+ * The output of the View.
*/
function commerce_message_order_summary(Message $message) {
$wrapper = entity_metadata_wrapper('message', $message);
$view = views_get_view('commerce_cart_summary');
$view->set_arguments(array($wrapper->message_commerce_order->getIdentifier()));
$view->hide_admin_links = TRUE;
+
+ // Disable SQL query rewrite so this renders properly for token.
+ // @link https://www.drupal.org/node/1895418
+ $view->display['default']->display_options['query']['options']['disable_sql_rewrite'] = TRUE;
+
return $view->preview();
}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_message/commerce_message.rules_defaults.inc b/profiles/commerce_kickstart/modules/contrib/commerce_message/commerce_message.rules_defaults.inc
index 8253d657..1b5410fb 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_message/commerce_message.rules_defaults.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_message/commerce_message.rules_defaults.inc
@@ -217,6 +217,39 @@ function commerce_message_default_rules_configuration() {
}
}');
+ $rules['rules_commerce_order_message_admin_order_notification'] = entity_import('rules_config', '{ "rules_commerce_order_message_admin_order_notification" : {
+ "LABEL" : "Commerce order message: admin order notification e-mail",
+ "PLUGIN" : "reaction rule",
+ "WEIGHT" : "3",
+ "OWNER" : "rules",
+ "REQUIRES" : [ "rules", "message_notify", "commerce_checkout" ],
+ "ON" : { "commerce_checkout_complete" : [] },
+ "DO" : [
+ { "entity_create" : {
+ "USING" : {
+ "type" : "message",
+ "param_type" : "commerce_order_admin_order_confirmation",
+ "param_user" : [ "commerce-order:owner" ]
+ },
+ "PROVIDE" : { "entity_created" : { "entity_created" : "Created entity" } }
+ }
+ },
+ { "data_set" : {
+ "data" : [ "entity-created:message-commerce-order" ],
+ "value" : [ "commerce-order" ]
+ }
+ },
+ { "entity_save" : { "data" : [ "entity-created" ], "immediate" : 1 } },
+ { "message_notify_process" : {
+ "message" : [ "entity-created" ],
+ "save_on_fail" : 0,
+ "save_on_success" : 0
+ }
+ }
+ ]
+ }
+ }');
+
return $rules;
}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_message/commerce_message.test b/profiles/commerce_kickstart/modules/contrib/commerce_message/commerce_message.test
new file mode 100644
index 00000000..c119480e
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_message/commerce_message.test
@@ -0,0 +1,560 @@
+resetAll();
+
+ $this->store_admin = $this->createStoreAdmin();
+
+ if (!$this->store_admin) {
+ $this->fail(t('Failed to create Store Admin user for test.'));
+ }
+
+ // Set the default country to US.
+ variable_set('site_default_country', 'US');
+ }
+
+ /**
+ * Loads message entities referencing an order.
+ *
+ * @param object $order
+ * The commerce_order entity.
+ *
+ * @return Message[]
+ * Array of entities.
+ */
+ protected function loadMessagesForOrder($order) {
+ $query = new EntityFieldQuery();
+ $query->entityCondition('entity_type', 'message')
+ ->fieldCondition('message_commerce_order', 'target_id', $order->order_id)
+ ->propertyOrderBy('timestamp', 'ASC');
+ $results = $query->execute();
+
+ if (!empty($results)) {
+ return entity_load('message', array_keys($results['message']));
+ }
+
+ return array();
+ }
+
+ /**
+ * Asserts if a Message entity's bundle matches.
+ *
+ * @param \Message $message
+ * The Message entity.
+ * @param string $bundle
+ * The bundle.
+ */
+ protected function assertBundle(Message $message, $bundle) {
+ $this->assertEqual($bundle, $message->bundle(), t('Message type @expected expected, got: @actual', array(
+ '@expected' => $bundle,
+ '@actual' => $message->bundle(),
+ )
+ ));
+ }
+}
+
+/**
+ * Class CommerceMessageOrderHistoryTest
+ */
+class CommerceMessageOrderHistoryTest extends CommerceMessageTestBase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Commerce Message order history',
+ 'description' => 'Tests messages as order history',
+ 'group' => 'Commerce Message',
+ 'dependencies' => array('rules'),
+ );
+ }
+
+ /**
+ * Test order history programmatically.
+ */
+ public function testOrderHistory() {
+ $order = $this->createDummyOrder();
+ commerce_order_status_update($order, 'pending');
+ commerce_order_status_update($order, 'completed');
+ RulesLog::logger()->checkLog();
+
+ $messages = $this->loadMessagesForOrder($order);
+
+ $this->assertEqual(4, count($messages));
+
+ // Assert order created.
+ $message = reset($messages);
+ array_shift($messages);
+ $this->assertBundle($message, 'commerce_order_created');
+ $this->assertEqual('Order has been created.', $message->getText(LANGUAGE_NONE));
+
+ // Assert product added to cart.
+ $message = reset($messages);
+ array_shift($messages);
+ $this->assertBundle($message, 'commerce_order_cart_add');
+ $this->assertEqual('Product PROD-01 added to the cart.', $message->getText(LANGUAGE_NONE));
+
+ // Assert status updates.
+ $message = reset($messages);
+ array_shift($messages);
+ $this->assertBundle($message, 'commerce_order_state');
+ $this->assertEqual('Status has been set to Pending (previously: Shopping cart).', $message->getText(LANGUAGE_NONE));
+
+ $message = reset($messages);
+ array_shift($messages);
+ $this->assertBundle($message, 'commerce_order_state');
+ $this->assertEqual('Status has been set to Completed (previously: Pending).', $message->getText(LANGUAGE_NONE));
+ }
+
+ /**
+ * Test order history UI.
+ */
+ public function testOrderHistoryUi() {
+ $order = $this->createDummyOrder();
+ commerce_order_status_update($order, 'pending');
+ commerce_order_status_update($order, 'completed');
+ RulesLog::logger()->checkLog();
+
+ $this->drupalLogin($this->store_admin);
+
+ $this->drupalGet('admin/commerce/orders/' . $order->order_id . '/history');
+ $this->assertText('Order has been created.');
+ $this->assertText('Product PROD-01 added to the cart.');
+ $this->assertText('Status has been set to Pending (previously: Shopping cart).');
+ $this->assertText('Status has been set to Completed (previously: Pending).');
+
+ $this->drupalLogout();
+ $this->drupalGet('admin/commerce/orders/' . $order->order_id . '/history');
+ $this->assertResponse(403, 'Anonymoous users cannot view order history.');
+ }
+}
+
+/**
+ * Class CommerceMessageOrderNotificationTest
+ *
+ * @see MailTestCase
+ */
+class CommerceMessageOrderNotificationTest extends CommerceMessageTestBase implements MailSystemInterface {
+ /**
+ * The most recent message that was sent through the test case.
+ */
+ private static $sent_message;
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Commerce Message order notification',
+ 'description' => 'Tests messages as order history',
+ 'group' => 'Commerce Message',
+ 'dependencies' => array('rules'),
+ );
+ }
+
+ public function setUp() {
+ parent::setUp();
+ // Set MailTestCase (i.e. this class) as the SMTP library.
+ variable_set('mail_system', array('default-system' => 'CommerceMessageOrderNotificationTest'));
+ }
+
+ /**
+ * Concatenate and wrap the e-mail body for plain-text mails.
+ *
+ * @see DefaultMailSystem
+ */
+ public function format(array $message) {
+ // Join the body array into one string.
+ $message['body'] = implode("\n\n", $message['body']);
+ // Convert any HTML to plain-text.
+ $message['body'] = drupal_html_to_text($message['body']);
+ // Wrap the mail body for sending.
+ $message['body'] = drupal_wrap_mail($message['body']);
+ return $message;
+ }
+
+ /**
+ * Send function that is called through the mail system.
+ */
+ public function mail(array $message) {
+ self::$sent_message = $message;
+ }
+
+
+ /**
+ * Test the order message's content.
+ */
+ public function testOrderNotificationMessageContent() {
+ $order = $this->createDummyOrder();
+ $message = message_create('commerce_order_order_confirmation', array(), $this->store_admin);
+ $message->wrapper()->message_commerce_order = $order;
+ $message->save();
+ $mid = $message->mid;
+
+ // Reload the message to see it was saved.
+ $message = message_load($mid);
+ $this->assertTrue(!empty($message->mid), t('Message was saved to the database.'));
+
+ $message = $message->buildContent();
+
+ global $language;
+ $url_options = array(
+ 'absolute' => TRUE,
+ 'language' => $language,
+ );
+
+ $this->assertEqual(
+ t('Order @order_id at @site', array(
+ '@order_id' => $order->order_id,
+ '@site' => variable_get('site_name', 'Drupal'),
+ )),
+ $message['message__message_text__0']['#markup']);
+
+ $body = t('Thanks for your order @order_id at @site.
+
+If this is your first order with us, you will receive a separate e-mail with login instructions. You can view your order history with us at any time by logging into our website at:
+
+@login-url
+
+You can find the status of your current order at:
+
+@order-view
+
+Please contact us if you have any questions about your order.', array(
+ '@order_id' => $order->order_id,
+ '@site' => variable_get('site_name', 'Drupal'),
+ '@login-url' => url('user', $url_options),
+ '@order-view' => url('user/' . $order->uid . '/orders/' . $order->order_id, $url_options),
+ ));
+ $this->assertEqual($body, $message['message__message_text__1']['#markup']);
+ }
+
+ /**
+ * Tests that the notification is generated on checkout complete.
+ */
+ public function testOrderNotificationMessageCreation() {
+ $order = $this->createDummyOrder();
+ commerce_checkout_complete($order);
+
+ $messages = $this->loadMessagesForOrder($order);
+ foreach ($messages as $message) {
+ if ($message->bundle() == 'commerce_order_order_confirmation') {
+ $this->pass('Order that completed checkout had an order notification generated.');
+ }
+ }
+
+ $this->assertNotNull(self::$sent_message);
+ }
+}
+
+/**
+ * Class CommerceMessageAdminOrderNotificationTest
+ *
+ * @see MailTestCase
+ */
+class CommerceMessageAdminOrderNotificationTest extends CommerceMessageTestBase implements MailSystemInterface {
+ /**
+ * The most recent message that was sent through the test case.
+ */
+ private static $sent_message;
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Commerce Message admin order notification',
+ 'description' => 'Tests messages as order history',
+ 'group' => 'Commerce Message',
+ 'dependencies' => array('rules'),
+ );
+ }
+
+ public function setUp() {
+ parent::setUp();
+ // Set MailTestCase (i.e. this class) as the SMTP library.
+ variable_set('mail_system', array('default-system' => 'CommerceMessageAdminOrderNotificationTest'));
+ }
+
+ /**
+ * Concatenate and wrap the e-mail body for plain-text mails.
+ *
+ * @see DefaultMailSystem
+ */
+ public function format(array $message) {
+ // Join the body array into one string.
+ $message['body'] = implode("\n\n", $message['body']);
+ // Convert any HTML to plain-text.
+ $message['body'] = drupal_html_to_text($message['body']);
+ // Wrap the mail body for sending.
+ $message['body'] = drupal_wrap_mail($message['body']);
+ return $message;
+ }
+
+ /**
+ * Send function that is called through the mail system.
+ */
+ public function mail(array $message) {
+ self::$sent_message = $message;
+ }
+
+
+ /**
+ * Test the order message's content.
+ */
+ public function testOrderNotificationMessageContent() {
+ $order = $this->createDummyOrder();
+ $message = message_create('commerce_order_admin_order_confirmation', array(), $this->store_admin);
+ $message->wrapper()->message_commerce_order = $order;
+ $message->save();
+ $mid = $message->mid;
+
+ // Reload the message to see it was saved.
+ $message = message_load($mid);
+ $this->assertTrue(!empty($message->mid), t('Message was saved to the database.'));
+
+ $message = $message->buildContent();
+
+ global $language;
+ $url_options = array(
+ 'absolute' => TRUE,
+ 'language' => $language,
+ );
+
+ $this->assertEqual(
+ t('Order @order_id at @site', array(
+ '@order_id' => $order->order_id,
+ '@site' => variable_get('site_name', 'Drupal'),
+ )),
+ $message['message__message_text__0']['#markup']);
+
+ $body = t('A new order (@order_id) has been placed at @site.
+Here is a link to the order:
+
+@order-view', array(
+ '@order_id' => $order->order_id,
+ '@site' => variable_get('site_name', 'Drupal'),
+ '@login-url' => url('user', $url_options),
+ '@order-view' => url('user/' . $order->uid . '/orders/' . $order->order_id, $url_options),
+ ));
+ $this->assertEqual($body, $message['message__message_text__1']['#markup']);
+ }
+
+ /**
+ * Tests that the notification is generated on checkout complete.
+ */
+ public function testOrderNotificationMessageCreation() {
+ $order = $this->createDummyOrder();
+ commerce_checkout_complete($order);
+
+ $messages = $this->loadMessagesForOrder($order);
+ foreach ($messages as $message) {
+ if ($message->bundle() == 'commerce_order_admin_order_confirmation') {
+ $this->pass('Order that completed checkout had an admin order notification generated.');
+ }
+ }
+
+ $this->assertNotNull(self::$sent_message);
+ }
+}
+
+class CommerceMessageTokenTest extends CommerceMessageTestBase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Commerce Message order summary token',
+ 'description' => 'Tests the order summary token',
+ 'group' => 'Commerce Message',
+ );
+ }
+
+ public function testOrderSummaryToken() {
+ $order = $this->createDummyOrder();
+ $message = message_create('commerce_order_order_confirmation', array(), $this->store_admin);
+ $message->wrapper()->message_commerce_order = $order;
+ $message->save();
+
+ $this->assertTrue(isset($message->arguments['!order-summary']));
+
+ $message = message_create('commerce_order_admin_order_confirmation', array(), $this->store_admin);
+ $message->wrapper()->message_commerce_order = $order;
+ $message->save();
+
+ $this->assertTrue(isset($message->arguments['!order-summary']));
+ }
+
+ public function testTokenCustomMessageType() {
+ $message_type = message_type_create('foo', array('message_text' => array(LANGUAGE_NONE => array(array('value' => 'Example text.\n\n!order-summary')))));
+ $message_type->save();
+
+ $message = message_create('foo', array(), $this->store_admin);
+ $message->save();
+
+ $this->assertFalse(isset($message->arguments['!order-summary']));
+
+ // Attach field to message type.
+ $fields['message_commerce_order']['field'] = array(
+ 'type' => 'entityreference',
+ 'module' => 'entityreference',
+ 'cardinality' => '1',
+ 'translatable' => FALSE,
+ 'settings' => array(
+ 'target_type' => 'commerce_order',
+ 'handler' => 'base',
+ 'handler_settings' => array(
+ 'target_bundles' => array(),
+ 'sort' => array(
+ 'type' => 'property',
+ 'property' => 'order_id',
+ 'direction' => 'ASC',
+ ),
+ ),
+ ),
+ 'locked' => TRUE,
+ );
+ $fields['message_commerce_order']['instances'][] = array(
+ 'entity_type' => 'message',
+ 'bundles' => array('foo'),
+ 'label' => 'Order',
+ 'required' => TRUE,
+ 'widget' => array(
+ 'type' => 'entityreference_autocomplete',
+ 'module' => 'entityreference',
+ 'settings' => array(
+ 'match_operator' => 'CONTAINS',
+ 'size' => '60',
+ 'path' => '',
+ ),
+ ),
+ 'settings' => array(),
+ 'display' => array(
+ 'default' => array(
+ 'label' => 'above',
+ 'type' => 'entityreference_label',
+ 'settings' => array(
+ 'link' => FALSE,
+ ),
+ 'module' => 'entityreference',
+ 'weight' => 0,
+ ),
+ ),
+ );
+ foreach ($fields as $field_name => $info) {
+ $field = $info['field'];
+ $field += array(
+ 'field_name' => $field_name,
+ );
+ if (!field_info_field($field_name)) {
+ field_create_field($field);
+ }
+
+ foreach ($info['instances'] as $instance) {
+ foreach ($instance['bundles'] as $bundle) {
+ $instance['bundle'] = $bundle;
+ unset($instance['bundles']);
+ $instance['field_name'] = $field_name;
+ if (!field_info_instance($instance['entity_type'], $instance['field_name'], $instance['bundle'])) {
+ field_create_instance($instance);
+ }
+ }
+ }
+ }
+
+ $order = $this->createDummyOrder();
+ $message = message_create('foo', array(), $this->store_admin);
+ $message->wrapper()->message_commerce_order = $order;
+ $message->save();
+
+ $this->assertTrue(isset($message->arguments['!order-summary']));
+
+ }
+
+ public function testCloneHasToken() {
+ $this->drupalLogin($this->store_admin);
+ $edit = array(
+ 'name' => 'commerce_order_order_confirmation_cloned_',
+ 'description' => 'Commerce Order: order confirmation (cloned)',
+ );
+ $this->drupalPost('admin/structure/messages/manage/commerce_order_order_confirmation/clone', $edit, t('Save message type'));
+
+ if (!message_type_load('commerce_order_order_confirmation_cloned_')) {
+ $this->fail('Failed to clone the message type');
+ }
+
+ $this->drupalGet('admin/structure/messages/manage/commerce_order_order_confirmation_cloned_/fields');
+ $this->assertText('message_commerce_order');
+
+ }
+}
+
+class CommerceMessageOrderSummaryTest extends CommerceMessageTestBase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Commerce Message order summary token',
+ 'description' => 'Tests the order summary token',
+ 'group' => 'Commerce Message',
+ );
+ }
+
+ public function testViewAsOrderOwner() {
+ $original_user = $GLOBALS['user'];
+
+ $customer = $this->createStoreCustomer();
+ $order = $this->createDummyOrder($customer->uid);
+ $message = message_create('commerce_order_order_confirmation', array(), $customer);
+ $message->wrapper()->message_commerce_order = $order;
+ $message->save();
+
+ $GLOBALS['user'] = $customer;
+ $this->assertIdentical($GLOBALS['user']->uid, $customer->uid);
+ $summary = commerce_message_order_summary($message);
+ // The view-dom-id-* class is dynamic each time, so we need to check for
+ // the order total area class in our returned markup.
+ $this->assertTrue(strpos($summary, 'commerce-order-handler-area-order-total') !== FALSE);
+
+ $GLOBALS['user'] = $this->store_admin;
+ $this->assertIdentical($GLOBALS['user']->uid, $this->store_admin->uid);
+ $summary = commerce_message_order_summary($message);
+ $this->assertTrue(strpos($summary, 'commerce-order-handler-area-order-total') !== FALSE);
+
+ // Now there is a chance a payment gateway's IPN returns when there is not
+ // and active session. That means it'll run as anonymous and ruin our fun.
+ // Here we test SQL rewrite is disabled so our messages work.
+ $GLOBALS['user'] = drupal_anonymous_user();
+ $this->assertIdentical($GLOBALS['user']->uid, 0);
+ $summary = commerce_message_order_summary($message);
+ $this->assertTrue(strpos($summary, 'commerce-order-handler-area-order-total') !== FALSE);
+
+ // Reset just in case.
+ $GLOBALS['user'] = $original_user;
+
+ }
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_message/includes/commerce_message.message.inc b/profiles/commerce_kickstart/modules/contrib/commerce_message/includes/commerce_message.message.inc
index df6e18e2..e8496b93 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_message/includes/commerce_message.message.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_message/includes/commerce_message.message.inc
@@ -202,6 +202,31 @@ function commerce_message_default_message_type() {
"rdf_mapping" : []
}');
+ $items['commerce_order_admin_order_confirmation'] = entity_import('message_type', '{
+ "name" : "commerce_order_admin_order_confirmation",
+ "description" : "Commerce Order: admin order confirmation",
+ "argument_keys" : [],
+ "argument" : [],
+ "category" : "message_type",
+ "data" : { "purge" : { "override" : 0, "enabled" : 0, "quota" : "", "days" : "" } },
+ "language" : "",
+ "arguments" : null,
+ "message_text" : { "und" : [
+ {
+ "value" : "Order @{message:message-commerce-order:order-number} at [site:name]",
+ "format" : null,
+ "safe_value" : "Order @{message:message-commerce-order:order-number} at [site:name]"
+ },
+ {
+ "value" : "A new order (@{message:message-commerce-order:order-number}) has been placed at [site:name].\r\nHere is a link to the order:\r\n\r\n[message:message-commerce-order:view-url]",
+ "format" : "commerce_order_message",
+ "safe_value" : "A new order (@{message:message-commerce-order:order-number}) has been placed at [site:name].\r\nHere is a link to the order:\r\n\r\n[message:message-commerce-order:view-url]"
+ }
+ ]
+ },
+ "rdf_mapping" : []
+ }');
+
return $items;
}
@@ -212,9 +237,10 @@ function commerce_message_default_message_type() {
function commerce_message_default_message_type_alter(&$items) {
if (module_exists('locale')) {
$languages = locale_language_list();
+ $default_messages = array_keys(commerce_message_default_message_type());
foreach ($languages as $langcode => $langname) {
foreach ($items as $message_type => $item) {
- if ($item->module != 'commerce_message') {
+ if (!in_array($message_type, $default_messages)) {
continue;
}
if (isset($items[$message_type]->message_text[LANGUAGE_NONE])) {
@@ -261,6 +287,7 @@ function commerce_message_message_field_refresh() {
'commerce_order_user_comment',
'commerce_order_admin_comment',
'commerce_order_order_confirmation',
+ 'commerce_order_admin_order_confirmation',
);
$fields['message_commerce_order']['instances'][] = array(
'entity_type' => 'message',
@@ -563,6 +590,8 @@ function commerce_message_message_form_validate($form, &$form_state) {
* Submit callback for commerce_message_message_form().
*/
function commerce_message_message_form_submit($form, &$form_state) {
+ // Update date to current one
+ $form['#entity']->timestamp = REQUEST_TIME;
// Notify field widgets.
field_attach_submit('message', $form['#entity'], $form['content'], $form_state);
entity_save('message', $form['#entity']);
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_message/includes/views/commerce_message.views_default.inc b/profiles/commerce_kickstart/modules/contrib/commerce_message/includes/views/commerce_message.views_default.inc
index 0b8d789e..c284b302 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_message/includes/views/commerce_message.views_default.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_message/includes/views/commerce_message.views_default.inc
@@ -263,17 +263,19 @@ function commerce_message_views_default_views() {
'commerce_order_message' => 'commerce_order_message',
);
- /* Display: Entity content */
- $handler = $view->new_display('entity_view', 'Entity content', 'order_view');
- $handler->display->display_options['defaults']['pager'] = FALSE;
- $handler->display->display_options['pager']['type'] = 'some';
- $handler->display->display_options['pager']['options']['items_per_page'] = '4';
- $handler->display->display_options['pager']['options']['offset'] = '0';
- $handler->display->display_options['entity_type'] = 'commerce_order';
- $handler->display->display_options['bundles'] = array(
- 0 => 'commerce_order',
- );
- $handler->display->display_options['show_title'] = 1;
+ if (module_exists('eva')) {
+ /* Display: Entity content */
+ $handler = $view->new_display('entity_view', 'Entity content', 'order_view');
+ $handler->display->display_options['defaults']['pager'] = FALSE;
+ $handler->display->display_options['pager']['type'] = 'some';
+ $handler->display->display_options['pager']['options']['items_per_page'] = '4';
+ $handler->display->display_options['pager']['options']['offset'] = '0';
+ $handler->display->display_options['entity_type'] = 'commerce_order';
+ $handler->display->display_options['bundles'] = array(
+ 0 => 'commerce_order',
+ );
+ $handler->display->display_options['show_title'] = 1;
+ }
/* Display: Block */
$handler = $view->new_display('block', 'Block', 'block_1');
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_migrate/PATCHES.txt b/profiles/commerce_kickstart/modules/contrib/commerce_migrate/PATCHES.txt
index 29bb797d..e71b2e11 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_migrate/PATCHES.txt
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_migrate/PATCHES.txt
@@ -1,4 +1,4 @@
The following patches have been applied to this project:
-- https://www.drupal.org/files/commerce_products_source_migration-1931302-2.patch
+- https://www.drupal.org/files/issues/reference_fields_should-2701333-3.patch
-This file was automatically generated by Drush Make (http://drupal.org/project/drush).
\ No newline at end of file
+This file was automatically generated by Drush Make (http://drupal.org/project/drush).
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_migrate/README.txt b/profiles/commerce_kickstart/modules/contrib/commerce_migrate/README.txt
index 5e9d8edf..f41460a4 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_migrate/README.txt
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_migrate/README.txt
@@ -1,16 +1,18 @@
-Commerce Migrate is a general-purpose migration framework extending Migrate Module
-for bringing store information into Drupal Commerce.
+Commerce Migrate is a general-purpose migration framework extending Migrate
+Module for bringing store information into Drupal Commerce.
-- Migrate destination field handlers for commerce fields (reference fields, price field)
+- Migrate destination field handlers for commerce fields (reference fields,
+ price field)
- Migrate destination plugin for commerce product types.
-Commerce Migrate depends on Migrate Extras for Entity API and Address Field integration.
+ Commerce Migrate depends on Migrate Extras for Entity API and Address Field
+ integration.
Ubercart migration
------------------
Commerce Migrate Ubercart has moved to its own project,
http://drupal.org/project/commerce_migrate_ubercart
-It can migrate 6.x and 7.x Ubercart stores from either the existing Drupal database
-or a remote database.
+It can migrate 6.x and 7.x Ubercart stores from either the existing Drupal
+database or a remote database.
Price fields
------------
@@ -41,4 +43,3 @@ The Migrate handbook page at http://drupal.org/node/415260
http://cyrve.com/import
http://www.gizra.com/content/data-migration-part-1
http://www.gizra.com/content/data-migration-part-2
-
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_migrate/commerce_migrate.info b/profiles/commerce_kickstart/modules/contrib/commerce_migrate/commerce_migrate.info
index db5164ac..cca541de 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_migrate/commerce_migrate.info
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_migrate/commerce_migrate.info
@@ -7,13 +7,14 @@ dependencies[] = migrate_extras
dependencies[] = commerce_product
; Destination plugins
+files[] = plugins/destinations/commerce_license.inc
files[] = plugins/destinations/commerce_product_type.inc
files[] = plugins/destinations/commerce_product.inc
files[] = plugins/destinations/fields.inc
-; Information added by drupal.org packaging script on 2012-12-06
-version = "7.x-1.1"
+; Information added by Drupal.org packaging script on 2015-11-14
+version = "7.x-1.2"
core = "7.x"
project = "commerce_migrate"
-datestamp = "1354758712"
+datestamp = "1447468741"
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_migrate/commerce_migrate.module b/profiles/commerce_kickstart/modules/contrib/commerce_migrate/commerce_migrate.module
index 99af93f2..da245c0c 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_migrate/commerce_migrate.module
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_migrate/commerce_migrate.module
@@ -1,6 +1,6 @@
2,
+ 'groups' => array(
+ 'commerce_example' => array(
+ 'title' => t('Commerce Example Imports'),
+ ),
+ ),
+ 'migrations' => array(
+ 'CommerceExampleProduct' => array(
+ 'class_name' => 'CommerceMigrateExampleProductMigration',
+ 'group' => 'commerce_example',
+ ),
+ 'CommerceExampleProductDisplay' => array(
+ 'class_name' => 'CommerceMigrateExampleDisplayNodeMigration',
+ 'group' => 'commerce_example',
+ 'dependencies' => array(
+ 'CommerceExampleProduct',
+ ),
+ ),
+ ),
+ );
+
+ return $api;
+}
+
+/**
+ * A simple base class that contains things common to all
+ * CommerceMigrateExample classes.
+ */
+abstract class CommerceMigrateExampleMigration extends Migration {
+ public function __construct($arguments = array()) {
+ // Always call the parent constructor first for basic setup
+ parent::__construct($arguments);
+ }
+
+ /**
+ * Provide the names of the incoming CSV file columns.
+ */
+ function csvcolumns() {
+ $columns[0] = array('SKU', 'SKU');
+ $columns[1] = array('Title', 'Title');
+ $columns[2] = array('Price', 'Price');
+ $columns[3] = array('Image', 'Image');
+ $columns[4] = array('Description', 'Description');
+ return $columns;
+ }
+}
+
+/**
+ * Import Products into the "product" product type.
+ *
+ * This simple migration assumes that a product type called 'product'
+ * already exists, and has the sku, title, commerce_price, and field_image
+ * fields.
+ */
+class CommerceMigrateExampleProductMigration extends CommerceMigrateExampleMigration {
+ public function __construct($arguments = array()) {
+ parent::__construct($arguments);
+ $this->description = t('Import products from CSV file (with no header).');
+
+ // Create a map object for tracking the relationships between source rows
+ $this->map = new MigrateSQLMap($this->machineName,
+ array(
+ // The 'SKU' field in the CSV file is the key.
+ 'SKU' => array('type' => 'varchar',
+ 'length' => 24,
+ 'not null' => TRUE,
+ 'description' => 'SKU',
+ ),
+ ),
+ // Rather than specifying the type directly here, we would probably use
+ // arguments, but instead this just specifies the 'product' product type
+ // to make it obvious what's going on.
+ MigrateDestinationEntityAPI::getKeySchema('commerce_product', 'product')
+ );
+
+ // Create a MigrateSource object, which manages retrieving the input data.
+ $csv_file = drupal_get_path('module', 'commerce_migrate_example') . '/commerce_migrate_example.csv';
+ $this->source = new MigrateSourceCSV($csv_file, $this->csvcolumns());
+
+ // Again here we're hardwiring the product type to 'product'.
+ $this->destination = new MigrateDestinationEntityAPI('commerce_product', 'product');
+
+ $this->addFieldMapping('sku', 'SKU');
+ $this->addFieldMapping('title', 'Title');
+ $this->addFieldMapping('commerce_price', 'Price');
+ $this->addFieldMapping('field_image', 'Image');
+ $this->addFieldMapping('field_image:file_class')
+ ->defaultValue('MigrateFileUri');
+ $this->addFieldMapping('field_image:source_dir')
+ ->defaultValue(drupal_get_path('module', 'commerce_migrate_example') . '/images');
+ }
+}
+
+/**
+ * Import nodes of type 'product_display' from the same CSV file.
+ *
+ * This is hard-wired to the node type 'product_display' with a
+ * product reference field of type field_product.
+ */
+class CommerceMigrateExampleDisplayNodeMigration extends CommerceMigrateExampleMigration {
+ public function __construct($arguments = array()) {
+ parent::__construct($arguments);
+ $this->description = t('Import product display nodes from CSV file (with no header).');
+ $this->dependencies = array('CommerceExampleProduct');
+
+ // Create a map object for tracking the relationships between source rows
+ $this->map = new MigrateSQLMap($this->machineName,
+ array(
+ 'SKU' => array('type' => 'varchar',
+ 'length' => 24,
+ 'not null' => TRUE,
+ 'description' => 'SKU',
+ ),
+ ),
+ MigrateDestinationNode::getKeySchema()
+ );
+
+ // Create a MigrateSource object, which manages retrieving the input data.
+ $csv_file = drupal_get_path('module', 'commerce_migrate_example') . '/commerce_migrate_example.csv';
+ $this->source = new MigrateSourceCSV($csv_file, $this->csvcolumns());
+
+ $this->destination = new MigrateDestinationNode('product_display');
+
+ // For a multivalued import, see the field_migrate_example_country mapping
+ // in the Migrate Example in beer.inc.
+ // Here we do a single SKU per product node.
+ $this->addFieldMapping('field_product', 'SKU')->sourceMigration('CommerceExampleProduct');
+
+ $this->addFieldMapping('title', 'Title');
+ $this->addFieldMapping('body', 'Description');
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_migrate/commerce_migrate_example/commerce_migrate_example.module b/profiles/commerce_kickstart/modules/contrib/commerce_migrate/commerce_migrate_example/commerce_migrate_example.module
new file mode 100644
index 00000000..a4abe2da
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_migrate/commerce_migrate_example/commerce_migrate_example.module
@@ -0,0 +1,2 @@
+ $field_name,
@@ -245,8 +252,8 @@ class MigrateDestinationCommerceProductType extends MigrateDestination {
'type' => 'image',
'settings' => array('image_style' => 'large', 'image_link' => ''),
'weight' => -1,
- ),
- 'teaser' => array(
+ ),
+ 'teaser' => array(
'label' => 'hidden',
'type' => 'image',
'settings' => array('image_style' => 'medium', 'image_link' => 'content'),
@@ -257,6 +264,7 @@ class MigrateDestinationCommerceProductType extends MigrateDestination {
field_create_instance($instance);
}
}
+
/**
* Implementation of __toString().
*
@@ -264,6 +272,6 @@ class MigrateDestinationCommerceProductType extends MigrateDestination {
* Description of the destination being migrated into
*/
public function __toString() {
- return 'Creates commerce product types';
+ return 'Creates commerce product types';
}
}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_migrate/plugins/destinations/fields.inc b/profiles/commerce_kickstart/modules/contrib/commerce_migrate/plugins/destinations/fields.inc
index 2562de1f..fc3149ca 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_migrate/plugins/destinations/fields.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_migrate/plugins/destinations/fields.inc
@@ -2,76 +2,41 @@
/**
* @file
- * Support for processing commerce fields (product reference, customer profile reference, price)
+ * Support for processing commerce fields (product reference, customer profile
+ * reference, price)
*/
-class MigrateCommerceCustomerProfileReferenceFieldHandler extends MigrateFieldHandler {
+class MigrateCommerceCustomerProfileReferenceFieldHandler extends MigrateSimpleFieldHandler {
public function __construct() {
+ parent::__construct(array(
+ 'value_key' => 'profile_id',
+ 'skip_empty' => TRUE,
+ ));
$this->registerTypes(array('commerce_customer_profile_reference'));
}
- public function prepare($entity, array $field_info, array $instance, array $values) {
- $migration = Migration::currentMigration();
- $arguments = (isset($values['arguments']))? $values['arguments']: array();
- $language = $this->getFieldLanguage($entity, $field_info, $arguments);
- // Setup the standard Field API array for saving.
- $delta = 0;
- foreach (array_filter($values) as $value) {
- $return[$language][$delta]['profile_id'] = $value;
- $delta++;
- }
- if (!isset($return)) {
- $return = NULL;
- }
- return $return;
- }
}
-class MigrateCommerceLineItemReferenceFieldHandler extends MigrateFieldHandler {
+class MigrateCommerceLineItemReferenceFieldHandler extends MigrateSimpleFieldHandler {
public function __construct() {
+ parent::__construct(array(
+ 'value_key' => 'line_item_id',
+ 'skip_empty' => TRUE,
+ ));
$this->registerTypes(array('commerce_line_item_reference'));
}
- public function prepare($entity, array $field_info, array $instance, array $values) {
- $migration = Migration::currentMigration();
- $arguments = (isset($values['arguments']))? $values['arguments']: array();
- $language = $this->getFieldLanguage($entity, $field_info, $arguments);
- // Setup the standard Field API array for saving.
- $delta = 0;
- foreach (array_filter($values) as $value) {
- $return[$language][$delta]['line_item_id'] = $value;
- $delta++;
- }
- if (!isset($return)) {
- $return = NULL;
- }
- return $return;
- }
}
-class MigrateCommerceProductReferenceFieldHandler extends MigrateFieldHandler {
+class MigrateCommerceProductReferenceFieldHandler extends MigrateSimpleFieldHandler {
public function __construct() {
+ parent::__construct(array(
+ 'value_key' => 'product_id',
+ 'skip_empty' => TRUE,
+ ));
$this->registerTypes(array('commerce_product_reference'));
}
- public function prepare($entity, array $field_info, array $instance, array $values) {
- $migration = Migration::currentMigration();
- $arguments = (isset($values['arguments']))? $values['arguments']: array();
- $language = $this->getFieldLanguage($entity, $field_info, $arguments);
- // Setup the standard Field API array for saving.
- $delta = 0;
- if(!is_array(reset($values))) {
- $values = array($values);
- }
- foreach (array_filter($values) as $value) {
- $return[$language][$delta]['product_id'] = reset($value);
- $delta++;
- }
- if (!isset($return)) {
- $return = NULL;
- }
- return $return;
- }
}
class MigrateCommercePriceFieldHandler extends MigrateFieldHandler {
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_moneybookers/PATCHES.txt b/profiles/commerce_kickstart/modules/contrib/commerce_moneybookers/PATCHES.txt
index 2eaca867..9f97ebf0 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_moneybookers/PATCHES.txt
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_moneybookers/PATCHES.txt
@@ -1,4 +1,4 @@
The following patches have been applied to this project:
- http://drupal.org/files/commerce_moneybookers-disable_payment_method_by_default-1962226-3.patch
-This file was automatically generated by Drush Make (http://drupal.org/project/drush).
\ No newline at end of file
+This file was automatically generated by Drush Make (http://drupal.org/project/drush).
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_nosto_tagging/commerce_nosto_tagging.info b/profiles/commerce_kickstart/modules/contrib/commerce_nosto_tagging/commerce_nosto_tagging.info
index fdaec056..0d2dfb89 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_nosto_tagging/commerce_nosto_tagging.info
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_nosto_tagging/commerce_nosto_tagging.info
@@ -10,9 +10,9 @@ core = 7.x
package = Commerce (contrib)
configure = admin/config/services/nostotagging
-; Information added by drupal.org packaging script on 2013-09-10
-version = "7.x-1.0"
+; Information added by Drupal.org packaging script on 2016-01-07
+version = "7.x-1.1"
core = "7.x"
project = "commerce_nosto_tagging"
-datestamp = "1378843042"
+datestamp = "1452154140"
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_nosto_tagging/commerce_nosto_tagging.module b/profiles/commerce_kickstart/modules/contrib/commerce_nosto_tagging/commerce_nosto_tagging.module
index 4344917b..bdb2cd7a 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_nosto_tagging/commerce_nosto_tagging.module
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_nosto_tagging/commerce_nosto_tagging.module
@@ -836,18 +836,20 @@ function _commerce_nosto_tagging_get_commerce_product_image_url($commerce_produc
*/
function _commerce_nosto_tagging_get_commerce_product_availability($commerce_product) {
if (module_exists('commerce_stock') && isset($commerce_product->commerce_stock)) {
- $remaining_stock = 0;
$out_of_stock = FALSE;
// Commerce Stock 1.x-branch
if (function_exists('commerce_stock_product_check_out_of_stock')) {
+ $remaining_stock = 0;
$out_of_stock = commerce_stock_product_check_out_of_stock($commerce_product->product_id, 1, $remaining_stock);
}
// Commerce Stock 2.x-branch
elseif (function_exists('commerce_stock_check_product_checkout_rule')) {
- $stock_state = TRUE;
+ $stock_state = 0;
$message = NULL;
- $out_of_stock_status = commerce_stock_check_product_checkout_rule($commerce_product, 1, $stock_state, $message);
- $out_of_stock = $stock_state;
+ commerce_stock_check_product_checkout_rule($commerce_product, 1, $stock_state, $message);
+ if ($stock_state == 1 || $stock_state == 2) {
+ $out_of_stock = TRUE;
+ }
}
if ($out_of_stock) {
return COMMERCE_NOSTO_TAGGING_PRODUCT_OUT_OF_STOCK;
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/LICENSE.txt b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/LICENSE.txt
old mode 100755
new mode 100644
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/commerce_paypal.info b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/commerce_paypal.info
index 8f3cd1bf..59fa5a59 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/commerce_paypal.info
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/commerce_paypal.info
@@ -10,9 +10,9 @@ core = 7.x
; Simple tests
; files[] = tests/commerce_paypal.test
-; Information added by Drupal.org packaging script on 2014-01-14
-version = "7.x-2.3"
+; Information added by Drupal.org packaging script on 2017-06-19
+version = "7.x-2.4"
core = "7.x"
project = "commerce_paypal"
-datestamp = "1389740908"
+datestamp = "1497908944"
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/commerce_paypal.module b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/commerce_paypal.module
index 87678336..5e659c15 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/commerce_paypal.module
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/commerce_paypal.module
@@ -91,18 +91,42 @@ function commerce_paypal_process_ipn($payment_method = NULL, $debug_ipn = array(
$host = 'https://www.paypal.com/cgi-bin/webscr';
}
- // Process the HTTP request to validate the IPN.
- $response = drupal_http_request($host, array('method' => 'POST', 'data' => implode('&', $variables)));
+ // Setup the cURL request.
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $host);
+ curl_setopt($ch, CURLOPT_VERBOSE, 0);
+ curl_setopt($ch, CURLOPT_POST, 1);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, implode('&', $variables));
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($ch, CURLOPT_NOPROGRESS, 1);
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
+
+ // Commerce PayPal requires SSL peer verification, which may prevent out of
+ // date servers from successfully processing API requests. If you get an error
+ // related to peer verification, you may need to download the CA certificate
+ // bundle file from http://curl.haxx.se/docs/caextract.html, place it in a
+ // safe location on your web server, and update your settings.php to set the
+ // commerce_paypal_cacert variable to contain the absolute path of the file.
+ // Alternately, you may be able to update your php.ini to point to the file
+ // with the curl.cainfo setting.
+ if (variable_get('commerce_paypal_cacert', FALSE)) {
+ curl_setopt($ch, CURLOPT_CAINFO, variable_get('commerce_paypal_cacert', ''));
+ }
+
+ $response = curl_exec($ch);
// If an error occurred during processing, log the message and exit.
- if (property_exists($response, 'error')) {
- watchdog('commerce_paypal', 'Attempt to validate IPN failed with error @code: @error', array('@code' => $response->code, '@error' => $response->error), WATCHDOG_ERROR);
+ if ($error = curl_error($ch)) {
+ watchdog('commerce_paypal', 'Attempt to validate IPN failed with cURL error: @error', array('@error' => $error), WATCHDOG_ERROR);
return FALSE;
}
+ curl_close($ch);
- // If the IPN was invalid, log a message and exit.
- if ($response->data == 'INVALID') {
- watchdog('commerce_paypal', 'Invalid IPN received and ignored.', array(), WATCHDOG_ALERT);
+ // inspect IPN validation result and act accordingly
+ if (strcmp ($response, "INVALID") == 0) {
+ // If the IPN was invalid, log a message and exit.
+ watchdog('commerce_paypal', 'Invalid IPN received and ignored. Response: @response', array('@response' => $response), WATCHDOG_ALERT);
return FALSE;
}
}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/ec/commerce_paypal_ec.info b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/ec/commerce_paypal_ec.info
index f053f001..7e965d81 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/ec/commerce_paypal_ec.info
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/ec/commerce_paypal_ec.info
@@ -8,9 +8,9 @@ dependencies[] = commerce_order
dependencies[] = commerce_paypal
core = 7.x
-; Information added by Drupal.org packaging script on 2014-01-14
-version = "7.x-2.3"
+; Information added by Drupal.org packaging script on 2017-06-19
+version = "7.x-2.4"
core = "7.x"
project = "commerce_paypal"
-datestamp = "1389740908"
+datestamp = "1497908944"
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/ec/commerce_paypal_ec.module b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/ec/commerce_paypal_ec.module
index f6ea1b86..d179591b 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/ec/commerce_paypal_ec.module
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/ec/commerce_paypal_ec.module
@@ -875,7 +875,7 @@ function commerce_paypal_ec_paypal_ipn_process($order, $payment_method, &$ipn) {
}
// Exit when we don't get a payment status we recognize.
- if (!in_array($ipn['payment_status'], array('Failed', 'Voided', 'Pending', 'Completed', 'Refunded'))) {
+ if (!in_array($ipn['payment_status'], array('Failed', 'Voided', 'Pending', 'Completed', 'Refunded', 'Denied'))) {
commerce_payment_redirect_pane_previous_page($order);
return FALSE;
}
@@ -908,6 +908,24 @@ function commerce_paypal_ec_paypal_ipn_process($order, $payment_method, &$ipn) {
$transaction = commerce_payment_transaction_new('paypal_ec', $order->order_id);
$transaction->instance_id = $payment_method['instance_id'];
}
+ elseif (in_array($ipn['payment_status'], array('Completed','Denied')) && $ipn['payment_type'] === 'echeck') {
+ // E-checks use the same ipn transaction id, with an updated status. Check
+ // for existing transaction with a status that's not the same.
+ // Ensure there is an existing transaction.
+ $transaction = commerce_paypal_payment_transaction_load($ipn['txn_id']);
+ if (! $transaction) {
+ watchdog('commerce_paypal_ec', 'IPN for Order @order_number ignored: transaction not found.', array('@order_number' => $order->order_number), WATCHDOG_NOTICE);
+ return FALSE;
+ }
+
+ // The e-check status has updated, so change the transaction details.
+ if ($ipn['payment_status'] == 'Completed') {
+ $transaction->message = '' . t('eCheck payment successful') . '';
+ }
+ else {
+ $transaction->message = '' . t('eCheck payment denied') . '';
+ }
+ }
else {
// In other circumstances, exit the processing, because we handle those
// cases directly during API response processing.
@@ -953,6 +971,11 @@ function commerce_paypal_ec_paypal_ipn_process($order, $payment_method, &$ipn) {
$transaction->status = COMMERCE_PAYMENT_STATUS_SUCCESS;
$transaction->message .= t('Refund for transaction @txn_id', array('@txn_id' => $ipn['parent_txn_id']));
break;
+
+ case 'Denied' :
+ $transaction->status = COMMERCE_PAYMENT_STATUS_FAILURE;
+ $transaction->message .= t("The payment has been denied. This happens only if the payment was previously pending.");
+ break;
}
// Save the transaction information.
@@ -1049,7 +1072,7 @@ function commerce_paypal_ec_set_express_checkout($payment_method, $order, $flow)
if (module_exists('commerce_shipping')) {
// If we have a shipping address, pass it to PayPal and do not allow the
// customer to set a new one at PayPal.
- if (!empty($order_wrapper->commerce_customer_shipping->commerce_customer_address)) {
+ if (isset($order_wrapper->commerce_customer_shipping) && !empty($order_wrapper->commerce_customer_shipping->commerce_customer_address)) {
$shipping_address = $order_wrapper->commerce_customer_shipping->commerce_customer_address->value();
// Ensure there's a name_line.
@@ -1383,7 +1406,9 @@ function commerce_paypal_ec_customer_profile($order, $profile_type, $response, $
);
// Prepare an addressfield array to set to the customer profile.
- $address = addressfield_default_values();
+ $field = field_info_field('commerce_customer_address');
+ $instance = field_info_instance('commerce_customer_profile', 'commerce_customer_address', $profile_type);
+ $address = addressfield_default_values($field, $instance);
// Use the first name and last name if the profile is a billing profile.
if ($profile_type == 'billing') {
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/payflow/commerce_payflow.info b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/payflow/commerce_payflow.info
index 8b4ea845..6acd0c70 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/payflow/commerce_payflow.info
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/payflow/commerce_payflow.info
@@ -11,9 +11,9 @@ core = 7.x
; Simple tests
; files[] = tests/commerce_paypal_wps.test
-; Information added by Drupal.org packaging script on 2014-01-14
-version = "7.x-2.3"
+; Information added by Drupal.org packaging script on 2017-06-19
+version = "7.x-2.4"
core = "7.x"
project = "commerce_paypal"
-datestamp = "1389740908"
+datestamp = "1497908944"
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/payflow/commerce_payflow.module b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/payflow/commerce_payflow.module
index 3d34fa70..5ed1a0e7 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/payflow/commerce_payflow.module
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/payflow/commerce_payflow.module
@@ -1447,6 +1447,7 @@ function commerce_payflow_link_result_message($result) {
case 0:
return t('Transaction approved.');
case 1:
+ return t('Account authentication error. Please contact an administrator to resolve this issue.');
case 5:
case 26:
return t('The Payflow hosted checkout page is not configured for use. Please contact an administrator to resolve this issue.');
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/wpp/commerce_paypal_wpp.info b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/wpp/commerce_paypal_wpp.info
index e986ac66..8c1055e4 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/wpp/commerce_paypal_wpp.info
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/wpp/commerce_paypal_wpp.info
@@ -11,9 +11,9 @@ core = 7.x
; Simple tests
; files[] = tests/commerce_paypal_wps.test
-; Information added by Drupal.org packaging script on 2014-01-14
-version = "7.x-2.3"
+; Information added by Drupal.org packaging script on 2017-06-19
+version = "7.x-2.4"
core = "7.x"
project = "commerce_paypal"
-datestamp = "1389740908"
+datestamp = "1497908944"
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/wpp/includes/commerce_paypal_wpp.admin.inc b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/wpp/includes/commerce_paypal_wpp.admin.inc
index 9325ac80..ee7e3498 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/wpp/includes/commerce_paypal_wpp.admin.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/wpp/includes/commerce_paypal_wpp.admin.inc
@@ -98,10 +98,21 @@ function commerce_paypal_wpp_capture_form_submit($form, &$form_state) {
$order = $form_state['order'];
$payment_method = $form_state['payment_method'];
$authorization_valid = TRUE;
+ $reauth_needed = TRUE;
+
+ // Find a previous successful reauthorization. This is needed in edge cases
+ // where reauthorization was successful but capture failed.
+ foreach ($transaction->payload as $key => $payload) {
+ $is_reauth = strpos($key, 'reauthorization');
+ if ($is_reauth && $payload['ACK'] == 'Success') {
+ $reauth_needed = FALSE;
+ break;
+ }
+ }
// If the original authorization was more than 3 days ago, PayPal's honor
// period is over and a reauthorization is required before capturing.
- if (REQUEST_TIME - $transaction->created > 86400 * 3) {
+ if (REQUEST_TIME - $transaction->created > 86400 * 3 && $reauth_needed) {
// Build a name-value pair array for the reauthorization.
$nvp = array(
'METHOD' => 'DoReauthorization',
@@ -112,7 +123,7 @@ function commerce_paypal_wpp_capture_form_submit($form, &$form_state) {
// Submit the reauthorization request.
$response = commerce_paypal_api_request($payment_method, $nvp, $order);
- $transaction->payload[REQUEST_TIMESTAMP . '-reauthorization'] = $response;
+ $transaction->payload[REQUEST_TIME . '-reauthorization'] = $response;
// If the response contains an authorization ID...
if (!empty($response['AUTHORIZATIONID'])) {
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/wps/commerce_paypal_wps.info b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/wps/commerce_paypal_wps.info
index a2da517d..307a135b 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/wps/commerce_paypal_wps.info
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/wps/commerce_paypal_wps.info
@@ -11,9 +11,9 @@ core = 7.x
; Simple tests
; files[] = tests/commerce_paypal_wps.test
-; Information added by Drupal.org packaging script on 2014-01-14
-version = "7.x-2.3"
+; Information added by Drupal.org packaging script on 2017-06-19
+version = "7.x-2.4"
core = "7.x"
project = "commerce_paypal"
-datestamp = "1389740908"
+datestamp = "1497908944"
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/wps/commerce_paypal_wps.module b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/wps/commerce_paypal_wps.module
index 7b761f8e..6eb51376 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/wps/commerce_paypal_wps.module
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_paypal/modules/wps/commerce_paypal_wps.module
@@ -350,10 +350,15 @@ function commerce_paypal_wps_paypal_ipn_process($order, $payment_method, &$ipn)
// Create the new profile now.
$profile = commerce_customer_profile_new('billing', $order->uid);
+ // Prepare an addressfield array to set to the customer profile.
+ $field = field_info_field('commerce_customer_address');
+ $instance = field_info_instance('commerce_customer_profile', 'commerce_customer_address', 'billing');
+ $address = addressfield_default_values($field, $instance);
+
// Add the address value.
$profile_wrapper = entity_metadata_wrapper('commerce_customer_profile', $profile);
- $profile_wrapper->commerce_customer_address = array_merge(addressfield_default_values(), array(
+ $profile_wrapper->commerce_customer_address = array_merge($address, array(
'country' => $ipn['residence_country'],
'name_line' => $ipn['first_name'] . ' ' . $ipn['last_name'],
'first_name' => $ipn['first_name'],
@@ -472,7 +477,7 @@ function commerce_paypal_wps_order_form($form, &$form_state, $order, $settings)
$form['#action'] = commerce_paypal_wps_server_url($settings['server']);
foreach ($data as $name => $value) {
- if (!empty($value)) {
+ if (isset($value)) {
$form[$name] = array('#type' => 'hidden', '#value' => $value);
}
}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_physical/commerce_physical.info b/profiles/commerce_kickstart/modules/contrib/commerce_physical/commerce_physical.info
index 64c0d0b9..fe7f1d84 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_physical/commerce_physical.info
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_physical/commerce_physical.info
@@ -8,9 +8,7 @@ dependencies[] = commerce_product_reference
dependencies[] = physical
core = 7.x
-
-; Information added by drush on 2015-08-20
-version = ""
+; Information added by drush on 2016-10-22
+version = "7.x-1.x-dev"
project = "commerce_physical"
-datestamp = "1440110605"
-
+datestamp = "1477171345"
\ No newline at end of file
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_physical/commerce_physical.inline_conditions.inc b/profiles/commerce_kickstart/modules/contrib/commerce_physical/commerce_physical.inline_conditions.inc
new file mode 100644
index 00000000..21564626
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_physical/commerce_physical.inline_conditions.inc
@@ -0,0 +1,75 @@
+ t('Total order weight'),
+ 'entity type' => 'commerce_order',
+ 'callbacks' => array(
+ 'configure' => 'commerce_physical_order_weight_comparison_configure',
+ ),
+ );
+
+ return $conditions;
+}
+
+ /**
+ * Configuration callback for commerce_physical_order_weight_comparison_configure.
+ *
+ * @param array $settings
+ * An array of rules condition settings.
+ *
+ * @return array
+ * A form element array.
+ */
+function commerce_physical_order_weight_comparison_configure($settings) {
+ $form = array();
+
+ // Ensure the settings array contains default values.
+ $settings += array(
+ 'operator' => '>=',
+ 'value' => '',
+ 'unit' => '',
+ );
+
+ $form['operator'] = array(
+ '#type' => 'select',
+ '#multiple' => FALSE,
+ '#options' => commerce_numeric_comparison_operator_options_list(),
+ '#title' => t('Operator'),
+ '#title_display' => 'invisible',
+ '#default_value' => $settings['operator'],
+ '#require' => TRUE,
+ );
+
+ $form['value'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Value'),
+ '#title_display' => 'invisible',
+ '#default_value' => $settings['value'],
+ '#size' => 5,
+ '#required' => TRUE,
+ '#element_validate' => array('element_validate_number'),
+ );
+
+ $form['unit'] = array(
+ '#type' => 'select',
+ '#multiple' => FALSE,
+ '#options' => physical_weight_unit_options(),
+ '#title' => t('Weight unit'),
+ '#title_display' => 'invisible',
+ '#default_value' => $settings['unit'],
+ '#require' => TRUE,
+ );
+
+ return $form;
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_physical/commerce_physical.module b/profiles/commerce_kickstart/modules/contrib/commerce_physical/commerce_physical.module
index dde39e28..c5b040d0 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_physical/commerce_physical.module
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_physical/commerce_physical.module
@@ -2,52 +2,95 @@
/**
* @file
- * Provides API support for working with physical product types in Drupal Commerce.
+ * API for working with physical product types in Drupal Commerce.
*/
/**
* Determines the weight field to use for a given entity.
*
- * @param $entity_type
+ * @param string $entity_type
* The type of entity passed to the function.
- * @param $entity
+ * @param object $entity
* The actual entity whose weight field name should be determined.
*
- * @return
+ * @return string
* The name of the field to use on the entity to find a weight value or NULL
* if none was found.
*/
function commerce_physical_entity_weight_field_name($entity_type, $entity) {
+
+ $field_name = commerce_physical_entity_field_name($entity_type, $entity, 'physical_weight');
+
+ // Allow other modules to specify a different field name.
+ drupal_alter('commerce_physical_entity_weight_field_name', $field_name, $entity_type, $entity);
+
+ return $field_name;
+}
+
+/**
+ * Determines the dimensions field to use for a given entity.
+ *
+ * @param string $entity_type
+ * The type of entity passed to the function.
+ * @param object $entity
+ * The actual entity whose weight field name should be determined.
+ *
+ * @return string
+ * The name of the field to use on the entity to find a weight value or NULL
+ * if none was found.
+ */
+function commerce_physical_entity_dimensions_field_name($entity_type, $entity) {
+
+ $field_name = commerce_physical_entity_field_name($entity_type, $entity, 'physical_dimensions');
+
+ // Allow other modules to specify a different field name.
+ drupal_alter('commerce_physical_entity_dimensions_field_name', $field_name, $entity_type, $entity);
+
+ return $field_name;
+}
+
+/**
+ * Determines the field of a certain type to use for a given entity.
+ *
+ * @param string $entity_type
+ * The type of entity passed to the function.
+ * @param object $entity
+ * The actual entity whose weight field name should be determined.
+ * @param string $field_type
+ * The field type to use.
+ *
+ * @return string
+ * The name of the field to use on the entity to find a weight value or NULL
+ * if none was found.
+ */
+function commerce_physical_entity_field_name($entity_type, $entity, $field_type) {
$bundle = field_extract_bundle($entity_type, $entity);
$field_name = NULL;
- // Look for the first weight field available for the entity.
+ // Look for the first field available for the entity.
foreach (field_info_instances($entity_type, $bundle) as $instance_name => $instance) {
// Load the field info for the current instance.
$field = field_info_field($instance['field_name']);
// If it's of the proper type...
- if ($field['type'] == 'physical_weight') {
+ if ($field['type'] == $field_type) {
// Save its name and exit the loop.
$field_name = $instance_name;
break;
}
}
- // Allow other modules to specify a different field name.
- drupal_alter('commerce_physical_entity_weight_field_name', $field_name, $entity_type, $entity);
-
return $field_name;
}
/**
* Determines the weight to use for a product line item on an order.
*
- * @param $line_item
+ * @param commerce_line_item $line_item
* A product line item whose weight should be determined.
*
- * @return
+ * @return array
* A weight field value array representing the weight of the product line item
* or NULL if none was found.
*/
@@ -80,15 +123,57 @@ function commerce_physical_product_line_item_weight($line_item) {
return $weight;
}
+/**
+ * Determines the dimensions of a product line item on an order.
+ *
+ * @param commerce_line_item $line_item
+ * A product line item whose dimensions should be determined.
+ *
+ * @return array
+ * An array of dimensions field value arrays. There'll be one entry in the
+ * array per product, with the entry being an array of that product's
+ * dimensions. If this line item contains no products with dimensions, an
+ * empty array will be returned.
+ */
+function commerce_physical_product_line_item_dimensions($line_item) {
+ $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
+ $dimensions = array();
+
+ // If the line item references a valid product...
+ if (!empty($line_item_wrapper->commerce_product)) {
+ $product = $line_item_wrapper->commerce_product->value();
+
+ if (!empty($product)) {
+ // If the product has a valid dimensions field...
+ $field_name = commerce_physical_entity_dimensions_field_name('commerce_product', $product);
+
+ if (!empty($field_name) && !empty($product->{$field_name})) {
+ $product_wrapper = entity_metadata_wrapper('commerce_product', $product);
+
+ // Add dimension values per product in the line item.
+ for ($i = 0; $i < $line_item_wrapper->quantity->value(); $i++) {
+ $dimensions[] = $product_wrapper->{$field_name}->value();
+ }
+ }
+ }
+ }
+
+ // Allow other modules to alter the weight if necessary.
+ drupal_alter('commerce_physical_product_line_item_dimensions', $dimensions, $line_item);
+
+ return $dimensions;
+}
+
+
/**
* Determines the weight of an entire order.
*
- * @param $order
+ * @param commerce_order $order
* The order object whose weight value should be calculated.
- * @param $unit
+ * @param string $unit
* The unit of measurement to use for the returned weight of the order.
*
- * @return
+ * @return array
* A weight field value array representing the total weight of the order using
* the specified unit of measurement or NULL if no weight could be determined.
*/
@@ -99,7 +184,7 @@ function commerce_physical_order_weight($order, $unit = 'lb') {
// Loop over each line item on the order.
foreach ($order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {
// Get the weight value of product line items.
- if (in_array($line_item_wrapper->type->value(), commerce_product_line_item_types())) {
+ if (in_array($line_item_wrapper->getBundle(), commerce_product_line_item_types())) {
$line_item_weight = commerce_physical_product_line_item_weight($line_item_wrapper->value());
// Add it to the running total converting it to the required weight unit.
@@ -123,87 +208,16 @@ function commerce_physical_order_weight($order, $unit = 'lb') {
}
-/**
- * Determines the dimensions field to use for a given entity.
- *
- * @param $entity_type
- * The type of entity passed to the function.
- * @param $entity
- * The actual entity whose dimensions field name should be determined.
- *
- * @return
- * The name of the field to use on the entity to find a dimensions value or
- * NULL if none was found.
- */
-function commerce_physical_entity_dimensions_field_name($entity_type, $entity) {
- $bundle = field_extract_bundle($entity_type, $entity);
- $field_name = NULL;
-
- // Look for the first dimensions field available for the entity.
- foreach (field_info_instances($entity_type, $bundle) as $instance_name => $instance) {
- // Load the field info for the current instance.
- $field = field_info_field($instance['field_name']);
-
- // If it's of the proper type...
- if ($field['type'] == 'physical_dimensions') {
- // Save its name and exit the loop.
- $field_name = $instance_name;
- break;
- }
- }
-
- // Allow other modules to specify a different field name.
- drupal_alter('commerce_physical_entity_dimensions_field_name', $field_name, $entity_type, $entity);
-
- return $field_name;
-}
-
-/**
- * Determines the dimensions to use for a product line item on an order.
- *
- * @param $line_item
- * A product line item whose single quantity dimensions should be determined.
- *
- * @return
- * A dimensions field value array representing the dimensions of a single
- * product referenced by the line item or NULL if no dimensions were found.
- */
-function commerce_physical_product_line_item_dimensions($line_item) {
- $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
- $dimensions = NULL;
-
- // If the line item references a valid product...
- if (!empty($line_item_wrapper->commerce_product)) {
- $product = $line_item_wrapper->commerce_product->value();
-
- if (!empty($product)) {
- // If the product has a valid dimensions field...
- $field_name = commerce_physical_entity_dimensions_field_name('commerce_product', $product);
-
- if (!empty($field_name) && !empty($product->{$field_name})) {
- // Extract the dimensions value from the product.
- $product_wrapper = entity_metadata_wrapper('commerce_product', $product);
- $dimensions = $product_wrapper->{$field_name}->value();
- }
- }
- }
-
- // Allow other modules to alter the volume if necessary.
- drupal_alter('commerce_physical_product_line_item_dimensions', $dimensions, $line_item);
-
- return $dimensions;
-}
-
/**
* Determines the volume of an entire order.
*
- * @param $order
+ * @param commerce_order $order
* The order object whose volume should be calculated.
- * @param $unit
+ * @param string $unit
* The unit of measurement to convert dimensions to before calculating the
* volume of the order in the related cubic unit.
*
- * @return
+ * @return array
* A volume value array with keys representing the total 'volume' of the order
* in the 'unit' specified or NULL if no volume could be determined.
*/
@@ -216,6 +230,9 @@ function commerce_physical_order_volume($order, $unit = 'in') {
// Get the dimensions value of product line items.
if (in_array($line_item_wrapper->type->value(), commerce_product_line_item_types())) {
$line_item_dimensions = commerce_physical_product_line_item_dimensions($line_item_wrapper->value());
+ // Each product in a line item has the same dimensions, so we index into
+ // only the first product.
+ $line_item_dimensions = reset($line_item_dimensions);
// Add it to the running total converting it to the required weight unit.
if (!physical_field_is_empty($line_item_dimensions, array('type' => 'physical_dimensions'))) {
@@ -242,13 +259,57 @@ function commerce_physical_order_volume($order, $unit = 'in') {
return $volume;
}
+
+/**
+ * Determines the dimensions of each product in an entire order.
+ *
+ * Other code can then use this data to figure out things like what the maximum
+ * dimensions of any product in the order is, or what size shipping container
+ * everything will fit into.
+ *
+ * @param commerce_order $order
+ * The order object whose dimensions should be returned.
+ * @param string $unit
+ * The unit of measurement to use for the returned dimensions.
+ *
+ * @return array
+ * An array of dimension arrays. One per product in the order.
+ * weight field value array representing the total weight of the order using
+ * the specified unit of measurement or NULL if no weight could be determined.
+ */
+function commerce_physical_order_dimensions($order, $unit = 'cm') {
+ $order_wrapper = entity_metadata_wrapper('commerce_order', $order);
+
+ $order_dimensions = array();
+
+ // Loop over each line item on the order.
+ foreach ($order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {
+ // Get the weight value of product line items.
+ if (in_array($line_item_wrapper->type->value(), commerce_product_line_item_types())) {
+ $line_item_dimensions = commerce_physical_product_line_item_dimensions($line_item_wrapper->value());
+
+ $order_dimensions = array_merge($order_dimensions, $line_item_dimensions);
+ }
+ }
+
+ // Now ensure that all dimensions supplied are in the requested units.
+ foreach ($order_dimensions as $key => $dimensions) {
+ $order_dimensions[$key] = physical_dimensions_convert($dimensions, $unit);
+ }
+
+ // Allow other modules to alter the weight if necessary.
+ drupal_alter('commerce_physical_order_dimensions', $order_dimensions, $order, $unit);
+
+ return $order_dimensions;
+}
+
/**
* Determines whether or not a line item should be considered shippable.
*
- * @param $line_item
+ * @param commerce_line_item $line_item
* The line item object whose shippability is being determined.
*
- * @return
+ * @return bool
* Boolean indicating whether or not the given line item represents something
* shippable; defaults to FALSE unless the line item represents a product line
* item with a discernible weight.
@@ -275,10 +336,10 @@ function commerce_physical_line_item_shippable($line_item) {
/**
* Determines whether or not an order should be considered shippable.
*
- * @param $order
+ * @param commerce_order $order
* The order object whose shippability should be determined.
*
- * @return
+ * @return bool
* Boolean indicating whether or not the given order is shippable; defaults to
* FALSE unless any line item on the order is determined to be shippable.
*/
@@ -302,14 +363,13 @@ function commerce_physical_order_shippable($order) {
}
/**
- * Determines the name of the shipping customer profile reference field for the
- * given order.
+ * Name of the shipping customer profile reference field for the given order.
*
- * @param $order
+ * @param commerce_order $order
* The order whose shipping customer profile reference field name should be
* determined.
*
- * @return
+ * @return string
* The name of the field to use on the order to find shipping information or
* NULL if none was found; defaults to commerce_customer_shipping if available
* or another customer profile reference if not (preferring profiles other
@@ -348,10 +408,10 @@ function commerce_physical_order_shipping_field_name($order) {
/**
* Determines the name of the phone number field of a customer profile.
*
- * @param $profile
+ * @param commerce_cutomer_profile $profile
* The customer profile whose phone number field name should be determined.
*
- * @return
+ * @return string
* The name of the field to use on the customer profile to find a phone number
* or NULL if none was found. Defaults to field_phone or field_phone_number if
* available; otherwise it's up to you to alter it in a custom module since we
@@ -375,13 +435,12 @@ function commerce_physical_customer_profile_phone_number_field_name($profile) {
}
/**
- * Determines whether or not a shipping customer profile should be considered as
- * a residential address.
+ * Whether or not a shipping customer profile is a residential address.
*
- * @param $profile
+ * @param commerce_customer_profile $profile
* The customer profile whose residential status should be determined.
*
- * @return
+ * @return bool
* Boolean indicating whether or not the given profile has a residential
* address; defaults to TRUE unless otherwise determined by a custom module.
*/
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_physical/commerce_physical.rules.inc b/profiles/commerce_kickstart/modules/contrib/commerce_physical/commerce_physical.rules.inc
new file mode 100644
index 00000000..807867e3
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_physical/commerce_physical.rules.inc
@@ -0,0 +1,186 @@
+ t("Order total weight comparison"),
+ 'parameter' => array(
+ 'commerce_order' => array(
+ 'type' => 'commerce_order',
+ 'label' => t('Order'),
+ ),
+ 'operator' => array(
+ 'type' => 'text',
+ 'label' => t('Operator'),
+ 'description' => t('The comparison operator.'),
+ 'options list' => 'commerce_numeric_comparison_operator_options_list',
+ 'restriction' => 'input',
+ ),
+ 'value' => array(
+ 'type' => 'decimal',
+ 'label' => t('Value'),
+ ),
+ 'unit' => array(
+ 'type' => 'text',
+ 'label' => t('Weight unit'),
+ 'options list' => 'physical_weight_unit_options',
+ 'restriction' => 'input',
+ 'default value' => 'kg',
+ ),
+ ),
+ 'group' => t('Commerce Physical'),
+ );
+
+ $conditions['commerce_physical_rules_order_max_dimension_comparison'] = array(
+ 'label' => t("Maximum product dimension comparison"),
+ 'parameter' => array(
+ 'commerce_order' => array(
+ 'type' => 'commerce_order',
+ 'label' => t('Order'),
+ ),
+ 'operator' => array(
+ 'type' => 'text',
+ 'label' => t('Operator'),
+ 'description' => t('The comparison operator.'),
+ 'options list' => 'commerce_numeric_comparison_operator_options_list',
+ 'restriction' => 'input',
+ ),
+ 'value' => array(
+ 'type' => 'decimal',
+ 'label' => t('Value'),
+ ),
+ 'unit' => array(
+ 'type' => 'text',
+ 'label' => t('Dimension unit'),
+ 'options list' => 'physical_dimension_unit_options',
+ 'restriction' => 'input',
+ 'default value' => 'cm',
+ ),
+ ),
+ 'group' => t('Commerce Physical'),
+ );
+
+ $conditions['commerce_physical_rules_order_is_shippable'] = array(
+ 'label' => t("The order contains shippable products"),
+ 'parameter' => array(
+ 'commerce_order' => array(
+ 'type' => 'commerce_order',
+ 'label' => t('Order'),
+ ),
+ ),
+ 'group' => t('Commerce Physical'),
+ );
+
+ $conditions['commerce_physical_rules_line_item_is_shippable'] = array(
+ 'label' => t("The line item is a shippable product"),
+ 'parameter' => array(
+ 'commerce_line_item' => array(
+ 'type' => 'commerce_line_item',
+ 'label' => t('Line Item'),
+ ),
+ ),
+ 'group' => t('Commerce Physical'),
+ );
+
+ return $conditions;
+}
+
+
+/**
+ * Fetches the max. dimension in the order and compares it with a given value.
+ *
+ * Calculates the maximum single dimension of any product in the order and
+ * performs a comparison on it.
+ */
+function commerce_physical_rules_order_max_dimension_comparison($order, $operator, $value, $unit) {
+
+ $max_dimension = 0;
+
+ $dimension_keys = array(
+ 'length',
+ 'width',
+ 'height',
+ );
+
+ // Get the dimensions of every product in the order.
+ foreach (commerce_physical_order_dimensions($order, $unit) as $dimension) {
+
+ // Check each of length / width / height.
+ foreach ($dimension_keys as $dimension_key) {
+
+ // If this dimension's bigger than the current max, it's the new max.
+ if ($dimension[$dimension_key] > $max_dimension) {
+ $max_dimension = $dimension[$dimension_key];
+ }
+ }
+ }
+
+ switch ($operator) {
+ case '<':
+ return $max_dimension < $value;
+
+ case '<=':
+ return $max_dimension <= $value;
+
+ case '==':
+ return $max_dimension == $value;
+
+ case '>=':
+ return $max_dimension >= $value;
+
+ case '>':
+ return $max_dimension > $value;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Calculates the order's total weight and performs a comparison on it.
+ */
+function commerce_physical_rules_order_weight_comparison($order, $operator, $value, $unit) {
+
+ $order_weight = commerce_physical_order_weight($order, $unit);
+
+ switch ($operator) {
+ case '<':
+ return $order_weight['weight'] < $value;
+
+ case '<=':
+ return $order_weight['weight'] <= $value;
+
+ case '==':
+ return $order_weight['weight'] == $value;
+
+ case '>=':
+ return $order_weight['weight'] >= $value;
+
+ case '>':
+ return $order_weight['weight'] > $value;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Rules condition: check if the order contains shippable products.
+ */
+function commerce_physical_rules_order_is_shippable($order) {
+ return commerce_physical_order_shippable($order);
+}
+
+/**
+ * Rules condition: check if the line item is a shippable product.
+ */
+function commerce_physical_rules_line_item_is_shippable($line_item) {
+ return commerce_physical_line_item_shippable($line_item);
+}
\ No newline at end of file
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_search_api/commerce_search_api.facetapi_defaults.inc b/profiles/commerce_kickstart/modules/contrib/commerce_search_api/commerce_search_api.facetapi_defaults.inc
index eb734d51..efc28110 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_search_api/commerce_search_api.facetapi_defaults.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_search_api/commerce_search_api.facetapi_defaults.inc
@@ -1,12 +1,17 @@
'Configure the generated product display index.',
'page callback' => 'drupal_get_form',
'page arguments' => array('commerce_search_api_admin_settings_form'),
- 'access callback' => 'commerce_search_api_admin_settings_access',
- 'access arguments' => array('administer site configuration'),
+ 'access arguments' => array('configure store'),
'type' => MENU_NORMAL_ITEM,
'file' => 'includes/commerce_search_api.admin.inc',
);
return $items;
}
-/**
- * Access calback for the index admin settings form.
- */
-function commerce_search_api_admin_settings_access($permission) {
- return search_api_index_load('product_display') && user_access($permission);
-}
-
/**
* Implements hook_default_search_api_index().
*
* Create an automatic product display index.
*/
function commerce_search_api_default_search_api_index() {
+ // Don't generate a default Search Index if unnecessary.
+ if (!variable_get('commerce_search_api_provide_default_index', TRUE)) {
+ return;
+ }
+ module_load_include('inc', 'commerce_search_api', 'includes/commerce_search_api.callbacks');
$server = search_api_server_load('frontend');
if (empty($server)) {
$servers = search_api_server_load_multiple(FALSE);
@@ -52,256 +50,10 @@ function commerce_search_api_default_search_api_index() {
}
$server = reset($servers);
}
- $items['product_display'] = commerce_search_api_generate_product_display_index($server, 'product_display');
+ $items[COMMERCE_SEARCH_API_INDEX] = commerce_search_api_generate_product_display_index($server, COMMERCE_SEARCH_API_INDEX);
return $items;
}
-/**
- * Generate a SearchApiIndex with common defaults configuration.
- *
- * @param SearchApiServer $server
- * The server the generated index will resides on.
- *
- * @param $index_machine_name
- * The machine name of the generated index.
- *
- * @return SearchApiIndex
- * The generated SearchApiIndex.
- */
-function commerce_search_api_generate_product_display_index(SearchApiServer $server, $index_machine_name) {
- $product_reference_fields = commerce_info_fields('commerce_product_reference', 'node');
- // We only generate an index if there are product display types.
- if (empty($product_reference_fields) || !isset($server->machine_name)) {
- return entity_create('search_api_index', array());
- }
- $title = 'title';
- // Check if we should index the translated title or not.
- if (module_exists('title') && $title_field = title_field_replacement_info('node', 'title')) {
- $title = $title_field['field']['field_name'];
- }
- // We prepend temp_ to the machine name to prevent Search API from caching
- // the wrong fields when calling the getFields() method.
- $values = array(
- 'name' => t('Product display'),
- 'machine_name' => 'temp_' . $index_machine_name,
- 'server' => $server->machine_name,
- 'item_type' => 'node',
- 'enabled' => 1,
- 'read_only' => 0,
- 'options' => array(
- 'index_directly' => 1,
- 'cron_limit' => 50,
- 'fields' => array(
- 'nid' => array(
- 'type' => 'integer',
- ),
- 'search_api_language' => array(
- 'type' => 'string',
- ),
- 'type' => array(
- 'type' => 'string',
- ),
- $title => array(
- 'type' => 'string',
- ),
- 'created' => array(
- 'type' => 'date',
- ),
- 'changed' => array(
- 'type' => 'date',
- ),
- 'status' => array(
- 'type' => 'integer',
- ),
- 'search_api_aggregation_1' => array(
- 'type' => 'text',
- ),
- ),
- 'data_alter_callbacks' => array(
- 'commerce_search_api_product_display_filter' => array(
- 'status' => 1,
- 'weight' => -10,
- ),
- 'commerce_search_api_alter_product_status' => array(
- 'status' => 1,
- 'weight' => -9,
- ),
- 'search_api_alter_add_aggregation' => array(
- 'status' => 1,
- 'weight' => 0,
- 'settings' => array(
- 'fields' => array(
- 'search_api_aggregation_1' => array(
- 'name' => t('Title (Fulltext)'),
- 'type' => 'fulltext',
- 'fields' => array(
- $title,
- ),
- 'description' => t('A Fulltext aggregation of the title field.'),
- ),
- ),
- ),
- ),
- ),
- ),
- );
- // If a product reference field is called field_product, take it.
- if (isset($product_reference_fields['field_product'])) {
- $product_reference_field = $product_reference_fields['field_product'];
- }
- // Else, take the first one.
- else {
- $product_reference_field = reset($product_reference_fields);
- }
- $type = $product_reference_field['cardinality'] != 1 ? 'list' : 'integer';
- $values['options']['fields'] += array(
- $product_reference_field['field_name'] => array(
- 'type' => $type,
- 'entity_type' => 'commerce_product',
- ),
- );
- // Adding fields in the additional fields array will alow us to browse them.
- $values['options']['additional fields'][$product_reference_field['field_name']] = $product_reference_field['field_name'];
- $values['options']['additional fields'][$product_reference_field['field_name'] . ':commerce_price'] = $product_reference_field['field_name'] . ':commerce_price';
-
- // Create a temporary node index that allows us to browse the fields.
- $index = entity_create('search_api_index', $values);
- $aggregation_index = 2;
- foreach ($index->getFields(FALSE) as $field_name => $field) {
- // Index term reference fields.
- if (isset($field['entity_type']) && $field['entity_type'] == 'taxonomy_term') {
- $values['options']['fields'] += array(
- $field_name => array(
- 'type' => $field['type'],
- 'entity_type' => $field['entity_type'],
- ),
- // We're also indexing the name property of the taxonomy term.
- $field_name . ':name' => array(
- 'type' => search_api_nest_type('string', $field['type']),
- ),
- );
- // Check if the fulltext search is enabled for this taxonomy field.
- if (strpos($field_name, ':') === FALSE && variable_get('commerce_search_api_' . $field_name . '_fulltext', 1)) {
- $values['options']['data_alter_callbacks']['search_api_alter_add_aggregation']['settings']['fields'] += array(
- 'search_api_aggregation_' . $aggregation_index => array(
- 'name' => t('@field name (Fulltext)', array('@field' => $field['name'])),
- 'type' => 'fulltext',
- 'fields' => array(
- $field_name . ':name',
- ),
- 'description' => t('Name property of @field as fulltext', array('@field' => $field['name'])),
- ),
- );
- $values['options']['fields']['search_api_aggregation_' . $aggregation_index] = array(
- 'type' => 'text',
- );
- }
- $aggregation_index++;
- }
- else {
- // Index the price decimal property.
- if ($field_name == $product_reference_field['field_name'] . ':commerce_price:amount_decimal') {
- $values['options']['fields'] += array(
- $field_name => array(
- 'type' => $field['type'],
- ),
- );
- // Ranges support, we're using the decimal amount (Useful for facets).
- if (search_api_is_list_type($field['type']) && module_exists('search_api_ranges')) {
- $prefix = str_replace(':', '_', $field_name);
- $values['options']['fields'][$prefix . '_asc'] = array(
- 'type' => 'decimal',
- );
- $values['options']['fields'][$prefix . '_desc'] = array(
- 'type' => 'decimal',
- );
- $values['options']['data_alter_callbacks'] += array(
- 'search_api_ranges_alter' => array(
- 'status' => 1,
- 'weight' => 1,
- 'settings' => array(
- 'fields' => drupal_map_assoc(array($field_name)),
- ),
- ),
- );
- }
- }
- }
- }
- $index->options = $values['options'];
- $index->machine_name = $index_machine_name;
- return $index;
-}
-
-/**
- * Generate and enable facetapi facets with some defaults.
- *
- * @param $index_machine_name
- * The machine name of the index.
- *
- * @return array
- * An array of facets exports with some default configurations.
- */
-function commerce_search_api_generate_facets($index_machine_name) {
- $export = array();
- $searcher = 'search_api@' . $index_machine_name;
- $index = search_api_index_load($index_machine_name);
- $adapter = facetapi_adapter_load($searcher);
- if ((empty($adapter) || empty($index)) || (!empty($index) && !$index->server()->supportsFeature('search_api_facets'))) {
- return $export;
- }
- $product_attributes = commerce_info_fields('taxonomy_term_reference', 'commerce_product');
- $realm = facetapi_realm_load('block');
- $search_api_ranges_exists = module_exists('search_api_ranges');
- foreach (facetapi_get_facet_info($searcher) as $field_name => $facet_info) {
- $export_facet = FALSE;
- if (isset($facet_info['field type']) && $facet_info['field type'] == 'taxonomy_term') {
- $widget = 'facetapi_checkbox_links';
- $export_facet = TRUE;
- }
- if ($search_api_ranges_exists && strpos($field_name, ':amount_decimal') !== FALSE) {
- $widget = 'search_api_ranges_ui_slider';
- $export_facet = TRUE;
- }
- if ($export_facet) {
- $facet = $adapter->getFacetSettings($facet_info, $realm);
- if ($facet->export_type == EXPORT_IN_DATABASE) {
- continue;
- }
- $facet->settings['widget'] = $widget;
- $facet->settings['filters'] += array(
- 'active_items' => array(
- 'status' => 1,
- 'weight' => -1,
- ),
- );
- // Adding extra filters to product attribute fields.
- if (!empty($product_attributes)) {
- if (strpos($field_name, ':') !== FALSE) {
- list($prefix, $suffix) = explode(':', $field_name, 2);
- if (isset($product_attributes[$suffix])) {
- $facet->settings['filters'] += array(
- 'useless_searches' => array(
- 'status' => 1,
- 'weight' => 0,
- ),
- 'hide_search_start' => array(
- 'status' => 1,
- 'weight' => 1,
- ),
- );
- }
- }
- }
- $facet->api_version = 1;
- $facet->disabled = FALSE;
- $facet->enabled = TRUE;
- $export[$facet->name] = $facet;
- }
- }
- return $export;
-}
-
/**
* Implements hook_entity_property_info_alter().
*/
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_search_api/includes/callback_product_status.inc b/profiles/commerce_kickstart/modules/contrib/commerce_search_api/includes/callback_product_status.inc
index 01bb44e2..aeb99378 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_search_api/includes/callback_product_status.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_search_api/includes/callback_product_status.inc
@@ -22,7 +22,7 @@ class CommerceSearchApiAlterProductStatus extends SearchApiAbstractAlterCallback
*/
public function supportsIndex(SearchApiIndex $index) {
$bundles = commerce_product_reference_node_types();
- return ($index->item_type == 'node' && !empty($bundles));
+ return ($index->getEntityType() == 'node' && !empty($bundles));
}
/**
@@ -49,7 +49,7 @@ class CommerceSearchApiAlterProductStatus extends SearchApiAbstractAlterCallback
}
else {
foreach ($node_wrapper->{$field_name} as $delta => $product_wrapper) {
- if ($product_wrapper->status->raw() == 0) {
+ if (!$product_wrapper->value() || $product_wrapper->status->raw() == 0) {
$products_removed++;
if ($products_removed != $nb_products) {
$node_wrapper->{$field_name}->offsetUnset($delta);
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_search_api/includes/commerce_search_api.admin.inc b/profiles/commerce_kickstart/modules/contrib/commerce_search_api/includes/commerce_search_api.admin.inc
index 16fdf0ce..08ec6c62 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_search_api/includes/commerce_search_api.admin.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_search_api/includes/commerce_search_api.admin.inc
@@ -13,35 +13,33 @@
* @ingroup forms
*/
function commerce_search_api_admin_settings_form($form, &$form_state) {
- if ($index = search_api_index_load('product_display')) {
- $form['#entity'] = $index;
- $form['description'] = array(
- '#type' => 'item',
- '#title' => t('Commerce Search API'),
- '#markup' => t('This page allows you to change the behavior of the generated search index.'),
- );
- // Try to find taxonomy terms on
- foreach ($index->getFields(FALSE) as $field_name => $field) {
- if (!isset($field['entity_type']) || $field['entity_type'] != 'taxonomy_term' || strpos($field_name, ':') !== FALSE) {
- continue;
- }
- $form['commerce_search_api_' . $field_name . '_fulltext'] = array(
- '#title' => t('Allow users to search products by @field name', array('@field' => $field['name'])),
- '#type' => 'checkbox',
- '#default_value' => variable_get('commerce_search_api_' . $field_name . '_fulltext', 1),
- );
- }
- $form = system_settings_form($form);
- $form['#submit'][] = 'commerce_search_api_admin_settings_form_submit';
- return $form;
- }
+ $form['commerce_search_api_provide_default_index'] = array(
+ '#title' => t('Provide a default Search Index'),
+ '#description' => t('If checked, a default Search API Product display index will be generated with sensible defaults configuration.'),
+ '#type' => 'checkbox',
+ '#default_value' => variable_get('commerce_search_api_provide_default_index', TRUE),
+ );
+ $form['commerce_search_api_generate_facets'] = array(
+ '#title' => t('Generate default facets'),
+ '#description' => t('If checked, defaults Facet API facets will be generated for the Product display index.'),
+ '#type' => 'checkbox',
+ '#default_value' => variable_get('commerce_search_api_generate_facets', TRUE),
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="commerce_search_api_provide_default_index"]' => array('checked' => TRUE),
+ ),
+ ),
+ );
+ $form = system_settings_form($form);
+ $form['#submit'][] = 'commerce_search_api_admin_settings_form_submit';
+ return $form;
}
/**
- * Submit callback for the commerce_search_api_admin_settings_form.
+ * Form submission handler for commerce_search_api_admin_settings_form().
+ *
+ * @see commerce_search_api_admin_settings_form().
*/
function commerce_search_api_admin_settings_form_submit($form, &$form_state) {
entity_defaults_rebuild(array('search_api_index', 'search_api_server'));
- drupal_set_message(t('You need to reindex your items because we added/remove fields, Click on "Index now".'));
- $form_state['redirect'] = 'admin/config/search/search_api/index/product_display/status';
}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_search_api/includes/commerce_search_api.callbacks.inc b/profiles/commerce_kickstart/modules/contrib/commerce_search_api/includes/commerce_search_api.callbacks.inc
new file mode 100644
index 00000000..141e253d
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_search_api/includes/commerce_search_api.callbacks.inc
@@ -0,0 +1,257 @@
+machine_name)) {
+ return entity_create('search_api_index', array());
+ }
+ $title = 'title';
+ // Check if we should index the translated title or not.
+ if (module_exists('title') && $title_field = title_field_replacement_info('node', 'title')) {
+ $title = $title_field['field']['field_name'];
+ }
+ // We prepend temp_ to the machine name to prevent Search API from caching
+ // the wrong fields when calling the getFields() method.
+ $values = array(
+ 'name' => t('Product display'),
+ 'machine_name' => 'temp_' . $index_machine_name,
+ 'server' => $server->machine_name,
+ 'item_type' => 'node',
+ 'enabled' => 1,
+ 'read_only' => 0,
+ 'options' => array(
+ 'index_directly' => 1,
+ 'cron_limit' => 50,
+ 'fields' => array(
+ 'nid' => array(
+ 'type' => 'integer',
+ ),
+ 'search_api_language' => array(
+ 'type' => 'string',
+ ),
+ 'type' => array(
+ 'type' => 'string',
+ ),
+ $title => array(
+ 'type' => 'string',
+ ),
+ 'created' => array(
+ 'type' => 'date',
+ ),
+ 'changed' => array(
+ 'type' => 'date',
+ ),
+ 'status' => array(
+ 'type' => 'integer',
+ ),
+ 'search_api_aggregation_1' => array(
+ 'type' => 'text',
+ ),
+ ),
+ 'data_alter_callbacks' => array(
+ 'commerce_search_api_product_display_filter' => array(
+ 'status' => 1,
+ 'weight' => -10,
+ ),
+ 'commerce_search_api_alter_product_status' => array(
+ 'status' => 1,
+ 'weight' => -9,
+ ),
+ 'search_api_alter_add_aggregation' => array(
+ 'status' => 1,
+ 'weight' => 0,
+ 'settings' => array(
+ 'fields' => array(
+ 'search_api_aggregation_1' => array(
+ 'name' => t('Title (Fulltext)'),
+ 'type' => 'fulltext',
+ 'fields' => array(
+ $title,
+ ),
+ 'description' => t('A Fulltext aggregation of the title field.'),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ // If a product reference field is called field_product, take it.
+ if (isset($product_reference_fields['field_product'])) {
+ $product_reference_field = $product_reference_fields['field_product'];
+ }
+ // Else, take the first one.
+ else {
+ $product_reference_field = reset($product_reference_fields);
+ }
+ $type = $product_reference_field['cardinality'] != 1 ? 'list' : 'integer';
+ $values['options']['fields'] += array(
+ $product_reference_field['field_name'] => array(
+ 'type' => $type,
+ 'entity_type' => 'commerce_product',
+ ),
+ );
+ // Adding fields in the additional fields array will alow us to browse them.
+ $values['options']['additional fields'][$product_reference_field['field_name']] = $product_reference_field['field_name'];
+ $values['options']['additional fields'][$product_reference_field['field_name'] . ':commerce_price'] = $product_reference_field['field_name'] . ':commerce_price';
+
+ // Create a temporary node index that allows us to browse the fields.
+ $index = entity_create('search_api_index', $values);
+ $aggregation_index = 2;
+ foreach ($index->getFields(FALSE) as $field_name => $field) {
+ // Index term reference fields.
+ if (isset($field['entity_type']) && $field['entity_type'] == 'taxonomy_term') {
+ $field_info = field_info_field($field_name);
+ // Check if the field belongs to a product display bundle to include it
+ // in the index and create the aggregated field.
+ if (!empty($field_info['bundles']['node']) && !array_intersect($field_info['bundles']['node'], $product_reference_field['bundles']['node'])) {
+ continue;
+ }
+ $values['options']['fields'] += array(
+ $field_name => array(
+ 'type' => $field['type'],
+ 'entity_type' => $field['entity_type'],
+ ),
+ // We're also indexing the name property of the taxonomy term.
+ $field_name . ':name' => array(
+ 'type' => search_api_nest_type('string', $field['type']),
+ ),
+ );
+ // Check if the fulltext search is enabled for this taxonomy field.
+ if (strpos($field_name, ':') === FALSE) {
+ $values['options']['data_alter_callbacks']['search_api_alter_add_aggregation']['settings']['fields'] += array(
+ 'search_api_aggregation_' . $aggregation_index => array(
+ 'name' => t('@field name (Fulltext)', array('@field' => $field['name'])),
+ 'type' => 'fulltext',
+ 'fields' => array(
+ $field_name . ':name',
+ ),
+ 'description' => t('Name property of @field as fulltext', array('@field' => $field['name'])),
+ ),
+ );
+ $values['options']['fields']['search_api_aggregation_' . $aggregation_index] = array(
+ 'type' => 'text',
+ );
+ }
+ $aggregation_index++;
+ }
+ else {
+ // Index the price decimal property.
+ if ($field_name == $product_reference_field['field_name'] . ':commerce_price:amount_decimal') {
+ $values['options']['fields'] += array(
+ $field_name => array(
+ 'type' => $field['type'],
+ ),
+ );
+ // Ranges support, we're using the decimal amount (Useful for facets).
+ if (search_api_is_list_type($field['type']) && module_exists('search_api_ranges')) {
+ $prefix = str_replace(':', '_', $field_name);
+ $values['options']['fields'][$prefix . '_asc'] = array(
+ 'type' => 'decimal',
+ );
+ $values['options']['fields'][$prefix . '_desc'] = array(
+ 'type' => 'decimal',
+ );
+ $values['options']['data_alter_callbacks'] += array(
+ 'search_api_ranges_alter' => array(
+ 'status' => 1,
+ 'weight' => 1,
+ 'settings' => array(
+ 'fields' => drupal_map_assoc(array($field_name)),
+ ),
+ ),
+ );
+ }
+ }
+ }
+ }
+ $index->options = $values['options'];
+ $index->machine_name = $index_machine_name;
+ return $index;
+}
+
+/**
+ * Generate and enable Facetapi facets with some defaults.
+ *
+ * @param $index_machine_name
+ * The machine name of the index.
+ *
+ * @return array
+ * An array of facets exports with some default configurations.
+ */
+function commerce_search_api_generate_facets($index_machine_name) {
+ $export = array();
+ $searcher = 'search_api@' . $index_machine_name;
+ $index = search_api_index_load($index_machine_name);
+ $adapter = facetapi_adapter_load($searcher);
+ if ((empty($adapter) || empty($index)) || (!empty($index) && !$index->server()->supportsFeature('search_api_facets'))) {
+ return $export;
+ }
+ $product_attributes = commerce_info_fields('taxonomy_term_reference', 'commerce_product');
+ $realm = facetapi_realm_load('block');
+ $search_api_ranges_exists = module_exists('search_api_ranges');
+ foreach (facetapi_get_facet_info($searcher) as $field_name => $facet_info) {
+ $export_facet = FALSE;
+ if (isset($facet_info['field type']) && $facet_info['field type'] == 'taxonomy_term') {
+ $widget = 'facetapi_checkbox_links';
+ $export_facet = TRUE;
+ }
+ if ($search_api_ranges_exists && strpos($field_name, ':amount_decimal') !== FALSE) {
+ $widget = 'search_api_ranges_ui_slider';
+ $export_facet = TRUE;
+ }
+ if ($export_facet) {
+ $facet = $adapter->getFacetSettings($facet_info, $realm);
+ if ($facet->export_type == EXPORT_IN_DATABASE) {
+ continue;
+ }
+ $facet->settings['widget'] = $widget;
+ $facet->settings['filters'] += array(
+ 'active_items' => array(
+ 'status' => 1,
+ 'weight' => -1,
+ ),
+ );
+ // Adding extra filters to product attribute fields.
+ if (!empty($product_attributes)) {
+ if (strpos($field_name, ':') !== FALSE) {
+ list($prefix, $suffix) = explode(':', $field_name, 2);
+ if (isset($product_attributes[$suffix])) {
+ $facet->settings['filters'] += array(
+ 'useless_searches' => array(
+ 'status' => 1,
+ 'weight' => 0,
+ ),
+ 'hide_search_start' => array(
+ 'status' => 1,
+ 'weight' => 1,
+ ),
+ );
+ }
+ }
+ }
+ $facet->api_version = 1;
+ $facet->disabled = FALSE;
+ $facet->enabled = TRUE;
+ $export[$facet->name] = $facet;
+ }
+ }
+ return $export;
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_search_api/includes/commerce_search_api_product_display_filter.inc b/profiles/commerce_kickstart/modules/contrib/commerce_search_api/includes/commerce_search_api_product_display_filter.inc
index f51e13ea..17b86209 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_search_api/includes/commerce_search_api_product_display_filter.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_search_api/includes/commerce_search_api_product_display_filter.inc
@@ -22,7 +22,7 @@ class CommerceSearchApiProductDisplayFilter extends SearchApiAbstractAlterCallba
*/
public function supportsIndex(SearchApiIndex $index) {
$bundles = commerce_product_reference_node_types();
- return ($index->item_type == 'node' && !empty($bundles));
+ return ($index->getEntityType() == 'node' && !empty($bundles));
}
/**
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.api.php b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.api.php
index d815f567..468977f4 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.api.php
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.api.php
@@ -1,19 +1,24 @@
shipping_rates array containing shipping line items for rates
* calculated for the order.
*
- * @param $options
+ * @param array $options
* The options array used to select a calculated shipping rate.
- * @param $order
+ * @param object $order
* The order the options array was generated for.
*
* @see commerce_shipping_service_rate_options()
@@ -192,10 +212,12 @@ function hook_commerce_shipping_service_rate_options_alter(&$options, $order, &$
}
/**
- * Allows modules to alter newly created shipping line items after their service
- * and unit price values have been set.
+ * Allows modules to alter newly created shipping line items.
+ *
+ * Shipping line items will be altered after their service and
+ * unit price values have been set.
*
- * @param $line_item
+ * @param object $line_item
* The newly created shipping line item.
*
* @see commerce_shipping_line_item_new()
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.info b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.info
index ed4ae4dd..2657ffec 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.info
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.info
@@ -10,9 +10,9 @@ core = 7.x
files[] = includes/views/handlers/commerce_shipping_handler_relationship_shipping_line_item_representative.inc
-; Information added by Drupal.org packaging script on 2015-04-08
-version = "7.x-2.2"
+; Information added by Drupal.org packaging script on 2017-11-28
+version = "7.x-2.3"
core = "7.x"
project = "commerce_shipping"
-datestamp = "1428479882"
+datestamp = "1511853188"
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.install b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.install
index 3ec450e7..57396c61 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.install
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.install
@@ -1,10 +1,10 @@
fields('r', array('data', 'id'))
->condition('r.name', $rules_actions_to_rename, 'IN')
@@ -96,7 +96,7 @@ function commerce_shipping_update_7002(&$sandbox) {
preg_match('/(\d+):"commerce_shipping_enable_plugin-/', $row->data, $matches);
if (!empty($matches[1])) {
$replace = $matches[1] - 7;
- $data = preg_replace('/\d+(:"commerce_shipping_enable_)plugin-/', $replace . '$1' , $row->data);
+ $data = preg_replace('/\d+(:"commerce_shipping_enable_)plugin-/', $replace . '$1', $row->data);
db_update('rules_config')
->fields(array('data' => $row->data))
->condition('id', $row->id)
@@ -108,39 +108,41 @@ function commerce_shipping_update_7002(&$sandbox) {
}
/**
- * Rename the shipping_method field on the shipping line item to commerce_shipping_method.
- * This should actually never be run on 2.x but is here for reference.
+ * Rename the shipping_method field on the shipping line item.
*/
function commerce_shipping_update_7003(&$sandbox) {
+ // This should actually never be run on 2.x but is here for reference.
/*
- commerce_shipping_line_item_configuration(array('type' => 'shipping'));
- foreach (commerce_line_item_load_multiple(FALSE, array('type' => 'shipping')) as $line_item) {
- $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
- $line_item_wrapper->commerce_shipping_method = $line_item_wrapper->shipping_method->value();
- $line_item_wrapper->save();
- }
- field_delete_field('shipping_method');
+ commerce_shipping_line_item_configuration(array('type' => 'shipping'));
+ foreach (commerce_line_item_load_multiple(FALSE, array('type' => 'shipping')) as $line_item) {
+ $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
+ $line_item_wrapper->commerce_shipping_method = $line_item_wrapper->shipping_method->value();
+ $line_item_wrapper->save();
+ }
+ field_delete_field('shipping_method');
*/
}
/**
* Install the shipping rate cache table for Shipping 2.x if necessary.
- * This should actually never be run on 2.x but is here for reference.
*/
function commerce_shipping_update_7004($sandbox) {
+ // This should actually never be run on 2.x but is here for reference.
/*
- if (!db_table_exists('cache_commerce_shipping_rates')) {
- $table = drupal_get_schema_unprocessed('system', 'cache');
- $table['description'] = 'Cache table for the temporary storage of base calculated shipping rates for orders.';
- $table['fields']['cid']['description'] = 'Primary Key: Order ID and shipping method the rates are for.';
- db_create_table('cache_commerce_shipping_rates', $table);
- return t('Created shipping rate cache table for Shipping 2.x.');
- }
- return t('Skipped creating the shipping rate cache table; it already exists.');
+ if (!db_table_exists('cache_commerce_shipping_rates')) {
+ $table = drupal_get_schema_unprocessed('system', 'cache');
+ $table['description'] = 'Cache table for the temporary storage of base calculated shipping rates for orders.';
+ $table['fields']['cid']['description'] = 'Primary Key: Order ID and shipping method the rates are for.';
+ db_create_table('cache_commerce_shipping_rates', $table);
+ return t('Created shipping rate cache table for Shipping 2.x.');
+ }
+ return t('Skipped creating the shipping rate cache table; it already exists.');
*/
}
/**
+ * Upgrade from Commerce Shipping 1.x.
+ *
* Upgrade from Commerce Shipping 1.x by renaming the commerce_shipping_method
* field on the shipping line item type to commerce_shipping_service and
* converting price components on shipping line items to the generic Shipping
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.module b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.module
index c6542997..0a6974f0 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.module
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.module
@@ -16,7 +16,6 @@
* an order during the checkout process.
*/
-
/**
* Implements hook_hook_info().
*/
@@ -156,7 +155,7 @@ function commerce_shipping_modules_enabled($modules) {
/**
* Resets default Rules if necessary when modules are enabled or disabled.
*
- * @param $modules
+ * @param array $modules
* An array of module names that have been enabled or disabled.
*/
function _commerce_shipping_default_rules_reset($modules) {
@@ -200,7 +199,7 @@ function commerce_shipping_module_implements_alter(&$implementations, $hook) {
/**
* Returns an array of shipping methods defined by enabled modules.
*
- * @return
+ * @return array
* An associative array of shipping method arrays keyed by the method_id.
*/
function commerce_shipping_methods() {
@@ -248,10 +247,10 @@ function commerce_shipping_methods_reset() {
/**
* Returns a shipping method array.
*
- * @param $name
+ * @param string $name
* The machine-name of the shipping method to return.
*
- * @return
+ * @return array|bool
* The fully loaded shipping method array or FALSE if not found.
*/
function commerce_shipping_method_load($name) {
@@ -262,13 +261,13 @@ function commerce_shipping_method_load($name) {
/**
* Returns the human readable title of any or all shipping methods.
*
- * @param $name
+ * @param string $name
* The machine-name of the shipping method whose title should be returned. If
* left NULL, an array of all titles will be returned.
- * @param $title_type
+ * @param string $title_type
* The type of title to return: 'title' or 'display_title'.
*
- * @return
+ * @return array|string|bool
* Either an array of all shipping method titles keyed by the machine-name or
* a string containing the human readable title for the specified method. If a
* method is specified that does not exist, this function returns FALSE.
@@ -298,9 +297,12 @@ function commerce_shipping_method_get_title($name = NULL, $title_type = 'title')
}
/**
- * Wraps commerce_shipping_method_get_title() for the Entity module and Field API.
+ * Prepares commerce_shipping_method_get_title().
+ *
+ * Wraps commerce_shipping_method_get_title() for the Entity module
+ * and Field API.
*
- * @return
+ * @return array
* An array of shipping method titles keyed by machine-name for use in options
* lists and allowed values lists.
*/
@@ -311,8 +313,11 @@ function commerce_shipping_method_options_list() {
/**
* Returns an array of shipping services keyed by name.
*
- * @param $method
+ * @param string $method
* The machine-name of a shipping method to filter the return value by.
+ *
+ * @return array
+ * Array of shipping services.
*/
function commerce_shipping_services($method = NULL) {
// First check the static cache for a shipping services array.
@@ -344,7 +349,13 @@ function commerce_shipping_services($method = NULL) {
$shipping_service = array_merge($defaults, $shipping_service);
// Merge in default callbacks.
- foreach (array('rate', 'details_form', 'details_form_validate', 'details_form_submit') as $callback) {
+ $callbacks = array(
+ 'rate',
+ 'details_form',
+ 'details_form_validate',
+ 'details_form_submit',
+ );
+ foreach ($callbacks as $callback) {
if (!isset($shipping_service['callbacks'][$callback])) {
$shipping_service['callbacks'][$callback] = $shipping_service['base'] . '_' . $callback;
}
@@ -385,27 +396,27 @@ function commerce_shipping_services_reset() {
/**
* Returns a single shipping service array.
*
- * @param $name
+ * @param string $name
* The machine-name of the shipping service to return.
*
- * @return
+ * @return array|bool
* The specified shipping service array or FALSE if it did not exist.
*/
function commerce_shipping_service_load($name) {
- $shipping_services= commerce_shipping_services();
+ $shipping_services = commerce_shipping_services();
return empty($shipping_services[$name]) ? FALSE : $shipping_services[$name];
}
/**
* Returns the human readable title of any or all shipping services.
*
- * @param $name
+ * @param string $name
* The machine-name of the shipping service whose title should be returned. If
* left NULL, an array of all titles will be returned.
- * @param $title_type
+ * @param string $title_type
* The type of title to return: 'title' or 'display_title'.
*
- * @return
+ * @return array|string|bool
* Either an array of all shipping service titles keyed by the machine-name or
* a string containing the human readable title for the specified service. If
* a service is specified that does not exist, this function returns FALSE.
@@ -443,7 +454,7 @@ function commerce_shipping_service_get_title($name = NULL, $title_type = 'title'
/**
* Wraps commerce_shipping_service_get_title() for the Entity module.
*
- * @return
+ * @return array
* An array of shipping service titles keyed by machine-name as needed for
* options lists.
*/
@@ -451,20 +462,19 @@ function commerce_shipping_service_options_list() {
return commerce_shipping_service_get_title();
}
-
/**
* Returns the specified callback for the given shipping service if one exists.
*
- * @param $shipping_service
+ * @param array $shipping_service
* The shipping service info array.
- * @param $callback
+ * @param string $callback
* The callback function to return, one of:
* - rate
* - details_form
* - details_form_validate
- * - details_form_submit
+ * - details_form_submit.
*
- * @return
+ * @return string|bool
* A string containing the name of the callback function or FALSE if it could
* not be found.
*/
@@ -480,10 +490,12 @@ function commerce_shipping_service_callback($shipping_service, $callback) {
}
/**
- * Collects available shipping rates for an order, adding them to the order
- * object via an unsaved shipping_rates property.
+ * Collects available shipping rates for an order.
+ *
+ * Collect shipping rates for an order, adding them to the order object via
+ * an unsaved shipping_rates property.
*
- * @param $order
+ * @param object $order
* The order for which rates will be collected.
*/
function commerce_shipping_collect_rates($order) {
@@ -497,7 +509,9 @@ function commerce_shipping_collect_rates($order) {
}
/**
- * Sorts shipping rates based on the weight property added to shipping line
+ * Sorts shipping rates.
+ *
+ * Sort shipping rates based on the weight property added to shipping line
* items in an order's data array.
*/
function commerce_shipping_sort_rates($a, $b) {
@@ -517,9 +531,9 @@ function commerce_shipping_sort_rates($a, $b) {
* This function is typically called via the Rules action "Collect rates for a
* shipping method" attached to a default Rule.
*
- * @param $method
+ * @param string $method
* The machine-name of the shipping method whose services should be collected.
- * @param $order
+ * @param object $order
* The order to which the services should be made available.
*/
function commerce_shipping_method_collect_rates($method, $order) {
@@ -528,7 +542,8 @@ function commerce_shipping_method_collect_rates($method, $order) {
// Loop over each shipping service in search of matching components.
foreach (commerce_shipping_services() as $name => $shipping_service) {
- // If the current service matches the method and specifies a default component...
+ // If the current service matches the method and specifies
+ // a default component...
if ($shipping_service['shipping_method'] == $method && $shipping_service['rules_component']) {
$component_name = 'commerce_shipping_service_' . $name;
@@ -548,9 +563,9 @@ function commerce_shipping_method_collect_rates($method, $order) {
/**
* Adds a shipping rate to the given order object for the specified service.
*
- * @param $service
+ * @param string $service
* The machine-name of the shipping service to rate.
- * @param $order
+ * @param object $order
* The order for which the shipping service should be rated.
*/
function commerce_shipping_service_rate_order($service, $order) {
@@ -568,7 +583,8 @@ function commerce_shipping_service_rate_order($service, $order) {
$line_item = commerce_shipping_service_rate_calculate($service, $price, $order->order_id);
$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
- // Add the rate to the order as long as it doesn't have a NULL price amount.
+ // Add the rate to the order as long as it doesn't have
+ // a NULL price amount.
if (!is_null($line_item_wrapper->commerce_unit_price->amount->value())) {
// Include a weight property on the line item object from the shipping
// service for sorting rates.
@@ -580,17 +596,19 @@ function commerce_shipping_service_rate_order($service, $order) {
}
/**
+ * Creates a shipping line item and passes it through Rules.
+ *
* Creates a shipping line item with the specified initial price and passes it
* through Rules for additional calculation.
*
- * @param $service
+ * @param string $service
* The machine-name of the shipping service the rate is for.
- * @param $price
+ * @param array $price
* A price array used to establish the base unit price for the shipping.
- * @param $order
+ * @param int $order_id
* If available, the order to which the shipping line item will belong.
*
- * @return
+ * @return object
* The shipping line item with a calculated shipping rate.
*/
function commerce_shipping_service_rate_calculate($service, $price, $order_id = 0) {
@@ -621,11 +639,11 @@ function commerce_shipping_service_rate_calculate($service, $price, $order_id =
/**
* Turns an array of shipping rates into a form element options array.
*
- * @param $order
+ * @param object $order
* An order object with a shipping_rates property defined as an array of
* shipping rate price arrays keyed by shipping service name.
*
- * @return
+ * @return array
* An options array of calculated shipping rates labeled using the display
* title of the shipping services.
*/
@@ -650,11 +668,11 @@ function commerce_shipping_service_rate_options($order, &$form_state) {
/**
* Caches shipping rates for an order.
*
- * @param $method
+ * @param string $method
* The name of the shipping method the rates are being cached for.
- * @param $order
+ * @param object $order
* The order the rates were calculated for.
- * @param $rates
+ * @param array $rates
* An array of base rate price arrays keyed by shipping service name.
*/
function commerce_shipping_rates_cache_set($method, $order, $rates) {
@@ -664,16 +682,16 @@ function commerce_shipping_rates_cache_set($method, $order, $rates) {
/**
* Retrieves cached shipping rates for an order.
*
- * @param $method
+ * @param string $method
* The name of the shipping method the rates are being cached for.
- * @param $order
+ * @param object $order
* The order the rates were calculated for.
- * @param $timeout
+ * @param int $timeout
* Number of seconds after which cached rates should be considered invalid.
* Defaults to 0, meaning cached rates are only good for the current page
* request.
*
- * @return
+ * @return array|bool
* A cached array of base rate price arrays keyed by shipping service name or
* FALSE if no cache existed or the cache is invalid based on the timeout
* parameter if specified.
@@ -795,6 +813,8 @@ function commerce_shipping_line_item_title($line_item) {
}
/**
+ * Helper function.
+ *
* Returns the elements necessary to add a shipping line item through the line
* item manager widget.
*/
@@ -869,16 +889,16 @@ function commerce_shipping_line_item_add_form($form, &$form_state) {
/**
* Adds the selected shipping information to a new shipping line item.
*
- * @param $line_item
+ * @param object $line_item
* The newly created line item object.
- * @param $element
+ * @param array $element
* The array representing the widget form element.
- * @param $form_state
+ * @param array $form_state
* The present state of the form upon the latest submission.
- * @param $form
+ * @param array $form
* The actual form array.
*
- * @return
+ * @return bool
* NULL if all is well or an error message if something goes wrong.
*/
function commerce_shipping_line_item_add_form_submit($line_item, $element, &$form_state, $form) {
@@ -923,18 +943,18 @@ function commerce_shipping_line_item_add_form_submit($line_item, $element, &$for
/**
* Creates a new shipping line item populated with the proper shipping values.
*
- * @param $service
+ * @param string $service
* The machine-name of the shipping service the line item represents.
- * @param $unit_price
+ * @param array $unit_price
* A price array used to initialize the value of the line item's unit price.
- * @param $order_id
+ * @param int $order_id
* The ID of the order the line item belongs to.
- * @param $data
+ * @param array $data
* An array value to initialize the line item's data array with.
- * @param $type
+ * @param string $type
* The name of the line item type being created; defaults to 'shipping'.
*
- * @return
+ * @return Object
* The shipping line item for the specified service initialized to the given
* unit price.
*/
@@ -965,9 +985,9 @@ function commerce_shipping_line_item_new($service, $unit_price, $order_id = 0, $
/**
* Populates a shipping line item with the specified values.
*
- * @param $service
+ * @param string $service
* The machine-name of the shipping service the line item represents.
- * @param $unit_price
+ * @param array $unit_price
* A price array used to initialize the value of the line item's unit price.
*/
function commerce_shipping_line_item_populate($line_item, $service, $unit_price) {
@@ -987,22 +1007,23 @@ function commerce_shipping_line_item_populate($line_item, $service, $unit_price)
/**
* Deletes all shipping line items on an order.
*
- * @param $order
- * The order object to delete the shipping line items from.
- * @param $skip_save
- * Boolean indicating whether or not to skip saving the order in this function.
+ * @param object $order
+ * The order object to delete the shipping line items from.
+ * @param bool $skip_save
+ * Boolean indicating whether or not to skip saving the order
+ * in this function.
*/
function commerce_shipping_delete_shipping_line_items($order, $skip_save = FALSE) {
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
// When deleting more than one line item, metadata_wrapper will give problems
- // if deleting while looping through the line items. So first remove from order
- // and then delete the line items.
+ // if deleting while looping through the line items. So first remove from
+ // order and then delete the line items.
$line_item_ids = array();
foreach ($order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {
// If this line item is a shipping line item...
- if ($line_item_wrapper->type->value() == 'shipping') {
+ if ($line_item_wrapper->getBundle() == 'shipping') {
// Store its ID for later deletion and remove the reference from the line
// item reference field.
$line_item_ids[] = $line_item_wrapper->line_item_id->value();
@@ -1022,28 +1043,18 @@ function commerce_shipping_delete_shipping_line_items($order, $skip_save = FALSE
}
}
-/**
- * Implements hook_commerce_order_update().
- *
- * When an order is updated, we have no way of knowing if new information on the
- * order demands a recalculation of shipping rates. To be safe, we simply clear
- * the cached rates for an order any time that order is updated.
- */
-function commerce_shipping_commerce_order_update($order) {
- commerce_shipping_rates_cache_clear($order);
-}
-
/**
* Adds a shipping line item to an order.
*
- * @param $line_item
+ * @param object $line_item
* An unsaved shipping line item that should be added to the order.
- * @param $order
+ * @param object $order
* The order to add the shipping line item to.
- * @param $skip_save
- * Boolean indicating whether or not to skip saving the order in this function.
+ * @param bool $skip_save
+ * Boolean indicating whether or not to skip saving the order
+ * in this function.
*
- * @return
+ * @return object|bool
* The saved shipping line item object or FALSE on failure.
*/
function commerce_shipping_add_shipping_line_item($line_item, $order, $skip_save = FALSE) {
@@ -1083,7 +1094,16 @@ function commerce_shipping_form_commerce_checkout_form_alter(&$form, &$form_stat
if (commerce_shipping_recalculate_services($form)) {
// Build an array to limit validation errors to customer profile data and
// the currently selected shipping service.
- $limit_validation = array(array('commerce_shipping', 'shipping_service'), array('commerce_shipping', 'service_details'));
+ $limit_validation = array(
+ array(
+ 'commerce_shipping',
+ 'shipping_service',
+ ),
+ array(
+ 'commerce_shipping',
+ 'service_details',
+ ),
+ );
foreach (commerce_customer_profile_types() as $type => $profile_type) {
$limit_validation[] = array('customer_profile_' . $type);
@@ -1133,6 +1153,8 @@ function commerce_shipping_commerce_customer_profile_copy_refresh_alter(&$comman
}
/**
+ * Validates shipping service recalculations.
+ *
* Determines whether or not automatic shipping service recalculation is valid
* for the given form.
*/
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.rules.inc b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.rules.inc
index 83c20248..5782f451 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.rules.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.rules.inc
@@ -5,6 +5,7 @@
* Rules integration for shipping.
*
* @addtogroup rules
+ *
* @{
*/
@@ -27,7 +28,8 @@ function commerce_shipping_rules_event_info() {
'access callback' => 'commerce_order_rules_access',
);
- // Include the Line Item module's Rules integration to reuse its access callback.
+ // Include the Line Item module's Rules integration to reuse
+ // its access callback.
module_load_include('inc', 'commerce_line_item', 'commerce_line_item.rules');
$events['commerce_shipping_calculate_rate'] = array(
@@ -88,9 +90,9 @@ function commerce_shipping_service_rules_options_list() {
/**
* Checks an order for the existence of a shipping line item.
*
- * @param $order
+ * @param object $order
* The order to check for a shipping line item.
- * @param $service
+ * @param string $service
* The machine-name of a particular shipping service to search for; if '-any-'
* the condition returns TRUE for any found shipping line item.
*/
@@ -204,7 +206,6 @@ function commerce_shipping_rate_apply($order, $service_name = NULL) {
$service_name = key($order->shipping_rates);
}
-
// Delete any existing shipping line items from the order.
commerce_shipping_delete_shipping_line_items($order, TRUE);
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.rules_defaults.inc b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.rules_defaults.inc
index 1f23a830..3cf64e2a 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.rules_defaults.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping.rules_defaults.inc
@@ -5,17 +5,16 @@
* Default rules configurations for Shipping.
*/
-
/**
* Implements hook_default_rules_configuration().
*/
function commerce_shipping_default_rules_configuration() {
$rules = array();
- // When an order's status is updating to "Shopping cart" from any other status,
- // its shipping line items will be deleted. This captures any cart contents
- // change via Add to Cart forms / the Shopping cart Views form. It also happens
- // when the customer cancels out of the checkout form.
+ // When an order's status is updating to "Shopping cart" from any other
+ // status, its shipping line items will be deleted. This captures any
+ // cart contents change via Add to Cart forms / the Shopping cart Views form.
+ // It also happens when the customer cancels out of the checkout form.
$rule = rules_reaction_rule();
$rule->label = t('Delete shipping line items on shopping cart updates');
@@ -73,9 +72,9 @@ function commerce_shipping_default_rules_configuration() {
$rule
->event('commerce_shipping_collect_rates')
->action('commerce_shipping_method_collect_rates', array(
- 'shipping_method_name' => $name,
- 'commerce_order:select' => 'commerce-order',
- ));
+ 'shipping_method_name' => $name,
+ 'commerce_order:select' => 'commerce-order',
+ ));
$rules['commerce_shipping_method_' . $name] = $rule;
}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping_ui.info b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping_ui.info
index c90c6453..db0d7bf8 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping_ui.info
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping_ui.info
@@ -7,9 +7,9 @@ dependencies[] = commerce_shipping
core = 7.x
configure = admin/commerce/config/shipping
-; Information added by Drupal.org packaging script on 2015-04-08
-version = "7.x-2.2"
+; Information added by Drupal.org packaging script on 2017-11-28
+version = "7.x-2.3"
core = "7.x"
project = "commerce_shipping"
-datestamp = "1428479882"
+datestamp = "1511853188"
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping_ui.module b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping_ui.module
index c6f0a21b..87ae7c84 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping_ui.module
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/commerce_shipping_ui.module
@@ -212,7 +212,6 @@ function commerce_shipping_ui_help($path, $arg) {
}
}
-
/**
* Implements hook_menu_local_tasks_alter().
*/
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/includes/commerce_shipping.checkout_pane.inc b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/includes/commerce_shipping.checkout_pane.inc
index fed4752b..0b97407f 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/includes/commerce_shipping.checkout_pane.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/includes/commerce_shipping.checkout_pane.inc
@@ -5,7 +5,6 @@
* Callback functions for the shipping module's checkout panes.
*/
-
/**
* Checkout pane callback: returns the shipping service pane's settings form.
*/
@@ -141,7 +140,8 @@ function commerce_shipping_pane_checkout_form($form, &$form_state, $checkout_pan
$message = t('No valid shipping rates found for your order, and we require shipping service selection to complete checkout.') . ' ' . t('Please verify you have supplied all required information or contact us to resolve the issue.') . '';
}
else {
- // If live shipping rate recalculation is required, check if we can show shipping options.
+ // If live shipping rate recalculation is required, check if we can show
+ // shipping options.
if (commerce_shipping_recalculate_services($form, NULL, TRUE) && empty($form_state['recalculate'])) {
$message = t('Please supply all of the required information requested above to reveal your shipping options.');
}
@@ -160,7 +160,9 @@ function commerce_shipping_pane_checkout_form($form, &$form_state, $checkout_pan
}
/**
- * Ajax callback: Returns the shipping details form elements that match the
+ * Ajax callback.
+ *
+ * Returns the shipping details form elements that match the
* currently selected shipping service.
*/
function commerce_shipping_pane_service_details_refresh($form, $form_state) {
@@ -178,20 +180,6 @@ function commerce_shipping_recalculate_services_refresh($form, $form_state) {
* Validate callback for recalculating shipping services.
*/
function commerce_shipping_recalculate_services_validate($form, &$form_state) {
-
- // Load latest version of the order.
- $order = commerce_order_load($form_state['order']->order_id);
- // Check if the order is still on the same checkout step.
- $checkout_page = $form_state['checkout_page'];
- if ($form_state['order']->changed < $order->changed || !commerce_checkout_page_access($checkout_page, $order)) {
- // Clear all errors.
- form_clear_error();
- watchdog('access denied', check_plain($_GET['q']), NULL, WATCHDOG_WARNING);
- drupal_set_message(t('You are not authorized to access this command.'), 'error');
- $form_state['rebuild'] = TRUE;
- return FALSE;
- }
-
// Call all validation callbacks.
$recalculate = commerce_shipping_recalculate_services($form, $form_state);
@@ -210,7 +198,8 @@ function commerce_shipping_recalculate_services_validate($form, &$form_state) {
$form_state['rebuild'] = TRUE;
}
- // Store the validation result so that it can be examined in the submit handler.
+ // Store the validation result so that it can be examined
+ // in the submit handler.
$form_state['recalculate'] = $recalculate;
return TRUE;
@@ -261,8 +250,8 @@ function commerce_shipping_recalculate_services_submit($form, &$form_state) {
$profile = $wrapper->{$source_field_name}->value();
}
elseif (!empty($form_state['order']->data['profiles'][$source_id])) {
- // Otherwise fallback to the customer profile referenced in the order
- // data array.
+ // Otherwise fallback to the customer profile referenced
+ // in the order data array.
$profile = commerce_customer_profile_load($form_state['order']->data['profiles'][$source_id]);
}
@@ -275,9 +264,14 @@ function commerce_shipping_recalculate_services_submit($form, &$form_state) {
}
// Unset any cached addressfield data for this customer profile.
- foreach ($form_state['addressfield'] as $key => $value) {
- if (strpos($key, 'commerce_customer_profile|' . $type) === 0) {
- unset($form_state['addressfield'][$key]);
+ foreach (field_read_fields(array('type' => 'addressfield')) as $field) {
+ if (isset($form_state['input']['customer_profile_' . $type][$field['field_name']])) {
+ foreach ($form_state['input']['customer_profile_' . $type][$field['field_name']][LANGUAGE_NONE][0] as $key => &$value) {
+ if ($key == 'country') {
+ continue;
+ }
+ $value = '';
+ }
}
}
}
@@ -298,10 +292,12 @@ function commerce_shipping_recalculate_services_submit($form, &$form_state) {
// Save the order and rebuild the form to reflect the updated customer data.
if ($rebuild) {
// Avoid overwriting an already updated order.
- $stored_order = commerce_order_load($order->order_id);
+ $stored_order = entity_load_unchanged('commerce_order', $order->order_id);
+
if ($stored_order->changed <= $order->changed) {
commerce_order_save($order);
}
+
$form_state['rebuild'] = TRUE;
}
}
@@ -342,9 +338,9 @@ function commerce_shipping_pane_checkout_form_validate($form, &$form_state, $che
if ($callback = commerce_shipping_service_callback($shipping_service, 'details_form_validate')) {
$result = $callback($pane_form['service_details'], $pane_values['service_details'], $shipping_service, $order, array($checkout_pane['pane_id'], 'service_details'));
- // To prevent payment method validation routines from having to return TRUE
- // explicitly, only return FALSE if it was specifically returned. Otherwise
- // default to TRUE.
+ // To prevent payment method validation routines from having to return
+ // TRUE explicitly, only return FALSE if it was specifically returned.
+ // Otherwise default to TRUE.
return $result === FALSE ? FALSE : TRUE;
}
}
@@ -406,7 +402,9 @@ function commerce_shipping_pane_checkout_form_submit($form, &$form_state, $check
}
/**
- * Checkout pane callback: show the selected shipping service on the review pane.
+ * Checkout pane callback.
+ *
+ * Show the selected shipping service on the review pane.
*/
function commerce_shipping_pane_review($form, $form_state, $checkout_pane, $order) {
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/includes/commerce_shipping_ui.admin.inc b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/includes/commerce_shipping_ui.admin.inc
index 1f2d705f..80450e97 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/includes/commerce_shipping_ui.admin.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/includes/commerce_shipping_ui.admin.inc
@@ -57,7 +57,7 @@ function commerce_shipping_ui_overview($type, $method = NULL) {
array(
'data' => $empty_text,
'colspan' => 2,
- )
+ ),
);
}
@@ -67,7 +67,7 @@ function commerce_shipping_ui_overview($type, $method = NULL) {
/**
* Builds an overview of a shipping method for display to an administrator.
*
- * @param $variables
+ * @param array $variables
* An array of variables used to generate the display; by default includes the
* shipping_method key with a value of the shipping method info array.
*
@@ -87,7 +87,7 @@ function theme_shipping_method_admin_overview($variables) {
/**
* Builds an overview of a shipping service for display to an administrator.
*
- * @param $variables
+ * @param array $variables
* An array of variables used to generate the display; by default includes the
* shipping_service key with a value of the shipping service info array.
*
@@ -112,7 +112,11 @@ function commerce_shipping_ui_rate_calculation_rules() {
$content['enabled']['title']['#markup'] = '
';
- $conditions = array('event' => 'commerce_shipping_calculate_rate', 'plugin' => 'reaction rule', 'active' => TRUE);
+ $conditions = array(
+ 'event' => 'commerce_shipping_calculate_rate',
+ 'plugin' => 'reaction rule',
+ 'active' => TRUE,
+ );
$content['enabled']['rules'] = RulesPluginUI::overviewTable($conditions, $options);
$content['enabled']['rules']['#empty'] = t('There are no active shipping rate calculation rules.');
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/includes/views/commerce_shipping.views.inc b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/includes/views/commerce_shipping.views.inc
index 2205dfaf..eeda8393 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/includes/views/commerce_shipping.views.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/includes/views/commerce_shipping.views.inc
@@ -5,9 +5,8 @@
* Defines Views integration for Commerce Shipping.
*/
-
/**
- * Implements hook_views_data_alter()
+ * Implements hook_views_data_alter().
*/
function commerce_shipping_views_data_alter(&$data) {
// Add a relationship to the order table to join to a representative shipping
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/includes/views/handlers/commerce_shipping_handler_relationship_shipping_line_item_representative.inc b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/includes/views/handlers/commerce_shipping_handler_relationship_shipping_line_item_representative.inc
index 3e4c979e..c5b1f6a8 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/includes/views/handlers/commerce_shipping_handler_relationship_shipping_line_item_representative.inc
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/includes/views/handlers/commerce_shipping_handler_relationship_shipping_line_item_representative.inc
@@ -6,14 +6,15 @@
*/
class commerce_shipping_handler_relationship_shipping_line_item_representative extends views_handler_relationship {
- function label() {
+
+ public function label() {
if (!isset($this->options['label'])) {
return $this->ui_name();
}
return $this->options['label'];
}
- function query() {
+ public function query() {
// Get the JOIN type from the relationship settings.
$join_type = empty($this->options['required']) ? 'LEFT' : 'INNER';
@@ -40,4 +41,5 @@ class commerce_shipping_handler_relationship_shipping_line_item_representative e
$alias = 'commerce_order_shipping_line_item_representiative';
$this->alias = $this->query->add_relationship($alias, $join, 'commerce_line_item', $this->relationship);
}
+
}
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/modules/commerce_shipping_example.info b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/modules/commerce_shipping_example.info
index 16cc4590..39927ff5 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/modules/commerce_shipping_example.info
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/modules/commerce_shipping_example.info
@@ -5,9 +5,9 @@ dependencies[] = commerce
dependencies[] = commerce_shipping
core = 7.x
-; Information added by Drupal.org packaging script on 2015-04-08
-version = "7.x-2.2"
+; Information added by Drupal.org packaging script on 2017-11-28
+version = "7.x-2.3"
core = "7.x"
project = "commerce_shipping"
-datestamp = "1428479882"
+datestamp = "1511853188"
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/modules/commerce_shipping_example.module b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/modules/commerce_shipping_example.module
index 0c75e74a..dcfa75a6 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_shipping/modules/commerce_shipping_example.module
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_shipping/modules/commerce_shipping_example.module
@@ -5,7 +5,6 @@
* Defines an example shipping method for testing and development.
*/
-
/**
* Implements hook_commerce_shipping_method_info().
*/
@@ -44,7 +43,9 @@ function commerce_shipping_example_commerce_shipping_service_info() {
}
/**
- * Shipping service callback: returns a base price array for a shipping service
+ * Shipping service callback.
+ *
+ * Returns a base price array for a shipping service
* calculated for the given order.
*/
function commerce_shipping_example_service_rate($shipping_service, $order) {
@@ -100,7 +101,9 @@ function commerce_shipping_example_service_details_form_validate($details_form,
}
/**
- * Shipping service callback: increases the shipping line item's unit price if
+ * Shipping service callback.
+ *
+ * Increases the shipping line item's unit price if
* express delivery was selected.
*/
function commerce_shipping_example_service_details_form_submit($details_form, $details_values, $line_item) {
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_yotpo/LICENSE.txt b/profiles/commerce_kickstart/modules/contrib/commerce_yotpo/LICENSE.txt
new file mode 100644
index 00000000..d159169d
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_yotpo/LICENSE.txt
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ , 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_yotpo/commerce_yotpo.info b/profiles/commerce_kickstart/modules/contrib/commerce_yotpo/commerce_yotpo.info
index 4561a201..be10e063 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_yotpo/commerce_yotpo.info
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_yotpo/commerce_yotpo.info
@@ -9,10 +9,9 @@ dependencies[] = commerce
dependencies[] = commerce_order
dependencies[] = commerce_product
-
-; Information added by drush on 2015-08-20
-version = "7.x-1.1+9-dev"
+; Information added by Drupal.org packaging script on 2015-05-07
+version = "7.x-1.2"
core = "7.x"
project = "commerce_yotpo"
-datestamp = "1440110603"
+datestamp = "1431015501"
diff --git a/profiles/commerce_kickstart/modules/contrib/commerce_yotpo/commerce_yotpo.module b/profiles/commerce_kickstart/modules/contrib/commerce_yotpo/commerce_yotpo.module
index baee1431..bfa71233 100644
--- a/profiles/commerce_kickstart/modules/contrib/commerce_yotpo/commerce_yotpo.module
+++ b/profiles/commerce_kickstart/modules/contrib/commerce_yotpo/commerce_yotpo.module
@@ -265,6 +265,10 @@ function commerce_yotpo_create_purchase($commerce_order) {
$data['products'] = $products;
$response = $yotpo->create_purchase($data);
+ if (!isset($response->code) || $response->code != 200) {
+ $code = isset($response->code) ? $response->code : 'NULL';
+ watchdog('commerce_yotpo', 'Unexpected response code: @code', array('@code' => $code));
+ }
}
else {
watchdog('commerce_yotpo', 'Could not load Yotpo library');
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/CHANGELOG.txt b/profiles/commerce_kickstart/modules/contrib/ctools/CHANGELOG.txt
deleted file mode 100644
index c5bd5e6d..00000000
--- a/profiles/commerce_kickstart/modules/contrib/ctools/CHANGELOG.txt
+++ /dev/null
@@ -1,82 +0,0 @@
-Current API VERSION: 2.0. See API.txt for more information.
-
-ctools 7.x-1.x-dev
-==================
-#1008120: "New custom content" shows empty form if custom content panes module is not enabled.
-#999302 by troky: Fix jump menu. Apparently this wasn't actually committed the last time it was committed.
-#1065976 by tekante and David_Rothstein: Reset plugin static cache during module enable to prevent stale data from harming export ui.
-#1016510 by EclipseGC: Make the taxonomy system page functional.
-
-ctools 7.x-1.x-alpha2 (05-Jan-2011)
-===================================
-
-#911396 by alex_b: Prevent notices in export UI.
-#919768 by mikey_p: Allow url options to be sent to ctools_ajax_command_url().
-#358953 by cedarm: Allow term context to return lowercase, spaces to dashes versions of terms.
-#931434 by EclipseGc: Argument plugin for node revision ID.
-#910656: CTools AJAX sample wizard demo "domesticated" checkbox value not stored.
-#922442 by EugenMayer, neclimdul and voxpelli: Make sure ctools_include can handle '' or NULL directory.
-#919956 by traviss359: Correct example in wizard advanced help.
-#942968: Fix taxonomy term access rule with tag term vocabs.
-#840344: node add argument had crufty code causing notices.
-#944462 by longhairedgit: Invalid character in regex causes rare notice.
-#938778 by dereine: Fix profile content type for D7 updates.
-Add detach event to modal close so that wysiwyg can detach the editor.
-Variant titles showing up as blank if more than one variant on a page.
-#940016: token support was not yet updated for D7.
-#940446: Skip validation on back and cancel buttons in all wizards.
-#954492: Redirect not always working in wizard.inc
-#955348: Lack of redirect on "Update" button in Page Manager causing data loss sometimes.
-#941778: Update and save button should not appear in the "Add variant" path.
-#955070 by EclipseGc: Update ctools internal page tokens to work properly on content all content.
-#956890 by EclipseGc: Update views_content to not use views dependency since that is gone.
-#954728 by EclipseGc: Update node template page function name to not collide with new hook_node_view().
-#946534 by EclipseGc: Add support for field content on all entitities.
-#952586 by EclipseGc: Fix node_author content type.
-#959206: If a context is not set when rendering content, attempt to guess the context (fixes Views panes where "From context" was added but pane was never edited.)
-#961654 by benshell: drupal_alter() only supports 4 arguments.
-#911362 by alex_b: Facilitate plugin cache resets for tests.
-#945360 by naxoc: node_tag_new() not updated to D7.
-#953804 by EclipseGc: Fix node comment rendering.
-#953542 by EclipseGc: Fix node rendering.
-#953776 by EclipseGc: Fix node link rendering.
-#954772 by EclipseGc: Fix node build mode selection in node content type.
-#954762 by EclipseGc: Fix comment forbidden theme call.
-#954894 by EclipseGc: Fix breadcrumb content type.
-#955180 by EclipseGc: Fix page primary navigation type.
-#957190 by EclipseGc: Fix page secondary navigation type.
-#957194 by EclipseGc: Remove mission content type, since D7 no longer has a site mission.
-#957348 by EclipseGc: Fix search form URL path.
-#952586 by andypost: Use format_username for displaying unlinked usernames.
-#963800 by benshell: Fix query to fetch custom block title.
-#983496 by Amitaibu: Fix term argument to use proper load function.
-#989484 by Amitaibu: Fix notice in views plugin.
-#982496: Fix token context.
-#995026: Fix export UI during enable/disable which would throw notices and not properly set/unset menu items.
-#998870 by Amitaibu: Fix notice when content has no icon by using function already designed for that.
-#983576 by Amitaibu: Node view fallback task showed white screen.
-#1004644 by pillarsdotnet: Update a missed theme() call to D7.
-#1006162 by aspilicious: .info file cleanup.
-#998312 by dereine: Support the expanded/hidden options that Views did for dependent.js
-#955030: Remove no longer supported footer message content type.
-Fix broken query in term context config.
-#992022 by pcambra: Fix node autocomplete.
-#946302 by BerdArt and arywyr: Fix PHP 5.3 reference error.
-#980528 by das-peter: Notice fix with entity settings.
-#999302 by troky: ctools_jump_menu() needed updating to new form parameters.
-#964174: stylizer plugin theme delegation was in the wrong place, causing errors.
-#991658 by burlap: Fully load the "user" context for the logged in user because not all fields are in $user.
-#1014866 by das-peter: Smarter title panes, notice fix on access plugin descriptions.
-#1015662 by troky: plugin .info files were not using correct filepaths.
-#941780 by EclipseGc: Restore the "No blocks" functionality.
-#951048 by EclipseGc: Tighter entity integration so that new entities are automatic contexts and relationships.
-#941800 by me and aspilicious: Use Drupal 7 #machine_name automation on page manager pages and all export_ui defaults.
-Disabled exportables and pages not properly greyed out.
-#969208 by me and benshell: Get user_view and user profile working.
-#941796: Recategorize blocks
-
-ctools 7.x-1.x-alpha1
-=====================
-
-Changelog reset for 7.x
-Basic conversion done during sprint.
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/bulk_export/bulk_export.info b/profiles/commerce_kickstart/modules/contrib/ctools/bulk_export/bulk_export.info
index dd9f3e91..59bbd18a 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/bulk_export/bulk_export.info
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/bulk_export/bulk_export.info
@@ -5,10 +5,9 @@ dependencies[] = ctools
package = Chaos tool suite
version = CTOOLS_MODULE_VERSION
-
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.x-1.9"
+; Information added by Drupal.org packaging script on 2018-02-04
+version = "7.x-1.13"
core = "7.x"
project = "ctools"
-datestamp = "1440020680"
+datestamp = "1517704095"
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/bulk_export/bulk_export.module b/profiles/commerce_kickstart/modules/contrib/ctools/bulk_export/bulk_export.module
index afb15b9e..1050caa6 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/bulk_export/bulk_export.module
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/bulk_export/bulk_export.module
@@ -137,7 +137,7 @@ function bulk_export_export($cli = FALSE, $options = array()) {
// Add hook_ctools_plugin_api at the top of the module code, if there is any.
if ($api_code) {
foreach ($api_code as $api_hook => $text) {
- $api = "\n/**\n";
+ $api = "\n/**\n";
$api .= " * Implements hook_$api_hook().\n";
$api .= " */\n";
$api .= "function {$module_name}_$api_hook(\$module, \$api) {\n";
@@ -148,7 +148,7 @@ function bulk_export_export($cli = FALSE, $options = array()) {
}
if ($module_code) {
- $module = "conf['css_id'] = 'my-id';
+}
+
/**
* @} End of "addtogroup hooks".
*/
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools.info b/profiles/commerce_kickstart/modules/contrib/ctools/ctools.info
index 02c86f52..7c8d5f41 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools.info
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools.info
@@ -2,16 +2,32 @@ name = Chaos tools
description = A library of helpful tools by Merlin of Chaos.
core = 7.x
package = Chaos tool suite
-version = CTOOLS_MODULE_VERSION
files[] = includes/context.inc
files[] = includes/css-cache.inc
files[] = includes/math-expr.inc
files[] = includes/stylizer.inc
+
+; Tests.
+files[] = tests/context.test
+files[] = tests/css.test
files[] = tests/css_cache.test
+files[] = tests/ctools.plugins.test
+files[] = tests/ctools.test
+files[] = tests/math_expression.test
+files[] = tests/math_expression_stack.test
+files[] = tests/object_cache.test
+files[] = tests/object_cache_unit.test
+files[] = tests/page_tokens.test
+files[] = tests/uuid_with_uuid.test
+files[] = tests/uuid_without_uuid.test
+
+; Dependencies that are only used for the tests.
+; @see tests/uuid_with_uuid.test
+test_dependencies[] = uuid
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.x-1.9"
+; Information added by Drupal.org packaging script on 2018-02-04
+version = "7.x-1.13"
core = "7.x"
project = "ctools"
-datestamp = "1440020680"
+datestamp = "1517704095"
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools.install b/profiles/commerce_kickstart/modules/contrib/ctools/ctools.install
index e96c7432..47f01fb7 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools.install
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools.install
@@ -40,7 +40,19 @@ function ctools_requirements($phase) {
* Implements hook_schema().
*/
function ctools_schema() {
- return ctools_schema_3();
+ return ctools_schema_4();
+}
+
+/**
+ * Version 4 of the CTools schema.
+ */
+function ctools_schema_4() {
+ $schema = ctools_schema_3();
+
+ // Update the 'name' field to be 255 bytes long:
+ $schema['ctools_object_cache']['fields']['name']['length'] = 255;
+
+ return $schema;
}
/**
@@ -49,7 +61,7 @@ function ctools_schema() {
function ctools_schema_3() {
$schema = ctools_schema_2();
- // update the 'obj' field to be 128 bytes long:
+ // Update the 'obj' field to be 128 bytes long:
$schema['ctools_object_cache']['fields']['obj']['length'] = 128;
return $schema;
@@ -61,7 +73,7 @@ function ctools_schema_3() {
function ctools_schema_2() {
$schema = ctools_schema_1();
- // update the 'name' field to be 128 bytes long:
+ // Update the 'name' field to be 128 bytes long:
$schema['ctools_object_cache']['fields']['name']['length'] = 128;
// Update the 'data' field to be type 'blob'.
@@ -95,10 +107,10 @@ function ctools_schema_2() {
'serialize' => TRUE,
),
'filter' => array(
- 'type' => 'int',
- 'size' => 'tiny',
- 'description' => 'Whether or not this CSS needs to be filtered.',
- ),
+ 'type' => 'int',
+ 'size' => 'tiny',
+ 'description' => 'Whether or not this CSS needs to be filtered.',
+ ),
),
'primary key' => array('cid'),
);
@@ -197,7 +209,7 @@ function ctools_update_6003() {
if ($result) {
db_delete('system')->condition('name', 'panels_views')->execute();
module_enable(array('views_content'), TRUE);
- }
+ }
}
/**
@@ -216,7 +228,7 @@ function ctools_update_6005() {
}
/**
- * ctools_custom_content table was originally here, but is now moved to
+ * The ctools_custom_content table was originally here, but is now moved to
* its own module.
*/
function ctools_update_6007() {
@@ -230,18 +242,18 @@ function ctools_update_6007() {
}
/**
- * ctools_object_cache needs to be defined as a blob.
+ * The ctools_object_cache needs to be defined as a blob.
*/
function ctools_update_6008() {
db_delete('ctools_object_cache')
->execute();
db_change_field('ctools_object_cache', 'data', 'data', array(
- 'type' => 'blob',
- 'size' => 'big',
- 'description' => 'Serialized data being stored.',
- 'serialize' => TRUE,
- )
+ 'type' => 'blob',
+ 'size' => 'big',
+ 'description' => 'Serialized data being stored.',
+ 'serialize' => TRUE,
+ )
);
}
@@ -263,3 +275,14 @@ function ctools_update_7001() {
'description' => 'The type of the object this cache is attached to; this essentially represents the owner so that several sub-systems can use this cache.',
));
}
+
+/**
+ * Increase the length of the ctools_object_cache.name column to 255.
+ */
+function ctools_update_7002() {
+ db_change_field('ctools_object_cache', 'name', 'name', array(
+ 'type' => 'varchar',
+ 'length' => '255',
+ 'not null' => TRUE,
+ ));
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools.module b/profiles/commerce_kickstart/modules/contrib/ctools/ctools.module
index 008214e2..3a805808 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools.module
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools.module
@@ -9,7 +9,7 @@
* must be implemented in the module file.
*/
-define('CTOOLS_API_VERSION', '2.0.8');
+define('CTOOLS_API_VERSION', '2.0.9');
/**
* The current working ctools version.
@@ -23,7 +23,7 @@ define('CTOOLS_API_VERSION', '2.0.8');
* ; Requires CTools v7.x-1.4 or newer.
* dependencies[] = ctools (>=1.4)
*/
-define('CTOOLS_MODULE_VERSION', '7.x-1.9');
+define('CTOOLS_MODULE_VERSION', '7.x-1.13');
/**
* Test the CTools API version.
@@ -75,6 +75,9 @@ define('CTOOLS_MODULE_VERSION', '7.x-1.9');
* The minimum version of CTools necessary for your software to run with it.
* @param $maximum
* The maximum version of CTools allowed for your software to run with it.
+ *
+ * @return bool
+ * TRUE if the running ctools is usable, FALSE otherwise.
*/
function ctools_api_version($minimum, $maximum = NULL) {
if (version_compare(CTOOLS_API_VERSION, $minimum, '<')) {
@@ -89,8 +92,7 @@ function ctools_api_version($minimum, $maximum = NULL) {
}
// -----------------------------------------------------------------------
-// General utility functions
-
+// General utility functions.
/**
* Include .inc files as necessary.
*
@@ -118,6 +120,7 @@ function ctools_api_version($minimum, $maximum = NULL) {
* @param $dir
* Optional subdirectory containing the include file.
*/
+
function ctools_include($file, $module = 'ctools', $dir = 'includes') {
static $used = array();
@@ -147,8 +150,8 @@ function ctools_form_include(&$form_state, $file, $module = 'ctools', $dir = 'in
/**
* Add an arbitrary path to the $form_state so it can work with form cache.
*
- * module_load_include uses an unfortunately annoying syntax to work, making it
- * difficult to translate the more simple $path + $file syntax.
+ * The module_load_include() function uses an unfortunately annoying syntax to
+ * work, making it difficult to translate the more simple $path + $file syntax.
*/
function ctools_form_include_file(&$form_state, $filename) {
if (!isset($form_state['build_info']['args'])) {
@@ -172,6 +175,9 @@ function ctools_form_include_file(&$form_state, $filename) {
* Optional module containing the include.
* @param $dir
* Optional subdirectory containing the include file.
+ *
+ * @return string
+ * A string containing the appropriate path from drupal root.
*/
function ctools_image_path($image, $module = 'ctools', $dir = 'images') {
return drupal_get_path('module', $module) . "/$dir/" . $image;
@@ -211,6 +217,9 @@ function ctools_add_css($file, $module = 'ctools', $dir = 'css') {
* Optional module containing the include.
* @param $dir
* Optional subdirectory containing the include file.
+ *
+ * @return string
+ * A string containing the appropriate path from drupal root.
*/
function ctools_attach_css($file, $module = 'ctools', $dir = 'css') {
return drupal_get_path('module', $module) . "/$dir/$file.css";
@@ -249,6 +258,9 @@ function ctools_add_js($file, $module = 'ctools', $dir = 'js') {
* Optional module containing the include.
* @param $dir
* Optional subdirectory containing the include file.
+ *
+ * @return string
+ * A string containing the appropriate path from drupal root.
*/
function ctools_attach_js($file, $module = 'ctools', $dir = 'js') {
return drupal_get_path('module', $module) . "/$dir/$file.js";
@@ -267,16 +279,29 @@ function ctools_get_roles() {
return user_roles();
}
-/*
- * Break x,y,z and x+y+z into an array. Numeric only.
+/**
+ * Parse integer sequences of the form "x,y,z" or "x+y+z" into separate values.
+ *
+ * A string with integers separated by comma (,) is reported as an 'and' set;
+ * separation by a plus sign (+) or a space ( ) is an 'or' set. The meaning
+ * of this is up to the caller. Negative or fractional numbers are not
+ * recognised.
+ *
+ * Additional space characters within or around the sequence are not allowed.
*
* @param $str
* The string to parse.
*
- * @return $object
- * An object containing
- * - operator: Either 'and' or 'or'
- * - value: An array of numeric values.
+ * @return object
+ * An object containing the properties:
+ *
+ * - operator: Either 'and' or 'or' when there are multiple matched values.
+ * Absent when invalid_input is TRUE or there is only one value.
+ * - value: An array of integers (never strings) from $str. An empty array is
+ * returned if the input is empty. A single integer input is returned
+ * as a single value, but no 'operator' is defined.
+ * - invalid_input: TRUE if input could not be parsed and the values array
+ * will contain just -1. This property is otherwise absent.
*/
function ctools_break_phrase($str) {
$object = new stdClass();
@@ -286,7 +311,7 @@ function ctools_break_phrase($str) {
$object->operator = 'or';
$object->value = preg_split('/[+ ]/', $str);
}
- else if (preg_match('/^([0-9]+,)*[0-9]+$/', $str)) {
+ elseif (preg_match('/^([0-9]+,)*[0-9]+$/', $str)) {
$object->operator = 'and';
$object->value = explode(',', $str);
}
@@ -304,7 +329,7 @@ function ctools_break_phrase($str) {
// Doubly ensure that all values are numeric only.
foreach ($object->value as $id => $value) {
- $object->value[$id] = intval($value);
+ $object->value[$id] = (int) $value;
}
return $object;
@@ -314,23 +339,29 @@ function ctools_break_phrase($str) {
* Set a token/value pair to be replaced later in the request, specifically in
* ctools_page_token_processing().
*
- * @param $token
+ * @param string $token
* The token to be replaced later, during page rendering. This should
- * ideally be a string inside of an HTML comment, so that if there is
- * no replacement, the token will not render on the page.
- * @param $type
+ * ideally be a string inside of an HTML comment, so that if there is
+ * no replacement, the token will not render on the page.
+ * If $token is NULL, the token set is not changed, but is still
+ * returned.
+ * @param string $type
* The type of the token. Can be either 'variable', which will pull data
- * directly from the page variables
- * @param $argument
- * If $type == 'variable' then argument should be the key to fetch from
- * the $variables. If $type == 'callback' then it should either be the
- * callback, or an array that will be sent to call_user_func_array().
- *
- * @return
+ * directly from the page variables, or 'callback', which causes a function
+ * to be called to calculate the value. No other values are supported.
+ * @param string|array $argument
+ * For $type of:
+ * - 'variable': argument should be the key to fetch from the $variables.
+ * - 'callback': then it should either be the callback function name as a
+ * string, or an array that will be sent to call_user_func_array(). Argument
+ * arrays must not use array keys (i.e. $a[0] is the first and $a[1] the
+ * second element, etc.)
+ *
+ * @return array
* A array of token/variable names to be replaced.
*/
function ctools_set_page_token($token = NULL, $type = NULL, $argument = NULL) {
- static $tokens = array();
+ $tokens = &drupal_static('ctools_set_page_token', array());
if (isset($token)) {
$tokens[$token] = array($type, $argument);
@@ -339,13 +370,32 @@ function ctools_set_page_token($token = NULL, $type = NULL, $argument = NULL) {
}
/**
- * Easily set a token from the page variables.
+ * Reset the defined page tokens within this request.
+ *
+ * Introduced for simpletest purposes. Normally not needed.
+ */
+function ctools_reset_page_tokens() {
+ drupal_static_reset('ctools_set_page_token');
+}
+
+/**
+ * Set a replacement token from the containing element's children during #post_render.
*
* This function can be used like this:
- * $token = ctools_set_variable_token('tabs');
+ * $token = ctools_set_variable_token('tabs');
+ *
+ * The token "" would then be replaced by the value of
+ * this element's (sibling) render array key 'tabs' during post-render (or be
+ * deleted if there was no such key by that point).
+ *
+ * @param string $token
+ * The token string for the page callback, e.g. 'title'.
+ *
+ * @return string
+ * The constructed token.
*
- * $token will then be a simple replacement for the 'tabs' about of the
- * variables available in the page template.
+ * @see ctools_set_callback_token()
+ * @see ctools_page_token_processing()
*/
function ctools_set_variable_token($token) {
$string = '';
@@ -354,10 +404,45 @@ function ctools_set_variable_token($token) {
}
/**
- * Easily set a token from the page variables.
+ * Set a replacement token from the value of a function during #post_render.
*
* This function can be used like this:
- * $token = ctools_set_variable_token('id', 'mymodule_myfunction');
+ * $token = ctools_set_callback_token('id', 'mymodule_myfunction');
+ *
+ * Or this (from its use in ctools_page_title_content_type_render):
+ * $token = ctools_set_callback_token('title', array(
+ * 'ctools_page_title_content_type_token', $conf['markup'], $conf['id'], $conf['class']
+ * )
+ * );
+ *
+ * The token (e.g: "")
+ * would then be replaced during post-render by the return value of:
+ *
+ * ctools_page_title_content_type_token($value_markup, $value_id, $value_class);
+ *
+ * @param string $token
+ * The token string for the page callback, e.g. 'title'.
+ *
+ * @param string|array $callback
+ * For callback functions that require no args, the name of the function as a
+ * string; otherwise an array of two or more elements: the function name
+ * followed by one or more function arguments.
+ *
+ * NB: the value of $callback must be a procedural (non-class) function that
+ * passes the php function_exists() check.
+ *
+ * The callback function itself will be called with args dependent
+ * on $callback. If:
+ * - $callback is a string, the function is called with a reference to the
+ * render array;
+ * - $callback is an array, the function is called with $callback merged
+ * with an array containing a reference to the render array.
+ *
+ * @return string
+ * The constructed token.
+ *
+ * @see ctools_set_variable_token()
+ * @see ctools_page_token_processing()
*/
function ctools_set_callback_token($token, $callback) {
// If the callback uses arguments they are considered in the token.
@@ -384,9 +469,9 @@ function ctools_set_no_blocks($blocks = FALSE) {
/**
* Wrapper function to create UUIDs via ctools, falls back on UUID module
* if it is enabled. This code is a copy of uuid.inc from the uuid module.
+ *
* @see http://php.net/uniqid#65879
*/
-
function ctools_uuid_generate() {
if (!module_exists('uuid')) {
ctools_include('uuid');
@@ -413,6 +498,7 @@ function ctools_uuid_generate() {
/**
* Check that a string appears to be in the format of a UUID.
+ *
* @see http://drupal.org/project/uuid
*
* @param $uuid
@@ -468,6 +554,8 @@ function ctools_class_add($classes, $hook = 'html') {
*/
function ctools_class_remove($classes, $hook = 'html') {
if (!is_array($classes)) {
+ // @todo Consider using explode(' ', $classes);
+ // @todo Consider checking that $classes is a string before adding.
$classes = array($classes);
}
@@ -480,12 +568,35 @@ function ctools_class_remove($classes, $hook = 'html') {
}
}
-// -----------------------------------------------------------------------
-// Drupal core hooks
+/**
+ * Reset the storage used for ctools_class_add and ctools_class_remove.
+ *
+ * @see ctools_class_add()
+ * @see ctools_class_remove()
+ */
+function ctools_class_reset() {
+ drupal_static_reset('ctools_process_classes');
+}
+
+/**
+ * Return the classes for the body (added by ctools_class_add).
+ *
+ * @return array
+ * A copy of the array of classes to add to the body tag. If none have been
+ * added, this will be an empty array.
+ *
+ * @see ctools_class_add()
+ */
+function ctools_get_classes() {
+ return drupal_static('ctools_process_classes', array());
+}
+// -----------------------------------------------------------------------
+// Drupal core hooks.
/**
* Implement hook_init to keep our global CSS at the ready.
*/
+
function ctools_init() {
ctools_add_css('ctools');
// If we are sure that CTools' AJAX is in use, change the error handling.
@@ -504,7 +615,7 @@ function ctools_init() {
* Shutdown handler used during ajax operations to help catch fatal errors.
*/
function ctools_shutdown_handler() {
- if (function_exists('error_get_last') AND ($error = error_get_last())) {
+ if (function_exists('error_get_last') && ($error = error_get_last())) {
switch ($error['type']) {
case E_ERROR:
case E_CORE_ERROR:
@@ -583,7 +694,6 @@ function ctools_flush_caches() {
/**
* Implements hook_element_info_alter().
- *
*/
function ctools_element_info_alter(&$type) {
ctools_include('dependent');
@@ -619,10 +729,10 @@ function ctools_registry_files_alter(&$files, $indexed_modules) {
// -----------------------------------------------------------------------
// FAPI hooks that must be in the .module file.
-
/**
* Alter the comment form to get a little more control over it.
*/
+
function ctools_form_comment_form_alter(&$form, &$form_state) {
if (!empty($form_state['ctools comment alter'])) {
// Force the form to post back to wherever we are.
@@ -640,11 +750,11 @@ function ctools_node_comment_form_submit(&$form, &$form_state) {
// -----------------------------------------------------------------------
// CTools hook implementations.
-
/**
* Implementation of hook_ctools_plugin_directory() to let the system know
* where all our own plugins are.
*/
+
function ctools_ctools_plugin_directory($owner, $plugin_type) {
if ($owner == 'ctools') {
return 'plugins/' . $plugin_type;
@@ -665,11 +775,11 @@ function ctools_ctools_plugin_type() {
// -----------------------------------------------------------------------
// Drupal theme preprocess hooks that must be in the .module file.
-
/**
* A theme preprocess function to automatically allow panels-based node
* templates based upon input when the panel was configured.
*/
+
function ctools_preprocess_node(&$vars) {
// The 'ctools_template_identifier' attribute of the node is added when the pane is
// rendered.
@@ -679,14 +789,13 @@ function ctools_preprocess_node(&$vars) {
}
}
-
/**
* Implements hook_page_alter().
*
* Last ditch attempt to remove sidebar regions if the "no blocks"
* functionality has been activated.
*
- * @see ctools_block_list_alter().
+ * @see ctools_block_list_alter()
*/
function ctools_page_alter(&$page) {
$check = drupal_static('ctools_set_no_blocks', TRUE);
@@ -716,6 +825,7 @@ function ctools_page_token_processing($children, $elements) {
case 'variable':
$tokens[$token] = isset($elements[$argument]) ? $elements[$argument] : '';
break;
+
case 'callback':
if (is_string($argument) && function_exists($argument)) {
$tokens[$token] = $argument($elements);
@@ -744,7 +854,7 @@ function ctools_process(&$variables, $hook) {
return;
}
- $classes = drupal_static('ctools_process_classes', array());
+ $classes = ctools_get_classes();
// Process the classses to add.
if (!empty($classes[$hook]['add'])) {
@@ -765,7 +875,6 @@ function ctools_process(&$variables, $hook) {
// -----------------------------------------------------------------------
// Menu callbacks that must be in the .module file.
-
/**
* Determine if the current user has access via a plugin.
*
@@ -789,6 +898,7 @@ function ctools_process(&$variables, $hook) {
* @return
* TRUE if access is granted, false if otherwise.
*/
+
function ctools_access_menu($access) {
// Short circuit everything if there are no access tests.
if (empty($access['plugins'])) {
@@ -817,7 +927,7 @@ function ctools_access_menu($access) {
* An indexed array of zero or more permission strings to be checked by
* user_access().
*
- * @return
+ * @return bool
* Iff all checks pass will this function return TRUE. If an invalid argument
* is passed (e.g., not a string), this function errs on the safe said and
* returns FALSE.
@@ -879,7 +989,6 @@ function ctools_export_ui_load($item_name, $plugin_name) {
// -----------------------------------------------------------------------
// Caching callbacks on behalf of export-ui.
-
/**
* Menu access callback for various tasks of export-ui.
*/
@@ -923,7 +1032,7 @@ function ctools_export_ui_ctools_access_get($argument) {
}
/**
- * Callback for access control ajax form on behalf of export ui
+ * Callback for access control ajax form on behalf of export ui.
*
* Returns the cached access config and contexts used.
* Note that this is assuming that access will be in $item->access -- if it
@@ -956,8 +1065,9 @@ function ctools_menu_local_tasks_alter(&$data, $router_item, $root_path) {
}
/**
- * Implement hook_block_list_alter() to potentially remove blocks.
+ * Implements hook_block_list_alter().
*
+ * Used to potentially remove blocks.
* This exists in order to replicate Drupal 6's "no blocks" functionality.
*/
function ctools_block_list_alter(&$blocks) {
@@ -1020,6 +1130,7 @@ function ctools_ctools_entity_context_alter(&$plugin, &$entity, $plugin_id) {
case 'entity_id:taxonomy_term':
$plugin['no ui'] = TRUE;
break;
+
case 'entity:user':
$plugin = ctools_get_context('user');
unset($plugin['no ui']);
@@ -1053,18 +1164,21 @@ function ctools_field_create_field($field) {
function ctools_field_create_instance($instance) {
ctools_flush_field_caches();
}
+
/**
* Implements hook_field_delete_field().
*/
function ctools_field_delete_field($field) {
ctools_flush_field_caches();
}
+
/**
* Implements hook_field_delete_instance().
*/
function ctools_field_delete_instance($instance) {
ctools_flush_field_caches();
}
+
/**
* Implements hook_field_update_field().
*/
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/ctools_access_ruleset.info b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/ctools_access_ruleset.info
index 66ca12c0..e208eab7 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/ctools_access_ruleset.info
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/ctools_access_ruleset.info
@@ -5,9 +5,9 @@ package = Chaos tool suite
version = CTOOLS_MODULE_VERSION
dependencies[] = ctools
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.x-1.9"
+; Information added by Drupal.org packaging script on 2018-02-04
+version = "7.x-1.13"
core = "7.x"
project = "ctools"
-datestamp = "1440020680"
+datestamp = "1517704095"
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/ctools_access_ruleset.install b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/ctools_access_ruleset.install
index 3f008772..70afb3c6 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/ctools_access_ruleset.install
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/ctools_access_ruleset.install
@@ -1,5 +1,9 @@
t('Custom rulesets are combinations of access plugins you can use for access control, selection criteria and pane visibility.'),
);
- // Load all mini panels and their displays.
+ // Load all mini panels and their displays.
ctools_include('export');
$items = ctools_export_crud_load_all('ctools_access_ruleset');
$count = 0;
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/plugins/access/ruleset.inc b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/plugins/access/ruleset.inc
index f8abea6d..95f32c37 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/plugins/access/ruleset.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/plugins/access/ruleset.inc
@@ -35,7 +35,7 @@ function ctools_ruleset_ctools_access_merge_plugin($plugin, $parent, $item) {
$plugin['required context'] = array();
foreach ($item->requiredcontexts as $context) {
$info = ctools_get_context($context['name']);
- // TODO: allow an optional setting
+ // TODO: allow an optional setting.
$plugin['required context'][] = new ctools_context_required($context['identifier'], $info['context name']);
}
}
@@ -72,7 +72,7 @@ function ctools_ruleset_ctools_access_get_children($plugin, $parent) {
}
/**
- * Settings form for the 'by ruleset' access plugin
+ * Settings form for the 'by ruleset' access plugin.
*/
function ctools_ruleset_ctools_access_settings(&$form, &$form_state, $conf) {
if (!empty($form_state['plugin']['ruleset']->admin_description)) {
@@ -106,4 +106,3 @@ function ctools_ruleset_ctools_access_summary($conf, $context, $plugin) {
return check_plain($plugin['ruleset']->admin_title);
}
}
-
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/plugins/export_ui/ctools_access_ruleset.inc b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/plugins/export_ui/ctools_access_ruleset.inc
index d2a1c605..2589ac38 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/plugins/export_ui/ctools_access_ruleset.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/plugins/export_ui/ctools_access_ruleset.inc
@@ -1,5 +1,9 @@
'ctools_access_ruleset',
'access' => 'administer ctools access ruleset',
@@ -26,4 +30,3 @@ $plugin = array(
),
),
);
-
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/plugins/export_ui/ctools_access_ruleset_ui.class.php b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/plugins/export_ui/ctools_access_ruleset_ui.class.php
index b1814645..c9f8c20f 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/plugins/export_ui/ctools_access_ruleset_ui.class.php
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_access_ruleset/plugins/export_ui/ctools_access_ruleset_ui.class.php
@@ -2,7 +2,7 @@
class ctools_access_ruleset_ui extends ctools_export_ui {
- function edit_form_context(&$form, &$form_state) {
+ public function edit_form_context(&$form, &$form_state) {
ctools_include('context-admin');
ctools_context_admin_includes();
ctools_add_css('ruleset');
@@ -27,7 +27,7 @@ function edit_form_context(&$form, &$form_state) {
ctools_context_add_relationship_form($module, $form, $form_state, $form['right']['relationships_table'], $form_state['item'], $name);
}
- function edit_form_rules(&$form, &$form_state) {
+ public function edit_form_rules(&$form, &$form_state) {
// The 'access' UI passes everything via $form_state, unlike the 'context' UI.
// The main difference is that one is about 3 years newer than the other.
ctools_include('context');
@@ -43,11 +43,12 @@ function edit_form_rules(&$form, &$form_state) {
$form = ctools_access_admin_form($form, $form_state);
}
- function edit_form_rules_submit(&$form, &$form_state) {
+ public function edit_form_rules_submit(&$form, &$form_state) {
$form_state['item']->access['logic'] = $form_state['values']['logic'];
}
- function edit_form_submit(&$form, &$form_state) {
+ public function edit_form_submit(&$form, &$form_state) {
parent::edit_form_submit($form, $form_state);
}
+
}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_ajax_sample/css/ctools-ajax-sample.css b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_ajax_sample/css/ctools-ajax-sample.css
index 8df17de5..c312e991 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_ajax_sample/css/ctools-ajax-sample.css
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_ajax_sample/css/ctools-ajax-sample.css
@@ -1,52 +1,52 @@
div.ctools-sample-modal-content {
- background:none;
- border:0;
- color:#000000;
- margin:0;
- padding:0;
- text-align:left;
+ background: none;
+ border: 0;
+ color: #000;
+ margin: 0;
+ padding: 0;
+ text-align: left;
}
-div.ctools-sample-modal-content .modal-scroll{
- overflow:hidden;
- overflow-y:auto;
+div.ctools-sample-modal-content .modal-scroll {
+ overflow: hidden;
+ overflow-y: auto;
}
div.ctools-sample-modal-content #popups-overlay {
- background-color:transparent;
+ background-color: transparent;
}
div.ctools-sample-modal-content #popups-loading {
- width:248px;
- position:absolute;
- display:none;
- opacity:1;
+ width: 248px;
+ position: absolute;
+ display: none;
+ opacity: 1;
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
- z-index:99;
+ z-index: 99;
}
div.ctools-sample-modal-content #popups-loading span.popups-loading-message {
- background:#FFF url(../images/loading-large.gif) no-repeat 8px center;
- display:block;
- color:#444444;
- font-family:Arial;
- font-size:22px;
- font-weight:bold;
- height:36px;
- line-height:36px;
- padding:0 40px;
+ background: #fff url(../images/loading-large.gif) no-repeat 8px center;
+ display: block;
+ color: #444;
+ font-family: Arial, serif;
+ font-size: 22px;
+ font-weight: bold;
+ height: 36px;
+ line-height: 36px;
+ padding: 0 40px;
}
div.ctools-sample-modal-content #popups-loading table,
div.ctools-sample-modal-content .popups-box table {
- margin:0px;
+ margin: 0;
}
div.ctools-sample-modal-content #popups-loading tbody,
div.ctools-sample-modal-content .popups-box tbody {
- border:none;
+ border: none;
}
div.ctools-sample-modal-content .popups-box tr {
- background-color:transparent;
+ background-color: transparent;
}
div.ctools-sample-modal-content td.popups-border {
background: url(../images/popups-border.png);
- background-color:transparent;
+ background-color: transparent;
border: none;
}
div.ctools-sample-modal-content td.popups-tl,
@@ -54,79 +54,94 @@ div.ctools-sample-modal-content td.popups-tr,
div.ctools-sample-modal-content td.popups-bl,
div.ctools-sample-modal-content td.popups-br {
background-repeat: no-repeat;
- height:10px;
- padding:0px;
+ height: 10px;
+ padding: 0;
+}
+div.ctools-sample-modal-content td.popups-tl {
+ background-position: 0 0;
}
-div.ctools-sample-modal-content td.popups-tl { background-position: 0px 0px; }
div.ctools-sample-modal-content td.popups-t,
div.ctools-sample-modal-content td.popups-b {
- background-position: 0px -40px;
+ background-position: 0 -40px;
background-repeat: repeat-x;
}
-div.ctools-sample-modal-content td.popups-tr { background-position: 0px -10px; width: 10px; }
+div.ctools-sample-modal-content td.popups-tr {
+ background-position: 0 -10px;
+ width: 10px;
+}
div.ctools-sample-modal-content td.popups-cl,
div.ctools-sample-modal-content td.popups-cr {
background-position: -10px 0;
background-repeat: repeat-y;
- width:10px;
+ width: 10px;
}
div.ctools-sample-modal-content td.popups-cl,
div.ctools-sample-modal-content td.popups-cr,
-div.ctools-sample-modal-content td.popups-c { padding:0; border: none; }
-div.ctools-sample-modal-content td.popups-c { background:#fff; }
-div.ctools-sample-modal-content td.popups-bl { background-position: 0px -20px; }
-div.ctools-sample-modal-content td.popups-br { background-position: 0px -30px; width: 10px; }
+div.ctools-sample-modal-content td.popups-c {
+ padding: 0;
+ border: none;
+}
+div.ctools-sample-modal-content td.popups-c {
+ background: #fff;
+}
+div.ctools-sample-modal-content td.popups-bl {
+ background-position: 0 -20px;
+}
+div.ctools-sample-modal-content td.popups-br {
+ background-position: 0 -30px;
+ width: 10px;
+}
div.ctools-sample-modal-content .popups-box,
div.ctools-sample-modal-content #popups-loading {
- border: 0px solid #454545;
- opacity:1;
- overflow:hidden;
- padding:0;
- background-color:transparent;
+ border: 0 solid #454545;
+ opacity: 1;
+ overflow: hidden;
+ padding: 0;
+ background-color: transparent;
}
div.ctools-sample-modal-content .popups-container {
- overflow:hidden;
- height:100%;
- background-color:#fff;
+ overflow: hidden;
+ height: 100%;
+ background-color: #fff;
}
div.ctools-sample-modal-content div.popups-title {
- -moz-border-radius-topleft: 0px;
- -webkit-border-radius-topleft: 0px;
- margin-bottom:0px;
- background-color:#ff7200;
- border:1px solid #ce5c00;
- padding:4px 10px 5px;
- color:white;
- font-size:1em;
- font-weight:bold;
+ -moz-border-radius-topleft: 0;
+ -webkit-border-radius-topleft: 0;
+ margin-bottom: 0;
+ background-color: #ff7200;
+ border: 1px solid #ce5c00;
+ padding: 4px 10px 5px;
+ color: white;
+ font-size: 1em;
+ font-weight: bold;
}
div.ctools-sample-modal-content .popups-body {
- background-color:#fff;
- padding:8px;
+ background-color: #fff;
+ padding: 8px;
}
div.ctools-sample-modal-content .popups-box .popups-buttons,
div.ctools-sample-modal-content .popups-box .popups-footer {
- background-color:#fff;
+ background-color: #fff;
}
div.ctools-sample-modal-content .popups-title a.close {
color: #fff;
- text-decoration:none;
+ text-decoration: none;
}
div.ctools-sample-modal-content .popups-close {
- font-size:120%;
- float:right;
- text-align:right;
+ font-size: 120%;
+ float: right;
+ text-align: right;
}
div.ctools-sample-modal-content .modal-loading-wrapper {
- width:220px;
- height:19px;
- margin:0 auto;
- margin-top:2%;
+ width: 220px;
+ height: 19px;
+ margin: 0 auto;
+ margin-top: 2%;
}
-div.ctools-sample-modal-content tbody{
- border:none;
+div.ctools-sample-modal-content tbody {
+ border: none;
}
div.ctools-sample-modal-content .modal-content .modal-throbber-wrapper img {
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_ajax_sample/ctools_ajax_sample.info b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_ajax_sample/ctools_ajax_sample.info
index f5d1e745..89fc1af3 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_ajax_sample/ctools_ajax_sample.info
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_ajax_sample/ctools_ajax_sample.info
@@ -5,9 +5,9 @@ version = CTOOLS_MODULE_VERSION
dependencies[] = ctools
core = 7.x
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.x-1.9"
+; Information added by Drupal.org packaging script on 2018-02-04
+version = "7.x-1.13"
core = "7.x"
project = "ctools"
-datestamp = "1440020680"
+datestamp = "1517704095"
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_ajax_sample/ctools_ajax_sample.install b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_ajax_sample/ctools_ajax_sample.install
index 04325dbf..e0fdfc6f 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_ajax_sample/ctools_ajax_sample.install
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_ajax_sample/ctools_ajax_sample.install
@@ -1,18 +1,18 @@
'Chaos Tools AJAX Demo',
- 'page callback' => 'ctools_ajax_sample_page',
- 'access callback' => TRUE,
- 'type' => MENU_NORMAL_ITEM,
+ 'title' => 'Chaos Tools AJAX Demo',
+ 'page callback' => 'ctools_ajax_sample_page',
+ 'access callback' => TRUE,
+ 'type' => MENU_NORMAL_ITEM,
);
$items['ctools_ajax_sample/simple_form'] = array(
'title' => 'Simple Form',
@@ -26,39 +26,39 @@ function ctools_ajax_sample_menu() {
'type' => MENU_CALLBACK,
);
$items['ctools_ajax_sample/%ctools_js/hello'] = array(
- 'title' => 'Hello World',
- 'page callback' => 'ctools_ajax_sample_hello',
- 'page arguments' => array(1),
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
+ 'title' => 'Hello World',
+ 'page callback' => 'ctools_ajax_sample_hello',
+ 'page arguments' => array(1),
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
);
$items['ctools_ajax_sample/%ctools_js/tablenix/%'] = array(
- 'title' => 'Hello World',
- 'page callback' => 'ctools_ajax_sample_tablenix',
- 'page arguments' => array(1, 3),
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
+ 'title' => 'Hello World',
+ 'page callback' => 'ctools_ajax_sample_tablenix',
+ 'page arguments' => array(1, 3),
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
);
$items['ctools_ajax_sample/%ctools_js/login'] = array(
- 'title' => 'Login',
- 'page callback' => 'ctools_ajax_sample_login',
- 'page arguments' => array(1),
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
+ 'title' => 'Login',
+ 'page callback' => 'ctools_ajax_sample_login',
+ 'page arguments' => array(1),
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
);
$items['ctools_ajax_sample/%ctools_js/animal'] = array(
- 'title' => 'Animal',
- 'page callback' => 'ctools_ajax_sample_animal',
- 'page arguments' => array(1),
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
+ 'title' => 'Animal',
+ 'page callback' => 'ctools_ajax_sample_animal',
+ 'page arguments' => array(1),
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
);
$items['ctools_ajax_sample/%ctools_js/login/%'] = array(
- 'title' => 'Post-Login Action',
- 'page callback' => 'ctools_ajax_sample_login_success',
- 'page arguments' => array(1, 3),
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
+ 'title' => 'Post-Login Action',
+ 'page callback' => 'ctools_ajax_sample_login_success',
+ 'page arguments' => array(1, 3),
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
);
$items['ctools_ajax_sample/jumped'] = array(
'title' => 'Successful Jumping',
@@ -104,11 +104,11 @@ function ctools_ajax_sample_theme() {
}
// ---------------------------------------------------------------------------
-// Page callbacks
-
+// Page callbacks.
/**
* Page callback to display links and render a container for AJAX stuff.
*/
+
function ctools_ajax_sample_page() {
global $user;
@@ -156,14 +156,14 @@ function ctools_ajax_sample_page() {
// The extra class points to the info in ctools-sample-style which we added
// to the settings, prefixed with 'ctools-modal'.
- $links[] = ctools_modal_text_button(t('Modal Login (custom style)'), 'ctools_ajax_sample/nojs/login', t('Login via modal'), 'ctools-modal-ctools-sample-style');
+ $links[] = ctools_modal_text_button(t('Modal Login (custom style)'), 'ctools_ajax_sample/nojs/login', t('Login via modal'), 'ctools-modal-ctools-sample-style');
}
// Four ways to do our animal picking wizard.
$button_form = ctools_ajax_sample_ajax_button_form();
$links[] = l(t('Wizard (no modal)'), 'ctools_ajax_sample/nojs/animal');
$links[] = ctools_modal_text_button(t('Wizard (default modal)'), 'ctools_ajax_sample/nojs/animal', t('Pick an animal'));
- $links[] = ctools_modal_text_button(t('Wizard (custom modal)'), 'ctools_ajax_sample/nojs/animal', t('Pick an animal'), 'ctools-modal-ctools-sample-style');
+ $links[] = ctools_modal_text_button(t('Wizard (custom modal)'), 'ctools_ajax_sample/nojs/animal', t('Pick an animal'), 'ctools-modal-ctools-sample-style');
$links[] = drupal_render($button_form);
$links[] = ctools_ajax_text_button(t('Hello world!'), "ctools_ajax_sample/nojs/hello", t('Replace text with "hello world"'));
@@ -176,9 +176,9 @@ function ctools_ajax_sample_page() {
// Create a table that we can have data removed from via AJAX.
$header = array(t('Row'), t('Content'), t('Actions'));
$rows = array();
- for($i = 1; $i < 11; $i++) {
+ for ($i = 1; $i < 11; $i++) {
$rows[] = array(
- 'class' => array('ajax-sample-row-'. $i),
+ 'class' => array('ajax-sample-row-' . $i),
'data' => array(
$i,
md5($i),
@@ -189,10 +189,10 @@ function ctools_ajax_sample_page() {
$output .= theme('table', array('header' => $header, 'rows' => $rows, array('class' => array('ajax-sample-table'))));
- // Show examples of ctools javascript widgets
- $output .= '
'. t('CTools Javascript Widgets') .'
';
+ // Show examples of ctools javascript widgets.
+ $output .= '
' . t('CTools Javascript Widgets') . '
';
- // Create a drop down menu
+ // Create a drop down menu.
$links = array();
$links[] = array('title' => t('Link 1'), 'href' => $_GET['q']);
$links[] = array('title' => t('Link 2'), 'href' => $_GET['q']);
@@ -201,16 +201,16 @@ function ctools_ajax_sample_page() {
$output .= '
' . t('Drop Down Menu') . '
';
$output .= theme('ctools_dropdown', array('title' => t('Click to Drop Down'), 'links' => $links));
- // Create a collapsible div
+ // Create a collapsible div.
$handle = t('Click to Collapse');
$content = 'Nulla ligula ante, aliquam at adipiscing egestas, varius vel arcu. Etiam laoreet elementum mi vel consequat. Etiam scelerisque lorem vel neque consequat quis bibendum libero congue. Nulla facilisi. Mauris a elit a leo feugiat porta. Phasellus placerat cursus est vitae elementum.';
- $output .= '
Login successful. You can now choose whether to ' . $inplace . ', or go to ' . $account . '.
');
}
print ajax_render($output);
exit;
@@ -283,7 +284,7 @@ function ctools_ajax_sample_login($js = NULL) {
*/
function ctools_ajax_sample_login_success($js, $action) {
if (!$js) {
- // we should never be here out of ajax context
+ // We should never be here out of ajax context.
return MENU_NOT_FOUND;
}
@@ -291,11 +292,11 @@ function ctools_ajax_sample_login_success($js, $action) {
ctools_add_js('ajax-responder');
$commands = array();
if ($action == 'inplace') {
- // stay here
+ // Stay here.
$commands[] = ctools_ajax_command_reload();
}
else {
- // bounce bounce
+ // Bounce bounce.
$commands[] = ctools_ajax_command_redirect('user');
}
print ajax_render($commands);
@@ -318,18 +319,18 @@ function ctools_ajax_sample_animal($js = NULL, $step = NULL) {
'show back' => TRUE,
'show cancel' => TRUE,
'show return' => FALSE,
- 'next callback' => 'ctools_ajax_sample_wizard_next',
+ 'next callback' => 'ctools_ajax_sample_wizard_next',
'finish callback' => 'ctools_ajax_sample_wizard_finish',
'cancel callback' => 'ctools_ajax_sample_wizard_cancel',
- // this controls order, as well as form labels
+ // This controls order, as well as form labels.
'order' => array(
'start' => t('Choose animal'),
),
- // here we map a step to a form id.
+ // Here we map a step to a form id.
'forms' => array(
- // e.g. this for the step at wombat/create
+ // e.g. this for the step at wombat/create.
'start' => array(
- 'form id' => 'ctools_ajax_sample_start'
+ 'form id' => 'ctools_ajax_sample_start',
),
),
);
@@ -341,7 +342,6 @@ function ctools_ajax_sample_animal($js = NULL, $step = NULL) {
// in creation.
//
// We skip all this here by just using an id of 1.
-
$object_id = 1;
if (empty($step)) {
@@ -406,7 +406,7 @@ function ctools_ajax_sample_animal($js = NULL, $step = NULL) {
$commands[] = ajax_command_html('#ctools-sample', $animal);
$commands[] = ctools_modal_command_dismiss();
}
- else if (!empty($form_state['cancel'])) {
+ elseif (!empty($form_state['cancel'])) {
// If cancelling, return to the activity.
$commands[] = ctools_modal_command_dismiss();
}
@@ -420,7 +420,7 @@ function ctools_ajax_sample_animal($js = NULL, $step = NULL) {
if ($output === FALSE || !empty($form_state['complete'])) {
return $animal;
}
- else if (!empty($form_state['cancel'])) {
+ elseif (!empty($form_state['cancel'])) {
drupal_goto('ctools_ajax_sample');
}
else {
@@ -430,11 +430,11 @@ function ctools_ajax_sample_animal($js = NULL, $step = NULL) {
}
// ---------------------------------------------------------------------------
-// Themes
-
+// Themes.
/**
* Theme function for main rendered output.
*/
+
function theme_ctools_ajax_sample_container($vars) {
$output = '
';
$output .= $vars['content'];
@@ -445,7 +445,6 @@ function theme_ctools_ajax_sample_container($vars) {
// ---------------------------------------------------------------------------
// Stuff needed for our little wizard.
-
/**
* Get a list of our animals and associated forms.
*
@@ -453,6 +452,7 @@ function theme_ctools_ajax_sample_container($vars) {
* which is often how it will work in the real world. If using CTools, what
* you would probably really have, here, is a set of plugins for each animal.
*/
+
function ctools_ajax_sample_animals() {
return array(
'sheep' => array(
@@ -478,10 +478,10 @@ function ctools_ajax_sample_animals() {
// ---------------------------------------------------------------------------
// Wizard caching helpers.
-
/**
* Store our little cache so that we can retain data from form to form.
*/
+
function ctools_ajax_sample_cache_set($id, $object) {
ctools_include('object-cache');
ctools_object_cache_set('ctools_ajax_sample', $id, $object);
@@ -495,7 +495,7 @@ function ctools_ajax_sample_cache_get($id) {
$object = ctools_object_cache_get('ctools_ajax_sample', $id);
if (!$object) {
// Create a default object.
- $object = new stdClass;
+ $object = new stdClass();
$object->type = 'unknown';
$object->name = '';
}
@@ -513,12 +513,12 @@ function ctools_ajax_sample_cache_clear($id) {
// ---------------------------------------------------------------------------
// Wizard in-between helpers; what to do between or after forms.
-
/**
* Handle the 'next' click on the add/edit pane form wizard.
*
* All we need to do is store the updated pane in the cache.
*/
+
function ctools_ajax_sample_wizard_next(&$form_state) {
ctools_ajax_sample_cache_set($form_state['object_id'], $form_state['object']);
}
@@ -542,10 +542,10 @@ function ctools_ajax_sample_wizard_cancel(&$form_state) {
// ---------------------------------------------------------------------------
// Wizard forms for our simple info collection wizard.
-
/**
* Wizard start form. Choose an animal.
*/
+
function ctools_ajax_sample_start($form, &$form_state) {
$form_state['title'] = t('Choose animal');
@@ -713,7 +713,7 @@ function ctools_ajax_sample_show_raptor($object) {
}
/**
- * Helper function to provide a sample jump menu form
+ * Helper function to provide a sample jump menu form.
*/
function ctools_ajax_sample_jump_menu_form() {
$url = url('ctools_ajax_sample/jumped');
@@ -723,7 +723,7 @@ function ctools_ajax_sample_jump_menu_form() {
}
/**
- * Provide a message to the user that the jump menu worked
+ * Provide a message to the user that the jump menu worked.
*/
function ctools_ajax_sample_jump_menu_page() {
$return_link = l(t('Return to the examples page.'), 'ctools_ajax_sample');
@@ -732,7 +732,7 @@ function ctools_ajax_sample_jump_menu_page() {
}
/**
- * Provide a form for an example ajax modal button
+ * Provide a form for an example ajax modal button.
*/
function ctools_ajax_sample_ajax_button_form() {
$form = array();
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_custom_content/ctools_custom_content.info b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_custom_content/ctools_custom_content.info
index 185d8b64..094d2788 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_custom_content/ctools_custom_content.info
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_custom_content/ctools_custom_content.info
@@ -5,9 +5,9 @@ package = Chaos tool suite
version = CTOOLS_MODULE_VERSION
dependencies[] = ctools
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.x-1.9"
+; Information added by Drupal.org packaging script on 2018-02-04
+version = "7.x-1.13"
core = "7.x"
project = "ctools"
-datestamp = "1440020680"
+datestamp = "1517704095"
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_custom_content/ctools_custom_content.install b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_custom_content/ctools_custom_content.install
index b4512f2a..dcf87e73 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_custom_content/ctools_custom_content.install
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_custom_content/ctools_custom_content.install
@@ -1,5 +1,9 @@
type == 'custom') {
- if(!isset($pane->configuration['name'])) {
+ if (!isset($pane->configuration['name'])) {
$name_of_pane = $pane->subtype;
}
else {
@@ -80,7 +80,7 @@ function ctools_custom_content_panels_dashboard_blocks(&$vars) {
'description' => t('Custom content panes are basic HTML you enter that can be reused in all of your panels.'),
);
- // Load all mini panels and their displays.
+ // Load all mini panels and their displays.
ctools_include('export');
$items = ctools_export_crud_load_all('ctools_custom_content');
$count = 0;
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_custom_content/plugins/export_ui/ctools_custom_content.inc b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_custom_content/plugins/export_ui/ctools_custom_content.inc
index 467dc580..c7933bcb 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_custom_content/plugins/export_ui/ctools_custom_content.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_custom_content/plugins/export_ui/ctools_custom_content.inc
@@ -1,5 +1,9 @@
'ctools_custom_content',
'access' => 'administer custom content',
@@ -17,4 +21,3 @@ $plugin = array(
'handler' => 'ctools_custom_content_ui',
);
-
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_custom_content/plugins/export_ui/ctools_custom_content_ui.class.php b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_custom_content/plugins/export_ui/ctools_custom_content_ui.class.php
index 56fe4b21..e56f7a7e 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_custom_content/plugins/export_ui/ctools_custom_content_ui.class.php
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_custom_content/plugins/export_ui/ctools_custom_content_ui.class.php
@@ -2,7 +2,7 @@
class ctools_custom_content_ui extends ctools_export_ui {
- function edit_form(&$form, &$form_state) {
+ public function edit_form(&$form, &$form_state) {
// Correct for an error that came in because filter format changed.
if (is_array($form_state['item']->settings['body'])) {
$form_state['item']->settings['format'] = $form_state['item']->settings['body']['format'];
@@ -23,6 +23,22 @@ function edit_form(&$form, &$form_state) {
'#title' => t('Title'),
);
+ $form['title_heading'] = array(
+ '#title' => t('Title heading'),
+ '#type' => 'select',
+ '#default_value' => isset($form_state['item']->settings['title_heading']) ? $form_state['item']->settings['title_heading'] : 'h2',
+ '#options' => array(
+ 'h1' => t('h1'),
+ 'h2' => t('h2'),
+ 'h3' => t('h3'),
+ 'h4' => t('h4'),
+ 'h5' => t('h5'),
+ 'h6' => t('h6'),
+ 'div' => t('div'),
+ 'span' => t('span'),
+ ),
+ );
+
$form['body'] = array(
'#type' => 'text_format',
'#title' => t('Body'),
@@ -38,17 +54,18 @@ function edit_form(&$form, &$form_state) {
);
}
- function edit_form_submit(&$form, &$form_state) {
+ public function edit_form_submit(&$form, &$form_state) {
parent::edit_form_submit($form, $form_state);
// Since items in our settings are not in the schema, we have to do these manually:
$form_state['item']->settings['title'] = $form_state['values']['title'];
+ $form_state['item']->settings['title_heading'] = $form_state['values']['title_heading'];
$form_state['item']->settings['body'] = $form_state['values']['body']['value'];
$form_state['item']->settings['format'] = $form_state['values']['body']['format'];
$form_state['item']->settings['substitute'] = $form_state['values']['substitute'];
}
- function list_form(&$form, &$form_state) {
+ public function list_form(&$form, &$form_state) {
parent::list_form($form, $form_state);
$options = array('all' => t('- All -'));
@@ -65,7 +82,7 @@ function list_form(&$form, &$form_state) {
);
}
- function list_filter($form_state, $item) {
+ public function list_filter($form_state, $item) {
if ($form_state['values']['category'] != 'all' && $form_state['values']['category'] != $item->category) {
return TRUE;
}
@@ -73,7 +90,7 @@ function list_filter($form_state, $item) {
return parent::list_filter($form_state, $item);
}
- function list_sort_options() {
+ public function list_sort_options() {
return array(
'disabled' => t('Enabled, title'),
'title' => t('Title'),
@@ -83,21 +100,25 @@ function list_sort_options() {
);
}
- function list_build_row($item, &$form_state, $operations) {
- // Set up sorting
+ public function list_build_row($item, &$form_state, $operations) {
+ // Set up sorting.
switch ($form_state['values']['order']) {
case 'disabled':
$this->sorts[$item->name] = empty($item->disabled) . $item->admin_title;
break;
+
case 'title':
$this->sorts[$item->name] = $item->admin_title;
break;
+
case 'name':
$this->sorts[$item->name] = $item->name;
break;
+
case 'category':
$this->sorts[$item->name] = $item->category;
break;
+
case 'storage':
$this->sorts[$item->name] = $item->type . $item->admin_title;
break;
@@ -117,7 +138,7 @@ function list_build_row($item, &$form_state, $operations) {
);
}
- function list_table_header() {
+ public function list_table_header() {
return array(
array('data' => t('Name'), 'class' => array('ctools-export-ui-name')),
array('data' => t('Title'), 'class' => array('ctools-export-ui-title')),
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/README.txt b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/README.txt
index 42edcdc9..2f9b0fff 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/README.txt
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/README.txt
@@ -11,4 +11,4 @@ There are a number of ways to profit from this:
2. There is a sample panel. You can access it at /ctools_plugin_example/xxxx
to see how it works.
-3. There is Advanced Help at admin/advanced_help/ctools_plugin_example.
\ No newline at end of file
+3. There is Advanced Help at admin/advanced_help/ctools_plugin_example.
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.info b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.info
index d378641e..77c311f7 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.info
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.info
@@ -8,9 +8,9 @@ dependencies[] = page_manager
dependencies[] = advanced_help
core = 7.x
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.x-1.9"
+; Information added by Drupal.org packaging script on 2018-02-04
+version = "7.x-1.13"
core = "7.x"
project = "ctools"
-datestamp = "1440020680"
+datestamp = "1517704095"
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.module b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.module
index 01d53382..a9a6080b 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.module
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.module
@@ -1,9 +1,8 @@
.pages_default.inc
+ * .pages_default.inc.
*/
function ctools_plugin_example_ctools_plugin_api($module, $api) {
// @todo -- this example should explain how to put it in a different file.
@@ -71,7 +70,8 @@ function ctools_plugin_example_ctools_plugin_api($module, $api) {
}
/**
- * Just provide an explanation page for the admin section
+ * Just provide an explanation page for the admin section.
+ *
* @return unknown_type
*/
function ctools_plugin_example_explanation_page() {
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.pages_default.inc b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.pages_default.inc
index 10a76193..bbabf227 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.pages_default.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/ctools_plugin_example.pages_default.inc
@@ -6,7 +6,7 @@
*/
/**
- * Default panels pages for CTools Plugin Example
+ * Default panels pages for CTools Plugin Example.
*
* To pick up this file, your module needs to implement
* hook_ctools_plugin_api() - See ctools_plugin_example_ctools_plugin_api() in
@@ -23,12 +23,10 @@
* @return
* Array of pages, normally exported from Panels.
*/
-
function ctools_plugin_example_default_page_manager_pages() {
- // begin exported panel.
-
- $page = new stdClass;
+ // Begin exported panel.
+ $page = new stdClass();
$page->disabled = FALSE; /* Edit this to true to make a default page disabled initially */
$page->api_version = 1;
$page->name = 'ctools_plugin_example';
@@ -37,31 +35,31 @@ function ctools_plugin_example_default_page_manager_pages() {
$page->admin_description = 'This panel provides no functionality to a working Drupal system. It\'s intended to display the various sample plugins provided by the CTools Plugin Example module. ';
$page->path = 'ctools_plugin_example/%sc';
$page->access = array(
- 'logic' => 'and',
+ 'logic' => 'and',
);
$page->menu = array(
- 'type' => 'normal',
- 'title' => 'CTools plugin example',
- 'name' => 'navigation',
- 'weight' => '0',
- 'parent' => array(
- 'type' => 'none',
- 'title' => '',
+ 'type' => 'normal',
+ 'title' => 'CTools plugin example',
'name' => 'navigation',
'weight' => '0',
- ),
+ 'parent' => array(
+ 'type' => 'none',
+ 'title' => '',
+ 'name' => 'navigation',
+ 'weight' => '0',
+ ),
);
$page->arguments = array(
- 'sc' => array(
- 'id' => 2,
- 'identifier' => 'simplecontext-arg',
- 'name' => 'simplecontext_arg',
- 'settings' => array(),
- ),
+ 'sc' => array(
+ 'id' => 2,
+ 'identifier' => 'simplecontext-arg',
+ 'name' => 'simplecontext_arg',
+ 'settings' => array(),
+ ),
);
$page->conf = array();
$page->default_handlers = array();
- $handler = new stdClass;
+ $handler = new stdClass();
$handler->disabled = FALSE; /* Edit this to true to make a default handler disabled initially */
$handler->api_version = 1;
$handler->name = 'page_ctools_panel_context';
@@ -70,44 +68,44 @@ function ctools_plugin_example_default_page_manager_pages() {
$handler->handler = 'panel_context';
$handler->weight = 0;
$handler->conf = array(
- 'title' => 'Panel',
- 'no_blocks' => FALSE,
- 'css_id' => '',
- 'css' => '',
- 'contexts' => array(
- '0' => array(
- 'name' => 'simplecontext',
- 'id' => 1,
- 'identifier' => 'Configured simplecontext (not from argument)',
- 'keyword' => 'configured_simplecontext',
- 'context_settings' => array(
- 'sample_simplecontext_setting' => 'default simplecontext setting',
- ),
- ),
- ),
- 'relationships' => array(
- '0' => array(
- 'context' => 'argument_simplecontext_arg_2',
- 'name' => 'relcontext_from_simplecontext',
- 'id' => 1,
- 'identifier' => 'Relcontext from simplecontext (from relationship)',
- 'keyword' => 'relcontext',
- ),
- ),
- 'access' => array(
- 'logic' => 'and',
- ),
+ 'title' => 'Panel',
+ 'no_blocks' => FALSE,
+ 'css_id' => '',
+ 'css' => '',
+ 'contexts' => array(
+ '0' => array(
+ 'name' => 'simplecontext',
+ 'id' => 1,
+ 'identifier' => 'Configured simplecontext (not from argument)',
+ 'keyword' => 'configured_simplecontext',
+ 'context_settings' => array(
+ 'sample_simplecontext_setting' => 'default simplecontext setting',
+ ),
+ ),
+ ),
+ 'relationships' => array(
+ '0' => array(
+ 'context' => 'argument_simplecontext_arg_2',
+ 'name' => 'relcontext_from_simplecontext',
+ 'id' => 1,
+ 'identifier' => 'Relcontext from simplecontext (from relationship)',
+ 'keyword' => 'relcontext',
+ ),
+ ),
+ 'access' => array(
+ 'logic' => 'and',
+ ),
);
- $display = new panels_display;
+ $display = new panels_display();
$display->layout = 'threecol_33_34_33_stacked';
$display->layout_settings = array();
$display->panel_settings = array(
- 'style' => 'rounded_corners',
- 'style_settings' => array(
- 'default' => array(
- 'corner_location' => 'pane',
- ),
- ),
+ 'style' => 'rounded_corners',
+ 'style_settings' => array(
+ 'default' => array(
+ 'corner_location' => 'pane',
+ ),
+ ),
);
$display->cache = array();
$display->title = 'CTools plugin example panel';
@@ -115,7 +113,7 @@ function ctools_plugin_example_default_page_manager_pages() {
$display->title_pane = 1;
$display->content = array();
$display->panels = array();
- $pane = new stdClass;
+ $pane = new stdClass();
$pane->pid = 'new-1';
$pane->panel = 'left';
$pane->type = 'no_context_content_type';
@@ -135,7 +133,7 @@ function ctools_plugin_example_default_page_manager_pages() {
$pane->position = 0;
$display->content['new-1'] = $pane;
$display->panels['left'][0] = 'new-1';
- $pane = new stdClass;
+ $pane = new stdClass();
$pane->pid = 'new-2';
$pane->panel = 'left';
$pane->type = 'custom';
@@ -148,10 +146,10 @@ function ctools_plugin_example_default_page_manager_pages() {
'settings' => array(
'greater_than' => '1',
'arg_length' => '4',
- ),
+ ),
'context' => 'argument_simplecontext_arg_2',
- ),
- ),
+ ),
+ ),
);
$pane->configuration = array(
'title' => 'Long Arg Visibility Block',
@@ -166,7 +164,7 @@ function ctools_plugin_example_default_page_manager_pages() {
$pane->position = 1;
$display->content['new-2'] = $pane;
$display->panels['left'][1] = 'new-2';
- $pane = new stdClass;
+ $pane = new stdClass();
$pane->pid = 'new-3';
$pane->panel = 'left';
$pane->type = 'custom';
@@ -179,10 +177,10 @@ function ctools_plugin_example_default_page_manager_pages() {
'settings' => array(
'greater_than' => '0',
'arg_length' => '4',
- ),
+ ),
'context' => 'argument_simplecontext_arg_2',
- ),
- ),
+ ),
+ ),
);
$pane->configuration = array(
'title' => 'Short Arg Visibility',
@@ -197,7 +195,7 @@ function ctools_plugin_example_default_page_manager_pages() {
$pane->position = 2;
$display->content['new-3'] = $pane;
$display->panels['left'][2] = 'new-3';
- $pane = new stdClass;
+ $pane = new stdClass();
$pane->pid = 'new-4';
$pane->panel = 'middle';
$pane->type = 'simplecontext_content_type';
@@ -241,7 +239,7 @@ function ctools_plugin_example_default_page_manager_pages() {
$pane->position = 0;
$display->content['new-4'] = $pane;
$display->panels['middle'][0] = 'new-4';
- $pane = new stdClass;
+ $pane = new stdClass();
$pane->pid = 'new-5';
$pane->panel = 'middle';
$pane->type = 'simplecontext_content_type';
@@ -285,7 +283,7 @@ function ctools_plugin_example_default_page_manager_pages() {
$pane->position = 1;
$display->content['new-5'] = $pane;
$display->panels['middle'][1] = 'new-5';
- $pane = new stdClass;
+ $pane = new stdClass();
$pane->pid = 'new-6';
$pane->panel = 'middle';
$pane->type = 'custom';
@@ -309,7 +307,7 @@ function ctools_plugin_example_default_page_manager_pages() {
$pane->position = 2;
$display->content['new-6'] = $pane;
$display->panels['middle'][2] = 'new-6';
- $pane = new stdClass;
+ $pane = new stdClass();
$pane->pid = 'new-7';
$pane->panel = 'right';
$pane->type = 'relcontext_content_type';
@@ -353,7 +351,7 @@ function ctools_plugin_example_default_page_manager_pages() {
$pane->position = 0;
$display->content['new-7'] = $pane;
$display->panels['right'][0] = 'new-7';
- $pane = new stdClass;
+ $pane = new stdClass();
$pane->pid = 'new-8';
$pane->panel = 'top';
$pane->type = 'custom';
@@ -378,12 +376,11 @@ function ctools_plugin_example_default_page_manager_pages() {
$handler->conf['display'] = $display;
$page->default_handlers[$handler->name] = $handler;
- // end of exported panel.
+ // End of exported panel.
$pages['ctools_plugin_example_demo_page'] = $page;
- // begin exported panel
-
- $page = new stdClass;
+ // Begin exported panel.
+ $page = new stdClass();
$page->disabled = FALSE; /* Edit this to true to make a default page disabled initially */
$page->api_version = 1;
$page->name = 'ctools_plugin_example_base';
@@ -396,7 +393,7 @@ function ctools_plugin_example_default_page_manager_pages() {
$page->arguments = array();
$page->conf = array();
$page->default_handlers = array();
- $handler = new stdClass;
+ $handler = new stdClass();
$handler->disabled = FALSE; /* Edit this to true to make a default handler disabled initially */
$handler->api_version = 1;
$handler->name = 'page_ctools_plugin_example_base_panel_context';
@@ -405,14 +402,14 @@ function ctools_plugin_example_default_page_manager_pages() {
$handler->handler = 'panel_context';
$handler->weight = 0;
$handler->conf = array(
- 'title' => 'Panel',
- 'no_blocks' => FALSE,
- 'css_id' => '',
- 'css' => '',
- 'contexts' => array(),
- 'relationships' => array(),
+ 'title' => 'Panel',
+ 'no_blocks' => FALSE,
+ 'css_id' => '',
+ 'css' => '',
+ 'contexts' => array(),
+ 'relationships' => array(),
);
- $display = new panels_display;
+ $display = new panels_display();
$display->layout = 'onecol';
$display->layout_settings = array();
$display->panel_settings = array();
@@ -421,7 +418,7 @@ function ctools_plugin_example_default_page_manager_pages() {
$display->hide_title = FALSE;
$display->content = array();
$display->panels = array();
- $pane = new stdClass;
+ $pane = new stdClass();
$pane->pid = 'new-1';
$pane->panel = 'middle';
$pane->type = 'custom';
@@ -443,9 +440,8 @@ function ctools_plugin_example_default_page_manager_pages() {
$display->panels['middle'][0] = 'new-1';
$handler->conf['display'] = $display;
$page->default_handlers[$handler->name] = $handler;
- // end exported panel.
-
+ // End exported panel.
$pages['base_page'] = $page;
return $pages;
-}
\ No newline at end of file
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/access/arg_length.inc b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/access/arg_length.inc
index 2a09eea1..3b5d8636 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/access/arg_length.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/access/arg_length.inc
@@ -59,7 +59,8 @@ function ctools_plugin_example_arg_length_ctools_access_check($conf, $context) {
*/
function ctools_plugin_example_arg_length_ctools_access_summary($conf, $context) {
return t('Simpletext argument must be !comp @length characters',
- array('!comp' => $conf['greater_than'] ? 'greater than' : 'less than or equal to',
- '@length' => $conf['arg_length']));
+ array(
+ '!comp' => $conf['greater_than'] ? 'greater than' : 'less than or equal to',
+ '@length' => $conf['arg_length'],
+ ));
}
-
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/access/example_role.inc b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/access/example_role.inc
index bbe364c1..75721e8b 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/access/example_role.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/access/example_role.inc
@@ -4,7 +4,7 @@
* @file
* Plugin to provide access control based upon role membership.
* This is directly from the ctools module, but serves as a good
- * example of an access plugin
+ * example of an access plugin.
*/
/**
@@ -73,4 +73,3 @@ function ctools_plugin_example_example_role_ctools_access_summary($conf, $contex
}
return format_plural(count($names), '@identifier must have role "@roles"', '@identifier can be one of "@roles"', array('@roles' => implode(', ', $names), '@identifier' => $context->identifier));
}
-
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/arguments/simplecontext_arg.inc b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/arguments/simplecontext_arg.inc
index 51c7c601..7fb732c6 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/arguments/simplecontext_arg.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/arguments/simplecontext_arg.inc
@@ -2,7 +2,6 @@
/**
* @file
- *
* Sample plugin to provide an argument handler for a simplecontext.
*
* Given any argument to the page, simplecontext will get it
@@ -18,14 +17,12 @@
*/
$plugin = array(
'title' => t("Simplecontext arg"),
- // keyword to use for %substitution
+ // Keyword to use for %substitution.
'keyword' => 'simplecontext',
'description' => t('Creates a "simplecontext" from the arg.'),
'context' => 'simplecontext_arg_context',
- // 'settings form' => 'simplecontext_arg_settings_form',
-
// placeholder_form is used in panels preview, for example, so we can
- // preview without getting the arg from a URL
+ // preview without getting the arg from a URL.
'placeholder form' => array(
'#type' => 'textfield',
'#description' => t('Enter the simplecontext arg'),
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/content_types/no_context_content_type.inc b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/content_types/no_context_content_type.inc
index 3c02ab84..48ce0f5c 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/content_types/no_context_content_type.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/content_types/no_context_content_type.inc
@@ -5,7 +5,6 @@
* "No context" sample content type. It operates with no context at all. It would
* be basically the same as a 'custom content' block, but it's not even that
* sophisticated.
- *
*/
/**
@@ -33,7 +32,7 @@ $plugin = array(
'icon' => 'icon_example.png',
'category' => array(t('CTools Examples'), -9),
- // this example does not provide 'admin info', which would populate the
+ // This example does not provide 'admin info', which would populate the
// panels builder page preview.
);
@@ -56,7 +55,7 @@ function no_context_content_type_render($subtype, $conf, $args, $context) {
$ctools_help = theme('advanced_help_topic', array('module' => 'ctools', 'topic' => 'plugins', 'type' => 'title'));
$ctools_plugin_example_help = theme('advanced_help_topic', array('module' => 'ctools_plugin_example', 'topic' => 'Chaos-Tools--CTools--Plugin-Examples', 'type' => 'title'));
- // The title actually used in rendering
+ // The title actually used in rendering.
$block->title = check_plain("No-context content type");
$block->content = t("
Welcome to the CTools Plugin Example demonstration content type.
@@ -84,7 +83,6 @@ function no_context_content_type_render($subtype, $conf, $args, $context) {
* Note that if we had not provided an entry for this in hook_content_types,
* this could have had the default name
* ctools_plugin_example_no_context_content_type_edit_form.
- *
*/
function no_context_content_type_edit_form($form, &$form_state) {
$conf = $form_state['conf'];
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/content_types/relcontext_content_type.inc b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/content_types/relcontext_content_type.inc
index bf54dce6..ced64117 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/content_types/relcontext_content_type.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/content_types/relcontext_content_type.inc
@@ -1,6 +1,5 @@
array(t('CTools Examples'), -9),
'edit form' => 'relcontext_edit_form',
- // this example does not provide 'admin info', which would populate the
+ // This example does not provide 'admin info', which would populate the
// panels builder page preview.
-
);
/**
@@ -60,7 +58,7 @@ function relcontext_content_type_render($subtype, $conf, $args, $context) {
In our case, the configuration form (\$conf) has just one field, 'config_item_1;
and it's configured with:
");
- if (!empty($conf)) {
+ if (!empty($conf)) {
$block->content .= '
' . var_export($conf['config_item_1'], TRUE) . '
';
}
if (!empty($context)) {
@@ -77,7 +75,6 @@ function relcontext_content_type_render($subtype, $conf, $args, $context) {
/**
* 'Edit' callback for the content type.
* This example just returns a form.
- *
*/
function relcontext_edit_form($form, &$form_state) {
$conf = $form_state['conf'];
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/content_types/simplecontext_content_type.inc b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/content_types/simplecontext_content_type.inc
index a308683c..e34fa18e 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/content_types/simplecontext_content_type.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/content_types/simplecontext_content_type.inc
@@ -1,6 +1,5 @@
'simplecontext_content_type_edit_form',
'admin title' => 'ctools_plugin_example_simplecontext_content_type_admin_title',
- // presents a block which is used in the preview of the data.
+ // Presents a block which is used in the preview of the data.
// Pn Panels this is the preview pane shown on the panels building page.
'admin info' => 'ctools_plugin_example_simplecontext_content_type_admin_info',
'category' => array(t('CTools Examples'), -9),
@@ -103,7 +101,6 @@ function simplecontext_content_type_render($subtype, $conf, $args, $context) {
/**
* 'Edit' callback for the content type.
* This example just returns a form.
- *
*/
function simplecontext_content_type_edit_form($form, &$form_state) {
$conf = $form_state['conf'];
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/contexts/relcontext.inc b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/contexts/relcontext.inc
index 0c7ef113..61e25db0 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/contexts/relcontext.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/contexts/relcontext.inc
@@ -80,4 +80,3 @@ function relcontext_settings_form($conf, $external = FALSE) {
);
return $form;
}
-
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/contexts/simplecontext.inc b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/contexts/simplecontext.inc
index e19a8422..0ee4658d 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/contexts/simplecontext.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/contexts/simplecontext.inc
@@ -1,10 +1,8 @@
t("Simplecontext"),
'description' => t('A single "simplecontext" context, or data element.'),
- 'context' => 'ctools_plugin_example_context_create_simplecontext', // func to create context
+// Func to create context.
+ 'context' => 'ctools_plugin_example_context_create_simplecontext',
'context name' => 'simplecontext',
'settings form' => 'simplecontext_settings_form',
'keyword' => 'simplecontext',
@@ -69,7 +68,7 @@ function ctools_plugin_example_context_create_simplecontext($empty, $data = NULL
// This is used for keyword.
$context->title = $data;
$context->argument = $data;
- // Make up a bogus context
+ // Make up a bogus context.
$context->data = new stdClass();
$context->data->item1 = t("Item1");
$context->data->item2 = t("Item2");
@@ -102,8 +101,6 @@ function simplecontext_settings_form($conf, $external = FALSE) {
return $form;
}
-
-
/**
* Provide a list of sub-keywords.
*
@@ -125,10 +122,11 @@ function simplecontext_convert($context, $type) {
switch ($type) {
case 'item1':
return $context->data->item1;
+
case 'item2':
return $context->data->item2;
+
case 'description':
return $context->data->description;
}
}
-
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/panels.pages.inc b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/panels.pages.inc
index d3022af7..25422cfa 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/panels.pages.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/panels.pages.inc
@@ -19,24 +19,24 @@ function ctools_plugin_example_default_panel_pages() {
$page->load_flags = 1;
$page->css_id = '';
$page->arguments = array(
- 0 =>
+ 0 =>
array(
- 'name' => 'simplecontext_arg',
- 'id' => 1,
- 'default' => '404',
- 'title' => '',
- 'identifier' => 'Simplecontext arg',
- 'keyword' => 'simplecontext',
+ 'name' => 'simplecontext_arg',
+ 'id' => 1,
+ 'default' => '404',
+ 'title' => '',
+ 'identifier' => 'Simplecontext arg',
+ 'keyword' => 'simplecontext',
),
);
$page->relationships = array(
- 0 =>
+ 0 =>
array(
- 'context' => 'argument_simplecontext_arg_1',
- 'name' => 'relcontext_from_simplecontext',
- 'id' => 1,
- 'identifier' => 'Relcontext from Simplecontext',
- 'keyword' => 'relcontext',
+ 'context' => 'argument_simplecontext_arg_1',
+ 'name' => 'relcontext_from_simplecontext',
+ 'id' => 1,
+ 'identifier' => 'Relcontext from Simplecontext',
+ 'keyword' => 'relcontext',
),
);
$page->no_blocks = '0';
@@ -58,14 +58,14 @@ function ctools_plugin_example_default_panel_pages() {
$pane->subtype = 'custom';
$pane->access = array();
$pane->configuration = array(
- 'style' => 'default',
- 'override_title' => 0,
- 'override_title_text' => '',
- 'css_id' => '',
- 'css_class' => '',
- 'title' => '"No Context Item"',
- 'body' => 'The "no context item" content type is here to demonstrate that you can create a content_type that does not require a context. This is probably the same as just creating a custom php block on the fly, and might serve the same purpose.',
- 'format' => '1',
+ 'style' => 'default',
+ 'override_title' => 0,
+ 'override_title_text' => '',
+ 'css_id' => '',
+ 'css_class' => '',
+ 'title' => '"No Context Item"',
+ 'body' => 'The "no context item" content type is here to demonstrate that you can create a content_type that does not require a context. This is probably the same as just creating a custom php block on the fly, and might serve the same purpose.',
+ 'format' => '1',
);
$pane->cache = array();
$display->content['new-1'] = $pane;
@@ -78,14 +78,14 @@ function ctools_plugin_example_default_panel_pages() {
$pane->subtype = 'description';
$pane->access = array();
$pane->configuration = array(
- 'style' => 'default',
- 'override_title' => 0,
- 'override_title_text' => '',
- 'css_id' => '',
- 'css_class' => '',
- 'item1' => 'one',
- 'item2' => 'two',
- 'item3' => 'three',
+ 'style' => 'default',
+ 'override_title' => 0,
+ 'override_title_text' => '',
+ 'css_id' => '',
+ 'css_class' => '',
+ 'item1' => 'one',
+ 'item2' => 'two',
+ 'item3' => 'three',
);
$pane->cache = array();
$display->content['new-2'] = $pane;
@@ -98,16 +98,16 @@ function ctools_plugin_example_default_panel_pages() {
$pane->subtype = 'custom';
$pane->access = array();
$pane->configuration = array(
- 'style' => 'default',
- 'override_title' => 0,
- 'override_title_text' => '',
- 'css_id' => '',
- 'css_class' => '',
- 'title' => 'Simplecontext',
- 'body' => 'The "Simplecontext" content and content type demonstrate a very basic context and how to display it.
+ 'style' => 'default',
+ 'override_title' => 0,
+ 'override_title_text' => '',
+ 'css_id' => '',
+ 'css_class' => '',
+ 'title' => 'Simplecontext',
+ 'body' => 'The "Simplecontext" content and content type demonstrate a very basic context and how to display it.
Simplecontext includes configuration, so it can get info from the config. It can also get its information to run from a simplecontext context, generated either from an arg to the panels page or via explicitly adding a context to the page.',
- 'format' => '1',
+ 'format' => '1',
);
$pane->cache = array();
$display->content['new-3'] = $pane;
@@ -119,17 +119,17 @@ function ctools_plugin_example_default_panel_pages() {
$pane->shown = '1';
$pane->subtype = 'description';
$pane->access = array(
- 0 => '2',
- 1 => '4',
+ 0 => '2',
+ 1 => '4',
);
$pane->configuration = array(
- 'context' => 'argument_simplecontext_arg_1',
- 'style' => 'default',
- 'override_title' => 0,
- 'override_title_text' => '',
- 'css_id' => '',
- 'css_class' => '',
- 'config_item_1' => 'simplecontext called from arg',
+ 'context' => 'argument_simplecontext_arg_1',
+ 'style' => 'default',
+ 'override_title' => 0,
+ 'override_title_text' => '',
+ 'css_id' => '',
+ 'css_class' => '',
+ 'config_item_1' => 'simplecontext called from arg',
);
$pane->cache = array();
$display->content['new-4'] = $pane;
@@ -142,14 +142,14 @@ function ctools_plugin_example_default_panel_pages() {
$pane->subtype = 'custom';
$pane->access = array();
$pane->configuration = array(
- 'style' => 'default',
- 'override_title' => 0,
- 'override_title_text' => '',
- 'css_id' => '',
- 'css_class' => '',
- 'title' => 'Relcontext',
- 'body' => 'The relcontext content_type gets its data from a relcontext, which is an example of a relationship. This panel should be run with an argument like "/xxx", which allows the simplecontext to get its context, and then the relcontext is configured in this panel to get (create) its data from the simplecontext.',
- 'format' => '1',
+ 'style' => 'default',
+ 'override_title' => 0,
+ 'override_title_text' => '',
+ 'css_id' => '',
+ 'css_class' => '',
+ 'title' => 'Relcontext',
+ 'body' => 'The relcontext content_type gets its data from a relcontext, which is an example of a relationship. This panel should be run with an argument like "/xxx", which allows the simplecontext to get its context, and then the relcontext is configured in this panel to get (create) its data from the simplecontext.',
+ 'format' => '1',
);
$pane->cache = array();
$display->content['new-5'] = $pane;
@@ -162,13 +162,13 @@ function ctools_plugin_example_default_panel_pages() {
$pane->subtype = 'description';
$pane->access = array();
$pane->configuration = array(
- 'context' => 'relationship_relcontext_from_simplecontext_1',
- 'style' => 'default',
- 'override_title' => 0,
- 'override_title_text' => '',
- 'css_id' => '',
- 'css_class' => '',
- 'config_item_1' => 'default1',
+ 'context' => 'relationship_relcontext_from_simplecontext_1',
+ 'style' => 'default',
+ 'override_title' => 0,
+ 'override_title_text' => '',
+ 'css_id' => '',
+ 'css_class' => '',
+ 'config_item_1' => 'default1',
);
$pane->cache = array();
$display->content['new-6'] = $pane;
@@ -181,13 +181,13 @@ function ctools_plugin_example_default_panel_pages() {
$pane->subtype = 'custom_php';
$pane->access = array();
$pane->configuration = array(
- 'style' => 'default',
- 'override_title' => 0,
- 'override_title_text' => '',
- 'css_id' => '',
- 'css_class' => '',
- 'title' => '',
- 'body' => '$arg = arg(1);
+ 'style' => 'default',
+ 'override_title' => 0,
+ 'override_title_text' => '',
+ 'css_id' => '',
+ 'css_class' => '',
+ 'title' => '',
+ 'body' => '$arg = arg(1);
$arg0 = arg(0);
if (!$arg) {
$block->content = <<displays = array();
$pages['ctools_plugin_example'] = $page;
-
return $pages;
}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/relationships/relcontext_from_simplecontext.inc b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/relationships/relcontext_from_simplecontext.inc
index 62246210..087d5ecf 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/relationships/relcontext_from_simplecontext.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/ctools_plugin_example/plugins/relationships/relcontext_from_simplecontext.inc
@@ -1,9 +1,7 @@
'Space separated list of exportables you want to view.',
),
'options' => array(
- 'indent' => 'The string to use for indentation when dispalying the exportable export code. Defaults to \'\'.',
+ 'indent' => 'The string to use for indentation when displaying the exportable export code. Defaults to \'\'.',
'no-colour' => 'Remove any colour formatting from export string output. Ideal if you are sending the output of this command to a file.',
'module' => $module_text,
'all' => $all_text,
@@ -140,13 +140,14 @@ function ctools_drush_help($section) {
switch ($section) {
case 'meta:ctools:title':
return dt('CTools commands');
+
case 'meta:entity:summary':
return dt('CTools drush commands.');
}
}
/**
- * Drush callback: export
+ * Drush callback: export.
*/
function ctools_drush_export($module = 'foo') {
$error = FALSE;
@@ -338,7 +339,7 @@ function _ctools_drush_selection_screen(array $tables = array()) {
$build[$table_choice]['count'] = count($multi_select);
$selections[$table_choice] = array();
foreach ($multi_select as $key) {
- $selections[$table_choice][$key] = $key;
+ $selections[$table_choice][$key] = $key;
}
}
}
@@ -445,6 +446,7 @@ function ctools_drush_export_info() {
}
}
}
+
/**
* Drush callback: Acts as the hub for all op commands to keep
* all arg handling etc in one place.
@@ -457,17 +459,20 @@ function ctools_drush_export_op_command() {
switch ($command['command']) {
case 'ctools-export-view':
$op = 'view';
- break;
+ break;
+
case 'ctools-export-revert':
// Revert is same as deleting. As any objects in the db are deleted.
$op = 'delete';
- break;
+ break;
+
case 'ctools-export-enable':
$op = 'enable';
- break;
+ break;
+
case 'ctools-export-disable':
$op = 'disable';
- break;
+ break;
}
if (!$op) {
@@ -475,7 +480,7 @@ function ctools_drush_export_op_command() {
}
if (drush_get_option('all', FALSE)) {
- $info = _ctools_drush_export_info('', TRUE);
+ $info = _ctools_drush_export_info(array(), TRUE);
$exportable_info = $info['exportables'];
$all = drush_confirm(dt('Are you sure you would like to !op all exportables on the system?',
@@ -512,7 +517,6 @@ function ctools_drush_export_op_command() {
* @param $op
* @param $table_name
* @param $exportables
- *
*/
function ctools_drush_export_op($op = '', $table_name = '', $exportables = NULL) {
$objects = ctools_export_crud_load_multiple($table_name, array_keys($exportables));
@@ -538,7 +542,7 @@ function ctools_drush_export_op($op = '', $table_name = '', $exportables = NULL)
* @param $object_names
*
* @return
- * Array of exportable objects (filtered if necessary, by name etc..) or FALSE if not.
+ * Array of exportable objects (filtered if necessary, by name etc..) or FALSE if not.
*/
function _ctools_drush_export_op_command_logic($op = '', $table_name = NULL, array $object_names = array()) {
if (!$table_name) {
@@ -644,7 +648,7 @@ function _ctools_drush_export_info(array $table_names = array(), $load = FALSE)
return array('exportables' => $exportables, 'schemas' => $schemas);
}
-/*
+/**
* View a single object.
*
* @param $table_name
@@ -662,7 +666,7 @@ function _ctools_drush_export_view($table_name, $object) {
}
}
-/*
+/**
* Revert a single object.
*
* @param $table_name
@@ -681,7 +685,7 @@ function _ctools_drush_export_delete($table_name, $object) {
}
}
-/*
+/**
* Enable a single object.
*
* @param $table_name
@@ -701,7 +705,7 @@ function _ctools_drush_export_enable($table_name, $object) {
}
}
-/*
+/**
* Disable a single object.
*
* @param $table_name
@@ -723,9 +727,9 @@ function _ctools_drush_export_disable($table_name, $object) {
/**
* Filter a nested array of exportables by export module.
*
- * @param $exportables array
+ * @param array $exportables
* Passed by reference. A nested array of exportables, keyed by table name.
- * @param $export_module string
+ * @param string $export_module
* The name of the export module providing the exportable.
*/
function _ctools_drush_export_module_filter($exportables, $export_module) {
@@ -778,7 +782,7 @@ function _ctools_drush_object_is_disabled($object) {
/**
* Determine if an object is enabled.
*
- * @see _ctools_drush_object_is_disabled.
+ * @see _ctools_drush_object_is_disabled()
*/
function _ctools_drush_object_is_enabled($object) {
return (empty($object->disabled)) ? TRUE : FALSE;
@@ -835,7 +839,7 @@ function _ctools_drush_object_is_not_code_only($object) {
* Array of exportables to count.
*
* @return
- * Array of count data containing the following:
+ * Array of count data containing the following:
* 'total' - A total count of all exportables.
* 'exportables' - An array of exportable counts per table.
*/
@@ -867,26 +871,32 @@ function _ctools_drush_filter_exportables($exportables, $filter) {
// Show enabled exportables only.
case 'enabled':
$eval = '_ctools_drush_object_is_disabled';
- break;
+ break;
+
// Show disabled exportables only.
case 'disabled':
$eval = '_ctools_drush_object_is_enabled';
- break;
+ break;
+
// Show overridden exportables only.
case 'overridden':
$eval = '_ctools_drush_object_is_not_overridden';
- break;
+ break;
+
// Show database only exportables.
case 'database':
$eval = '_ctools_drush_object_is_not_db_only';
- break;
+ break;
+
// Show code only exportables.
case 'code':
$eval = '_ctools_drush_object_is_not_code_only';
- break;
+ break;
+
// Do nothing.
case 'all':
break;
+
default:
drush_log(dt('Invalid filter option. Available options are: enabled, disabled, overridden, database, and code.'), 'error');
return;
@@ -983,33 +993,42 @@ class shellColours {
'light_gray' => '47',
);
+ /**
+ *
+ */
private function __construct() {}
- // Returns coloured string
+ /**
+ * Returns coloured string.
+ */
public static function getColouredOutput($string, $foreground_colour = NULL, $background_colour = NULL) {
$coloured_string = "";
- // Check if given foreground colour found
+ // Check if given foreground colour found.
if ($foreground_colour) {
$coloured_string .= "\033[" . self::$foreground_colours[$foreground_colour] . "m";
}
- // Check if given background colour found
+ // Check if given background colour found.
if ($background_colour) {
$coloured_string .= "\033[" . self::$background_colours[$background_colour] . "m";
}
- // Add string and end colouring
- $coloured_string .= $string . "\033[0m";
+ // Add string and end colouring.
+ $coloured_string .= $string . "\033[0m";
return $coloured_string;
}
- // Returns all foreground colour names
+ /**
+ * Returns all foreground colour names.
+ */
public static function getForegroundColours() {
return array_keys(self::$foreground_colours);
}
- // Returns all background colour names
+ /**
+ * Returns all background colour names.
+ */
public static function getBackgroundColours() {
return array_keys(self::$background_colours);
}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/help/export.html b/profiles/commerce_kickstart/modules/contrib/ctools/help/export.html
index ce24cad9..573c98a6 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/help/export.html
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/help/export.html
@@ -154,7 +154,7 @@
The export section of the schema file
Bulk export callback to provide a list of exportable objects to be chosen for bulk exporting. Defaults to $module . '_' . $table . '_list' if the function exists. If it is not, a default listing function will be provided that will make a best effort to list the titles. See ctools_export_default_list().
to hook code callback
-
Function used to generate an export for the bulk export process. This is only necessary if the export is more complicated than simply listing the fields. Defaults to $module . '_' . $table . '_to_hook_code'.
+
Function used to generate an export for the bulk export process. This is only necessary if the export is more complicated than simply listing the fields. Defaults to $module . '_' . $table . '_to_hook_code'.
boolean
Explicitly indicate if a table field contains a boolean or not. The Schema API does not model the
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/help/modal.html b/profiles/commerce_kickstart/modules/contrib/ctools/help/modal.html
index ea823a0d..761fd2e3 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/help/modal.html
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/help/modal.html
@@ -82,7 +82,7 @@
Customizing the modal
modalSize: an array of data to control the sizing of the modal. It can contain:
type: Either fixed or scale. If fixed, the modal will always be a fixed size. If scale the modal will scale to a percentage of the browser window. Default: scale.
-
width: If fixed the width in pixels. If scale the percentage of the screen expressed as a number less than zero. (For 80 percent, use .8, for example). Default: .8
+
width: If fixed the width in pixels. If scale the percentage of the screen expressed as a number less than zero. (For 80 percent, use .8, for example). Default: .8
height: If fixed the height in pixels. If scale the percentage of the screen expressed as a number less than zero. (For 80 percent, use .8, for example). Default: .8
addWidth: Any additional width to add to the modal in pixels. Only useful if the type is scale. Default: 0
addHeight: Any additional height to add to the modal in pixels. Only useful if the type is scale. Default: 0
If 'cache' is TRUE, then this value specifies the cache table where the cached plugin information will be stored.
classes
Defaults to:array()
-
An array of class identifiers(i.e. plugin array keys) which a plugin of this type uses to provide classes to the CTools autoloader. For example, if classes is set to array('class'), then CTools will search each $plugin['class'] for a class to autoload. Depending of the plugin structure, a class identifier may be either:
+
An array of class identifiers(i.e. plugin array keys) which a plugin of this type uses to provide classes to the CTools autoloader. For example, if classes is set to array('class'), then CTools will search each $plugin['class'] for a class to autoload. Depending of the plugin structure, a class identifier may be either:
- a file name:
the file which holds the class with the name structure as: [filename].[class].php
@@ -35,6 +35,7 @@
Defining a plugin
if the class is in the same file as the $plugin
the plugin .inc file can have a different name than the class identifier
+
defaults
Defaults to:array()
An array of defaults that should be added to each plugin; this can be used to ensure that every plugin has the basic data necessary. These defaults will not ovewrite data supplied by the plugin. This could also be a function name, in which case the callback will be used to provide defaults. NOTE, however, that the callback-based approach is deprecated as it is redundant with the 'process' callback, and as such will be removed in later versions. Consequently, you should only use the array form for maximum cross-version compatibility.
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/action-links.theme.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/action-links.theme.inc
index 3a2398a1..f53f59c8 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/action-links.theme.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/action-links.theme.inc
@@ -1,4 +1,5 @@
' . $links . '';
-}
\ No newline at end of file
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/ajax.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/ajax.inc
index 96f5068f..4d72d0c6 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/ajax.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/ajax.inc
@@ -1,6 +1,10 @@
'attr',
- 'selector' => $selector,
- 'name' => $name,
- 'value' => $value,
- );
- }
+ 'command' => 'attr',
+ 'selector' => $selector,
+ 'name' => $name,
+ 'value' => $value,
+ );
+}
/**
* Force a client-side redirect.
@@ -154,4 +158,3 @@ function ctools_ajax_render_error($error = '') {
print ajax_render($commands);
exit;
}
-
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/cache.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/cache.inc
index 3918683b..67d97fa3 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/cache.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/cache.inc
@@ -2,7 +2,6 @@
/**
* @file
- *
* Plugins to handle cache-indirection.
*
* Simple plugin management to allow clients to more tightly control where
@@ -150,7 +149,7 @@ function ctools_cache_operation($mechanism, $key, $op, $object = NULL) {
*/
function ctools_cache_find_plugin($mechanism) {
if (strpos($mechanism, '::') !== FALSE) {
- // use explode(2) to ensure that the data can contain double
+ // Use explode(2) to ensure that the data can contain double
// colons, just in case.
list($name, $data) = explode('::', $mechanism, 2);
}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/cleanstring.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/cleanstring.inc
index 56b3e36f..11ffceff 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/cleanstring.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/cleanstring.inc
@@ -1,5 +1,4 @@
$length) {
- $string = drupal_substr($string, 0, $length + 1); // leave one more character
- if ($last_break = strrpos($string, $separator)) { // space exists AND is not on position 0
+ // Leave one more character.
+ $string = drupal_substr($string, 0, $length + 1);
+ // Space exists AND is not on position 0.
+ if ($last_break = strrpos($string, $separator)) {
$string = substr($string, 0, $last_break);
}
else {
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/collapsible.theme.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/collapsible.theme.inc
index f7bbbb37..d19efd8a 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/collapsible.theme.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/collapsible.theme.inc
@@ -76,4 +76,3 @@ function theme_ctools_collapsible_remembered($vars) {
return $output;
}
-
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/content.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/content.inc
index ae1c6073..49c35650 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/content.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/content.inc
@@ -86,7 +86,7 @@ function ctools_content_process(&$plugin, $info) {
/**
* Fetch metadata on a specific content_type plugin.
*
- * @param $content type
+ * @param mixed $content
* Name of a panel content type.
*
* @return
@@ -146,7 +146,7 @@ function ctools_content_get_subtypes($type) {
if (is_array($function)) {
$subtypes = $function;
}
- else if (function_exists($function)) {
+ elseif (function_exists($function)) {
// Cast to array to prevent errors from non-array returns.
$subtypes = (array) $function($plugin);
}
@@ -155,6 +155,11 @@ function ctools_content_get_subtypes($type) {
// Walk through the subtypes and ensure minimal settings are
// retained.
foreach ($subtypes as $id => $subtype) {
+ // Ensure that the 'subtype_id' value exists.
+ if (!isset($subtype['subtype_id'])) {
+ $subtypes[$id]['subtype_id'] = $id;
+ }
+
// Use exact name since this is a modify by reference.
ctools_content_prepare_subtype($subtypes[$id], $plugin);
}
@@ -202,6 +207,13 @@ function ctools_content_get_subtype($type, $subtype_id) {
}
if ($subtype) {
+ // Ensure that the 'subtype_id' value exists. This is also done in
+ // ctools_content_get_subtypes(), but it wouldn't be called if the plugin
+ // provides the subtype through its own function.
+ if (!isset($subtype['subtype_id'])) {
+ $subtype['subtype_id'] = $subtype_id;
+ }
+
ctools_content_prepare_subtype($subtype, $plugin);
}
return $subtype;
@@ -217,6 +229,7 @@ function ctools_content_prepare_subtype(&$subtype, $plugin) {
}
}
+ // Trigger hook_ctools_content_subtype_alter().
drupal_alter('ctools_content_subtype', $subtype, $plugin);
}
@@ -241,8 +254,8 @@ function ctools_content_prepare_subtype(&$subtype, $plugin) {
* Any incoming content, if this display is a wrapper.
*
* @return
- * The content as rendered by the plugin. This content should be an array
- * with the following possible keys:
+ * The content as rendered by the plugin, or NULL.
+ * This content should be an object with the following possible properties:
* - title: The safe to render title of the content.
* - title_heading: The title heading.
* - content: The safe to render HTML content.
@@ -294,7 +307,7 @@ function ctools_content_render($type, $subtype, $conf, $keywords = array(), $arg
$content->subtype = $subtype;
}
- // Override the title if configured to
+ // Override the title if configured to.
if (!empty($conf['override_title'])) {
// Give previous title as an available substitution here.
$keywords['%title'] = empty($content->title) ? '' : $content->title;
@@ -304,12 +317,12 @@ function ctools_content_render($type, $subtype, $conf, $keywords = array(), $arg
}
if (!empty($content->title)) {
- // Perform substitutions
+ // Perform substitutions.
if (!empty($keywords) || !empty($context)) {
$content->title = ctools_context_keyword_substitute($content->title, $keywords, $context);
}
- // Sterilize the title
+ // Sterilize the title.
$content->title = filter_xss_admin($content->title);
// If a link is specified, populate.
@@ -320,7 +333,7 @@ function ctools_content_render($type, $subtype, $conf, $keywords = array(), $arg
else {
$url = $content->title_link;
}
- // set defaults so we don't bring up notices
+ // Set defaults so we don't bring up notices.
$url += array('href' => '', 'attributes' => array(), 'query' => array(), 'fragment' => '', 'absolute' => NULL, 'html' => TRUE);
$content->title = l($content->title, $url['href'], $url);
}
@@ -342,7 +355,7 @@ function ctools_content_editable($type, $subtype, $conf) {
}
$function = FALSE;
-
+
if (!empty($subtype['check editable'])) {
$function = ctools_plugin_get_function($subtype, 'check editable');
}
@@ -373,7 +386,7 @@ function ctools_content_admin_title($type, $subtype, $conf, $context = NULL) {
if (is_array($type)) {
$plugin = $type;
}
- else if (is_string($type)) {
+ elseif (is_string($type)) {
$plugin = ctools_get_content_type($type);
}
else {
@@ -391,10 +404,10 @@ function ctools_content_admin_title($type, $subtype, $conf, $context = NULL) {
return $function($subtype, $conf, $pane_context);
}
- else if (isset($plugin['admin title'])) {
+ elseif (isset($plugin['admin title'])) {
return $plugin['admin title'];
}
- else if (isset($plugin['title'])) {
+ elseif (isset($plugin['title'])) {
return $plugin['title'];
}
}
@@ -429,7 +442,7 @@ function ctools_content_get_defaults($plugin, $subtype) {
if (isset($plugin['defaults'])) {
$defaults = $plugin['defaults'];
}
- else if (isset($subtype['defaults'])) {
+ elseif (isset($subtype['defaults'])) {
$defaults = $subtype['defaults'];
}
if (isset($defaults)) {
@@ -438,7 +451,7 @@ function ctools_content_get_defaults($plugin, $subtype) {
return $return;
}
}
- else if (is_array($defaults)) {
+ elseif (is_array($defaults)) {
return $defaults;
}
}
@@ -472,7 +485,7 @@ function ctools_content_admin_info($type, $subtype, $conf, $context = NULL) {
if (empty($output) || !is_object($output)) {
$output = new stdClass();
- // replace the _ with " " for a better output
+ // Replace the _ with " " for a better output.
$subtype = check_plain(str_replace("_", " ", $subtype));
$output->title = $subtype;
$output->content = t('No info available.');
@@ -481,7 +494,7 @@ function ctools_content_admin_info($type, $subtype, $conf, $context = NULL) {
}
/**
- * Add the default FAPI elements to the content type configuration form
+ * Add the default FAPI elements to the content type configuration form.
*/
function ctools_content_configure_form_defaults($form, &$form_state) {
$plugin = $form_state['plugin'];
@@ -598,7 +611,7 @@ function ctools_content_form($op, $form_info, &$form_state, $plugin, $subtype_na
if (!empty($subtype['add form'])) {
_ctools_content_create_form_info($form_info, $subtype['add form'], $subtype, $subtype, $op);
}
- else if (!empty($plugin['add form'])) {
+ elseif (!empty($plugin['add form'])) {
_ctools_content_create_form_info($form_info, $plugin['add form'], $plugin, $subtype, $op);
}
}
@@ -608,7 +621,7 @@ function ctools_content_form($op, $form_info, &$form_state, $plugin, $subtype_na
if (!empty($subtype['edit form'])) {
_ctools_content_create_form_info($form_info, $subtype['edit form'], $subtype, $subtype, $op);
}
- else if (!empty($plugin['edit form'])) {
+ elseif (!empty($plugin['edit form'])) {
_ctools_content_create_form_info($form_info, $plugin['edit form'], $plugin, $subtype, $op);
}
}
@@ -627,7 +640,7 @@ function _ctools_content_create_form_info(&$form_info, $info, $plugin, $subtype,
if (empty($subtype['title'])) {
$title = t('Configure');
}
- else if ($op == 'add') {
+ elseif ($op == 'add') {
$title = t('Configure new !subtype_title', array('!subtype_title' => $subtype['title']));
}
else {
@@ -642,7 +655,7 @@ function _ctools_content_create_form_info(&$form_info, $info, $plugin, $subtype,
),
);
}
- else if (is_array($info)) {
+ elseif (is_array($info)) {
$form_info['order'] = array();
$form_info['forms'] = array();
$count = 0;
@@ -693,7 +706,7 @@ function ctools_content_get_available_types($contexts = NULL, $has_content = FAL
foreach ($plugins as $id => $plugin) {
foreach (ctools_content_get_subtypes($plugin) as $subtype_id => $subtype) {
- // exclude items that require content if we're saying we don't
+ // Exclude items that require content if we're saying we don't
// provide it.
if (!empty($subtype['requires content']) && !$has_content) {
continue;
@@ -733,7 +746,6 @@ function ctools_content_get_available_types($contexts = NULL, $has_content = FAL
* Get an array of all content types that can be fed into the
* display editor for the add content list, regardless of
* availability.
- *
*/
function ctools_content_get_all_types() {
$plugins = ctools_get_content_types();
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/content.menu.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/content.menu.inc
index f7f93406..4e1c2f08 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/content.menu.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/content.menu.inc
@@ -62,9 +62,8 @@ function ctools_content_autocomplete_entity($entity_type, $string = '') {
}
}
-/*
- * Use well known/tested entity reference code to build our search query
- * From EntityReference_SelectionHandler_Generic class
+/**
+ * Use EntityReference_SelectionHandler_Generic class to build our search query.
*/
function _ctools_buildQuery($entity_type, $entity_info, $match = NULL, $match_operator = 'CONTAINS') {
$base_table = $entity_info['base table'];
@@ -125,7 +124,7 @@ function _ctools_getReferencableEntities($entity_type, $entity_info, $match = NU
global $user;
$account = $user;
$options = array();
- // We're an entity ID, return the id
+ // We're an entity ID, return the id.
if (is_numeric($match) && $match_operator == '=') {
if ($entity = array_shift(entity_load($entity_type, array($match)))) {
if (isset($entity_info['access callback']) && function_exists($entity_info['access callback'])) {
@@ -143,10 +142,10 @@ function _ctools_getReferencableEntities($entity_type, $entity_info, $match = NU
// If you don't have access, or an access callback or a valid entity, just
// Return back the Entity ID.
return array(
- $match => array(
+ $match => array(
'label' => $match,
'bundle' => NULL,
- ),
+ ),
);
}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/content.plugin-type.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/content.plugin-type.inc
index a0debc3e..0364a927 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/content.plugin-type.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/content.plugin-type.inc
@@ -14,4 +14,4 @@ function ctools_content_plugin_type(&$items) {
'path' => drupal_get_path('module', 'ctools') . '/includes',
),
);
-}
\ No newline at end of file
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/context-access-admin.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/context-access-admin.inc
index 76643cf6..d8c4f3b1 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/context-access-admin.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/context-access-admin.inc
@@ -245,10 +245,10 @@ function ctools_access_admin_form_submit($form, &$form_state) {
// --------------------------------------------------------------------------
// AJAX menu entry points.
-
/**
* AJAX callback to add a new access test to the list.
*/
+
function ctools_access_ajax_add($fragment = NULL, $name = NULL) {
ctools_include('ajax');
ctools_include('modal');
@@ -263,7 +263,7 @@ function ctools_access_ajax_add($fragment = NULL, $name = NULL) {
ctools_ajax_render_error();
}
- // Separate the fragment into 'module' and 'argument'
+ // Separate the fragment into 'module' and 'argument'.
if (strpos($fragment, '-') === FALSE) {
$module = $fragment;
$argument = NULL;
@@ -279,7 +279,7 @@ function ctools_access_ajax_add($fragment = NULL, $name = NULL) {
list($access, $contexts) = $function($argument);
- // Make sure we have the logged in user context
+ // Make sure we have the logged in user context.
if (!isset($contexts['logged-in-user'])) {
$contexts['logged-in-user'] = ctools_access_get_loggedin_context();
}
@@ -306,6 +306,9 @@ function ctools_access_ajax_add($fragment = NULL, $name = NULL) {
);
$output = ctools_modal_form_wrapper('ctools_access_ajax_edit_item', $form_state);
+ $access = $form_state['access'];
+ $access['plugins'][$id] = $form_state['test'];
+
if (!isset($output[0])) {
$function = $module . '_ctools_access_set';
if (function_exists($function)) {
@@ -333,7 +336,7 @@ function ctools_access_ajax_edit($fragment = NULL, $id = NULL) {
ctools_ajax_render_error();
}
- // Separate the fragment into 'module' and 'argument'
+ // Separate the fragment into 'module' and 'argument'.
if (strpos($fragment, '-') === FALSE) {
$module = $fragment;
$argument = NULL;
@@ -353,7 +356,7 @@ function ctools_access_ajax_edit($fragment = NULL, $id = NULL) {
ctools_ajax_render_error();
}
- // Make sure we have the logged in user context
+ // Make sure we have the logged in user context.
if (!isset($contexts['logged-in-user'])) {
$contexts['logged-in-user'] = ctools_access_get_loggedin_context();
}
@@ -367,12 +370,14 @@ function ctools_access_ajax_edit($fragment = NULL, $id = NULL) {
'contexts' => $contexts,
'title' => t('Edit criteria'),
'ajax' => TRUE,
- 'ajax' => TRUE,
'modal' => TRUE,
'modal return' => TRUE,
);
$output = ctools_modal_form_wrapper('ctools_access_ajax_edit_item', $form_state);
+ $access = $form_state['access'];
+ $access['plugins'][$id] = $form_state['test'];
+
if (!isset($output[0])) {
$function = $module . '_ctools_access_set';
if (function_exists($function)) {
@@ -452,7 +457,7 @@ function ctools_access_ajax_delete($fragment = NULL, $id = NULL) {
ajax_render_error();
}
- // Separate the fragment into 'module' and 'argument'
+ // Separate the fragment into 'module' and 'argument'.
if (strpos($fragment, '-') === FALSE) {
$module = $fragment;
$argument = NULL;
@@ -472,7 +477,7 @@ function ctools_access_ajax_delete($fragment = NULL, $id = NULL) {
unset($access['plugins'][$id]);
}
- // re-cache
+ // re-cache.
$function = $module . '_ctools_access_set';
if (function_exists($function)) {
$function($argument, $access);
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/context-task-handler.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/context-task-handler.inc
index 21ceea5d..b0f9474d 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/context-task-handler.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/context-task-handler.inc
@@ -31,6 +31,7 @@
* If TRUE then this renderer owns the page and can use theme('page')
* for no blocks; if false, output is returned regardless of any no
* blocks settings.
+ *
* @return
* Either the output or NULL if there was output, FALSE if no handler
* accepted the task. If $page is FALSE then the $info block is returned instead.
@@ -84,7 +85,7 @@ function ctools_context_handler_get_render_handler($task, $subtask, $handlers, $
*/
function ctools_context_handler_default_test($handler, $base_contexts, $args) {
ctools_include('context');
- // Add my contexts
+ // Add my contexts.
$contexts = ctools_context_handler_get_handler_contexts($base_contexts, $handler);
// Test.
@@ -128,7 +129,7 @@ function ctools_context_handler_render_handler($task, $subtask, $handler, $conte
'contexts' => $contexts,
'task' => $task,
'subtask' => $subtask,
- 'handler' => $handler
+ 'handler' => $handler,
);
drupal_alter('ctools_render', $info, $page, $context);
@@ -141,12 +142,15 @@ function ctools_context_handler_render_handler($task, $subtask, $handler, $conte
switch ($info['response code']) {
case 403:
return MENU_ACCESS_DENIED;
+
case 404:
return MENU_NOT_FOUND;
+
case 410:
drupal_add_http_header('Status', '410 Gone');
drupal_exit();
break;
+
case 301:
case 302:
case 303:
@@ -162,7 +166,7 @@ function ctools_context_handler_render_handler($task, $subtask, $handler, $conte
'fragment' => $info['fragment'],
);
drupal_goto($info['destination'], $options, $info['response code']);
- // @todo -- should other response codes be supported here?
+ // @todo -- should other response codes be supported here?
}
}
@@ -241,7 +245,7 @@ function ctools_task_handler_default_contextual_link($handler, $plugin, $context
if (is_array($plugin['tab operation'])) {
$trail = $plugin['tab operation'];
}
- else if (function_exists($plugin['tab operation'])) {
+ elseif (function_exists($plugin['tab operation'])) {
$trail = $plugin['tab operation']($handler, $contexts, $args);
}
}
@@ -251,7 +255,8 @@ function ctools_task_handler_default_contextual_link($handler, $plugin, $context
'href' => $path,
'title' => $title,
'query' => drupal_get_destination(),
- ));
+ ),
+ );
return $links;
}
@@ -259,7 +264,12 @@ function ctools_task_handler_default_contextual_link($handler, $plugin, $context
/**
* Called to execute actions that should happen before a handler is rendered.
*/
-function ctools_context_handler_pre_render($handler, $contexts, $args) { }
+function ctools_context_handler_pre_render($handler, $contexts, $args) {
+ foreach (module_implements('ctools_context_handler_pre_render') as $module) {
+ $function = $module . '_ctools_context_handler_pre_render';
+ $function($handler, $contexts, $args);
+ }
+}
/**
* Compare arguments to contexts for selection purposes.
@@ -320,7 +330,6 @@ function ctools_context_handler_summary($task, $subtask, $handler) {
// the task handler, for example) but sometimes we need them separately
// (when a task has contexts loaded and is trying out the task handlers,
// for example). Therefore there are two paths we can take to getting contexts.
-
/**
* Load the contexts for a task, using arguments.
*
@@ -368,7 +377,7 @@ function ctools_context_handler_get_all_contexts($task, $subtask, $handler) {
* expects things in a certain, kind of clunky format.
*/
function ctools_context_handler_get_handler_object($handler) {
- $object = new stdClass;
+ $object = new stdClass();
$object->name = $handler->name;
$object->contexts = isset($handler->conf['contexts']) ? $handler->conf['contexts'] : array();
$object->relationships = isset($handler->conf['relationships']) ? $handler->conf['relationships'] : array();
@@ -382,7 +391,7 @@ function ctools_context_handler_get_handler_object($handler) {
* arguments from the task.
*/
function ctools_context_handler_get_task_object($task, $subtask, $handler) {
- $object = new stdClass;
+ $object = new stdClass();
$object->name = !empty($handler->name) ? $handler->name : 'temp';
$object->base_contexts = ctools_context_handler_get_base_contexts($task, $subtask, TRUE);
$object->arguments = ctools_context_handler_get_task_arguments($task, $subtask);
@@ -456,7 +465,7 @@ function ctools_context_handler_edit_criteria($form, &$form_state) {
ctools_modal_add_plugin_js(ctools_get_access_plugins());
ctools_include('context-access-admin');
$form_state['module'] = (isset($form_state['module'])) ? $form_state['module'] : 'page_manager_task_handler';
- // Encode a bunch of info into the argument so we can get our cache later
+ // Encode a bunch of info into the argument so we can get our cache later.
$form_state['callback argument'] = $form_state['task_name'] . '*' . $form_state['handler']->name;
$form_state['access'] = $form_state['handler']->conf['access'];
$form_state['no buttons'] = TRUE;
@@ -472,7 +481,7 @@ function ctools_context_handler_edit_criteria($form, &$form_state) {
}
/**
- * Submit handler for rules selection
+ * Submit handler for rules selection.
*/
function ctools_context_handler_edit_criteria_submit(&$form, &$form_state) {
$form_state['handler']->conf['access']['logic'] = $form_state['values']['logic'];
@@ -537,4 +546,3 @@ function ctools_context_handler_edit_context_submit(&$form, &$form_state) {
unset($form_state['page']->context_cache[$cache_name]);
}
}
-
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/context.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/context.inc
index 1f9c1e45..0fc62080 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/context.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/context.inc
@@ -2,7 +2,6 @@
/**
* @file
- *
* Contains code related to the ctools system of 'context'.
*
* Context, originally from Panels, is a method of packaging objects into
@@ -28,28 +27,104 @@
* of the context is important.
*/
class ctools_context {
- var $type = NULL;
- var $data = NULL;
- // The title of this object.
- var $title = '';
- // The title of the page if this object exists
- var $page_title = '';
- // The identifier (in the UI) of this object
- var $identifier = '';
- var $argument = NULL;
- var $keyword = '';
- var $original_argument = NULL;
- var $restrictions = array();
- var $empty = FALSE;
-
- function ctools_context($type = 'none', $data = NULL) {
- $this->type = $type;
- $this->data = $data;
+ /**
+ * @var string|array
+ * A string naming this specific context type. The values 'any' and 'none'
+ * are special:
+ * - 'any': used in is_type() to match any other type.
+ * - 'none': used to signal the type is not defined.
+ */
+ public $type;
+
+ /**
+ * @var mixed
+ * The data payload for this context object.
+ */
+ public $data;
+
+ /**
+ * @var string
+ * The title of this object.
+ */
+ public $title;
+
+ /**
+ * @var string
+ * The title of the page if this object exists
+ */
+ public $page_title;
+
+ /**
+ * @var string
+ * The identifier (in the UI) of this object.
+ */
+ public $identifier;
+
+ /**
+ * @var
+ */
+ public $argument;
+
+ /**
+ * @var string
+ */
+ public $keyword;
+
+ /**
+ * @var
+ */
+ public $original_argument;
+
+ /**
+ * @var array
+ */
+ public $restrictions;
+
+ /**
+ * @var bool
+ */
+ public $empty;
+
+ /**
+ * The ctools_context constructor.
+ *
+ * @param string $type
+ * The type name of this context. Should be unique. Use the machine_name
+ * conventions: lowercase, short, underscores and no spaces.
+ * @param mixed $data
+ * The data payload, if required for this context.
+ */
+ public function __construct($type = 'none', $data = NULL) {
+ $this->type = $type;
+ $this->data = $data;
$this->title = t('Unknown context');
+ $this->page_title = '';
+ $this->identifier = '';
+ $this->keyword = '';
+ $this->restrictions = array();
+ $this->empty = FALSE;
+ // Other vars are NULL.
}
- function is_type($type) {
- if ($type == 'any' || $this->type == 'any') {
+ /**
+ * Determine whether this object is of type @var $type .
+ *
+ * Both the internal value ($this->type) and the supplied value ($type) can
+ * be a string or an array of strings, and if one or both are arrays the match
+ * succeeds if at least one common element is found.
+ *
+ * Type names
+ *
+ * @param string|array $type
+ * 'type' can be:
+ * - 'any' to match all types (this is true of the internal value too).
+ * - an array of type name strings, when more than one type is acceptable.
+ *
+ * @return bool
+ * True if the type matches, False otherwise.
+ */
+ public function is_type($type) {
+ if ($type === 'any' || $this->type === 'any') {
return TRUE;
}
@@ -58,32 +133,71 @@ class ctools_context {
return (bool) array_intersect($a, $b);
}
- function get_argument() {
+ /**
+ * Return the argument.
+ *
+ * @return mixed
+ * The value of $argument.
+ */
+ public function get_argument() {
return $this->argument;
}
- function get_original_argument() {
+ /**
+ * Return the value of argument (or arg) variable as it was passed in.
+ *
+ * For example see ctools_plugin_load_function() and ctools_terms_context().
+ *
+ * @return mixed
+ * The original arg value.
+ */
+ public function get_original_argument() {
if (!is_null($this->original_argument)) {
return $this->original_argument;
}
return $this->argument;
}
- function get_keyword() {
+ /**
+ * Return the keyword.
+ *
+ * @return mixed
+ * The value of $keyword.
+ */
+ public function get_keyword() {
return $this->keyword;
}
- function get_identifier() {
+ /**
+ * Return the identifier.
+ *
+ * @return mixed
+ * The value of $identifier.
+ */
+ public function get_identifier() {
return $this->identifier;
}
- function get_title() {
+ /**
+ * Return the title.
+ *
+ * @return mixed
+ * The value of $title.
+ */
+ public function get_title() {
return $this->title;
}
- function get_page_title() {
+ /**
+ * Return the page title.
+ *
+ * @return mixed
+ * The value of $page_title.
+ */
+ public function get_page_title() {
return $this->page_title;
}
+
}
/**
@@ -91,39 +205,57 @@ class ctools_context {
* match a required context type.
*/
class ctools_context_required {
- var $keywords = '';
+ /**
+ * @var array
+ * Keyword strings associated with the context.
+ */
+ public $keywords;
/**
* If set, the title will be used in the selector to identify
* the context. This is very useful when multiple contexts
* are required to inform the user will be used for what.
*/
- var $title = NULL;
+ public $title;
/**
* Test to see if this context is required.
*/
- var $required = TRUE;
+ public $required = TRUE;
/**
* If TRUE, skip the check in ctools_context_required::select()
* for contexts whose names may have changed.
*/
- var $skip_name_check = FALSE;
+ public $skip_name_check = FALSE;
/**
+ * The ctools_context_required constructor.
+ *
+ * Note: Constructor accepts a variable number of arguments, with optional
+ * type-dependent args at the end of the list and one required argument,
+ * the title. Note in particular that skip_name_check MUST be passed in as
+ * a boolean (and not, for example, as an integer).
*
- * @param $title
- * The first parameter should be the 'title' of the context for use
- * in UYI selectors when multiple contexts qualify.
- * @param ...
+ * @param string $title
+ * The title of the context for use in UI selectors when multiple contexts
+ * qualify.
+ * @param string $keywords
* One or more keywords to use for matching which contexts are allowed.
+ * @param array $restrictions
+ * Array of context restrictions.
+ * @param bool $skip_name_check
+ * If True, skip the check in select() for contexts whose names may have
+ * changed.
*/
- function ctools_context_required($title) {
+ public function __construct($title) {
+ // If it was possible, using variadic syntax this should be:
+ // __construct($title, string ...$keywords, array $restrictions = NULL, bool $skip = NULL)
+ // but that form isn't allowed.
$args = func_get_args();
$this->title = array_shift($args);
- // If we have a boolean value at the end for $skip_name_check, store it
+ // If we have a boolean value at the end for $skip_name_check, store it.
if (is_bool(end($args))) {
$this->skip_name_check = array_pop($args);
}
@@ -133,20 +265,44 @@ class ctools_context_required {
$this->restrictions = array_pop($args);
}
- if (count($args) == 1) {
+ if (count($args) === 1) {
$args = array_shift($args);
}
$this->keywords = $args;
}
- function filter($contexts) {
+ /**
+ * Filter the contexts to determine which apply in the current environment.
+ *
+ * A context passes the filter if:
+ * - the context matches 'type' of the required keywords (uses
+ * ctools_context::is_type(), so includes 'any' matches, etc).
+ * - AND if restrictions are present, there are some common elements between
+ * the requirement and the context.
+ *
+ * @param array $contexts
+ * An array of ctools_context objects (or something which will cast to an
+ * array of them). The contexts to apply the filter on.
+ *
+ * @return array
+ * An array of context objects, keyed with the same keys used for $contexts,
+ * which pass the filter.
+ *
+ * @see ctools_context::is_type()
+ */
+ public function filter($contexts) {
$result = array();
- // See which of these contexts are valid
+ /**
+ * See which of these contexts are valid.
+ * @var ctools_context $context
+ */
foreach ((array) $contexts as $cid => $context) {
if ($context->is_type($this->keywords)) {
+
// Compare to see if our contexts were met.
if (!empty($this->restrictions) && !empty($context->restrictions)) {
+
foreach ($this->restrictions as $key => $values) {
// If we have a restriction, the context must either not have that
// restriction listed, which means we simply don't know what it is,
@@ -155,11 +311,16 @@ class ctools_context_required {
if (!is_array($values)) {
$values = array($values);
}
- if (!empty($context->restrictions[$key]) && !array_intersect($values, $context->restrictions[$key])) {
+
+ if (!empty($context->restrictions[$key])
+ && !array_intersect($values, $context->restrictions[$key])
+ ) {
+ // Break out to check next context; this one fails the filter.
continue 2;
}
}
}
+ // This context passes the filter.
$result[$cid] = $context;
}
}
@@ -167,7 +328,28 @@ class ctools_context_required {
return $result;
}
- function select($contexts, $context) {
+ /**
+ * Select one context from the list of contexts, accounting for changed IDs.
+ *
+ * Fundamentally, this returns $contexts[$context] or FALSE if that does not
+ * exist. Additional logic accounts for changes in context names and dealing
+ * with a $contexts parameter that is not an array.
+ *
+ * If we had requested a $context but that $context doesn't exist in our
+ * context list, there is a good chance that what happened is the context
+ * IDs changed. Look for another context that satisfies our requirements,
+ * unless $skip_name_check is set.
+ *
+ * @param ctools_context|array $contexts
+ * A context, or an array of ctools_context.
+ * @param string $context
+ * A context ID.
+ *
+ * @return bool|ctools_context
+ * The matching ctools_context, or False if no such context was found.
+ */
+ public function select($contexts, $context) {
+ // Easier to deal with a standalone object as a 1-element array of objects.
if (!is_array($contexts)) {
if (is_object($contexts) && $contexts instanceof ctools_context) {
$contexts = array($contexts->id => $contexts);
@@ -177,11 +359,12 @@ class ctools_context_required {
}
}
- // If we had requested a $context but that $context doesn't exist
- // in our context list, there is a good chance that what happened
- // is our context IDs changed. See if there's another context
- // that satisfies our requirements.
- if (!$this->skip_name_check && !empty($context) && !isset($contexts[$context])) {
+ // If we had requested a $context but that $context doesn't exist in our
+ // context list, there is a good chance that what happened is the context
+ // IDs changed. Check for another context that satisfies our requirements.
+ if (!$this->skip_name_check
+ && !empty($context) && !isset($contexts[$context])
+ ) {
$choices = $this->filter($contexts);
// If we got a hit, take the first one that matches.
@@ -196,6 +379,7 @@ class ctools_context_required {
}
return $contexts[$context];
}
+
}
/**
@@ -203,28 +387,73 @@ class ctools_context_required {
* can produce empty contexts to use as placeholders.
*/
class ctools_context_optional extends ctools_context_required {
- var $required = FALSE;
- function ctools_context_optional() {
- $args = func_get_args();
- call_user_func_array(array($this, 'ctools_context_required'), $args);
- }
/**
- * Add the 'empty' context which is possible for optional
+ * {@inheritdoc}
*/
- function add_empty(&$contexts) {
+ public $required = FALSE;
+
+ /**
+ * Add the 'empty' context to the existing set.
+ *
+ * @param array &$contexts
+ * An array of ctools_context objects.
+ */
+ public function add_empty(&$contexts) {
$context = new ctools_context('any');
- $context->title = t('No context');
+ $context->title = t('No context');
$context->identifier = t('No context');
$contexts['empty'] = $context;
}
- function filter($contexts) {
+ /**
+ * Filter the contexts to determine which apply in the current environment.
+ *
+ * As for ctools_context_required, but we add the empty context to those
+ * passed in so the check is optional (i.e. if nothing else matches, the
+ * empty context will, and so there will always be at least one matched).
+ *
+ * @param array $contexts
+ * An array of ctools_context objects (or something which will cast to an
+ * array of them). The contexts to apply the filter on.
+ *
+ * @return array
+ * An array of context objects, keyed with the same keys used for $contexts,
+ * which pass the filter.
+ *
+ * @see ctools_context::is_type()
+ */
+ public function filter($contexts) {
+ /**
+ * @todo We are assuming here that $contexts is actually an array, whereas
+ * ctools_context_required::filter only requires $contexts is convertible
+ * to an array.
+ */
$this->add_empty($contexts);
return parent::filter($contexts);
}
- function select($contexts, $context) {
+ /**
+ * Select and return one context from the list of applicable contexts.
+ *
+ * Fundamentally, this returns $contexts[$context] or the empty context if
+ * that does not exist.
+ *
+ * @param array $contexts
+ * The applicable contexts to check.
+ * @param string $context
+ * The context id to check for.
+ *
+ * @return bool|ctools_context
+ * The matching ctools_context, or False if no such context was found.
+ *
+ * @see ctools_context_required::select()
+ */
+ public function select($contexts, $context) {
+ /**
+ * @todo We are assuming here that $contexts is actually an array, whereas
+ * ctools_context_required::select permits ctools_context objects as well.
+ */
$this->add_empty($contexts);
if (empty($context)) {
return $contexts['empty'];
@@ -234,11 +463,12 @@ class ctools_context_optional extends ctools_context_required {
// Don't flip out if it can't find the context; this is optional, put
// in an empty.
- if ($result == FALSE) {
+ if ($result === FALSE) {
$result = $contexts['empty'];
}
return $result;
}
+
}
/**
@@ -253,20 +483,20 @@ class ctools_context_optional extends ctools_context_required {
* Since multiple contexts can be required, this function will accept either
* an array of all required contexts, or just a single required context object.
*
- * @param $contexts
+ * @param array $contexts
* A keyed array of all available contexts.
- * @param $required
- * A ctools_context_required or ctools_context_optional object, or an array
- * of such objects.
+ * @param array|ctools_context_required|ctools_context_optional $required
+ * A *_required or *_optional object, or an array of such objects, which
+ * define the selection condition.
*
- * @return
+ * @return array
* A keyed array of contexts that match the filter.
*/
function ctools_context_filter($contexts, $required) {
if (is_array($required)) {
$result = array();
- foreach ($required as $r) {
- $result = array_merge($result, _ctools_context_filter($contexts, $r));
+ foreach ($required as $item) {
+ $result = array_merge($result, _ctools_context_filter($contexts, $item));
}
return $result;
}
@@ -274,6 +504,21 @@ function ctools_context_filter($contexts, $required) {
return _ctools_context_filter($contexts, $required);
}
+/**
+ * Helper function for ctools_context_filter().
+ *
+ * Used to transform the required context during the merge into the final array.
+ *
+ * @internal This function DOES NOT form part of the CTools API.
+ *
+ * @param array $contexts
+ * A keyed array of all available contexts.
+ * @param ctools_context_required|ctools_context_optional $required
+ * A ctools_context_required or ctools_context_optional object, although if
+ * given something else will return an empty array.
+ *
+ * @return array
+ */
function _ctools_context_filter($contexts, $required) {
$result = array();
@@ -293,12 +538,17 @@ function _ctools_context_filter($contexts, $required) {
* If an array of required contexts is provided, one selector will be
* provided for each context.
*
- * @param $contexts
+ * @param array $contexts
* A keyed array of all available contexts.
- * @param $required
+ * @param array|ctools_context_required|ctools_context_optional $required
* The required context object or array of objects.
+ * @param array|string $default
+ * The default value for the select object, suitable for a #default_value
+ * render key. Where $required is an array, this is an array keyed by the
+ * same key values as $required for all keys where an empty string is not a
+ * suitable default. Otherwise it is just the default value.
*
- * @return
+ * @return array
* A form element, or NULL if there are no contexts that satisfy the
* requirements.
*/
@@ -306,8 +556,10 @@ function ctools_context_selector($contexts, $required, $default) {
if (is_array($required)) {
$result = array('#tree' => TRUE);
$count = 1;
- foreach ($required as $id => $r) {
- $result[] = _ctools_context_selector($contexts, $r, isset($default[$id]) ? $default[$id] : '', $count++);
+ foreach ($required as $id => $item) {
+ $result[] = _ctools_context_selector(
+ $contexts, $item, isset($default[$id]) ? $default[$id] : '', $count++
+ );
}
return $result;
}
@@ -315,6 +567,27 @@ function ctools_context_selector($contexts, $required, $default) {
return _ctools_context_selector($contexts, $required, $default);
}
+/**
+ * Helper function for ctools_context_selector().
+ *
+ * @internal This function DOES NOT form part of the CTools API. Use the API
+ * function ctools_context_selector() instead.
+ *
+ * @param array $contexts
+ * A keyed array of all available contexts.
+ * @param ctools_context_required|ctools_context_optional $required
+ * The required context object.
+ * @param $default
+ * The default value for the select object, suitable for a #default_value
+ * render key.
+ * @param int $num
+ * If supplied and non-zero, the title of the select form element will be
+ * "Context $num", otherwise it will be "Context".
+ *
+ * @return array
+ * A form element, or NULL if there are no contexts that satisfy the
+ * requirements.
+ */
function _ctools_context_selector($contexts, $required, $default, $num = 0) {
$filtered = ctools_context_filter($contexts, $required);
$count = count($filtered);
@@ -358,8 +631,8 @@ function _ctools_context_selector($contexts, $required, $default, $num = 0) {
* @param $required
* The required context object or array of objects.
*
- * @return
- * TRUE if there are enough contexts, FALSE if there are not.
+ * @return bool
+ * True if there are enough contexts, otherwise False.
*/
function ctools_context_match_requirements($contexts, $required) {
if (!is_array($required)) {
@@ -392,8 +665,13 @@ function ctools_context_match_requirements($contexts, $required) {
* A keyed array of all available contexts.
* @param $required
* The required context object or array of objects.
+ * @param array|string $default
+ * The default value for the select object, suitable for a #default_value
+ * render key. Where $required is an array, this is an array keyed by the
+ * same key values as $required for all keys where an empty string is not a
+ * suitable default. Otherwise it is just the default value.
*
- * @return
+ * @return array
* A form element, or NULL if there are no contexts that satisfy the
* requirements.
*/
@@ -401,8 +679,11 @@ function ctools_context_converter_selector($contexts, $required, $default) {
if (is_array($required)) {
$result = array('#tree' => TRUE);
$count = 1;
- foreach ($required as $id => $r) {
- $result[] = _ctools_context_converter_selector($contexts, $r, isset($default[$id]) ? $default[$id] : '', $count++);
+ foreach ($required as $id => $dependency) {
+ $default_id = isset($default[$id]) ? $default[$id] : '';
+ $result[] = _ctools_context_converter_selector(
+ $contexts, $dependency, $default_id, $count++
+ );
}
return $result;
}
@@ -410,17 +691,36 @@ function ctools_context_converter_selector($contexts, $required, $default) {
return _ctools_context_converter_selector($contexts, $required, $default);
}
+/**
+ * Helper function for ctools_context_converter_selector().
+ *
+ * @internal This function DOES NOT form part of the CTools API. Use the API
+ * function ctools_context_converter_selector() instead.
+ *
+ * @param array $contexts
+ * A keyed array of all available contexts.
+ * @param ctools_context $required
+ * The required context object.
+ * @param $default
+ * The default value for the select object, suitable for a #default_value
+ * render key.
+ * @param int $num
+ * If supplied and non-zero, the title of the select form element will be
+ * "Context $num", otherwise it will be "Context".
+ *
+ * @return array|null
+ * A form element, or NULL if there are no contexts that satisfy the
+ * requirements.
+ */
function _ctools_context_converter_selector($contexts, $required, $default, $num = 0) {
$filtered = ctools_context_filter($contexts, $required);
$count = count($filtered);
- $form = array();
-
if ($count > 1) {
// If there's more than one to choose from, create a select widget.
$options = array();
foreach ($filtered as $cid => $context) {
- if ($context->type == 'any') {
+ if ($context->type === 'any') {
$options[''] = t('No context');
continue;
}
@@ -450,10 +750,22 @@ function _ctools_context_converter_selector($contexts, $required, $default, $num
'#default_value' => $default,
);
}
+ else {
+ // Not enough choices to need a selector, so don't make one.
+ return NULL;
+ }
}
/**
* Get a list of converters available for a given context.
+ *
+ * @param string $cid
+ * A context ID.
+ * @param ctools_context $context
+ * The context for which converters are needed.
+ *
+ * @return array
+ * A list of context converters.
*/
function ctools_context_get_converters($cid, $context) {
if (empty($context->plugin)) {
@@ -465,6 +777,17 @@ function ctools_context_get_converters($cid, $context) {
/**
* Get a list of converters available for a given context.
+ *
+ * @internal This function DOES NOT form part of the CTools API. Use the API
+ * function ctools_context_get_converters() instead.
+ *
+ * @param string $id
+ * A context ID.
+ * @param string $plugin_name
+ * The name of the context plugin.
+ *
+ * @return array
+ * A list of context converters.
*/
function _ctools_context_get_converters($id, $plugin_name) {
$plugin = ctools_get_context($plugin_name);
@@ -476,7 +799,7 @@ function _ctools_context_get_converters($id, $plugin_name) {
if (is_array($plugin['convert list'])) {
$converters = $plugin['convert list'];
}
- else if ($function = ctools_plugin_get_function($plugin, 'convert list')) {
+ elseif ($function = ctools_plugin_get_function($plugin, 'convert list')) {
$converters = (array) $function($plugin);
}
@@ -496,7 +819,13 @@ function _ctools_context_get_converters($id, $plugin_name) {
}
/**
- * Get a list of all contexts + converters available.
+ * Get a list of all contexts converters available.
+ *
+ * For all contexts returned by ctools_get_contexts(), return the converter
+ * for all contexts that have one.
+ *
+ * @return array
+ * A list of context converters, keyed by the title of the converter.
*/
function ctools_context_get_all_converters() {
$contexts = ctools_get_contexts();
@@ -516,21 +845,24 @@ function ctools_context_get_all_converters() {
/**
* Let the context convert an argument based upon the converter that was given.
*
- * @param $context
- * The context object
- * @param $converter
- * The converter to use, which should be a string provided by the converter list.
- * @param $converter_options
- * A n array of options to pass on to the generation function. For contexts
+ * @param ctools_context $context
+ * The context object.
+ * @param string $converter
+ * The type of converter to use, which should be a string provided by the
+ * converter list function.
+ * @param array $converter_options
+ * An array of options to pass on to the generation function. For contexts
* that use token module, of particular use is 'sanitize' => FALSE which can
* get raw tokens. This should ONLY be used in values that will later be
* treated as unsafe user input since these values are by themselves unsafe.
* It is particularly useful to get raw values from Field API.
+ *
+ * @return string|null
*/
function ctools_context_convert_context($context, $converter, $converter_options = array()) {
// Contexts without plugins might be optional placeholders.
if (empty($context->plugin)) {
- return;
+ return NULL;
}
$value = $context->argument;
@@ -551,22 +883,35 @@ function ctools_context_convert_context($context, $converter, $converter_options
* Choose a context or contexts based upon the selection made via
* ctools_context_filter.
*
- * @param $contexts
- * A keyed array of all available contexts
- * @param $required
- * The required context object provided by the plugin
+ * @param array $contexts
+ * A keyed array of all available contexts.
+ * @param array|ctools_context_required $required
+ * The required context object(s) provided by the plugin.
* @param $context
- * The selection made using ctools_context_selector
+ * The selection made using ctools_context_selector().
+ *
+ * @return ctools_context|array|false
+ * Returns FALSE if $required is not an object, or array of objects, or
+ * the value of $required->select() for the context, or an array of those (if
+ * passed an array in $required).
*/
function ctools_context_select($contexts, $required, $context) {
if (is_array($required)) {
+
+ /**
+ * @var array $required
+ * Array of required context objects.
+ * @var ctools_context_required $item
+ * A required context object.
+ */
$result = array();
- foreach ($required as $id => $r) {
+ foreach ($required as $id => $item) {
+ // @todo What's the difference between the following and "empty($item)" ?
if (empty($required[$id])) {
continue;
}
- if (($result[] = _ctools_context_select($contexts, $r, $context[$id])) === FALSE) {
+ if (($result[] = _ctools_context_select($contexts, $item, $context[$id])) === FALSE) {
return FALSE;
}
}
@@ -576,6 +921,22 @@ function ctools_context_select($contexts, $required, $context) {
return _ctools_context_select($contexts, $required, $context);
}
+/**
+ * Helper function for calling the required context object's selection function.
+ *
+ * This function DOES NOT form part of the CTools API.
+ *
+ * @param array $contexts
+ * A keyed array of all available contexts.
+ * @param ctools_context_required $required
+ * The required context object provided by the plugin.
+ * @param $context
+ * The selection made using ctools_context_selector().
+ *
+ * @return ctools_context|bool
+ * FALSE if the $required is not an object. A ctools_context object if one
+ * matched.
+ */
function _ctools_context_select($contexts, $required, $context) {
if (!is_object($required)) {
return FALSE;
@@ -587,16 +948,14 @@ function _ctools_context_select($contexts, $required, $context) {
/**
* Create a new context object.
*
- * @param $type
+ * @param string $type
* The type of context to create; this loads a plugin.
- * @param $data
+ * @param mixed $data
* The data to put into the context.
- * @param $empty
- * Whether or not this context is specifically empty.
* @param $conf
* A configuration structure if this context was created via UI.
*
- * @return
+ * @return ctools_context
* A $context or NULL if one could not be created.
*/
function ctools_context_create($type, $data = NULL, $conf = FALSE) {
@@ -619,7 +978,7 @@ function ctools_context_create($type, $data = NULL, $conf = FALSE) {
* @param $type
* The type of context to create; this loads a plugin.
*
- * @return
+ * @return ctools_context
* A $context or NULL if one could not be created.
*/
function ctools_context_create_empty($type) {
@@ -636,8 +995,21 @@ function ctools_context_create_empty($type) {
/**
* Perform keyword and context substitutions.
+ *
+ * @param string $string
+ * The string in which to replace keywords.
+ * @param array $keywords
+ * Array of keyword-replacement pairs.
+ * @param array $contexts
+ *
+ * @param array $converter_options
+ * Options to pass on to ctools_context_convert_context(), defaults to an
+ * empty array.
+ *
+ * @return string
+ * The returned string, with substitutions performed.
*/
-function ctools_context_keyword_substitute($string, $keywords, $contexts, $converter_options = array()) {
+function ctools_context_keyword_substitute($string, $keywords, $contexts, array $converter_options = array()) {
// Ensure a default keyword exists:
$keywords['%%'] = '%';
@@ -660,7 +1032,7 @@ function ctools_context_keyword_substitute($string, $keywords, $contexts, $conve
// If the keyword is already set by something passed in, don't try to
// overwrite it.
- if (!empty($keywords['%' . $keyword])) {
+ if (array_key_exists('%' . $keyword, $keywords)) {
continue;
}
@@ -680,14 +1052,21 @@ function ctools_context_keyword_substitute($string, $keywords, $contexts, $conve
}
}
- if (empty($context_keywords[$context]) || !empty($context_keywords[$context]->empty)) {
- $keywords['%' . $keyword] = '';
- }
- else if (!empty($converter)) {
- $keywords['%' . $keyword] = ctools_context_convert_context($context_keywords[$context], $converter, $converter_options);
+ if (!isset($context_keywords[$context])) {
+ $keywords['%' . $keyword] = '%' . $keyword;
}
else {
- $keywords['%' . $keyword] = $context_keywords[$keyword]->title;
+ if (empty($context_keywords[$context]) || !empty($context_keywords[$context]->empty)) {
+ $keywords['%' . $keyword] = '';
+ }
+ else {
+ if (!empty($converter)) {
+ $keywords['%' . $keyword] = ctools_context_convert_context($context_keywords[$context], $converter, $converter_options);
+ }
+ else {
+ $keywords['%' . $keyword] = $context_keywords[$keyword]->title;
+ }
+ }
}
}
}
@@ -695,18 +1074,22 @@ function ctools_context_keyword_substitute($string, $keywords, $contexts, $conve
}
/**
- * Determine a unique context ID for a context
+ * Determine a unique context ID for a context.
*
* Often contexts of many different types will be placed into a list. This
* ensures that even though contexts of multiple types may share IDs, they
* are unique in the final list.
*/
function ctools_context_id($context, $type = 'context') {
- if (!$context['id']) {
+ // If not set, FALSE or empty.
+ if (!isset($context['id']) || !$context['id']) {
$context['id'] = 1;
}
- return $type . '_' . $context['name'] . '_' . $context['id'];
+ // @todo is '' the appropriate default value?
+ $name = isset($context['name']) ? $context['name'] : '';
+
+ return $type . '_' . $name . '_' . $context['id'];
}
/**
@@ -714,42 +1097,46 @@ function ctools_context_id($context, $type = 'context') {
*
* This finds the next id available for the named object.
*
- * @param $objects
- * A list of context descriptor objects, i.e, arguments, relationships, contexts, etc.
- * @param $name
+ * @param array $objects
+ * A list of context descriptor objects, i.e, arguments, relationships,
+ * contexts, etc.
+ * @param string $name
* The name being used.
+ *
+ * @return int
+ * The next integer id available.
*/
function ctools_context_next_id($objects, $name) {
$id = 0;
- // Figure out which instance of this argument we're creating
+ // Figure out which instance of this argument we're creating.
if (!$objects) {
return $id + 1;
}
foreach ($objects as $object) {
- if (isset($object['name']) && $object['name'] == $name) {
- if ($object['id'] > $id) {
+ if (isset($object['name']) && $object['name'] === $name) {
+ if (isset($object['id']) && $object['id'] > $id) {
$id = $object['id'];
}
+ // @todo If obj has no 'id', should we increment local id? $id = $id + 1;
}
}
return $id + 1;
}
-
// ---------------------------------------------------------------------------
// Functions related to contexts from arguments.
-
/**
- * Fetch metadata on a specific argument plugin.
+ * Fetch metadata for a specific argument plugin.
*
* @param $argument
* Name of an argument plugin.
*
- * @return
+ * @return array
* An array with information about the requested argument plugin.
*/
+
function ctools_get_argument($argument) {
ctools_include('plugins');
return ctools_get_plugins('ctools', 'arguments', $argument);
@@ -758,7 +1145,7 @@ function ctools_get_argument($argument) {
/**
* Fetch metadata for all argument plugins.
*
- * @return
+ * @return array
* An array of arrays with information about all available argument plugins.
*/
function ctools_get_arguments() {
@@ -778,22 +1165,23 @@ function ctools_get_arguments() {
* - keyword: The keyword used for this argument for substitutions.
*
* @param $arg
- * The actual argument received. This is expected to be a string from a URL but
- * this does not have to be the only source of arguments.
+ * The actual argument received. This is expected to be a string from a URL
+ * but this does not have to be the only source of arguments.
* @param $empty
* If true, the $arg will not be used to load the context. Instead, an empty
* placeholder context will be loaded.
*
- * @return
+ * @return ctools_context
* A context object if one can be loaded.
*/
function ctools_context_get_context_from_argument($argument, $arg, $empty = FALSE) {
ctools_include('plugins');
if (empty($argument['name'])) {
- return;
+ return NULL;
}
- if ($function = ctools_plugin_load_function('ctools', 'arguments', $argument['name'], 'context')) {
+ $function = ctools_plugin_load_function('ctools', 'arguments', $argument['name'], 'context');
+ if ($function) {
// Backward compatibility: Merge old style settings into new style:
if (!empty($argument['settings'])) {
$argument += $argument['settings'];
@@ -805,8 +1193,8 @@ function ctools_context_get_context_from_argument($argument, $arg, $empty = FALS
if (is_object($context)) {
$context->identifier = $argument['identifier'];
$context->page_title = isset($argument['title']) ? $argument['title'] : '';
- $context->keyword = $argument['keyword'];
- $context->id = ctools_context_id($argument, 'argument');
+ $context->keyword = $argument['keyword'];
+ $context->id = ctools_context_id($argument, 'argument');
$context->original_argument = $arg;
if (!empty($context->empty)) {
@@ -822,6 +1210,12 @@ function ctools_context_get_context_from_argument($argument, $arg, $empty = FALS
/**
* Retrieve a list of empty contexts for all arguments.
+ *
+ * @param array $arguments
+ *
+ * @return array
+ *
+ * @see ctools_context_get_context_from_arguments()
*/
function ctools_context_get_placeholders_from_argument($arguments) {
$contexts = array();
@@ -837,19 +1231,21 @@ function ctools_context_get_placeholders_from_argument($arguments) {
/**
* Load the contexts for a given list of arguments.
*
- * @param $arguments
+ * @param array $arguments
* The array of argument definitions.
- * @param &$contexts
+ * @param array &$contexts
* The array of existing contexts. New contexts will be added to this array.
- * @param $args
+ * @param array $args
* The arguments to load.
*
- * @return
- * FALSE if an argument wants to 404.
+ * @return bool
+ * TRUE if all is well, FALSE if an argument wants to 404.
+ *
+ * @see ctools_context_get_context_from_argument()
*/
function ctools_context_get_context_from_arguments($arguments, &$contexts, $args) {
foreach ($arguments as $argument) {
- // pull the argument off the list.
+ // Pull the argument off the list.
$arg = array_shift($args);
$id = ctools_context_id($argument, 'argument');
@@ -864,7 +1260,10 @@ function ctools_context_get_context_from_arguments($arguments, &$contexts, $args
$context = $contexts[$id];
}
- if ((empty($context) || empty($context->data)) && !empty($argument['default']) && $argument['default'] == '404') {
+ if ((empty($context) || empty($context->data))
+ && !empty($argument['default'])
+ && $argument['default'] === '404'
+ ) {
return FALSE;
}
}
@@ -873,16 +1272,18 @@ function ctools_context_get_context_from_arguments($arguments, &$contexts, $args
// ---------------------------------------------------------------------------
// Functions related to contexts from relationships.
-
/**
- * Fetch metadata on a specific relationship plugin.
+ * Fetch plugin metadata for a specific relationship plugin.
*
- * @param $content type
+ * @param $relationship
* Name of a panel content type.
*
- * @return
+ * @return array
* An array with information about the requested relationship.
+ *
+ * @see ctools_get_relationships()
*/
+
function ctools_get_relationship($relationship) {
ctools_include('plugins');
return ctools_get_plugins('ctools', 'relationships', $relationship);
@@ -891,8 +1292,10 @@ function ctools_get_relationship($relationship) {
/**
* Fetch metadata for all relationship plugins.
*
- * @return
+ * @return array
* An array of arrays with information about all available relationships.
+ *
+ * @see ctools_get_relationship()
*/
function ctools_get_relationships() {
ctools_include('plugins');
@@ -900,8 +1303,9 @@ function ctools_get_relationships() {
}
/**
+ * Return a context from a relationship.
*
- * @param $relationship
+ * @param array $relationship
* The configuration of a relationship. It must contain the following data:
* - name: The name of the relationship plugin being used.
* - relationship_settings: The configuration based upon the plugin forms.
@@ -909,18 +1313,21 @@ function ctools_get_relationships() {
* defined by the UI.
* - keyword: The keyword used for this relationship for substitutions.
*
- * @param $source_context
+ * @param ctools_context $source_context
* The context this relationship is based upon.
- *
- * @param $placeholders
+ * @param bool $placeholders
* If TRUE, placeholders are acceptable.
*
- * @return
- * A context object if one can be loaded.
+ * @return ctools_context|null
+ * A context object if one can be loaded, otherwise NULL.
+ *
+ * @see ctools_context_get_relevant_relationships()
+ * @see ctools_context_get_context_from_relationships()
*/
function ctools_context_get_context_from_relationship($relationship, $source_context, $placeholders = FALSE) {
ctools_include('plugins');
- if ($function = ctools_plugin_load_function('ctools', 'relationships', $relationship['name'], 'context')) {
+ $function = ctools_plugin_load_function('ctools', 'relationships', $relationship['name'], 'context');
+ if ($function) {
// Backward compatibility: Merge old style settings into new style:
if (!empty($relationship['relationship_settings'])) {
$relationship += $relationship['relationship_settings'];
@@ -931,7 +1338,7 @@ function ctools_context_get_context_from_relationship($relationship, $source_con
if ($context) {
$context->identifier = $relationship['identifier'];
$context->page_title = isset($relationship['title']) ? $relationship['title'] : '';
- $context->keyword = $relationship['keyword'];
+ $context->keyword = $relationship['keyword'];
if (!empty($context->empty)) {
$context->placeholder = array(
'type' => 'relationship',
@@ -941,6 +1348,7 @@ function ctools_context_get_context_from_relationship($relationship, $source_con
return $context;
}
}
+ return NULL;
}
/**
@@ -954,18 +1362,24 @@ function ctools_context_get_context_from_relationship($relationship, $source_con
* @param $contexts
* An array of contexts used to figure out which relationships are relevant.
*
- * @return
+ * @return array
* An array of relationship keys that are relevant for the given set of
* contexts.
+ *
+ * @see ctools_context_filter()
+ * @see ctools_context_get_context_from_relationship()
+ * @see ctools_context_get_context_from_relationships()
*/
function ctools_context_get_relevant_relationships($contexts) {
$relevant = array();
$relationships = ctools_get_relationships();
- // Go through each relationship
+ // Go through each relationship.
foreach ($relationships as $rid => $relationship) {
// For each relationship, see if there is a context that satisfies it.
- if (empty($relationship['no ui']) && ctools_context_filter($contexts, $relationship['required context'])) {
+ if (empty($relationship['no ui'])
+ && ctools_context_filter($contexts, $relationship['required context'])
+ ) {
$relevant[$rid] = $relationship['title'];
}
}
@@ -974,7 +1388,7 @@ function ctools_context_get_relevant_relationships($contexts) {
}
/**
- * Fetch all active relationships
+ * Fetch all active relationships.
*
* @param $relationships
* An keyed array of relationship data including:
@@ -989,10 +1403,11 @@ function ctools_context_get_relevant_relationships($contexts) {
*
* @param $placeholders
* If TRUE, placeholders are acceptable.
+ *
+ * @see ctools_context_get_context_from_relationship()
+ * @see ctools_context_get_relevant_relationships()
*/
function ctools_context_get_context_from_relationships($relationships, &$contexts, $placeholders = FALSE) {
- $return = array();
-
foreach ($relationships as $rdata) {
if (!isset($rdata['context'])) {
continue;
@@ -1023,16 +1438,16 @@ function ctools_context_get_context_from_relationships($relationships, &$context
// ---------------------------------------------------------------------------
// Functions related to loading contexts from simple context definitions.
-
/**
* Fetch metadata on a specific context plugin.
*
- * @param $context
+ * @param string $context
* Name of a context.
*
- * @return
+ * @return array
* An array with information about the requested panel context.
*/
+
function ctools_get_context($context) {
static $gate = array();
ctools_include('plugins');
@@ -1056,7 +1471,7 @@ function ctools_get_context($context) {
/**
* Fetch metadata for all context plugins.
*
- * @return
+ * @return array
* An array of arrays with information about all available panel contexts.
*/
function ctools_get_contexts() {
@@ -1065,27 +1480,38 @@ function ctools_get_contexts() {
}
/**
+ * Return a context object from a context definition array.
*
- * @param $context
+ * The input $context contains the information needed to identify and invoke
+ * the context plugin and create the plugin context from that.
+ *
+ * @param array $context
* The configuration of a context. It must contain the following data:
* - name: The name of the context plugin being used.
* - context_settings: The configuration based upon the plugin forms.
* - identifier: The human readable identifier for this context, usually
* defined by the UI.
* - keyword: The keyword used for this context for substitutions.
- * @param $type
+ * @param string $type
* This is either 'context' which indicates the context will be loaded
- * from data in the settings, or 'required_context' which means the
+ * from data in the settings, or 'requiredcontext' which means the
* context must be acquired from an external source. This is the method
* used to pass pure contexts from one system to another.
+ * @param mixed $argument
+ * Optional information passed to the plugin context via the arg defined in
+ * the plugin's "placeholder name" field.
*
- * @return
+ * @return ctools_context|null
* A context object if one can be loaded.
+ *
+ * @see ctools_get_context()
+ * @see ctools_plugin_get_function()
*/
function ctools_context_get_context_from_context($context, $type = 'context', $argument = NULL) {
ctools_include('plugins');
$plugin = ctools_get_context($context['name']);
- if ($function = ctools_plugin_get_function($plugin, 'context')) {
+ $function = ctools_plugin_get_function($plugin, 'context');
+ if ($function) {
// Backward compatibility: Merge old style settings into new style:
if (!empty($context['context_settings'])) {
$context += $context['context_settings'];
@@ -1100,7 +1526,7 @@ function ctools_context_get_context_from_context($context, $type = 'context', $a
if ($return) {
$return->identifier = $context['identifier'];
$return->page_title = isset($context['title']) ? $context['title'] : '';
- $return->keyword = $context['keyword'];
+ $return->keyword = $context['keyword'];
if (!empty($context->empty)) {
$context->placeholder = array(
@@ -1112,6 +1538,8 @@ function ctools_context_get_context_from_context($context, $type = 'context', $a
return $return;
}
}
+
+ return NULL;
}
/**
@@ -1125,7 +1553,10 @@ function ctools_context_get_context_from_context($context, $type = 'context', $a
* Either 'context' or 'requiredcontext', which indicates whether the contexts
* are loaded from internal data or copied from an external source.
* @param $placeholders
- * If true, placeholders are acceptable.
+ * If True, placeholders are acceptable.
+ *
+ * @return array
+ * Array of contexts, keyed by context ID.
*/
function ctools_context_get_context_from_contexts($contexts, $type = 'context', $placeholders = FALSE) {
$return = array();
@@ -1144,17 +1575,20 @@ function ctools_context_get_context_from_contexts($contexts, $type = 'context',
/**
* Match up external contexts to our required contexts.
*
- * This function is used to create a list of contexts with proper
- * IDs based upon a list of required contexts.
+ * This function is used to create a list of contexts with proper IDs based
+ * upon a list of required contexts.
*
- * These contexts passed in should match the numeric positions of the
- * required contexts. The caller must ensure this has already happened
- * correctly as this function will not detect errors here.
+ * These contexts passed in should match the numeric positions of the required
+ * contexts. The caller must ensure this has already happened correctly as this
+ * function will not detect errors here.
*
* @param $required
* A list of required contexts as defined by the UI.
* @param $contexts
* A list of matching contexts as passed in from the calling system.
+ *
+ * @return array
+ * Array of contexts, keyed by context ID.
*/
function ctools_context_match_required_contexts($required, $contexts) {
$return = array();
@@ -1163,10 +1597,10 @@ function ctools_context_match_required_contexts($required, $contexts) {
}
foreach ($required as $r) {
- $context = clone(array_shift($contexts));
+ $context = clone array_shift($contexts);
$context->identifier = $r['identifier'];
$context->page_title = isset($r['title']) ? $r['title'] : '';
- $context->keyword = $r['keyword'];
+ $context->keyword = $r['keyword'];
$return[ctools_context_id($r, 'requiredcontext')] = $context;
}
@@ -1178,31 +1612,35 @@ function ctools_context_match_required_contexts($required, $contexts) {
*
* Not all of the types need to be supported by this object.
*
- * This function is not used to load contexts from external data, but may
- * be used to load internal contexts and relationships. Otherwise it can also
- * be used to generate a full set of placeholders for UI purposes.
+ * This function is not used to load contexts from external data, but may be
+ * used to load internal contexts and relationships. Otherwise it can also be
+ * used to generate a full set of placeholders for UI purposes.
*
- * @param $object
+ * @param object $object
* An object that contains some or all of the following variables:
*
- * - requiredcontexts: A list of UI configured contexts that are required
- * from an external source. Since these require external data, they will
- * only be added if $placeholders is set to TRUE, and empty contexts will
- * be created.
- * - arguments: A list of UI configured arguments that will create contexts.
- * Since these require external data, they will only be added if $placeholders
- * is set to TRUE.
- * - contexts: A list of UI configured contexts that have no external source,
- * and are essentially hardcoded. For example, these might configure a
- * particular node or a particular taxonomy term.
- * - relationships: A list of UI configured contexts to be derived from other
- * contexts that already exist from other sources. For example, these might
- * be used to get a user object from a node via the node author relationship.
- * @param $placeholders
- * If TRUE, this will generate placeholder objects for types this function
+ * - requiredcontexts: A list of UI configured contexts that are required
+ * from an external source. Since these require external data, they will
+ * only be added if $placeholders is set to TRUE, and empty contexts will
+ * be created.
+ * - arguments: A list of UI configured arguments that will create contexts.
+ * As these require external data, they will only be added if $placeholders
+ * is set to TRUE.
+ * - contexts: A list of UI configured contexts that have no external source,
+ * and are essentially hardcoded. For example, these might configure a
+ * particular node or a particular taxonomy term.
+ * - relationships: A list of UI configured contexts to be derived from other
+ * contexts that already exist from other sources. For example, these might
+ * be used to get a user object from a node via the node author
+ * relationship.
+ * @param bool $placeholders
+ * If True, this will generate placeholder objects for any types this function
* cannot load.
- * @param $contexts
+ * @param array $contexts
* An array of pre-existing contexts that will be part of the return value.
+ *
+ * @return array
+ * Merged output of all results of ctools_context_get_context_from_contexts().
*/
function ctools_context_load_contexts($object, $placeholders = TRUE, $contexts = array()) {
if (!empty($object->base_contexts)) {
@@ -1226,7 +1664,7 @@ function ctools_context_load_contexts($object, $placeholders = TRUE, $contexts =
$contexts += ctools_context_get_context_from_contexts($object->contexts, 'context', $placeholders);
}
- // add contexts from relationships
+ // Add contexts from relationships.
if (!empty($object->relationships) && is_array($object->relationships)) {
ctools_context_get_context_from_relationships($object->relationships, $contexts, $placeholders);
}
@@ -1245,7 +1683,7 @@ function ctools_context_load_contexts($object, $placeholders = TRUE, $contexts =
function ctools_context_get_form($contexts) {
if (!empty($contexts)) {
foreach ($contexts as $id => $context) {
- // if a form shows its id as being a 'required context' that means the
+ // If a form shows its id as being a 'required context' that means the
// the context is external to this display and does not count.
if (!empty($context->form_id) && substr($id, 0, 15) != 'requiredcontext') {
return $context;
@@ -1264,7 +1702,7 @@ function ctools_context_get_form($contexts) {
* The arguments. These will be acquired from $form_state['values'] and the
* keys must match the context IDs.
*
- * @return
+ * @return array
* A new $contexts array containing the replaced contexts. Not all contexts
* may be replaced if, for example, an argument was unable to be converted
* into a context.
@@ -1283,12 +1721,14 @@ function ctools_context_replace_placeholders($contexts, $arguments) {
$new_context = ctools_context_get_context_from_relationship($relationship, $contexts[$relationship['context']]);
}
break;
+
case 'argument':
if (isset($arguments[$cid]) && $arguments[$cid] !== '') {
$argument = $context->placeholder['conf'];
$new_context = ctools_context_get_context_from_argument($argument, $arguments[$cid]);
}
break;
+
case 'context':
if (!empty($arguments[$cid])) {
$context_info = $context->placeholder['conf'];
@@ -1337,32 +1777,37 @@ function ctools_context_replace_form(&$form, $contexts) {
if (is_array($plugin['placeholder form'])) {
$form[$cid] = $plugin['placeholder form'];
}
- else if (function_exists($plugin['placeholder form'])) {
- $widget = $plugin['placeholder form']($info);
- if ($widget) {
- $form[$cid] = $widget;
+ else {
+ if (function_exists($plugin['placeholder form'])) {
+ $widget = $plugin['placeholder form']($info);
+ if ($widget) {
+ $form[$cid] = $widget;
+ }
}
}
if (!empty($form[$cid])) {
- $form[$cid]['#title'] = t('@identifier (@keyword)', array('@keyword' => '%' . $context->keyword, '@identifier' => $context->identifier));
+ $form[$cid]['#title'] = t('@identifier (@keyword)', array(
+ '@keyword' => '%' . $context->keyword,
+ '@identifier' => $context->identifier,
+ ));
}
}
}
}
// ---------------------------------------------------------------------------
-// Functions related to loading access control plugins
-
+// Functions related to loading access control plugins.
/**
* Fetch metadata on a specific access control plugin.
*
* @param $name
* Name of a plugin.
*
- * @return
+ * @return array
* An array with information about the requested access control plugin.
*/
+
function ctools_get_access_plugin($name) {
ctools_include('plugins');
return ctools_get_plugins('ctools', 'access', $name);
@@ -1371,7 +1816,7 @@ function ctools_get_access_plugin($name) {
/**
* Fetch metadata for all access control plugins.
*
- * @return
+ * @return array
* An array of arrays with information about all available access control plugins.
*/
function ctools_get_access_plugins() {
@@ -1383,8 +1828,14 @@ function ctools_get_access_plugins() {
* Fetch a list of access plugins that are available for a given list of
* contexts.
*
- * if 'logged-in-user' is not in the list of contexts, it will be added as
+ * If 'logged-in-user' is not in the list of contexts, it will be added as
* this is required.
+ *
+ * @param array $contexts
+ * Array of ctools_context objects with which to select access plugins.
+ *
+ * @return array
+ * Array of applicable access plugins. Can be empty.
*/
function ctools_get_relevant_access_plugins($contexts) {
if (!isset($contexts['logged-in-user'])) {
@@ -1394,7 +1845,9 @@ function ctools_get_relevant_access_plugins($contexts) {
$all_plugins = ctools_get_access_plugins();
$plugins = array();
foreach ($all_plugins as $id => $plugin) {
- if (!empty($plugin['required context']) && !ctools_context_match_requirements($contexts, $plugin['required context'])) {
+ if (!empty($plugin['required context'])
+ && !ctools_context_match_requirements($contexts, $plugin['required context'])
+ ) {
continue;
}
$plugins[$id] = $plugin;
@@ -1409,14 +1862,17 @@ function ctools_get_relevant_access_plugins($contexts) {
function ctools_access_get_loggedin_context() {
$context = ctools_context_create('entity:user', array('type' => 'current'), TRUE);
$context->identifier = t('Logged in user');
- $context->keyword = 'viewer';
- $context->id = 0;
+ $context->keyword = 'viewer';
+ $context->id = 0;
return $context;
}
/**
* Get a summary of an access plugin's settings.
+ *
+ * @return string
+ * The summary text.
*/
function ctools_access_summary($plugin, $contexts, $test) {
if (!isset($contexts['logged-in-user'])) {
@@ -1426,8 +1882,9 @@ function ctools_access_summary($plugin, $contexts, $test) {
$description = '';
if ($function = ctools_plugin_get_function($plugin, 'summary')) {
$required_context = isset($plugin['required context']) ? $plugin['required context'] : array();
- $context = isset($test['context']) ? $test['context'] : array();
- $description = $function($test['settings'], ctools_context_select($contexts, $required_context, $context), $plugin);
+ $context = isset($test['context']) ? $test['context'] : array();
+ $selected_context = ctools_context_select($contexts, $required_context, $context);
+ $description = $function($test['settings'], $selected_context, $plugin);
}
if (!empty($test['not'])) {
@@ -1439,10 +1896,23 @@ function ctools_access_summary($plugin, $contexts, $test) {
/**
* Get a summary of a group of access plugin's settings.
+ *
+ * @param $access
+ * An array of settings theoretically set by the user, including the array
+ * of plugins to check:
+ * - 'plugins': the array of plugin metadata info to check
+ * - 'logic': (optional) either 'and' or 'or', indicating how to combine
+ * restrictions. Defaults to 'or'.
+ * @param array $contexts
+ * An array of zero or more contexts that may be used to determine if
+ * the user has access.
+ *
+ * @return string
+ * The summary text. Can be NULL if there are no plugins defined.
*/
function ctools_access_group_summary($access, $contexts) {
- if (empty($access['plugins'])) {
- return;
+ if (empty($access['plugins']) || !is_array($access['plugins'])) {
+ return NULL;
}
$descriptions = array();
@@ -1451,21 +1921,29 @@ function ctools_access_group_summary($access, $contexts) {
$descriptions[] = ctools_access_summary($plugin, $contexts, $test);
}
- $separator = (isset($access['logic']) && $access['logic'] == 'and') ? t(', and ') : t(', or ');
+ $separator =
+ (isset($access['logic']) && $access['logic'] === 'and')
+ ? t(', and ') : t(', or ');
return implode($separator, $descriptions);
}
/**
- * Determine if the current user has access via plugin.
+ * Determine if the current user has access via a plugin.
*
- * @param $settings
- * An array of settings theoretically set by the user.
- * @param $contexts
+ * @param array $settings
+ * An array of settings theoretically set by the user, including the array
+ * of plugins to check:
+ * - 'plugins': the array of plugin metadata info to check
+ * - 'logic': (optional) either 'and' or 'or', indicating how to combine
+ * restrictions. The 'or' case is not fully implemented and returns the
+ * input contexts unchanged.
+ *
+ * @param array $contexts
* An array of zero or more contexts that may be used to determine if
* the user has access.
*
- * @return
- * TRUE if access is granted, false if otherwise.
+ * @return bool
+ * TRUE if access is granted, FALSE if otherwise.
*/
function ctools_access($settings, $contexts = array()) {
if (empty($settings['plugins'])) {
@@ -1504,7 +1982,7 @@ function ctools_access($settings, $contexts = array()) {
// Pass if 'or' and this rule passed.
return TRUE;
}
- else if (!$pass && $settings['logic'] == 'and') {
+ elseif (!$pass && $settings['logic'] == 'and') {
// Fail if 'and' and this rule failed.
return FALSE;
}
@@ -1512,7 +1990,7 @@ function ctools_access($settings, $contexts = array()) {
// Return TRUE if logic was and, meaning all rules passed.
// Return FALSE if logic was or, meaning no rule passed.
- return $settings['logic'] == 'and';
+ return ($settings['logic'] === 'and');
}
/**
@@ -1521,7 +1999,7 @@ function ctools_access($settings, $contexts = array()) {
* @param $plugin
* The access plugin being used.
*
- * @return
+ * @return array
* A default configured test that should be placed in $access['plugins'];
*/
function ctools_access_new_test($plugin) {
@@ -1543,7 +2021,6 @@ function ctools_access_new_test($plugin) {
}
}
-
$default = NULL;
if (isset($plugin['default'])) {
$default = $plugin['default'];
@@ -1557,7 +2034,7 @@ function ctools_access_new_test($plugin) {
if (is_array($default)) {
$test['settings'] = $default;
}
- else if (function_exists($default)) {
+ elseif (function_exists($default)) {
$test['settings'] = $default();
}
else {
@@ -1571,11 +2048,23 @@ function ctools_access_new_test($plugin) {
/**
* Apply restrictions to contexts based upon the access control configured.
*
- * These restrictions allow the UI to not show content that may not
- * be relevant to all types of a particular context.
+ * These restrictions allow the UI to not show content that may not be relevant
+ * to all types of a particular context.
+ *
+ * @param array $settings
+ * Array of keys specifying the settings:
+ * - 'plugins': the array of plugin metadata info to check. If not set, or
+ * not an array, the function returns with no action.
+ * - 'logic': (optional) either 'and' or 'or', indicating how to combine
+ * restrictions. Defaults to 'and'.
+ * The 'or' case is not fully implemented and returns with no action if
+ * there is more than one plugin.
+ *
+ * @param array $contexts
+ * Array of available contexts.
*/
function ctools_access_add_restrictions($settings, $contexts) {
- if (empty($settings['plugins'])) {
+ if (empty($settings['plugins']) || !is_array($settings['plugins'])) {
return;
}
@@ -1584,16 +2073,20 @@ function ctools_access_add_restrictions($settings, $contexts) {
}
// We're not going to try to figure out restrictions on the or.
- if ($settings['logic'] == 'or' && count($settings['plugins']) > 1) {
+ if ($settings['logic'] === 'or' && count($settings['plugins']) > 1) {
return;
}
foreach ($settings['plugins'] as $test) {
$plugin = ctools_get_access_plugin($test['name']);
- if ($plugin && $function = ctools_plugin_get_function($plugin, 'restrictions')) {
+ // $plugin is 'array()' on error.
+ if ($plugin
+ && $function = ctools_plugin_get_function($plugin, 'restrictions')
+ ) {
$required_context = isset($plugin['required context']) ? $plugin['required context'] : array();
$context = isset($test['context']) ? $test['context'] : array();
$contexts = ctools_context_select($contexts, $required_context, $context);
+
if ($contexts !== FALSE) {
$function($test['settings'], $contexts);
}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/context.menu.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/context.menu.inc
index ee227cb7..798d167c 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/context.menu.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/context.menu.inc
@@ -25,7 +25,7 @@ function ctools_context_menu(&$items) {
'page callback' => 'ctools_context_ajax_item_delete',
) + $base;
- // For the access system
+ // For the access system.
$base['file'] = 'includes/context-access-admin.inc';
$items['ctools/context/ajax/access/add'] = array(
'page callback' => 'ctools_access_ajax_add',
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/context.theme.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/context.theme.inc
index 8f660b8c..d0d866f7 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/context.theme.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/context.theme.inc
@@ -19,7 +19,6 @@ function ctools_context_theme(&$theme) {
);
$theme['ctools_context_item_form'] = array(
'render element' => 'form',
-// 'variables' => array('form' => NULL),
'file' => 'includes/context.theme.inc',
);
$theme['ctools_context_item_row'] = array(
@@ -27,7 +26,7 @@ function ctools_context_theme(&$theme) {
'file' => 'includes/context.theme.inc',
);
- // For the access plugin
+ // For the access plugin.
$theme['ctools_access_admin_add'] = array(
'render element' => 'form',
'file' => 'includes/context-access-admin.inc',
@@ -62,10 +61,10 @@ function theme_ctools_context_item_row($vars) {
function theme_ctools_context_item_form($vars) {
$form = $vars['form'];
- $output = '';
- $type = $form['#ctools_context_type'];
- $module = $form['#ctools_context_module'];
- $cache_key = $form['#cache_key'];
+ $output = '';
+ $type = $form['#ctools_context_type'];
+ $module = $form['#ctools_context_module'];
+ $cache_key = $form['#cache_key'];
$type_info = ctools_context_info($type);
@@ -104,17 +103,17 @@ function theme_ctools_context_item_form($vars) {
if (!empty($form['buttons'])) {
// Display the add context item.
- $row = array();
- $row[] = array('data' => render($form['buttons'][$type]['item']), 'class' => array('title'));
- $row[] = array('data' => render($form['buttons'][$type]['add']), 'class' => array('add'), 'width' => "60%");
- $output .= '
';
}
if (!empty($form['description'])) {
$output .= render($form['description']);
@@ -139,7 +138,7 @@ function theme_ctools_context_list($vars) {
$description = (!empty($vars['description'])) ? $vars['description'] : NULL;
$titles = array();
$output = '';
- $count = 1;
+ $count = 1;
$contexts = ctools_context_load_contexts($object);
@@ -209,7 +208,7 @@ function theme_ctools_context_list($vars) {
}
}
- // And relationships
+ // And relationships.
if (!empty($object->relationships)) {
foreach ($object->relationships as $relationship) {
$output .= '
';
@@ -253,15 +252,15 @@ function theme_ctools_context_list($vars) {
}
/**
- * ctools_context_list() but not in a table format because tabledrag
- * won't let us have tables within tables and still drag.
+ * The ctools_context_list() function but not in a table format because
+ * tabledrag won't let us have tables within tables and still drag.
*/
function theme_ctools_context_list_no_table($vars) {
$object = $vars['object'];
ctools_add_css('context');
$titles = array();
$output = '';
- $count = 1;
+ $count = 1;
// Describe 'built in' contexts.
if (!empty($object->base_contexts)) {
foreach ($object->base_contexts as $id => $context) {
@@ -312,7 +311,7 @@ function theme_ctools_context_list_no_table($vars) {
$count++;
}
}
- // And relationships
+ // And relationships.
if (!empty($object->relationships)) {
foreach ($object->relationships as $relationship) {
$output .= '
';
@@ -341,4 +340,3 @@ function theme_ctools_context_list_no_table($vars) {
return $output;
}
-
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/css.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/css.inc
index 8cf5ed40..83fe1c34 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/css.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/css.inc
@@ -1,6 +1,6 @@
$declaration) {
foreach ($declaration as $property => $value) {
if (!in_array($property, $allowed_properties)) {
- // $filtered['properties'][$selector_str][$property] = $value;
+ // $filtered['properties'][$selector_str][$property] = $value;.
unset($css[$selector_str][$property]);
continue;
}
$value = str_replace('!important', '', $value);
if (preg_match($disallowed_values_regex, $value) || !(in_array($value, $allowed_values) || preg_match($allowed_values_regex, $value))) {
- // $filtered['values'][$selector_str][$property] = $value;
+ // $filtered['values'][$selector_str][$property] = $value;.
unset($css[$selector_str][$property]);
continue;
}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/dependent.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/dependent.inc
index 74de9197..20c25ded 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/dependent.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/dependent.inc
@@ -44,7 +44,7 @@
*
* A fuller example, that hides the menu title when no menu is selected:
* @code
- *function ctools_dependent_example() {
+ * function ctools_dependent_example() {
* $form = array();
* $form['menu'] = array(
* '#type' => 'fieldset',
@@ -72,12 +72,12 @@
* );
*
* return system_settings_form($form);
- *}
+ * }
* @endcode
*
* An example for hiding checkboxes using #prefix and #suffix:
* @code
- *function ctools_dependent_example_checkbox() {
+ * function ctools_dependent_example_checkbox() {
* $form = array();
* $form['object'] = array(
* '#type' => 'fieldset',
@@ -111,7 +111,7 @@
* );
*
* return system_settings_form($form);
- *}
+ * }
* @endcode
*
* Deprecated:
@@ -125,7 +125,6 @@
/**
* Process callback to add dependency to form items.
- *
*/
function ctools_dependent_process($element, &$form_state, &$form) {
return $element;
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/dropbutton.theme.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/dropbutton.theme.inc
index fcdd5a37..8ce99f07 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/dropbutton.theme.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/dropbutton.theme.inc
@@ -75,7 +75,7 @@ function theme_links__ctools_dropbutton($vars) {
if (!empty($vars['links'])) {
$is_drop_button = (count($vars['links']) > 1);
- // Add needed files
+ // Add needed files.
if ($is_drop_button) {
ctools_add_js('dropbutton');
ctools_add_css('dropbutton');
@@ -86,7 +86,7 @@ function theme_links__ctools_dropbutton($vars) {
static $id = 0;
$id++;
- // Wrapping div
+ // Wrapping div.
$class = 'ctools-no-js';
$class .= ($is_drop_button) ? ' ctools-dropbutton' : '';
$class .= ' ctools-button';
@@ -98,7 +98,7 @@ function theme_links__ctools_dropbutton($vars) {
$output .= '
';
- // Add a twisty if this is a dropbutton
+ // Add a twisty if this is a dropbutton.
if ($is_drop_button) {
$vars['title'] = ($vars['title'] ? check_plain($vars['title']) : t('open'));
@@ -109,10 +109,11 @@ function theme_links__ctools_dropbutton($vars) {
else {
$output .= '' . $vars['title'] . '';
}
- $output .= '
';
}
- // The button content
+ // The button content.
$output .= '
';
// Check for attributes. theme_links expects an array().
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/dropdown.theme.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/dropdown.theme.inc
index 7e748f5e..2437b89e 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/dropdown.theme.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/dropdown.theme.inc
@@ -57,7 +57,7 @@ function ctools_dropdown_theme(&$items) {
* to style a single dropdown however you like without interfering with
* other dropdowns.
*/
-function theme_ctools_dropdown($vars) {
+function theme_ctools_dropdown($vars) {
// Provide a unique identifier for every dropdown on the page.
static $id = 0;
$id++;
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/entity-access.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/entity-access.inc
index 972cf13b..69f2c335 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/entity-access.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/entity-access.inc
@@ -24,19 +24,23 @@ function _ctools_entity_access(&$entity_info, $entity_type) {
// Sad panda, we don't use Entity API, lets manually add access callbacks.
$entity_info['access callback'] = 'ctools_metadata_no_hook_node_access';
break;
+
case 'user':
$entity_info['access callback'] = 'ctools_metadata_user_access';
break;
+
case 'comment':
if (module_exists('comment')) {
$entity_info['access callback'] = 'ctools_metadata_comment_access';
}
break;
+
case 'taxonomy_term':
if (module_exists('taxonomy')) {
$entity_info['access callback'] = 'ctools_metadata_taxonomy_access';
}
break;
+
case 'taxonomy_vocabulary':
if (module_exists('taxonomy')) {
$entity_info['access callback'] = 'ctools_metadata_taxonomy_access';
@@ -64,7 +68,7 @@ function _ctools_entity_access(&$entity_info, $entity_type) {
*
* @throws EntityMalformedException
*
- * @return boolean
+ * @return bool
* TRUE if access is allowed, FALSE otherwise.
*/
function ctools_metadata_no_hook_node_access($op, $node = NULL, $account = NULL) {
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/export-ui.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/export-ui.inc
index 16e57d6e..1eb87ae7 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/export-ui.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/export-ui.inc
@@ -81,7 +81,6 @@ function ctools_export_ui_process(&$plugin, $info) {
// Add some default fields that appear often in exports
// If these use different keys they can easily be specified in the
// $plugin.
-
if (empty($plugin['export']['admin_title']) && !empty($schema['fields']['admin_title'])) {
$plugin['export']['admin_title'] = 'admin_title';
}
@@ -297,7 +296,6 @@ function ctools_export_ui_process(&$plugin, $info) {
);
// Define strings.
-
// For all strings, %title may be filled in at a later time via str_replace
// since we do not know the title now.
$plugin['strings'] += array(
@@ -414,6 +412,7 @@ function ctools_export_ui_plugin_base_path($plugin) {
* The id in the menu items from the plugin.
* @param $export_key
* The export key of the item being edited, if it exists.
+ *
* @return
* The menu path to the plugin's list.
*/
@@ -429,12 +428,11 @@ function ctools_export_ui_plugin_menu_path($plugin, $item_id, $export_key = NULL
* Helper function to include CTools plugins and get an export-ui exportable.
*
* @param $plugin_name
- * The plugin that should be laoded.
+ * The plugin that should be loaded.
*/
function ctools_get_export_ui($plugin_name) {
ctools_include('plugins');
return ctools_get_plugins('ctools', 'export_ui', $plugin_name);
-
}
/**
@@ -456,14 +454,14 @@ function ctools_export_ui_switcher_page($plugin_name, $op) {
$args = func_get_args();
$js = !empty($_REQUEST['js']);
- // Load the $plugin information
+ // Load the $plugin information.
$plugin = ctools_get_export_ui($plugin_name);
$handler = ctools_export_ui_get_handler($plugin);
if ($handler) {
$method = $op . '_page';
if (method_exists($handler, $method)) {
- // replace the first two arguments:
+ // Replace the first two arguments:
$args[0] = $js;
$args[1] = $_POST;
return call_user_func_array(array($handler, $method), $args);
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/export-ui.menu.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/export-ui.menu.inc
index d27bf157..0fda8c25 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/export-ui.menu.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/export-ui.menu.inc
@@ -1,5 +1,9 @@
array('handler'),
);
-}
\ No newline at end of file
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/export.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/export.inc
index 0b85c2ef..d2fff2fd 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/export.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/export.inc
@@ -4,7 +4,7 @@
* @file
* Contains code to make it easier to have exportable objects.
*
- * Documentation for exportable objects is contained in help/export.html
+ * Documentation for exportable objects is contained in help/export.html.
*/
/**
@@ -126,6 +126,7 @@ function ctools_export_crud_load_multiple($table, array $names) {
* If TRUE, the static cache of all objects will be flushed prior to
* loading all. This can be important on listing pages where items
* might have changed on the page load.
+ *
* @return
* An array of all loaded objects, keyed by the unique IDs of the export key.
*/
@@ -328,7 +329,6 @@ function ctools_export_crud_set_status($table, $object, $status) {
}
-
/**
* Enable a certain object.
*
@@ -426,7 +426,7 @@ function ctools_export_load_object($table, $type = 'all', $args = array()) {
}
}
- // Build the query
+ // Build the query.
$query = db_select($table, 't__0')->fields('t__0');
$alias_count = 1;
if (!empty($schema['join'])) {
@@ -451,7 +451,7 @@ function ctools_export_load_object($table, $type = 'all', $args = array()) {
if ($type == 'names') {
$query->condition($export['key'], $args, 'IN');
}
- else if ($type == 'conditions') {
+ elseif ($type == 'conditions') {
foreach ($args as $key => $value) {
if (isset($schema['fields'][$key])) {
$query->condition($key, $value);
@@ -499,7 +499,7 @@ function ctools_export_load_object($table, $type = 'all', $args = array()) {
if ($defaults) {
foreach ($defaults as $object) {
if ($type == 'conditions') {
- // if this does not match all of our conditions, skip it.
+ // If this does not match all of our conditions, skip it.
foreach ($args as $key => $value) {
if (!isset($object->$key)) {
continue 2;
@@ -509,12 +509,12 @@ function ctools_export_load_object($table, $type = 'all', $args = array()) {
continue 2;
}
}
- else if ($object->$key != $value) {
+ elseif ($object->$key != $value) {
continue 2;
}
}
}
- else if ($type == 'names') {
+ elseif ($type == 'names') {
if (!in_array($object->{$export['key']}, $args)) {
continue;
}
@@ -561,7 +561,6 @@ function ctools_export_load_object($table, $type = 'all', $args = array()) {
}
}
- // For conditions,
return $return;
}
@@ -807,10 +806,10 @@ function _ctools_export_get_some_defaults($table, $export, $names) {
function _ctools_export_unpack_object($schema, $data, $object = 'stdClass') {
if (is_string($object)) {
if (class_exists($object)) {
- $object = new $object;
+ $object = new $object();
}
else {
- $object = new stdClass;
+ $object = new stdClass();
}
}
@@ -873,14 +872,14 @@ function ctools_var_export($var, $prefix = '') {
$output .= $prefix . ')';
}
}
- else if (is_object($var) && get_class($var) === 'stdClass') {
+ elseif (is_object($var) && get_class($var) === 'stdClass') {
// var_export() will export stdClass objects using an undefined
// magic method __set_state() leaving the export broken. This
// workaround avoids this by casting the object as an array for
// export and casting it back to an object when evaluated.
$output = '(object) ' . ctools_var_export((array) $var, $prefix);
}
- else if (is_bool($var)) {
+ elseif (is_bool($var)) {
$output = $var ? 'TRUE' : 'FALSE';
}
else {
@@ -902,7 +901,8 @@ function ctools_export_object($table, $object, $indent = '', $identifier = NULL,
$output = $indent . '$' . $identifier . ' = new ' . get_class($object) . "();\n";
if ($schema['export']['can disable']) {
- $output .= $indent . '$' . $identifier . '->disabled = FALSE; /* Edit this to true to make a default ' . $identifier . ' disabled initially */' . "\n";
+ $disabled = !isset($object->disabled) || $object->disabled != TRUE ? 'FALSE' : 'TRUE';
+ $output .= $indent . '$' . $identifier . '->disabled = ' . $disabled . '; /* Edit this to true to make a default ' . $identifier . ' disabled initially */' . "\n";
}
if (!empty($schema['export']['api']['current_version'])) {
$output .= $indent . '$' . $identifier . '->api_version = ' . $schema['export']['api']['current_version'] . ";\n";
@@ -958,7 +958,7 @@ function ctools_export_object($table, $object, $indent = '', $identifier = NULL,
}
}
- // And bottom additions here
+ // And bottom additions here.
foreach ($additions2 as $field => $value) {
$output .= $indent . '$' . $identifier . '->' . $field . ' = ' . ctools_var_export($value, $indent) . ";\n";
}
@@ -986,7 +986,7 @@ function ctools_export_get_schema($table) {
// simply hasn't been cached. If we've been asked, let's force the
// issue.
if (!$schema || empty($schema['export'])) {
- // force a schema reset:
+ // Force a schema reset:
$schema = drupal_get_schema($table, TRUE);
}
@@ -998,7 +998,7 @@ function ctools_export_get_schema($table) {
return array();
}
- // Add some defaults
+ // Add some defaults.
$schema['export'] += array(
'key' => 'name',
'key name' => 'Name',
@@ -1106,7 +1106,7 @@ function ctools_export_set_object_status($object, $new_status = TRUE) {
$export = $schema['export'];
$status = variable_get($export['status'], array());
- // Compare
+ // Compare.
if (!$new_status && $object->export_type & EXPORT_IN_DATABASE) {
unset($status[$object->{$export['key']}]);
}
@@ -1149,12 +1149,12 @@ function ctools_export_new_object($table, $set_defaults = TRUE) {
$schema = ctools_export_get_schema($table);
$export = $schema['export'];
- $object = new $export['object'];
+ $object = new $export['object']();
foreach ($schema['fields'] as $field => $info) {
if (isset($info['object default'])) {
$object->$field = $info['object default'];
}
- else if (isset($info['default'])) {
+ elseif (isset($info['default'])) {
$object->$field = $info['default'];
}
else {
@@ -1179,11 +1179,11 @@ function ctools_export_new_object($table, $set_defaults = TRUE) {
function ctools_export_to_hook_code(&$code, $table, $names = array(), $name = 'foo') {
$schema = ctools_export_get_schema($table);
$export = $schema['export'];
- // Use the schema-specified function for generating hook code, if one exists
+ // Use the schema-specified function for generating hook code, if one exists.
if (function_exists($export['to hook code callback'])) {
$output = $export['to hook code callback']($names, $name);
}
- // Otherwise, the following code generates basic hook code
+ // Otherwise, the following code generates basic hook code.
else {
$output = ctools_export_default_to_hook_code($schema, $table, $names, $name);
}
@@ -1227,7 +1227,7 @@ function ctools_export_default_to_hook_code($schema, $table, $names, $name) {
$output .= " \${$export['identifier']}s = array();\n\n";
foreach ($objects as $object) {
$output .= ctools_export_crud_export($table, $object, ' ');
- $output .= " \${$export['identifier']}s['" . check_plain($object->$export['key']) . "'] = \${$export['identifier']};\n\n";
+ $output .= " \${$export['identifier']}s['" . check_plain($object->{$export['key']}) . "'] = \${$export['identifier']};\n\n";
}
$output .= " return \${$export['identifier']}s;\n";
$output .= "}\n";
@@ -1235,6 +1235,7 @@ function ctools_export_default_to_hook_code($schema, $table, $names, $name) {
return $output;
}
+
/**
* Default function for listing bulk exportable objects.
*/
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/fields.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/fields.inc
index f379f5e9..0d3256f2 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/fields.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/fields.inc
@@ -5,7 +5,6 @@
* Extend core fields with some helper functions to reduce code complexity within views and ctools plugins.
*/
-
/**
* Fake an instance of a field.
*
@@ -75,27 +74,30 @@ function ctools_fields_get_field_formatter_settings_form($field, $formatter_type
$conf['formatter_settings'] += $formatter['settings'];
}
$function = $formatter['module'] . '_field_formatter_settings_form';
+
+ $instance = ctools_fields_fake_field_instance($field['field_name'], $view_mode, $formatter_type, $conf['formatter_settings']);
if (function_exists($function)) {
- $instance = ctools_fields_fake_field_instance($field['field_name'], $view_mode, $formatter_type, $conf['formatter_settings']);
$settings_form = $function($field, $instance, $view_mode, $form, $form_state);
- if ($settings_form) {
- // Allow other modules to alter the formatter settings form.
- $context = array(
- 'module' => $formatter['module'],
- 'formatter' => $formatter,
- 'field' => $field,
- 'instance' => $instance,
- 'view_mode' => $view_mode,
- 'form' => $form,
- 'form_state' => $form_state,
- );
- drupal_alter('field_formatter_settings_form', $settings_form, $context);
-
- $settings_form['#tree'] = TRUE;
- $form['ctools_field_list']['#value'][] = $field;
- $form += $settings_form;
- }
}
+ if (empty($settings_form)) {
+ $settings_form = array();
+ }
+
+ // Allow other modules to alter the formatter settings form.
+ $context = array(
+ 'module' => $formatter['module'],
+ 'formatter' => $formatter,
+ 'field' => $field,
+ 'instance' => $instance,
+ 'view_mode' => $view_mode,
+ 'form' => $form,
+ 'form_state' => $form_state,
+ );
+ drupal_alter('field_formatter_settings_form', $settings_form, $context);
+
+ $settings_form['#tree'] = TRUE;
+ $form['ctools_field_list']['#value'][] = $field;
+ $form += $settings_form;
if (isset($field['cardinality']) && $field['cardinality'] != 1) {
list($prefix, $suffix) = explode('@count', t('Skip the first @count item(s)'));
@@ -137,7 +139,7 @@ function ctools_fields_get_field_formatter_settings_form($field, $formatter_type
*/
function ctools_fields_get_field_formatter_info($fields) {
$info = array();
- $field_info = module_invoke_all('field_formatter_info');
+ $field_info = field_info_formatter_types();
foreach ($fields as $field) {
foreach ($field_info as $format_name => $formatter_info) {
if (in_array($field['type'], $formatter_info['field types'])) {
@@ -145,7 +147,6 @@ function ctools_fields_get_field_formatter_info($fields) {
}
}
}
- drupal_alter('field_formatter_info', $info);
return $info;
}
@@ -209,15 +210,15 @@ function ctools_field_label($field_name) {
* - Otherwise NULL.
* @param $options
* An associative array of additional options, with the following keys:
- * - 'field_name': The name of the field whose operation should be
+ * - 'field_name': The name of the field whose operation should be
* invoked. By default, the operation is invoked on all the fields
* in the entity's bundle. NOTE: This option is not compatible with
* the 'deleted' option; the 'field_id' option should be used
* instead.
- * - 'field_id': The id of the field whose operation should be
+ * - 'field_id': The id of the field whose operation should be
* invoked. By default, the operation is invoked on all the fields
* in the entity's' bundles.
- * - 'default': A boolean value, specifying which implementation of
+ * - 'default': A boolean value, specifying which implementation of
* the operation should be invoked.
* - if FALSE (default), the field types implementation of the operation
* will be invoked (hook_field_[op])
@@ -225,10 +226,10 @@ function ctools_field_label($field_name) {
* will be invoked (field_default_[op])
* Internal use only. Do not explicitely set to TRUE, but use
* _field_invoke_default() instead.
- * - 'deleted': If TRUE, the function will operate on deleted fields
+ * - 'deleted': If TRUE, the function will operate on deleted fields
* as well as non-deleted fields. If unset or FALSE, only
* non-deleted fields are operated on.
- * - 'language': A language code or an array of language codes keyed by field
+ * - 'language': A language code or an array of language codes keyed by field
* name. It will be used to narrow down to a single value the available
* languages to act on.
*
@@ -341,7 +342,7 @@ function ctools_field_foreign_keys($field_name) {
$foreign_keys[$field_name] = $field['foreign keys'];
}
else {
- // try to fetch foreign keys from schema, as not everything
+ // Try to fetch foreign keys from schema, as not everything
// stores foreign keys properly in the field info.
$module = $field['module'];
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/jump-menu.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/jump-menu.inc
index 51f45982..e2ae1cfc 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/jump-menu.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/jump-menu.inc
@@ -8,7 +8,6 @@
* if javascript is in use. Each item is keyed to the href that the button
* should go to. With javascript, the page is immediately redirected. Without
* javascript, the form is submitted and a drupal_goto() is given.
- *
*/
/**
@@ -127,7 +126,7 @@ function ctools_jump_menu_submit($form, &$form_state) {
// This allows duplicate paths to be used in jump menus for multiple options.
$redirect_array = explode("::", $form_state['values']['jump']);
- if(isset($redirect_array[1]) && !empty($redirect_array[1])){
+ if (isset($redirect_array[1]) && !empty($redirect_array[1])) {
$redirect = $redirect_array[1];
}
else {
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/language.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/language.inc
index 9a7850b7..a850670e 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/language.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/language.inc
@@ -1,5 +1,9 @@
t("Current user's language"),
@@ -41,4 +44,4 @@ function ctools_language_list_all() {
);
$languages = array_merge($languages, ctools_language_list());
return $languages;
-}
\ No newline at end of file
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/math-expr.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/math-expr.inc
index eeb184d8..3105ec52 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/math-expr.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/math-expr.inc
@@ -99,7 +99,7 @@ class ctools_math_expr {
'sqrt','abs','ln','log',
'time', 'ceil', 'floor', 'min', 'max', 'round');
- function ctools_math_expr() {
+ function __construct() {
// make the variables a little more accurate
$this->v['pi'] = pi();
$this->v['e'] = exp(1);
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/modal.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/modal.inc
index fc990159..18b216fc 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/modal.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/modal.inc
@@ -55,9 +55,9 @@ function ctools_modal_add_js() {
'alt' => t('Close window'),
)),
'throbber' => theme('image', array(
- 'path' => ctools_image_path('throbber.gif'),
- 'title' => t('Loading...'),
- 'alt' => t('Loading'),
+ 'path' => ctools_image_path('throbber.gif'),
+ 'title' => t('Loading...'),
+ 'alt' => t('Loading'),
)),
),
);
@@ -85,7 +85,7 @@ function ctools_modal_add_plugin_js($plugins) {
if (file_exists($file)) {
$js[$file] = TRUE;
}
- else if (file(exists($subtype['path'] . '/' . $file))) {
+ elseif (file(exists($subtype['path'] . '/' . $file))) {
$js[$subtype['path'] . '/' . $file] = TRUE;
}
}
@@ -95,7 +95,7 @@ function ctools_modal_add_plugin_js($plugins) {
if (file_exists($file)) {
$css[$file] = TRUE;
}
- else if (file(exists($subtype['path'] . '/' . $file))) {
+ elseif (file(exists($subtype['path'] . '/' . $file))) {
$css[$subtype['path'] . '/' . $file] = TRUE;
}
}
@@ -140,7 +140,7 @@ function ctools_modal_command_dismiss() {
}
/**
- * Display loading screen in the modal
+ * Display loading screen in the modal.
*/
function ctools_modal_command_loading() {
return array(
@@ -189,7 +189,7 @@ function ctools_modal_text_button($text, $dest, $alt, $class = '') {
* Wrap a form so that we can use it properly with AJAX. Essentially if the
* form wishes to render, it automatically does that, otherwise it returns
* the render array so we can see submission results.
-
+ *
* @param array $form
* An associative array containing the structure of the form.
* @param array $form_state
@@ -222,7 +222,7 @@ function ctools_modal_form_wrapper($form_id, &$form_state) {
$output = drupal_build_form($form_id, $form_state);
if (!empty($form_state['ajax']) && (!$form_state['executed'] || $form_state['rebuild'])) {
- return ctools_modal_form_render($form_state, $output);
+ return ctools_modal_form_render($form_state, $output);
}
return $output;
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/object-cache.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/object-cache.inc
index 29225b05..614c56f0 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/object-cache.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/object-cache.inc
@@ -27,6 +27,7 @@
* defaults to session_id().
*
* @deprecated $skip_cache is deprecated in favor of drupal_static*
+ *
* @return
* The data that was cached.
*/
@@ -91,7 +92,7 @@ function ctools_object_cache_set($obj, $name, $cache, $sid = NULL) {
}
/**
- * Remove an object from the non-volatile ctools cache
+ * Remove an object from the non-volatile ctools cache.
*
* @param $obj
* A 128 character or less string to define what kind of object is being
@@ -117,7 +118,6 @@ function ctools_object_cache_clear($obj, $name, $sid = NULL) {
drupal_static_reset('ctools_object_cache_get');
}
-
/**
* Determine if another user has a given object cached.
*
@@ -197,7 +197,8 @@ function ctools_object_cache_clear_all($obj, $name) {
*/
function ctools_object_cache_clean($age = NULL) {
if (empty($age)) {
- $age = 86400 * 7; // 7 days
+ // 7 days.
+ $age = 86400 * 7;
}
db_delete('ctools_object_cache')
->condition('updated', REQUEST_TIME - $age, '<')
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/page-wizard.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/page-wizard.inc
index a211361b..9690aae0 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/page-wizard.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/page-wizard.inc
@@ -1,5 +1,9 @@
plugin = $plugin;
if ($function = ctools_plugin_get_function($plugin, 'default cache')) {
$function($cache);
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/plugins-admin.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/plugins-admin.inc
index d4ead0a4..c11fcfd6 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/plugins-admin.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/plugins-admin.inc
@@ -10,6 +10,7 @@
*
* Implementing this
*/
+
/**
* Get a plugin configuration form.
*
@@ -100,7 +101,7 @@ function _ctools_plugin_configure_create_form_info(&$form_info, $plugin_definiti
if (empty($plugin_definition['title'])) {
$title = t('Configure');
}
- else if ($op == 'add') {
+ elseif ($op == 'add') {
$title = t('Configure new !plugin_title', array('!plugin_title' => $plugin_definition['title']));
}
else {
@@ -134,10 +135,10 @@ function _ctools_plugin_configure_create_form_info(&$form_info, $plugin_definiti
$form_info['forms']['form']['wrapper'] = 'ctools_plugins_default_form_wrapper';
}
}
- else if (is_array($info)) {
- if (empty($form_info['order'])) {
- $form_info['order'] = array();
- }
+ elseif (is_array($info)) {
+ if (empty($form_info['order'])) {
+ $form_info['order'] = array();
+ }
if (empty($form_info['forms'])) {
$form_info['forms'] = array();
}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/plugins.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/plugins.inc
index 79a6087f..a4abb537 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/plugins.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/plugins.inc
@@ -2,7 +2,6 @@
/**
* @file
- *
* Contains routines to organize and load plugins. It allows a special
* variation of the hook system so that plugins can be kept in separate
* .inc files, and can be either loaded all at once or loaded only when
@@ -70,7 +69,7 @@ function ctools_plugin_api_info($owner, $api, $minimum_version, $current_version
if (isset($info['version'])) {
$version = $info['version'];
}
- else if (isset($info['api'])) {
+ elseif (isset($info['api'])) {
$version = $info['api'];
}
@@ -99,7 +98,7 @@ function ctools_plugin_api_info($owner, $api, $minimum_version, $current_version
}
// Only process if version is between minimum and current, inclusive.
- if (version_compare($info['version'], $minimum_version, '>=') && version_compare($info['version'], $current_version, '<=')) {
+ if (version_compare($info['version'], $minimum_version, '>=') && version_compare($info['version'], $current_version, '<=')) {
if (!isset($info['path'])) {
$info['path'] = '';
}
@@ -151,7 +150,7 @@ function ctools_plugin_api_include($owner, $api, $minimum_version, $current_vers
if (isset($plugin_info["$api file"])) {
$file = $plugin_info["$api file"];
}
- else if (isset($plugin_info['file'])) {
+ elseif (isset($plugin_info['file'])) {
$file = $plugin_info['file'];
}
else {
@@ -161,7 +160,7 @@ function ctools_plugin_api_include($owner, $api, $minimum_version, $current_vers
if (file_exists(DRUPAL_ROOT . "/$plugin_info[path]/$file")) {
require_once DRUPAL_ROOT . "/$plugin_info[path]/$file";
}
- else if (file_exists(DRUPAL_ROOT . "/$file")) {
+ elseif (file_exists(DRUPAL_ROOT . "/$file")) {
require_once DRUPAL_ROOT . "/$file";
}
$already_done[$owner][$api][$module] = TRUE;
@@ -184,7 +183,7 @@ function ctools_plugin_api_get_hook($owner, $api) {
if (function_exists($function = $owner . '_' . $api . '_hook_name')) {
$hook = $function();
}
- else if (function_exists($function = $owner . '_ctools_plugin_api_hook_name')) {
+ elseif (function_exists($function = $owner . '_ctools_plugin_api_hook_name')) {
$hook = $function();
}
@@ -200,18 +199,18 @@ function ctools_plugin_api_get_hook($owner, $api) {
/**
* Fetch a group of plugins by name.
*
- * @param $module
- * The name of the module that utilizes this plugin system. It will be
- * used to call hook_ctools_plugin_$plugin() to get more data about the plugin.
- * @param $type
+ * @param string $module
+ * The name of the module that utilizes this plugin system. It will be used to
+ * get more data about the plugin as defined on hook_ctools_plugin_type().
+ * @param string $type
* The type identifier of the plugin.
- * @param $id
+ * @param string $id
* If specified, return only information about plugin with this identifier.
* The system will do its utmost to load only plugins with this id.
*
- * @return
- * An array of information arrays about the plugins received. The contents
- * of the array are specific to the plugin.
+ * @return array
+ * An array of information arrays about the plugins received. The contents of
+ * the array are specific to the plugin.
*/
function ctools_get_plugins($module, $type, $id = NULL) {
// Store local caches of plugins and plugin info so we don't have to do full
@@ -224,10 +223,14 @@ function ctools_get_plugins($module, $type, $id = NULL) {
$info = ctools_plugin_get_plugin_type_info();
- // Bail out noisily if an invalid module/type combination is requested.
if (!isset($info[$module][$type])) {
- watchdog('ctools', 'Invalid plugin module/type combination requested: module @module and type @type', array('@module' => $module, '@type' => $type), WATCHDOG_ERROR);
- return array();
+ // If we don't find the plugin we attempt a cache rebuild before bailing out.
+ $info = ctools_plugin_get_plugin_type_info(TRUE);
+ // Bail out noisily if an invalid module/type combination is requested.
+ if (!isset($info[$module][$type])) {
+ watchdog('ctools', 'Invalid plugin module/type combination requested: module @module and type @type', array('@module' => $module, '@type' => $type), WATCHDOG_ERROR);
+ return array();
+ }
}
// Make sure our plugins array is populated.
@@ -235,8 +238,8 @@ function ctools_get_plugins($module, $type, $id = NULL) {
$plugins[$module][$type] = array();
}
- // Attempt to shortcut this whole piece of code if we already have
- // the requested plugin:
+ // Attempt to shortcut this whole piece of code if we already have the
+ // requested plugin:
if ($id && array_key_exists($id, $plugins[$module][$type])) {
return $plugins[$module][$type][$id];
}
@@ -254,9 +257,9 @@ function ctools_get_plugins($module, $type, $id = NULL) {
if (!empty($cache->data)) {
// Cache load succeeded so use the cached plugin list.
- $plugins[$module][$type] = $cache->data;
+ $plugins[$module][$type] = $cache->data;
// Set $setup to true so we know things where loaded.
- $setup[$module][$type] = TRUE;
+ $setup[$module][$type] = TRUE;
}
else {
// Cache load failed so store that we need to build and write the cache.
@@ -271,8 +274,8 @@ function ctools_get_plugins($module, $type, $id = NULL) {
$plugins[$module][$type] = ctools_plugin_load_hooks($info[$module][$type]);
}
- // Then see if we should load all files. We only do this if we
- // want a list of all plugins or there was a cache miss.
+ // Then see if we should load all files. We only do this if we want a list of
+ // all plugins or there was a cache miss.
if (empty($setup[$module][$type]) && ($build_cache || !$id)) {
$setup[$module][$type] = TRUE;
$plugins[$module][$type] = array_merge($plugins[$module][$type], ctools_plugin_load_includes($info[$module][$type]));
@@ -295,9 +298,8 @@ function ctools_get_plugins($module, $type, $id = NULL) {
}
}
-
- // If we were told earlier that this is cacheable and the cache was
- // empty, give something back.
+ // If we were told earlier that this is cacheable and the cache was empty,
+ // give something back.
if ($build_cache) {
cache_set("plugins:$module:$type", $plugins[$module][$type], $info[$module][$type]['cache table']);
}
@@ -309,7 +311,7 @@ function ctools_get_plugins($module, $type, $id = NULL) {
return array_filter($plugins[$module][$type]);
}
- // Check to see if we need to look for the file
+ // Check to see if we need to look for the file.
if (!array_key_exists($id, $plugins[$module][$type])) {
// If we can have child plugins, check to see if the plugin name is in the
// format of parent:child and break it up if it is.
@@ -415,19 +417,20 @@ function ctools_get_plugins_reset() {
/**
* Load plugins from a directory.
*
- * @param $info
+ * @param array $info
* The plugin info as returned by ctools_plugin_get_info()
- * @param $file
+ * @param string $filename
* The file to load if we're looking for just one particular plugin.
*
- * @return
- * An array of information created for this plugin.
+ * @return array
+ * A (possibly empty) array of information created for this plugin.
*/
function ctools_plugin_load_includes($info, $filename = NULL) {
// Keep a static array so we don't hit file_scan_directory more than necessary.
$all_files = &drupal_static(__FUNCTION__, array());
- // store static of plugin arrays for reference because they can't be reincluded.
+ // Store static of plugin arrays for reference because they can't be
+ // reincluded, so there is no point in using drupal_static().
static $plugin_arrays = array();
if (!isset($all_files[$info['module']][$info['type']])) {
@@ -462,24 +465,23 @@ function ctools_plugin_load_includes($info, $filename = NULL) {
}
foreach ($files as $file) {
if (!empty($info['info file'])) {
- // Parse a .info file
+ // Parse a .info file.
$result = ctools_plugin_process_info($info, $module, $file);
}
else {
// Parse a hook.
- $plugin = NULL; // ensure that we don't have something leftover from earlier.
+ // Ensure that we don't have something leftover from earlier.
+ $plugin = NULL;
if (isset($plugin_arrays[$file->uri])) {
$identifier = $plugin_arrays[$file->uri];
}
else {
-
- require_once DRUPAL_ROOT . '/' . $file->uri;
+ include_once DRUPAL_ROOT . '/' . $file->uri;
// .inc files have a special format for the hook identifier.
// For example, 'foo.inc' in the module 'mogul' using the plugin
- // whose hook is named 'borg_type' should have a function named (deep breath)
- // mogul_foo_borg_type()
-
+ // whose hook is named 'borg_type' should have a function named
+ // (deep breath) mogul_foo_borg_type().
// If, however, the .inc file set the quasi-global $plugin array, we
// can use that and not even call a function. Set the $identifier
// appropriately and ctools_plugin_process() will handle it.
@@ -492,7 +494,8 @@ function ctools_plugin_load_includes($info, $filename = NULL) {
}
}
- $result = ctools_plugin_process($info, $module, $identifier, dirname($file->uri), basename($file->uri), $file->name);
+ $result = ctools_plugin_process($info, $module, $identifier,
+ dirname($file->uri), basename($file->uri), $file->name);
}
if (is_array($result)) {
$plugins = array_merge($plugins, $result);
@@ -512,7 +515,7 @@ function ctools_plugin_load_includes($info, $filename = NULL) {
* @param $info
* The $info array for the plugin as returned by ctools_plugin_get_info().
*
- * @return array $directories
+ * @return array
* An array of directories to search.
*/
function ctools_plugin_get_directories($info) {
@@ -538,21 +541,21 @@ function ctools_plugin_get_directories($info) {
}
/**
- * Helper function to build a ctools-friendly list of themes capable of
- * providing plugins.
+ * Helper to build a ctools-friendly list of themes capable of providing plugins.
*
- * @return array $themes
+ * @return array
* A list of themes that can act as plugin providers, sorted parent-first with
* the active theme placed last.
*/
function _ctools_list_themes() {
+ // @TODO: Use drupal_static() here?
static $themes;
if (is_null($themes)) {
$current = variable_get('theme_default', FALSE);
$themes = $active = array();
$all_themes = list_themes();
foreach ($all_themes as $name => $theme) {
- // Only search from active themes
+ // Only search from active themes.
if (empty($theme->status) && $theme->name != $current) {
continue;
}
@@ -563,19 +566,19 @@ function _ctools_list_themes() {
}
}
- // Construct a parent-first list of all themes
+ // Construct a parent-first list of all themes.
foreach ($active as $name => $theme) {
$base_themes = isset($theme->base_themes) ? $theme->base_themes : array();
$themes = array_merge($themes, $base_themes, array($name => $theme->info['name']));
}
- // Put the actual theme info objects into the array
+ // Put the actual theme info objects into the array.
foreach (array_keys($themes) as $name) {
if (isset($all_themes[$name])) {
$themes[$name] = $all_themes[$name];
}
}
- // Make sure the current default theme always gets the last word
+ // Make sure the current default theme always gets the last word.
if ($current_key = array_search($current, array_keys($themes))) {
$themes += array_splice($themes, $current_key, 1);
}
@@ -583,7 +586,6 @@ function _ctools_list_themes() {
return $themes;
}
-
/**
* Find all the base themes for the specified theme.
*
@@ -599,9 +601,10 @@ function _ctools_list_themes() {
* The name of the theme whose base we are looking for.
* @param $used_keys
* A recursion parameter preventing endless loops.
- * @return
+ *
+ * @return array
* Returns an array of all of the theme's ancestors; the first element's value
- * will be NULL if an error occurred.
+ * will be NULL if an error occurred. (Note: this is NOT $arr[0]).
*/
function ctools_find_base_themes($themes, $key, $used_keys = array()) {
$base_key = $themes[$key]->info['base theme'];
@@ -629,7 +632,6 @@ function ctools_find_base_themes($themes, $key, $used_keys = array()) {
return $current_base_theme;
}
-
/**
* Load plugin info for the provided hook; this is handled separately from
* plugins from files.
@@ -654,22 +656,28 @@ function ctools_plugin_load_hooks($info) {
/**
* Process a single hook implementation of a ctools plugin.
*
- * @param $info
+ * @param array $info
* The $info array about the plugin as returned by ctools_plugin_get_info()
- * @param $module
+ * @param string $module
* The module that implements the plugin being processed.
- * @param $identifier
- * The plugin identifier, which is used to create the name of the hook
- * function being called.
- * @param $path
+ * @param string|array $identifier
+ * Used to create the base setting of return value. If:
+ * - $identifier is a string, a hook name is created from this and the 'hook'
+ * key of the $info array, and the return value of that hook function is
+ * used. The hook is called like this: $identifier_$hook($info);
+ * - $identifier is an array, this array is used directly.
+ * @param string $path
* The path where files utilized by this plugin will be found.
- * @param $file
+ * @param string $file
* The file that was loaded for this plugin, if it exists.
- * @param $base
+ * @param string $base
* The base plugin name to use. If a file was loaded for the plugin, this
* is the plugin to assume must be present. This is used to automatically
* translate the array to make the syntax more friendly to plugin
* implementors.
+ *
+ * @return null|array
+ * NULL on failure, otherwise an array containing the results keyed by name.
*/
function ctools_plugin_process($info, $module, $identifier, $path, $file = NULL, $base = NULL) {
if (is_array($identifier)) {
@@ -737,9 +745,19 @@ function _ctools_process_data($result, $plugin_type_info, $module, $path, $file)
return $result;
}
-
/**
* Process an info file for plugin information, rather than a hook.
+ *
+ * @param array $info
+ * The $info array about the plugin as returned by ctools_plugin_get_info()
+ * @param string $module
+ * The module that implements the plugin being processed.
+ * @param object $file
+ * An object containing 'uri' and 'name' properties. 'uri' is the name of the
+ * 'info' file to process. 'name' is the plugin key-name.
+ *
+ * @return null|array
+ * NULL on failure, otherwise an array containing the results keyed by name.
*/
function ctools_plugin_process_info($info, $module, $file) {
$result = drupal_parse_info_file($file->uri);
@@ -766,7 +784,7 @@ function ctools_plugin_get_info($module, $type) {
* @param $function_name
* The identifier of the function. For example, 'settings form'.
*
- * @return
+ * @return string
* The actual name of the function to call, or NULL if the function
* does not exist.
*/
@@ -783,7 +801,7 @@ function ctools_plugin_get_function($plugin_definition, $function_name) {
}
if (!isset($plugin_definition[$function_name])) {
- return;
+ return NULL;
}
if (is_array($plugin_definition[$function_name]) && isset($plugin_definition[$function_name]['function'])) {
@@ -818,7 +836,7 @@ function ctools_plugin_get_function($plugin_definition, $function_name) {
* @param $function_name
* The identifier of the function. For example, 'settings form'.
*
- * @return
+ * @return string
* The actual name of the function to call, or NULL if the function
* does not exist.
*/
@@ -836,7 +854,7 @@ function ctools_plugin_load_function($module, $type, $id, $function_name) {
* @param $class_name
* The identifier of the class. For example, 'handler'.
*
- * @return
+ * @return string
* The actual name of the class to call, or NULL if the class does not exist.
*/
function ctools_plugin_get_class($plugin_definition, $class_name) {
@@ -855,11 +873,11 @@ function ctools_plugin_get_class($plugin_definition, $class_name) {
if (!isset($plugin_definition[$class_name])) {
return;
}
- else if (is_string($plugin_definition[$class_name])) {
+ elseif (is_string($plugin_definition[$class_name])) {
// Plugin uses the string form shorthand.
$return = $plugin_definition[$class_name];
}
- else if (isset($plugin_definition[$class_name]['class'])) {
+ elseif (isset($plugin_definition[$class_name]['class'])) {
// Plugin uses the verbose array form.
$return = $plugin_definition[$class_name]['class'];
}
@@ -881,7 +899,7 @@ function ctools_plugin_get_class($plugin_definition, $class_name) {
* @param $class_name
* The identifier of the class. For example, 'handler'.
*
- * @return
+ * @return string
* The actual name of the class to call, or NULL if the class does not exist.
*/
function ctools_plugin_load_class($module, $type, $id, $class_name) {
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/registry.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/registry.inc
index 9d4328e6..7e517bb9 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/registry.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/registry.inc
@@ -2,7 +2,6 @@
/**
* @file
- *
* Registry magic. In a separate file to minimize unnecessary code loading.
*/
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/uuid.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/uuid.inc
index 6e4c42c3..13897f1f 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/uuid.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/uuid.inc
@@ -9,7 +9,9 @@
/**
* Pattern for detecting a valid UUID.
*/
-define('UUID_PATTERN', '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}');
+if (!defined('UUID_PATTERN')) {
+ define('UUID_PATTERN', '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}');
+}
/**
* Generates a UUID using the Windows internal GUID generator.
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/includes/wizard.inc b/profiles/commerce_kickstart/modules/contrib/ctools/includes/wizard.inc
index 1a821a58..e92e0e30 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/includes/wizard.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/includes/wizard.inc
@@ -469,10 +469,8 @@ function ctools_wizard_get_path($form_info, $step) {
if (!isset($path[1]) || !is_array($path[1])) {
$path[1] = array();
}
- // Ensure that the query part of options is an array.
- $path[1] += array('query' => array());
// Add the destination parameter, if not set already.
- $path[1]['query'] += drupal_get_destination();
+ $path[1] += drupal_get_destination();
}
return $path;
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/js/auto-submit.js b/profiles/commerce_kickstart/modules/contrib/ctools/js/auto-submit.js
index a3e9aa42..b658577a 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/js/auto-submit.js
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/js/auto-submit.js
@@ -36,9 +36,11 @@ Drupal.behaviors.CToolsAutoSubmit = {
attach: function(context) {
// 'this' references the form element
function triggerSubmit (e) {
- var $this = $(this);
- if (!$this.hasClass('ctools-ajaxing')) {
- $this.find('.ctools-auto-submit-click').click();
+ if ($.contains(document.body, this)) {
+ var $this = $(this);
+ if (!$this.hasClass('ctools-ajaxing')) {
+ $this.find('.ctools-auto-submit-click').click();
+ }
}
}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/js/dependent.js b/profiles/commerce_kickstart/modules/contrib/ctools/js/dependent.js
index f74ec81b..a60fc120 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/js/dependent.js
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/js/dependent.js
@@ -97,7 +97,13 @@
else {
switch ($(trigger).attr('type')) {
case 'checkbox':
- var val = $(trigger).attr('checked') ? true : false;
+ // **This check determines if using a jQuery version 1.7 or newer which requires the use of the prop function instead of the attr function when not called on an attribute
+ if ($().prop) {
+ var val = $(trigger).prop('checked') ? true : false;
+ }
+ else {
+ var val = $(trigger).attr('checked') ? true : false;
+ }
if (val) {
$(trigger).siblings('label').removeClass('hidden-options').addClass('expanded-options');
@@ -148,34 +154,41 @@
len++;
}
- var object = $('#' + id + '-wrapper');
- if (!object.size()) {
- // Some elements can't use the parent() method or they can
- // damage things. They are guaranteed to have wrappers but
- // only if dependent.inc provided them. This check prevents
- // problems when multiple AJAX calls cause settings to build
- // up.
- var $original = $('#' + id);
- if ($original.is('fieldset') || $original.is('textarea')) {
- continue;
- }
-
- object = $('#' + id).parent();
+ var $original = $('#' + id);
+ if ($original.is('fieldset') || $original.is('textarea')) {
+ continue;
}
+ var object = $original.parent();
+
if (Drupal.settings.CTools.dependent[id].type == 'disable') {
if (Drupal.settings.CTools.dependent[id].num <= len) {
// Show if the element if criteria is matched
- object.attr('disabled', false);
- object.addClass('dependent-options');
- object.children().attr('disabled', false);
+ // **This check determines if using a jQuery version 1.7 or newer which requires the use of the prop function instead of the attr function when not called on an attribute
+ if (typeof $().prop == 'function') {
+ object.prop('disabled', false);
+ object.addClass('dependent-options');
+ object.children().prop('disabled', false);
+ }
+ else {
+ object.attr('disabled', false);
+ object.addClass('dependent-options');
+ object.children().attr('disabled', false);
+ }
}
else {
// Otherwise hide. Use css rather than hide() because hide()
// does not work if the item is already hidden, for example,
// in a collapsed fieldset.
- object.attr('disabled', true);
- object.children().attr('disabled', true);
+ // **This check determines if using a jQuery version 1.7 or newer which requires the use of the prop function instead of the attr function when not called on an attribute
+ if (typeof $().prop == 'function') {
+ object.prop('disabled', true);
+ object.children().prop('disabled', true);
+ }
+ else {
+ object.attr('disabled', true);
+ object.children().attr('disabled', true);
+ }
}
}
else {
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/js/modal.js b/profiles/commerce_kickstart/modules/contrib/ctools/js/modal.js
index c757ef27..e65f51af 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/js/modal.js
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/js/modal.js
@@ -121,18 +121,18 @@
*/
Drupal.theme.prototype.CToolsModalDialog = function () {
var html = ''
- html += '
';
return html;
}
@@ -142,11 +142,11 @@
*/
Drupal.theme.prototype.CToolsModalThrobber = function () {
var html = '';
- html += '
';
- html += '
';
- html += Drupal.CTools.Modal.currentSettings.throbber;
- html += '
';
+ html += '
';
+ html += '
';
+ html += Drupal.CTools.Modal.currentSettings.throbber;
html += '
';
+ html += '
';
return html;
};
@@ -265,7 +265,10 @@
}
// An empty event means we were triggered via .click() and
// in jquery 1.4 this won't trigger a submit.
- if (event.bubbles == undefined) {
+ // We also have to check jQuery version to prevent
+ // IE8 + jQuery 1.4.4 to break on other events
+ // bound to the submit button.
+ if (jQuery.fn.jquery.substr(0, 3) === '1.4' && typeof event.bubbles === "undefined") {
$(this.form).trigger('submit');
return false;
}
@@ -299,7 +302,7 @@
// Attach behaviors within a modal dialog.
var settings = response.settings || ajax.settings || Drupal.settings;
- Drupal.attachBehaviors('#modalContent', settings);
+ Drupal.attachBehaviors($('#modalContent'), settings);
if ($('#modal-content').hasClass('ctools-modal-loading')) {
$('#modal-content').removeClass('ctools-modal-loading');
@@ -551,6 +554,7 @@
// Create our content div, get the dimensions, and hide it
var modalContent = $('#modalContent').css('top','-1000px');
+ var $modalHeader = modalContent.find('.modal-header');
var mdcTop = wt + ( winHeight / 2 ) - ( modalContent.outerHeight() / 2);
var mdcLeft = ( winWidth / 2 ) - ( modalContent.outerWidth() / 2);
$('#modalBackdrop').css(css).css('top', 0).css('height', docHeight + 'px').css('width', docWidth + 'px').show();
@@ -558,7 +562,7 @@
// Bind a click for closing the modalContent
modalContentClose = function(){close(); return false;};
- $('.close').bind('click', modalContentClose);
+ $('.close', $modalHeader).bind('click', modalContentClose);
// Bind a keypress on escape for closing the modalContent
modalEventEscapeCloseHandler = function(event) {
@@ -574,7 +578,7 @@
// close button, but we should save the original focus to restore it after
// the dialog is closed.
var oldFocus = document.activeElement;
- $('.close').focus();
+ $('.close', $modalHeader).focus();
// Close the open modal content and backdrop
function close() {
@@ -583,7 +587,7 @@
$('body').unbind( 'focus', modalEventHandler);
$('body').unbind( 'keypress', modalEventHandler );
$('body').unbind( 'keydown', modalTabTrapHandler );
- $('.close').unbind('click', modalContentClose);
+ $('.close', $modalHeader).unbind('click', modalContentClose);
$('body').unbind('keypress', modalEventEscapeCloseHandler);
$(document).trigger('CToolsDetachBehaviors', $('#modalContent'));
@@ -659,9 +663,11 @@
$('body').unbind('focus', modalEventHandler);
$('body').unbind('keypress', modalEventHandler);
$('body').unbind( 'keydown', modalTabTrapHandler );
- $('.close').unbind('click', modalContentClose);
+ var $modalContent = $('#modalContent');
+ var $modalHeader = $modalContent.find('.modal-header');
+ $('.close', $modalHeader).unbind('click', modalContentClose);
$('body').unbind('keypress', modalEventEscapeCloseHandler);
- $(document).trigger('CToolsDetachBehaviors', $('#modalContent'));
+ $(document).trigger('CToolsDetachBehaviors', $modalContent);
// jQuery magic loop through the instances and run the animations or removal.
content.each(function(){
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/js/stylizer.js b/profiles/commerce_kickstart/modules/contrib/ctools/js/stylizer.js
index 16d6c49d..12ab7204 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/js/stylizer.js
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/js/stylizer.js
@@ -5,7 +5,7 @@
Drupal.CTools.Stylizer.addFarbtastic = function(context) {
// This behavior attaches by ID, so is only valid once on a page.
- if ($('ctools_stylizer_color_scheme_form .color-form.Stylizer-processed').size()) {
+ if ($('#ctools_stylizer_color_scheme_form .color-form.Stylizer-processed').size()) {
return;
}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/help/getting-started.html b/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/help/getting-started.html
index 4e4f24ae..6a75a370 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/help/getting-started.html
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/help/getting-started.html
@@ -4,7 +4,7 @@
This is a quick summary:
-
Visit administer >> site building >> pages to get to the primary page manager interface.
+
Visit administer >> structure >> pages to get to the primary page manager interface.
You can add custom pages for your basic landing pages, front pages, whatever you like for normal content display.
You can use the system pages to create finer control of how taxonomy vocabularies, nodes and user profiles are displayed.
When you add your first custom page, do not bother with the optional features. You will not need these until you get to more advanced tasks.
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/page_manager.admin.inc b/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/page_manager.admin.inc
index 0f164fe5..95d12255 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/page_manager.admin.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/page_manager.admin.inc
@@ -1542,25 +1542,42 @@ function page_manager_handler_import_submit(&$form, &$form_state) {
* Rearrange the order of variants.
*/
function page_manager_handler_rearrange($form, &$form_state) {
+ ctools_include('context-task-handler');
$page = $form_state['page'];
$form['handlers'] = array('#tree' => TRUE);
+ // Get the number of variants to be displayed in order to set the delta
+ // to the proper value. This fixes problems in previous versions with sorting
+ // large numbers of variants.
+ $delta = count($page->handler_info)/2 + 1;
+
foreach ($page->handler_info as $id => $info) {
if ($info['changed'] & PAGE_MANAGER_CHANGED_DELETED) {
continue;
}
$handler = $page->handlers[$id];
$plugin = page_manager_get_task_handler($handler->handler);
-
+ $object = ctools_context_handler_get_task_object($page->task, $page->subtask, $handler);
+ $display = new stdClass();
+ $display->context = ctools_context_load_contexts($object, TRUE);
+ $content = page_manager_get_handler_title($plugin, $handler, $page->task, $page->subtask_id);
+ $access = ctools_access_group_summary(!empty($handler->conf['access']) ? $handler->conf['access'] : array(), $display->context);
+ if ($access) {
+ $access = t('This panel will be selected if @conditions.', array('@conditions' => $access));
+ }
+ else {
+ $access = t('This panel will always be selected.');
+ }
+ $content .= '
' . $access . '
';
$form['handlers'][$id]['title'] = array(
- '#markup' => page_manager_get_handler_title($plugin, $handler, $page->task, $page->subtask_id),
+ '#markup' => $content,
);
$form['handlers'][$id]['weight'] = array(
'#type' => 'weight',
'#default_value' => $info['weight'],
- '#delta' => 30,
+ '#delta' => $delta,
);
}
@@ -1671,6 +1688,12 @@ function page_manager_handler_clone_submit(&$form, &$form_state) {
page_manager_handler_add_to_page($form_state['page'], $handler, $form_state['values']['title']);
+ // Variant is cloned and added to the Page. Ensure the uuids are re-generated.
+ panels_panel_context_get_display($handler);
+ if (isset($handler->conf['display']) && method_exists($handler->conf['display'], 'clone_display')) {
+ $handler->conf['display'] = $handler->conf['display']->clone_display();
+ }
+
$plugin = page_manager_get_task_handler($handler->handler);
// It has no forms at all. Add the variant and go to its first operation.
$keys = array_keys($plugin['operations']);
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/page_manager.info b/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/page_manager.info
index c7f4df3a..f86687f8 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/page_manager.info
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/page_manager.info
@@ -5,9 +5,11 @@ dependencies[] = ctools
package = Chaos tool suite
version = CTOOLS_MODULE_VERSION
-; Information added by Drupal.org packaging script on 2015-08-19
-version = "7.x-1.9"
+files[] = tests/head_links.test
+
+; Information added by Drupal.org packaging script on 2018-02-04
+version = "7.x-1.13"
core = "7.x"
project = "ctools"
-datestamp = "1440020680"
+datestamp = "1517704095"
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/page_manager.module b/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/page_manager.module
index f3cb743e..a498f7fb 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/page_manager.module
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/page_manager.module
@@ -1202,7 +1202,7 @@ function page_manager_page_manager_pages_to_hook_code($names = array(), $name =
foreach ($objects as $object) {
// Have to implement our own because this export func sig requires it
$code .= $export['export callback']($object, TRUE, ' ');
- $code .= " \${$export['identifier']}s['" . check_plain($object->$export['key']) . "'] = \${$export['identifier']};\n\n";
+ $code .= " \${$export['identifier']}s['" . check_plain($object->{$export['key']}) . "'] = \${$export['identifier']};\n\n";
}
$code .= " return \${$export['identifier']}s;\n";
$code .= "}\n";
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/plugins/task_handlers/http_response.inc b/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/plugins/task_handlers/http_response.inc
index c4eba8e2..8fc0f256 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/plugins/task_handlers/http_response.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/plugins/task_handlers/http_response.inc
@@ -3,7 +3,8 @@
/**
* @file
*
- * This is the task handler plugin to handle generating 403, 404 and 301 response codes.
+ * This is the task handler plugin to handle generating 403, 404, 301 and 302
+ * response codes.
*/
// Plugin definition
@@ -108,7 +109,8 @@ function page_manager_http_response_codes() {
403 => t('403 Access denied'),
404 => t('404 Page not found'),
410 => t('410 Gone'),
- 301 => t('301 Redirect'),
+ 301 => t('301 Permanent redirect'),
+ 302 => t('302 Temporary redirect'),
);
}
@@ -256,7 +258,7 @@ function page_manager_http_response_edit_settings($form, &$form_state) {
'#type' => 'textfield',
'#title' => t('Redirect destination'),
'#default_value' => $conf['destination'],
- '#dependency' => array('edit-code' => array(301)),
+ '#dependency' => array('edit-code' => array(301, 302)),
'#description' => t('Enter the path to redirect to. You may use keyword substitutions from contexts. You can use external urls (http://www.example.com/foo) or internal urls (node/1).'),
);
@@ -313,7 +315,7 @@ function page_manager_http_response_render($handler, $base_contexts, $args, $tes
}
$info['response code'] = $handler->conf['code'];
- if ($info['response code'] == 301) {
+ if ($info['response code'] == 301 || $info['response code'] == 302) {
$path = ctools_context_keyword_substitute($handler->conf['destination'], array(), $contexts);
$url = parse_url($path);
if (isset($url['query'])) {
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/plugins/tasks/node_view.inc b/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/plugins/tasks/node_view.inc
index 89a29128..fb2f2a41 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/plugins/tasks/node_view.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/plugins/tasks/node_view.inc
@@ -85,6 +85,23 @@ function page_manager_node_view_page($node) {
ctools_include('context');
ctools_include('context-task-handler');
+ $uri = entity_uri('node', $node);
+ if (isset($uri['path'])) {
+ // Set the node path as the canonical URL to prevent duplicate content.
+ $meta_canon = array(
+ 'rel' => 'canonical',
+ 'href' => url($uri['path'], $uri['options']),
+ );
+ drupal_add_html_head_link($meta_canon, TRUE);
+
+ // Set the non-aliased path as a default shortlink.
+ $meta_short = array(
+ 'rel' => 'shortlink',
+ 'href' => url($uri['path'], array_merge($uri['options'], array('alias' => TRUE)))
+ );
+ drupal_add_html_head_link($meta_short, TRUE);
+ }
+
// Load all contexts.
$contexts = ctools_context_handler_get_task_contexts($task, '', array($node));
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/plugins/tasks/page.admin.inc b/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/plugins/tasks/page.admin.inc
index 97bd37bc..b2ae8cbe 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/plugins/tasks/page.admin.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/plugins/tasks/page.admin.inc
@@ -698,7 +698,7 @@ function page_manager_page_form_menu($form, &$form_state) {
'#title' => t('Title'),
'#type' => 'textfield',
'#default_value' => $menu['title'],
- '#description' => t('If set to normal or tab, enter the text to use for the menu item.'),
+ '#description' => t('If set to normal or tab, enter the text to use for the menu item. Renaming the menu item using the Drupal menu system (admin/structure/menu) will override this, even if it is renamed again here.'),
'#dependency' => array('radio:menu[type]' => array('normal', 'tab', 'default tab', 'action')),
);
@@ -1462,6 +1462,15 @@ function page_manager_page_form_clone_submit(&$form, &$form_state) {
$original->path = $form_state['values']['path'];
$handlers = !empty($form_state['values']['handlers']) ? $form_state['page']->handlers : FALSE;
+ // Ensure the handler uuids are re-generated.
+ if ($handlers) {
+ foreach ($handlers as &$handler) {
+ if (isset($handler->conf['display']) && method_exists($handler->conf['display'], 'clone_display')) {
+ $handler->conf['display'] = $handler->conf['display']->clone_display();
+ }
+ }
+ }
+
// Export the handler, which is a fantastic way to clean database IDs out of it.
$export = page_manager_page_export($original, $handlers);
ob_start();
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/tests/head_links.test b/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/tests/head_links.test
new file mode 100644
index 00000000..f3bc5a44
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/page_manager/tests/head_links.test
@@ -0,0 +1,74 @@
+ 'Head links test',
+ 'description' => 'Checks that the shortlink and canonical links are present on a node page overriden by Page manager',
+ 'group' => 'ctools',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setUp() {
+ parent::setUp('page_manager');
+
+ // First add an override for "node/%node".
+ variable_set('page_manager_node_view_disabled', FALSE);
+
+ $record = (object) array(
+ 'name' => 'node_view__http_response_707659df-062d-4252-8c2a-22a8e0289cd4',
+ 'task' => 'node_view',
+ 'subtask' => '',
+ 'handler' => 'http_response',
+ 'weight' => '1',
+ 'conf' => array(
+ 'title' => 'Test',
+ 'contexts' => array(
+ 0 => array(
+ 'identifier' => 'String',
+ 'keyword' => 'string',
+ 'name' => 'string',
+ 'string' => 'Test',
+ 'id' => 1,
+ ),
+ ),
+ 'relationships' => array(),
+ 'code' => '404',
+ 'destination' => '',
+ 'name' => '',
+ ),
+ );
+
+ page_manager_save_task_handler($record);
+
+ menu_rebuild();
+ }
+
+ /**
+ * Test the presence of the head links.
+ */
+ public function testHeadLinks() {
+ $node = $this->drupalCreateNode();
+ $url = 'node/' . $node->nid;
+ $this->drupalGet($url);
+
+ $shortlink = $this->xpath('//head//link[@rel="shortlink"]');
+ $this->assertEqual(url($url), (string) $shortlink[0]['href'], 'shortlink url found');
+
+ $canonical = $this->xpath('//head//link[@rel="canonical"]');
+ $this->assertEqual(url($url), (string) $canonical[0]['href'], 'canonical url found');
+ }
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/access/compare_users.inc b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/access/compare_users.inc
index c271ff4e..a8c44f4d 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/access/compare_users.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/access/compare_users.inc
@@ -2,7 +2,7 @@
/**
* @file
- * Ctools access plugin to provide access/visiblity if two user contexts are equal.
+ * CTools access plugin to provide access/visiblity if two user contexts are equal.
*/
/**
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/access/query_string_exists.inc b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/access/query_string_exists.inc
new file mode 100644
index 00000000..abec5f7a
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/access/query_string_exists.inc
@@ -0,0 +1,44 @@
+ t('Query string exists'),
+ 'description' => t('Control access by whether or not a query string exists.'),
+ 'callback' => 'ctools_query_string_exists_ctools_access_check',
+ 'settings form' => 'ctools_query_string_exists_ctools_access_settings',
+ 'summary' => 'ctools_query_string_exists_ctools_access_summary',
+ 'defaults' => array('key' => ''),
+);
+
+/**
+ * Settings form.
+ */
+function ctools_query_string_exists_ctools_access_settings($form, &$form_state, $config) {
+ $form['settings']['key'] = array(
+ '#title' => t('Query string key'),
+ '#description' => t('Enter the key of the query string.'),
+ '#type' => 'textfield',
+ '#required' => TRUE,
+ '#default_value' => $config['key']
+ );
+
+ return $form;
+}
+
+/**
+ * Check for access.
+ */
+function ctools_query_string_exists_ctools_access_check($config, $context) {
+ return isset($_GET[$config['key']]);
+}
+
+/**
+ * Provide a summary description.
+ */
+function ctools_query_string_exists_ctools_access_summary($config, $context) {
+ return t('@identifier exists', array('@identifier' => $config['key']));
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/arguments/term.inc b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/arguments/term.inc
index 868c8aa5..65c87ac7 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/arguments/term.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/arguments/term.inc
@@ -18,6 +18,7 @@ $plugin = array(
'context' => 'ctools_term_context',
'default' => array('input_form' => 'tid', 'breadcrumb' => TRUE, 'transform' => FALSE),
'settings form' => 'ctools_term_settings_form',
+ 'settings form validate' => 'ctools_term_settings_form_validate',
'placeholder form' => 'ctools_term_ctools_argument_placeholder',
'breadcrumb' => 'ctools_term_breadcrumb',
);
@@ -31,6 +32,16 @@ function ctools_term_context($arg = NULL, $conf = NULL, $empty = FALSE) {
return ctools_context_create_empty('entity:taxonomy_term');
}
+ if (isset($conf['vocabularies'])) {
+ $vocabularies = $conf['vocabularies'];
+ }
+ else {
+ $vids = isset($conf['vids']) ? $conf['vids'] : array();
+
+ // Convert legacy use of vids to machine names.
+ $vocabularies = _ctools_term_vocabulary_machine_name_convert($vids);
+ }
+
if (is_object($arg)) {
$term = $arg;
}
@@ -50,12 +61,11 @@ function ctools_term_context($arg = NULL, $conf = NULL, $empty = FALSE) {
}
$terms = taxonomy_get_term_by_name($arg);
-
- $conf['vids'] = is_array($conf['vids']) ? array_filter($conf['vids']) : NULL;
- if ((count($terms) > 1) && isset($conf['vids'])) {
+ // If only one term is found, fall through to vocabulary check below.
+ if ((count($terms) > 1) && $vocabularies) {
foreach ($terms as $potential) {
- foreach ($conf['vids'] as $vid => $active) {
- if ($active && $potential->vid == $vid) {
+ foreach ($vocabularies as $machine_name) {
+ if ($potential->vocabulary_machine_name == $machine_name) {
$term = $potential;
// break out of the foreaches AND the case
break 3;
@@ -72,7 +82,7 @@ function ctools_term_context($arg = NULL, $conf = NULL, $empty = FALSE) {
}
}
- if (!empty($conf['vids']) && array_filter($conf['vids']) && empty($conf['vids'][$term->vid])) {
+ if ($vocabularies && !isset($vocabularies[$term->vocabulary_machine_name])) {
return NULL;
}
@@ -98,13 +108,20 @@ function ctools_term_settings_form(&$form, &$form_state, $conf) {
$vocabularies = taxonomy_get_vocabularies();
$options = array();
foreach ($vocabularies as $vid => $vocab) {
- $options[$vid] = $vocab->name;
+ $options[$vocab->machine_name] = $vocab->name;
+ }
+
+ // Fallback on legacy 'vids', when no vocabularies are available.
+ if (empty($conf['vocabularies']) && !empty($conf['vids'])) {
+ $conf['vocabularies'] = _ctools_term_vocabulary_machine_name_convert(array_filter($conf['vids']));
+ unset($conf['vids']);
}
- $form['settings']['vids'] = array(
+
+ $form['settings']['vocabularies'] = array(
'#title' => t('Limit to these vocabularies'),
'#type' => 'checkboxes',
'#options' => $options,
- '#default_value' => !empty($conf['vids']) ? $conf['vids'] : array(),
+ '#default_value' => !empty($conf['vocabularies']) ? $conf['vocabularies'] : array(),
'#description' => t('If no vocabularies are checked, terms from all vocabularies will be accepted.'),
);
@@ -123,6 +140,12 @@ function ctools_term_settings_form(&$form, &$form_state, $conf) {
// return $form;
}
+function ctools_term_settings_form_validate (&$form, &$form_state) {
+ // Filter the selected vocabularies to avoid storing redundant data.
+ $vocabularies = array_filter($form_state['values']['settings']['vocabularies']);
+ form_set_value($form['settings']['vocabularies'], $vocabularies, $form_state);
+}
+
/**
* Form fragment to get an argument to convert a placeholder for preview.
*/
@@ -161,3 +184,20 @@ function ctools_term_breadcrumb($conf, $context) {
$breadcrumb = array_merge(drupal_get_breadcrumb(), array_reverse($breadcrumb));
drupal_set_breadcrumb($breadcrumb);
}
+
+/**
+ * Helper function to convert convert legacy vocabulary ids into machine names.
+ *
+ * @param array $vids
+ * Array of either vids.
+ * @return array
+ * A keyed array of machine names.
+ */
+function _ctools_term_vocabulary_machine_name_convert($vids) {
+ $vocabularies = taxonomy_vocabulary_load_multiple($vids);
+ $return = array();
+ foreach($vocabularies as $vocabulary) {
+ $return[$vocabulary->machine_name] = $vocabulary->machine_name;
+ }
+ return $return;
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/arguments/terms.inc b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/arguments/terms.inc
index 4298ea91..d31f28de 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/arguments/terms.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/arguments/terms.inc
@@ -65,6 +65,7 @@ function ctools_terms_breadcrumb($conf, $context) {
return;
}
+ $current = new stdClass();
$current->tid = $context->tids[0];
$breadcrumb = array();
while ($parents = taxonomy_get_parents($current->tid)) {
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/cache/export_ui.inc b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/cache/export_ui.inc
index 53483a53..469edac8 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/cache/export_ui.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/cache/export_ui.inc
@@ -14,6 +14,10 @@ $plugin = array(
// Some operations use a 'finalize' but that really just means set
// for us, since we're not using temporary storage for subsystems.
'cache finalize' => 'ctools_cache_export_ui_cache_set',
+ // @todo The API specifications say that a 'cache clear' callback is required,
+ // but there is none provided?
+ // @see cache.inc
+ // 'cache clear' => ???
);
function ctools_cache_export_ui_cache_get($plugin_name, $key) {
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/content_types/block/block.inc b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/content_types/block/block.inc
index 4d4c31c3..46b02e9e 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/content_types/block/block.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/content_types/block/block.inc
@@ -372,9 +372,9 @@ function profile_ctools_block_info($module, $delta, &$info) {
}
function book_ctools_block_info($module, $delta, &$info) {
- // Hide the book navigation block which isn't as rich as what we can
- // do with context.
- $info = NULL;
+ $info['title'] = t('Book navigation menu');
+ $info['icon'] = 'icon_core_block_menu.png';
+ $info['category'] = t('Node');
}
function blog_ctools_block_info($module, $delta, &$info) {
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/content_types/comment/comment_links.inc b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/content_types/comment/comment_links.inc
index c8fefcca..fcca9703 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/content_types/comment/comment_links.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/content_types/comment/comment_links.inc
@@ -26,7 +26,7 @@ function ctools_comment_links_content_type_render($subtype, $conf, $panel_args,
return;
}
- $comment = isset($context->data) ? clone($context->data) : NULL;
+ $comment = isset($context->data) ? clone $context->data : NULL;
$block = new stdClass();
$block->module = 'comment';
$block->delta = $comment->cid;
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/content_types/comment/comment_reply_form.inc b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/content_types/comment/comment_reply_form.inc
index c05effb6..11e48b2a 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/content_types/comment/comment_reply_form.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/content_types/comment/comment_reply_form.inc
@@ -2,7 +2,7 @@
/**
* @file
- * Ctools content-type plugin to provide a comment-reply form (replying either
+ * CTools content-type plugin to provide a comment-reply form (replying either
* to a node or to another comment).
*/
@@ -25,7 +25,7 @@ if (module_exists('comment')) {
function ctools_comment_reply_form_content_type_render($subtype, $conf, $panel_args, $context) {
- $comment = ($context[1]->identifier == t('No context')) ? NULL : clone($context[1]->data);
+ $comment = ($context[1]->identifier == t('No context')) ? NULL : clone $context[1]->data;
$block = new stdClass();
$block->module = 'comments';
if ($comment) $block->delta = $comment->cid;
diff --git a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/content_types/custom/custom.inc b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/content_types/custom/custom.inc
index ac2f2a3f..d9ac79f5 100644
--- a/profiles/commerce_kickstart/modules/contrib/ctools/plugins/content_types/custom/custom.inc
+++ b/profiles/commerce_kickstart/modules/contrib/ctools/plugins/content_types/custom/custom.inc
@@ -16,7 +16,7 @@
$plugin = array(
'title' => t('Custom content'),
'no title override' => TRUE,
- 'defaults' => array('admin_title' => '', 'title' => '', 'body' => '', 'format' => filter_default_format(), 'substitute' => TRUE),
+ 'defaults' => array('admin_title' => '', 'title' => '', 'title_heading' => 'h2', 'body' => '', 'format' => filter_default_format(), 'substitute' => TRUE),
'js' => array('misc/autocomplete.js', 'misc/textarea.js', 'misc/collapse.js'),
// Make sure the edit form is only used for some subtypes.
'edit form' => '',
@@ -135,6 +135,7 @@ function ctools_custom_content_type_get_conf($subtype, $conf) {
$settings = array(
'admin_title' => t('Missing/deleted content'),
'title' => '',
+ 'title_heading' => '',
'body' => '',
'format' => filter_default_format(),
'substitute' => TRUE,
@@ -180,6 +181,8 @@ function ctools_custom_content_type_render($subtype, $conf, $args, $contexts) {
$block = new stdClass();
$block->subtype = ++$delta;
$block->title = filter_xss_admin($settings['title']);
+ $block->title_heading = isset($settings['title_heading']) ? $settings['title_heading'] : 'h2';
+
// Add keyword substitutions if we were configured to do so.
$content = $settings['body'];
@@ -277,10 +280,36 @@ function ctools_custom_content_type_edit_form($form, &$form_state) {
'#description' => t('This title will be used administratively to identify this pane. If blank, the regular title will be used.'),
);
+ // Copy over the title override settings for a title heading.
+ $form['aligner_start'] = array(
+ '#markup' => '
';
+}
+
/** @} End of addtogroup themeable */
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_admin.inc b/profiles/commerce_kickstart/modules/contrib/date/date_admin.inc
index 0e32fc5a..b800201e 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_admin.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_admin.inc
@@ -14,15 +14,24 @@ function date_default_formatter_settings_form($field, $instance, $view_mode, $fo
$formatter = $display['type'];
$form = array();
+ $date_formats = date_format_type_options();
$form['format_type'] = array(
'#title' => t('Choose how users view dates and times:'),
'#type' => 'select',
- '#options' => date_format_type_options(),
+ '#options' => $date_formats + array('custom' => t('Custom')),
'#default_value' => $settings['format_type'],
'#description' => t('To add or edit options, visit Date and time settings.', array('@date-time-page' => url('admin/config/regional/date-time'))),
'#weight' => 0,
);
+ $form['custom_date_format'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Custom date format'),
+ '#description' => t('If "Custom", see the PHP manual for date formats. Otherwise, enter the number of different time units to display, which defaults to 2.', array('@url' => 'http://php.net/manual/function.date.php')),
+ '#default_value' => isset($settings['custom_date_format']) ? $settings['custom_date_format'] : '',
+ '#dependency' => array('edit-options-settings-format-type' => array('custom')),
+ );
+
$form['fromto'] = array(
'#title' => t('Display:'),
'#type' => 'select',
@@ -74,6 +83,12 @@ function date_default_formatter_settings_form($field, $instance, $view_mode, $fo
'#description' => t('Identify specific start and/or end dates in the format YYYY-MM-DDTHH:MM:SS, or leave blank for all available dates.'),
);
+ $form['show_remaining_days'] = array(
+ '#title' => t('Show remaining days'),
+ '#type' => 'checkbox',
+ '#default_value' => $settings['show_remaining_days'],
+ '#weight' => 0,
+ );
return $form;
}
@@ -110,6 +125,14 @@ function date_interval_formatter_settings_form($field, $instance, $view_mode, $f
'#default_value' => $settings['interval_display'],
'#weight' => 0,
);
+ if (!empty($field['settings']['todate'])) {
+ $form['use_end_date'] = array(
+ '#title' => t('Use End date'),
+ '#description' => 'Use the End date, instead of the start date',
+ '#type' => 'checkbox',
+ '#default_value' => $settings['use_end_date'],
+ );
+ }
return $form;
}
@@ -127,9 +150,11 @@ function date_default_formatter_settings_summary($field, $instance, $view_mode)
case 'date_plain':
$format = t('Plain');
break;
+
case 'format_interval':
$format = t('Interval');
break;
+
default:
if (!empty($format_types[$settings['format_type']])) {
$format = $format_types[$settings['format_type']];
@@ -148,7 +173,9 @@ function date_default_formatter_settings_summary($field, $instance, $view_mode)
'value' => t('Display Start date only'),
'value2' => t('Display End date only'),
);
- $summary[] = $options[$settings['fromto']];
+ if (isset($options[$settings['fromto']])) {
+ $summary[] = $options[$settings['fromto']];
+ }
}
if (array_key_exists('multiple_number', $settings) && !empty($field['cardinality'])) {
@@ -159,6 +186,10 @@ function date_default_formatter_settings_summary($field, $instance, $view_mode)
));
}
+ if (array_key_exists('show_remaining_days', $settings)) {
+ $summary[] = t('Show remaining days: @value', array('@value' => ($settings['show_remaining_days'] ? 'yes' : 'no')));
+ }
+
return $summary;
}
@@ -172,7 +203,9 @@ function date_interval_formatter_settings_summary($field, $instance, $view_mode)
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$formatter = $display['type'];
- $summary[] = t('Display time ago, showing @interval units.', array('@interval' => $settings['interval']));
+ $field = ($settings['use_end_date'] == 1) ? 'End' : 'Start';
+ $summary[] = t('Display time ago, showing @interval units. Using @field Date',
+ array('@interval' => $settings['interval'], '@field' => $field));
return $summary;
}
@@ -191,7 +224,11 @@ function _date_field_instance_settings_form($field, $instance) {
'#type' => 'select',
'#title' => t('Default date'),
'#default_value' => $settings['default_value'],
- '#options' => array('blank' => t('No default value'), 'now' => t('Now'), 'strtotime' => t('Relative')),
+ '#options' => array(
+ 'blank' => t('No default value'),
+ 'now' => t('Now'),
+ 'strtotime' => t('Relative'),
+ ),
'#weight' => 1,
'#fieldset' => 'default_values',
);
@@ -204,8 +241,11 @@ function _date_field_instance_settings_form($field, $instance) {
'#default_value' => $settings['default_value_code'],
'#states' => array(
'visible' => array(
- ':input[name="instance[settings][default_value]"]' => array('value' => 'strtotime')),
+ ':input[name="instance[settings][default_value]"]' => array(
+ 'value' => 'strtotime',
+ ),
),
+ ),
'#weight' => 1.1,
'#fieldset' => 'default_values',
);
@@ -213,7 +253,12 @@ function _date_field_instance_settings_form($field, $instance) {
'#type' => !empty($field['settings']['todate']) ? 'select' : 'hidden',
'#title' => t('Default end date'),
'#default_value' => $settings['default_value2'],
- '#options' => array('same' => t('Same as Default date'), 'blank' => t('No default value'), 'now' => t('Now'), 'strtotime' => t('Relative')),
+ '#options' => array(
+ 'same' => t('Same as Default date'),
+ 'blank' => t('No default value'),
+ 'now' => t('Now'),
+ 'strtotime' => t('Relative'),
+ ),
'#weight' => 2,
'#fieldset' => 'default_values',
);
@@ -224,8 +269,11 @@ function _date_field_instance_settings_form($field, $instance) {
'#default_value' => $settings['default_value_code2'],
'#states' => array(
'visible' => array(
- ':input[name="instance[settings][default_value2]"]' => array('value' => 'strtotime')),
+ ':input[name="instance[settings][default_value2]"]' => array(
+ 'value' => 'strtotime',
+ ),
),
+ ),
'#weight' => 2.1,
'#fieldset' => 'default_values',
);
@@ -244,7 +292,7 @@ function _date_field_instance_settings_form($field, $instance) {
/**
* Form validation handler for _date_field_instance_settings_form().
*/
-function date_field_instance_settings_form_validate(&$form, &$form_state) {
+function _date_field_instance_settings_form_validate(&$form, &$form_state) {
$settings = $form_state['values']['instance']['settings'];
if ($settings['default_value'] == 'strtotime') {
@@ -284,6 +332,7 @@ function _date_field_widget_settings_form($field, $instance) {
$formats = drupal_map_assoc($formats);
}
$now = date_example_date();
+ $options['site-wide'] = t('Short date format: @date', array('@date' => date_format_date($now, 'short')));
foreach ($formats as $f) {
$options[$f] = date_format_date($now, 'custom', $f);
}
@@ -369,11 +418,18 @@ function _date_field_widget_settings_form($field, $instance) {
'#weight' => 9,
);
if (in_array($widget['type'], array('date_select'))) {
- $options = array('above' => t('Above'), 'within' => t('Within'), 'none' => t('None'));
+ $options = array(
+ 'above' => t('Above'),
+ 'within' => t('Within'),
+ 'none' => t('None'),
+ );
$description = t("The location of date part labels, like 'Year', 'Month', or 'Day' . 'Above' displays the label as titles above each date part. 'Within' inserts the label as the first option in the select list and in blank textfields. 'None' doesn't visually label any of the date parts. Theme functions like 'date_part_label_year' and 'date_part_label_month' control label text.");
}
else {
- $options = array('above' => t('Above'), 'none' => t('None'));
+ $options = array(
+ 'above' => t('Above'),
+ 'none' => t('None'),
+ );
$description = t("The location of date part labels, like 'Year', 'Month', or 'Day' . 'Above' displays the label as titles above each date part. 'None' doesn't visually label any of the date parts. Theme functions like 'date_part_label_year' and 'date_part_label_month' control label text.");
}
$form['advanced']['label_position'] = array(
@@ -403,6 +459,13 @@ function _date_field_widget_settings_form($field, $instance) {
}
}
+ $form['advanced']['no_fieldset'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Render as a regular field'),
+ '#default_value' => !empty($settings['no_fieldset']),
+ '#description' => t('Whether to render this field as a regular field instead of a fieldset. The date field elements are wrapped in a fieldset by default, and may not display well without it.'),
+ );
+
$context = array(
'field' => $field,
'instance' => $instance,
@@ -415,7 +478,7 @@ function _date_field_widget_settings_form($field, $instance) {
/**
* Form validation handler for _date_field_widget_settings_form().
*/
-function date_field_widget_settings_form_validate(&$form, &$form_state) {
+function _date_field_widget_settings_form_validate(&$form, &$form_state) {
// The widget settings are in the wrong place in the form because of #tree on
// the top level.
$settings = $form_state['values']['instance']['widget']['settings'];
@@ -470,7 +533,9 @@ function _date_field_settings_form($field, $instance, $has_data) {
'#title' => t('Date attributes to collect'),
'#default_value' => $granularity,
'#options' => $options,
- '#attributes' => array('class' => array('container-inline')),
+ '#attributes' => array(
+ 'class' => array('container-inline'),
+ ),
'#description' => $description,
'year' => $checkbox_year,
);
@@ -515,7 +580,7 @@ function _date_field_settings_form($field, $instance, $has_data) {
$form['cache_enabled'] = array(
'#type' => 'checkbox',
'#title' => t('Cache dates'),
- '#description' => t('Date objects can be created and cached as date fields are loaded rather than when they are displayed to improve performance.'),
+ '#description' => t('Date objects can be created and cached as date fields are loaded, rather than when they are displayed, to improve performance.'),
'#default_value' => !empty($settings['cache_enabled']),
'#weight' => 10,
);
@@ -528,7 +593,9 @@ function _date_field_settings_form($field, $instance, $has_data) {
'#weight' => 11,
'#states' => array(
'visible' => array(
- 'input[name="field[settings][cache_enabled]"]' => array('checked' => TRUE),
+ 'input[name="field[settings][cache_enabled]"]' => array(
+ 'checked' => TRUE,
+ ),
),
),
);
@@ -546,7 +613,7 @@ function _date_field_settings_form($field, $instance, $has_data) {
/**
* Form validation handler for _date_field_settings_form().
*/
-function date_field_settings_validate(&$form, &$form_state) {
+function _date_field_settings_validate(&$form, &$form_state) {
$field = &$form_state['values']['field'];
if ($field['settings']['tz_handling'] == 'none') {
@@ -600,7 +667,7 @@ function date_timezone_handling_options() {
'site' => t("Site's time zone"),
'date' => t("Date's time zone"),
'user' => t("User's time zone"),
- 'utc' => 'UTC',
+ 'utc' => 'UTC',
'none' => t('No time zone conversion'),
);
}
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_all_day/date_all_day.info b/profiles/commerce_kickstart/modules/contrib/date/date_all_day/date_all_day.info
index 8eeb7325..fcdc673a 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_all_day/date_all_day.info
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_all_day/date_all_day.info
@@ -5,9 +5,9 @@ dependencies[] = date
package = Date/Time
core = 7.x
-; Information added by Drupal.org packaging script on 2014-07-29
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
core = "7.x"
project = "date"
-datestamp = "1406653438"
+datestamp = "1491562090"
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_all_day/date_all_day.module b/profiles/commerce_kickstart/modules/contrib/date/date_all_day/date_all_day.module
index 93fc61ba..e79bc944 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_all_day/date_all_day.module
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_all_day/date_all_day.module
@@ -31,11 +31,11 @@ function date_all_day_theme() {
'format' => NULL,
'entity_type' => NULL,
'entity' => NULL,
- 'view' => NULL
- )
+ 'view' => NULL,
+ ),
),
'date_all_day_label' => array(
- 'variables' => array()
+ 'variables' => array(),
),
);
@@ -91,14 +91,29 @@ function date_all_day_date_formatter_dates_alter(&$dates, $context) {
/**
* Adjust start/end date format to account for 'all day' .
*
- * @param array $field, the field definition for this date field.
- * @param string $which, which value to return, 'date1' or 'date2' .
- * @param object $date1, a date/time object for the 'start' date.
- * @param object $date2, a date/time object for the 'end' date.
- * @param string $format
- * @param object $entity, the node this date comes from (may be incomplete, always contains nid).
- * @param object $view, the view this node comes from, if applicable.
- * @return formatted date.
+ * @params array $field
+ * The field definition for this date field.
+ *
+ * @params string $which
+ * Which value to return, 'date1' or 'date2'.
+ *
+ * @params object $date1
+ * A date/time object for the 'start' date.
+ *
+ * @params object $date2
+ * A date/time object for the 'end' date.
+ *
+ * @params string $format
+ * A date/time format
+ *
+ * @params object $entity
+ * The node this date comes from (may be incomplete, always contains nid).
+ *
+ * @params object $view
+ * The view this node comes from, if applicable.
+ *
+ * @return string
+ * Formatted date.
*/
function theme_date_all_day($vars) {
$field = $vars['field'];
@@ -135,23 +150,32 @@ function theme_date_all_day($vars) {
}
return trim(date_format_date($$which, 'custom', $format) . $suffix);
-
}
/**
* Theme the way an 'all day' label will look.
*/
function theme_date_all_day_label() {
- return '(' . t('All day', array(), array('context' => 'datetime')) .')';
+ return '(' . t('All day', array(), array('context' => 'datetime')) . ')';
}
/**
* Determine if a Start/End date combination qualify as 'All day'.
*
- * @param array $field, the field definition for this date field.
- * @param object $date1, a date/time object for the 'Start' date.
- * @param object $date2, a date/time object for the 'End' date.
- * @return TRUE or FALSE.
+ * @param array $field
+ * The field definition for this date field.
+ *
+ * @param array $instance
+ * The field instance for this date field.
+ *
+ * @param object $date1
+ * A date/time object for the 'Start' date.
+ *
+ * @param object $date2
+ * A date/time object for the 'End' date.
+ *
+ * @return bool
+ * TRUE or FALSE.
*/
function date_all_day_field($field, $instance, $date1, $date2 = NULL) {
if (empty($date1) || !is_object($date1)) {
@@ -167,7 +191,6 @@ function date_all_day_field($field, $instance, $date1, $date2 = NULL) {
$granularity = date_granularity_precision($field['settings']['granularity']);
$increment = isset($instance['widget']['settings']['increment']) ? $instance['widget']['settings']['increment'] : 1;
return date_is_all_day(date_format($date1, DATE_FORMAT_DATETIME), date_format($date2, DATE_FORMAT_DATETIME), $granularity, $increment);
-
}
/**
@@ -222,7 +245,8 @@ function date_all_day_date_combo_process_alter(&$element, &$form_state, $context
function date_all_day_date_text_process_alter(&$element, &$form_state, $context) {
$all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
if ($all_day_id != '') {
- // All Day handling on text dates works only if the user leaves the time out of the input value.
+ // All Day handling on text dates works only
+ // if the user leaves the time out of the input value.
// There is no element to hide or show.
}
}
@@ -234,10 +258,11 @@ function date_all_day_date_text_process_alter(&$element, &$form_state, $context)
*/
function date_all_day_date_select_process_alter(&$element, &$form_state, $context) {
- // Hide or show this element in reaction to the all_day status for this element.
+ // Hide or show this element in reaction
+ // to the all_day status for this element.
$all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
if ($all_day_id != '') {
- foreach(array('hour', 'minute', 'second', 'ampm') as $field) {
+ foreach (array('hour', 'minute', 'second', 'ampm') as $field) {
if (array_key_exists($field, $element)) {
$element[$field]['#states'] = array(
'visible' => array(
@@ -255,7 +280,8 @@ function date_all_day_date_select_process_alter(&$element, &$form_state, $contex
*/
function date_all_day_date_popup_process_alter(&$element, &$form_state, $context) {
- // Hide or show this element in reaction to the all_day status for this element.
+ // Hide or show this element in reaction to
+ // the all_day status for this element.
$all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
if ($all_day_id != '' && array_key_exists('time', $element)) {
$element['time']['#states'] = array(
@@ -272,7 +298,8 @@ function date_all_day_date_popup_process_alter(&$element, &$form_state, $context
* of the date_select validation gets fired.
*/
function date_all_day_date_text_pre_validate_alter(&$element, &$form_state, &$input) {
- // Let Date module massage the format for all day values so they will pass validation.
+ // Let Date module massage the format for all day
+ // values so they will pass validation.
// The All day flag, if used, actually exists on the parent element.
date_all_day_value($element, $form_state);
}
@@ -284,7 +311,8 @@ function date_all_day_date_text_pre_validate_alter(&$element, &$form_state, &$in
* of the date_select validation gets fired.
*/
function date_all_day_date_select_pre_validate_alter(&$element, &$form_state, &$input) {
- // Let Date module massage the format for all day values so they will pass validation.
+ // Let Date module massage the format for all
+ // day values so they will pass validation.
// The All day flag, if used, actually exists on the parent element.
date_all_day_value($element, $form_state);
}
@@ -296,13 +324,16 @@ function date_all_day_date_select_pre_validate_alter(&$element, &$form_state, &$
* of the date_popup validation gets fired.
*/
function date_all_day_date_popup_pre_validate_alter(&$element, &$form_state, &$input) {
- // Let Date module massage the format for all day values so they will pass validation.
+ // Let Date module massage the format for all
+ // day values so they will pass validation.
// The All day flag, if used, actually exists on the parent element.
date_all_day_value($element, $form_state);
}
/**
- * A helper function to check if the all day flag is set on the parent of an
+ * A helper function date_all_day_value().
+ *
+ * To check if the all day flag is set on the parent of an
* element, and adjust the date_format accordingly so the missing time will
* not cause validation errors.
*/
@@ -332,7 +363,8 @@ function date_all_day_date_combo_pre_validate_alter(&$element, &$form_state, $co
$field = $context['field'];
// If we have an all day flag on this date and the time is empty,
- // change the format to match the input value so we don't get validation errors.
+ // change the format to match the input value
+ // so we don't get validation errors.
$element['#date_is_all_day'] = TRUE;
$element['value']['#date_format'] = date_part_format('date', $element['value']['#date_format']);
if (!empty($field['settings']['todate'])) {
@@ -344,29 +376,29 @@ function date_all_day_date_combo_pre_validate_alter(&$element, &$form_state, $co
/**
* Implements hook_date_combo_validate_date_start_alter().
*
- * This hook lets us alter the local date objects created by the date_combo validation
- * before they are converted back to the database timezone and stored.
+ * This hook lets us alter the local date objects
+ * created by the date_combo validation before they are
+ * converted back to the database timezone and stored.
*/
function date_all_day_date_combo_validate_date_start_alter(&$date, &$form_state, $context) {
-
- // If this is an 'All day' value, set the time to midnight.
- if (!empty($context['element']['#date_is_all_day'])) {
- $date->setTime(0, 0, 0);
- }
+ // If this is an 'All day' value, set the time to midnight.
+ if (!empty($context['element']['#date_is_all_day'])) {
+ $date->setTime(0, 0, 0);
+ }
}
/**
* Implements hook_date_combo_validate_date_end_alter().
*
- * This hook lets us alter the local date objects created by the date_combo validation
- * before they are converted back to the database timezone and stored.
+ * This hook lets us alter the local date objects
+ * created by the date_combo validation before
+ * they are converted back to the database timezone and stored.
*/
function date_all_day_date_combo_validate_date_end_alter(&$date, &$form_state, $context) {
-
- // If this is an 'All day' value, set the time to midnight.
- if (!empty($context['element']['#date_is_all_day'])) {
- $date->setTime(0, 0, 0);
- }
+ // If this is an 'All day' value, set the time to midnight.
+ if (!empty($context['element']['#date_is_all_day'])) {
+ $date->setTime(0, 0, 0);
+ }
}
/**
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_api/date.css b/profiles/commerce_kickstart/modules/contrib/date/date_api/date.css
index 9b72ecdb..e47a2ae2 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_api/date.css
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_api/date.css
@@ -15,9 +15,11 @@
.container-inline-date > .form-item {
display: inline-block;
margin-right: 0.5em; /* LTR */
- margin-bottom: 10px;
vertical-align: top;
}
+fieldset.date-combo .container-inline-date > .form-item {
+ margin-bottom: 10px;
+}
.container-inline-date .form-item .form-item {
float: left; /* LTR */
}
@@ -52,9 +54,11 @@
/* The exposed Views form doesn't need some of these styles */
.container-inline-date .date-padding {
- padding: 10px;
float: left;
}
+fieldset.date-combo .container-inline-date .date-padding {
+ padding: 10px;
+}
.views-exposed-form .container-inline-date .date-padding {
padding: 0;
}
@@ -116,7 +120,7 @@ span.date-display-end {
}
/* Add space between the date and time portions of the date_select widget. */
-.form-type-date-select .form-type-select[class$=hour] {
+.form-type-date-select .form-type-select[class*=hour] {
margin-left: .75em; /* LTR */
}
@@ -173,6 +177,10 @@ div.date-calendar-day span.year {
padding: 2px;
}
+.date-form-element-content-multiline {
+ padding: 10px;
+ border: 1px solid #CCC;
+}
/* Admin styling */
.form-item.form-item-instance-widget-settings-input-format-custom,
.form-item.form-item-field-settings-enddate-required {
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api.admin.inc b/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api.admin.inc
index 966b1a42..3c706aeb 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api.admin.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api.admin.inc
@@ -10,112 +10,112 @@
*/
function _date_timezone_replacement($old) {
$replace = array(
- 'Brazil/Acre' => 'America/Rio_Branco',
- 'Brazil/DeNoronha' => 'America/Noronha',
- 'Brazil/East' => 'America/Recife',
- 'Brazil/West' => 'America/Manaus',
- 'Canada/Atlantic' => 'America/Halifax',
- 'Canada/Central' => 'America/Winnipeg',
- 'Canada/East-Saskatchewan' => 'America/Regina',
- 'Canada/Eastern' => 'America/Toronto',
- 'Canada/Mountain' => 'America/Edmonton',
- 'Canada/Newfoundland' => 'America/St_Johns',
- 'Canada/Pacific' => 'America/Vancouver',
- 'Canada/Saskatchewan' => 'America/Regina',
- 'Canada/Yukon' => 'America/Whitehorse',
- 'CET' => 'Europe/Berlin',
- 'Chile/Continental' => 'America/Santiago',
- 'Chile/EasterIsland' => 'Pacific/Easter',
- 'CST6CDT' => 'America/Chicago',
- 'Cuba' => 'America/Havana',
- 'EET' => 'Europe/Bucharest',
- 'Egypt' => 'Africa/Cairo',
- 'Eire' => 'Europe/Belfast',
- 'EST' => 'America/New_York',
- 'EST5EDT' => 'America/New_York',
- 'GB' => 'Europe/London',
- 'GB-Eire' => 'Europe/Belfast',
- 'Etc/GMT' => 'UTC',
- 'Etc/GMT+0' => 'UTC',
- 'Etc/GMT+1' => 'UTC',
- 'Etc/GMT+10' => 'UTC',
- 'Etc/GMT+11' => 'UTC',
- 'Etc/GMT+12' => 'UTC',
- 'Etc/GMT+2' => 'UTC',
- 'Etc/GMT+3' => 'UTC',
- 'Etc/GMT+4' => 'UTC',
- 'Etc/GMT+5' => 'UTC',
- 'Etc/GMT+6' => 'UTC',
- 'Etc/GMT+7' => 'UTC',
- 'Etc/GMT+8' => 'UTC',
- 'Etc/GMT+9' => 'UTC',
- 'Etc/GMT-0' => 'UTC',
- 'Etc/GMT-1' => 'UTC',
- 'Etc/GMT-10' => 'UTC',
- 'Etc/GMT-11' => 'UTC',
- 'Etc/GMT-12' => 'UTC',
- 'Etc/GMT-13' => 'UTC',
- 'Etc/GMT-14' => 'UTC',
- 'Etc/GMT-2' => 'UTC',
- 'Etc/GMT-3' => 'UTC',
- 'Etc/GMT-4' => 'UTC',
- 'Etc/GMT-5' => 'UTC',
- 'Etc/GMT-6' => 'UTC',
- 'Etc/GMT-7' => 'UTC',
- 'Etc/GMT-8' => 'UTC',
- 'Etc/GMT-9' => 'UTC',
- 'Etc/GMT0' => 'UTC',
- 'Etc/Greenwich' => 'UTC',
- 'Etc/UCT' => 'UTC',
- 'Etc/Universal' => 'UTC',
- 'Etc/UTC' => 'UTC',
- 'Etc/Zulu' => 'UTC',
- 'Factory' => 'UTC',
- 'GMT' => 'UTC',
- 'GMT+0' => 'UTC',
- 'GMT-0' => 'UTC',
- 'GMT0' => 'UTC',
- 'Hongkong' => 'Asia/Hong_Kong',
- 'HST' => 'Pacific/Honolulu',
- 'Iceland' => 'Atlantic/Reykjavik',
- 'Iran' => 'Asia/Tehran',
- 'Israel' => 'Asia/Tel_Aviv',
- 'Jamaica' => 'America/Jamaica',
- 'Japan' => 'Asia/Tokyo',
- 'Kwajalein' => 'Pacific/Kwajalein',
- 'Libya' => 'Africa/Tunis',
- 'MET' => 'Europe/Budapest',
- 'Mexico/BajaNorte' => 'America/Tijuana',
- 'Mexico/BajaSur' => 'America/Mazatlan',
- 'Mexico/General' => 'America/Mexico_City',
- 'MST' => 'America/Boise',
- 'MST7MDT' => 'America/Boise',
- 'Navajo' => 'America/Phoenix',
- 'NZ' => 'Pacific/Auckland',
- 'NZ-CHAT' => 'Pacific/Chatham',
- 'Poland' => 'Europe/Warsaw',
- 'Portugal' => 'Europe/Lisbon',
- 'PRC' => 'Asia/Chongqing',
- 'PST8PDT' => 'America/Los_Angeles',
- 'ROC' => 'Asia/Taipei',
- 'ROK' => 'Asia/Seoul',
- 'Singapore' => 'Asia/Singapore',
- 'Turkey' => 'Europe/Istanbul',
- 'US/Alaska' => 'America/Anchorage',
- 'US/Aleutian' => 'America/Adak',
- 'US/Arizona' => 'America/Phoenix',
- 'US/Central' => 'America/Chicago',
- 'US/East-Indiana' => 'America/Indianapolis',
- 'US/Eastern' => 'America/New_York',
- 'US/Hawaii' => 'Pacific/Honolulu',
- 'US/Indiana-Starke' => 'America/Indiana/Knox',
- 'US/Michigan' => 'America/Detroit',
- 'US/Mountain' => 'America/Boise',
- 'US/Pacific' => 'America/Los_Angeles',
- 'US/Pacific-New' => 'America/Los_Angeles',
- 'US/Samoa' => 'Pacific/Samoa',
- 'W-SU' => 'Europe/Moscow',
- 'WET' => 'Europe/Paris',
+ 'Brazil/Acre' => 'America/Rio_Branco',
+ 'Brazil/DeNoronha' => 'America/Noronha',
+ 'Brazil/East' => 'America/Recife',
+ 'Brazil/West' => 'America/Manaus',
+ 'Canada/Atlantic' => 'America/Halifax',
+ 'Canada/Central' => 'America/Winnipeg',
+ 'Canada/East-Saskatchewan' => 'America/Regina',
+ 'Canada/Eastern' => 'America/Toronto',
+ 'Canada/Mountain' => 'America/Edmonton',
+ 'Canada/Newfoundland' => 'America/St_Johns',
+ 'Canada/Pacific' => 'America/Vancouver',
+ 'Canada/Saskatchewan' => 'America/Regina',
+ 'Canada/Yukon' => 'America/Whitehorse',
+ 'CET' => 'Europe/Berlin',
+ 'Chile/Continental' => 'America/Santiago',
+ 'Chile/EasterIsland' => 'Pacific/Easter',
+ 'CST6CDT' => 'America/Chicago',
+ 'Cuba' => 'America/Havana',
+ 'EET' => 'Europe/Bucharest',
+ 'Egypt' => 'Africa/Cairo',
+ 'Eire' => 'Europe/Belfast',
+ 'EST' => 'America/New_York',
+ 'EST5EDT' => 'America/New_York',
+ 'GB' => 'Europe/London',
+ 'GB-Eire' => 'Europe/Belfast',
+ 'Etc/GMT' => 'UTC',
+ 'Etc/GMT+0' => 'UTC',
+ 'Etc/GMT+1' => 'UTC',
+ 'Etc/GMT+10' => 'UTC',
+ 'Etc/GMT+11' => 'UTC',
+ 'Etc/GMT+12' => 'UTC',
+ 'Etc/GMT+2' => 'UTC',
+ 'Etc/GMT+3' => 'UTC',
+ 'Etc/GMT+4' => 'UTC',
+ 'Etc/GMT+5' => 'UTC',
+ 'Etc/GMT+6' => 'UTC',
+ 'Etc/GMT+7' => 'UTC',
+ 'Etc/GMT+8' => 'UTC',
+ 'Etc/GMT+9' => 'UTC',
+ 'Etc/GMT-0' => 'UTC',
+ 'Etc/GMT-1' => 'UTC',
+ 'Etc/GMT-10' => 'UTC',
+ 'Etc/GMT-11' => 'UTC',
+ 'Etc/GMT-12' => 'UTC',
+ 'Etc/GMT-13' => 'UTC',
+ 'Etc/GMT-14' => 'UTC',
+ 'Etc/GMT-2' => 'UTC',
+ 'Etc/GMT-3' => 'UTC',
+ 'Etc/GMT-4' => 'UTC',
+ 'Etc/GMT-5' => 'UTC',
+ 'Etc/GMT-6' => 'UTC',
+ 'Etc/GMT-7' => 'UTC',
+ 'Etc/GMT-8' => 'UTC',
+ 'Etc/GMT-9' => 'UTC',
+ 'Etc/GMT0' => 'UTC',
+ 'Etc/Greenwich' => 'UTC',
+ 'Etc/UCT' => 'UTC',
+ 'Etc/Universal' => 'UTC',
+ 'Etc/UTC' => 'UTC',
+ 'Etc/Zulu' => 'UTC',
+ 'Factory' => 'UTC',
+ 'GMT' => 'UTC',
+ 'GMT+0' => 'UTC',
+ 'GMT-0' => 'UTC',
+ 'GMT0' => 'UTC',
+ 'Hongkong' => 'Asia/Hong_Kong',
+ 'HST' => 'Pacific/Honolulu',
+ 'Iceland' => 'Atlantic/Reykjavik',
+ 'Iran' => 'Asia/Tehran',
+ 'Israel' => 'Asia/Tel_Aviv',
+ 'Jamaica' => 'America/Jamaica',
+ 'Japan' => 'Asia/Tokyo',
+ 'Kwajalein' => 'Pacific/Kwajalein',
+ 'Libya' => 'Africa/Tunis',
+ 'MET' => 'Europe/Budapest',
+ 'Mexico/BajaNorte' => 'America/Tijuana',
+ 'Mexico/BajaSur' => 'America/Mazatlan',
+ 'Mexico/General' => 'America/Mexico_City',
+ 'MST' => 'America/Boise',
+ 'MST7MDT' => 'America/Boise',
+ 'Navajo' => 'America/Phoenix',
+ 'NZ' => 'Pacific/Auckland',
+ 'NZ-CHAT' => 'Pacific/Chatham',
+ 'Poland' => 'Europe/Warsaw',
+ 'Portugal' => 'Europe/Lisbon',
+ 'PRC' => 'Asia/Chongqing',
+ 'PST8PDT' => 'America/Los_Angeles',
+ 'ROC' => 'Asia/Taipei',
+ 'ROK' => 'Asia/Seoul',
+ 'Singapore' => 'Asia/Singapore',
+ 'Turkey' => 'Europe/Istanbul',
+ 'US/Alaska' => 'America/Anchorage',
+ 'US/Aleutian' => 'America/Adak',
+ 'US/Arizona' => 'America/Phoenix',
+ 'US/Central' => 'America/Chicago',
+ 'US/East-Indiana' => 'America/Indianapolis',
+ 'US/Eastern' => 'America/New_York',
+ 'US/Hawaii' => 'Pacific/Honolulu',
+ 'US/Indiana-Starke' => 'America/Indiana/Knox',
+ 'US/Michigan' => 'America/Detroit',
+ 'US/Mountain' => 'America/Boise',
+ 'US/Pacific' => 'America/Los_Angeles',
+ 'US/Pacific-New' => 'America/Los_Angeles',
+ 'US/Samoa' => 'Pacific/Samoa',
+ 'W-SU' => 'Europe/Moscow',
+ 'WET' => 'Europe/Paris',
);
if (array_key_exists($old, $replace)) {
return $replace[$old];
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api.info b/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api.info
index 3ca86e65..c537ca04 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api.info
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api.info
@@ -9,9 +9,9 @@ stylesheets[all][] = date.css
files[] = date_api.module
files[] = date_api_sql.inc
-; Information added by Drupal.org packaging script on 2014-07-29
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
core = "7.x"
project = "date"
-datestamp = "1406653438"
+datestamp = "1491562090"
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api.install b/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api.install
index ce5b746d..d5a68bbd 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api.install
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api.install
@@ -96,7 +96,7 @@ function date_api_uninstall() {
'date_php_min_year',
'date_db_tz_support',
'date_api_use_iso8601',
- );
+ );
foreach ($variables as $variable) {
variable_del($variable);
}
@@ -118,8 +118,9 @@ function date_api_update_last_removed() {
}
/**
- * Move old date format data to new date format tables, and delete the old
- * tables. Insert only values that don't already exist in the new tables, in
+ * Move old date format to new date format tables,and delete the old tables.
+ *
+ * Insert only values that don't already exist in the new tables, in
* case new version of those custom values have already been created.
*/
function date_api_update_7000() {
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api.module b/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api.module
index b1be6e5f..160bc9fb 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api.module
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api.module
@@ -59,16 +59,16 @@ function date_help($path, $arg) {
}
if (module_exists('date_tools')) {
- $output .= '
Date Tools
' . t('Dates and calendars can be complicated to set up. The !date_wizard makes it easy to create a simple date content type and with a date field. ', array('!date_wizard' => l(t('Date wizard'), 'admin/config/date/tools/date_wizard')));
+ $output .= '
Date Tools
' . t('Dates and calendars can be complicated to set up. The !date_wizard makes it easy to create a simple date content type and with a date field.', array('!date_wizard' => l(t('Date wizard'), 'admin/config/date/tools/date_wizard')));
}
else {
- $output .= '
Date Tools
' . t('Dates and calendars can be complicated to set up. If you enable the Date Tools module, it provides a Date Wizard that makes it easy to create a simple date content type with a date field. ');
+ $output .= '
Date Tools
' . t('Dates and calendars can be complicated to set up. If you enable the Date Tools module, it provides a Date Wizard that makes it easy to create a simple date content type with a date field.');
}
$output .= '
More Information
' . t('Complete documentation for the Date and Date API modules is available at http://drupal.org/node/92460.', array('@link' => 'http://drupal.org/node/262062')) . '
';
return $output;
- break;
+
}
}
@@ -101,7 +101,7 @@ function date_api_status() {
$value = variable_get('date_format_medium');
if (isset($value)) {
$now = date_now();
- $success_messages[] = $t('The medium date format type has been set to to @value. You may find it helpful to add new format types like Date, Time, Month, or Year, with appropriate formats, at Date and time settings.', array('@value' => $now->format($value), '@regional_date_time' => url('admin/config/regional/date-time')));
+ $success_messages[] = $t('The medium date format type has been set to @value. You may find it helpful to add new format types like Date, Time, Month, or Year, with appropriate formats, at Date and time settings.', array('@value' => $now->format($value), '@regional_date_time' => url('admin/config/regional/date-time')));
}
else {
$error_messages[] = $t('The Date API requires that you set up the system date formats to function correctly.', array('@regional_date_time' => url('admin/config/regional/date-time')));
@@ -143,7 +143,15 @@ function date_api_menu() {
class DateObject extends DateTime {
public $granularity = array();
public $errors = array();
- protected static $allgranularity = array('year', 'month', 'day', 'hour', 'minute', 'second', 'timezone');
+ protected static $allgranularity = array(
+ 'year',
+ 'month',
+ 'day',
+ 'hour',
+ 'minute',
+ 'second',
+ 'timezone'
+ );
private $serializedTime;
private $serializedTimezone;
@@ -402,7 +410,7 @@ class DateObject extends DateTime {
* A single date part.
*/
public function removeGranularity($g) {
- if ($key = array_search($g, $this->granularity)) {
+ if (($key = array_search($g, $this->granularity)) !== FALSE) {
unset($this->granularity[$key]);
}
}
@@ -458,23 +466,35 @@ class DateObject extends DateTime {
$true = $this->hasGranularity() && (!$granularity || $flexible || $this->hasGranularity($granularity));
if (!$true && $granularity) {
foreach ((array) $granularity as $part) {
- if (!$this->hasGranularity($part) && in_array($part, array('second', 'minute', 'hour', 'day', 'month', 'year'))) {
+ if (!$this->hasGranularity($part) && in_array($part, array(
+ 'second',
+ 'minute',
+ 'hour',
+ 'day',
+ 'month',
+ 'year')
+ )) {
switch ($part) {
case 'second':
$this->errors[$part] = t('The second is missing.');
break;
+
case 'minute':
$this->errors[$part] = t('The minute is missing.');
break;
+
case 'hour':
$this->errors[$part] = t('The hour is missing.');
break;
+
case 'day':
$this->errors[$part] = t('The day is missing.');
break;
+
case 'month':
$this->errors[$part] = t('The month is missing.');
break;
+
case 'year':
$this->errors[$part] = t('The year is missing.');
break;
@@ -537,7 +557,14 @@ class DateObject extends DateTime {
$temp = date_parse($time);
// Special case for 'now'.
if ($time == 'now') {
- $this->granularity = array('year', 'month', 'day', 'hour', 'minute', 'second');
+ $this->granularity = array(
+ 'year',
+ 'month',
+ 'day',
+ 'hour',
+ 'minute',
+ 'second',
+ );
}
else {
// This PHP date_parse() method currently doesn't have resolution down to
@@ -600,7 +627,14 @@ class DateObject extends DateTime {
return FALSE;
}
$this->granularity = array();
- $final_date = array('hour' => 0, 'minute' => 0, 'second' => 0, 'month' => 1, 'day' => 1, 'year' => 0);
+ $final_date = array(
+ 'hour' => 0,
+ 'minute' => 0,
+ 'second' => 0,
+ 'month' => 1,
+ 'day' => 1,
+ 'year' => 0,
+ );
foreach ($letters as $i => $letter) {
$value = $values[$i];
switch ($letter) {
@@ -609,21 +643,25 @@ class DateObject extends DateTime {
$final_date['day'] = intval($value);
$this->addGranularity('day');
break;
+
case 'n':
case 'm':
$final_date['month'] = intval($value);
$this->addGranularity('month');
break;
+
case 'F':
$array_month_long = array_flip(date_month_names());
$final_date['month'] = array_key_exists($value, $array_month_long) ? $array_month_long[$value] : -1;
$this->addGranularity('month');
break;
+
case 'M':
$array_month = array_flip(date_month_names_abbr());
$final_date['month'] = array_key_exists($value, $array_month) ? $array_month[$value] : -1;
$this->addGranularity('month');
break;
+
case 'Y':
$final_date['year'] = $value;
$this->addGranularity('year');
@@ -631,16 +669,19 @@ class DateObject extends DateTime {
$this->errors['year'] = t('The year is invalid. Please check that entry includes four digits.');
}
break;
+
case 'y':
$year = $value;
// If no century, we add the current one ("06" => "2006").
$final_date['year'] = str_pad($year, 4, substr(date("Y"), 0, 2), STR_PAD_LEFT);
$this->addGranularity('year');
break;
+
case 'a':
case 'A':
$ampm = strtolower($value);
break;
+
case 'g':
case 'h':
case 'G':
@@ -648,14 +689,17 @@ class DateObject extends DateTime {
$final_date['hour'] = intval($value);
$this->addGranularity('hour');
break;
+
case 'i':
$final_date['minute'] = intval($value);
$this->addGranularity('minute');
break;
+
case 's':
$final_date['second'] = intval($value);
$this->addGranularity('second');
break;
+
case 'U':
parent::__construct($value, $tz ? $tz : new DateTimeZone("UTC"));
$this->addGranularity('year');
@@ -665,7 +709,7 @@ class DateObject extends DateTime {
$this->addGranularity('minute');
$this->addGranularity('second');
return $this;
- break;
+
}
}
if (isset($ampm) && $ampm == 'pm' && $final_date['hour'] < 12) {
@@ -758,10 +802,24 @@ class DateObject extends DateTime {
// date or we will get date slippage, i.e. a value of 2011-00-00 will get
// interpreted as November of 2010 by PHP.
if ($full) {
- $arr += array('year' => 0, 'month' => 1, 'day' => 1, 'hour' => 0, 'minute' => 0, 'second' => 0);
+ $arr += array(
+ 'year' => 0,
+ 'month' => 1,
+ 'day' => 1,
+ 'hour' => 0,
+ 'minute' => 0,
+ 'second' => 0,
+ );
}
else {
- $arr += array('year' => '', 'month' => '', 'day' => '', 'hour' => '', 'minute' => '', 'second' => '');
+ $arr += array(
+ 'year' => '',
+ 'month' => '',
+ 'day' => '',
+ 'hour' => '',
+ 'minute' => '',
+ 'second' => '',
+ );
}
$datetime = '';
if ($arr['year'] !== '') {
@@ -839,28 +897,27 @@ class DateObject extends DateTime {
case 'year':
$fallback = $now->format('Y');
return !is_int($value) || empty($value) || $value < variable_get('date_min_year', 1) || $value > variable_get('date_max_year', 4000) ? $fallback : $value;
- break;
+
case 'month':
$fallback = $default == 'first' ? 1 : $now->format('n');
return !is_int($value) || empty($value) || $value <= 0 || $value > 12 ? $fallback : $value;
- break;
+
case 'day':
$fallback = $default == 'first' ? 1 : $now->format('j');
$max_day = isset($year) && isset($month) ? date_days_in_month($year, $month) : 31;
return !is_int($value) || empty($value) || $value <= 0 || $value > $max_day ? $fallback : $value;
- break;
+
case 'hour':
$fallback = $default == 'first' ? 0 : $now->format('G');
return !is_int($value) || $value < 0 || $value > 23 ? $fallback : $value;
- break;
+
case 'minute':
$fallback = $default == 'first' ? 0 : $now->format('i');
return !is_int($value) || $value < 0 || $value > 59 ? $fallback : $value;
- break;
+
case 'second':
$fallback = $default == 'first' ? 0 : $now->format('s');
return !is_int($value) || $value < 0 || $value > 59 ? $fallback : $value;
- break;
}
}
@@ -898,18 +955,23 @@ class DateObject extends DateTime {
case 'year':
$errors['year'] = t('The year is invalid.');
break;
+
case 'month':
$errors['month'] = t('The month is invalid.');
break;
+
case 'day':
$errors['day'] = t('The day is invalid.');
break;
+
case 'hour':
$errors['hour'] = t('The hour is invalid.');
break;
+
case 'minute':
$errors['minute'] = t('The minute is invalid.');
break;
+
case 'second':
$errors['second'] = t('The second is invalid.');
break;
@@ -929,7 +991,7 @@ class DateObject extends DateTime {
* The stop date.
* @param string $measure
* (optional) A granularity date part. Defaults to 'seconds'.
- * @param boolean $absolute
+ * @param bool $absolute
* (optional) Indicate whether the absolute value of the difference should
* be returned or if the sign should be retained. Defaults to TRUE.
*/
@@ -955,10 +1017,13 @@ class DateObject extends DateTime {
// The easy cases first.
case 'seconds':
return $diff;
+
case 'minutes':
return $diff / 60;
+
case 'hours':
return $diff / 3600;
+
case 'years':
return $year_diff;
@@ -1013,7 +1078,7 @@ class DateObject extends DateTime {
$sign = ($year_diff < 0) ? -1 : 1;
for ($i = 1; $i <= abs($year_diff); $i++) {
- date_modify($date1, (($sign > 0) ? '+': '-').'1 year');
+ date_modify($date1, (($sign > 0) ? '+' : '-') . '1 year');
$week_diff += (date_iso_weeks_in_year($date1) * $sign);
}
return $week_diff;
@@ -1060,10 +1125,13 @@ function date_type_format($type) {
switch ($type) {
case DATE_ISO:
return DATE_FORMAT_ISO;
+
case DATE_UNIX:
return DATE_FORMAT_UNIX;
+
case DATE_DATETIME:
return DATE_FORMAT_DATETIME;
+
case DATE_ICAL:
return DATE_FORMAT_ICAL;
}
@@ -1119,7 +1187,7 @@ function date_month_names($required = FALSE) {
}
/**
- * Constructs a translated array of month name abbreviations
+ * Constructs a translated array of month name abbreviations.
*
* @param bool $required
* (optional) If FALSE, the returned array will include a blank value.
@@ -1211,9 +1279,11 @@ function date_week_days_abbr($required = FALSE, $refresh = TRUE, $length = 3) {
case 1:
$context = 'day_abbr1';
break;
+
case 2:
$context = 'day_abbr2';
break;
+
default:
$context = '';
break;
@@ -1248,10 +1318,10 @@ function date_week_days_ordered($weekdays) {
/**
* Constructs an array of years.
*
- * @param int $min
- * The minimum year in the array.
- * @param int $max
- * The maximum year in the array.
+ * @param int $start
+ * The start year in the array.
+ * @param int $end
+ * The end year in the array.
* @param bool $required
* (optional) If FALSE, the returned array will include a blank value.
* Defaults to FALSE.
@@ -1259,16 +1329,16 @@ function date_week_days_ordered($weekdays) {
* @return array
* An array of years in the selected range.
*/
-function date_years($min = 0, $max = 0, $required = FALSE) {
+function date_years($start = 0, $end = 0, $required = FALSE) {
// Ensure $min and $max are valid values.
- if (empty($min)) {
- $min = intval(date('Y', REQUEST_TIME) - 3);
+ if (empty($start)) {
+ $start = intval(date('Y', REQUEST_TIME) - 3);
}
- if (empty($max)) {
- $max = intval(date('Y', REQUEST_TIME) + 3);
+ if (empty($end)) {
+ $end = intval(date('Y', REQUEST_TIME) + 3);
}
$none = array(0 => '');
- return !$required ? $none + drupal_map_assoc(range($min, $max)) : drupal_map_assoc(range($min, $max));
+ return !$required ? $none + drupal_map_assoc(range($start, $end)) : drupal_map_assoc(range($start, $end));
}
/**
@@ -1474,7 +1544,14 @@ function date_granularity_names() {
* An array of date parts.
*/
function date_granularity_sorted($granularity) {
- return array_intersect(array('year', 'month', 'day', 'hour', 'minute', 'second'), $granularity);
+ return array_intersect(array(
+ 'year',
+ 'month',
+ 'day',
+ 'hour',
+ 'minute',
+ 'second',
+ ), $granularity);
}
/**
@@ -1492,14 +1569,19 @@ function date_granularity_array_from_precision($precision) {
switch ($precision) {
case 'year':
return array_slice($granularity_array, -6, 1);
+
case 'month':
return array_slice($granularity_array, -6, 2);
+
case 'day':
return array_slice($granularity_array, -6, 3);
+
case 'hour':
return array_slice($granularity_array, -6, 4);
+
case 'minute':
return array_slice($granularity_array, -6, 5);
+
default:
return $granularity_array;
}
@@ -1533,14 +1615,19 @@ function date_granularity_format($granularity) {
switch ($granularity) {
case 'year':
return substr($format, 0, 1);
+
case 'month':
return substr($format, 0, 3);
+
case 'day':
return substr($format, 0, 5);
+
case 'hour';
return substr($format, 0, 7);
+
case 'minute':
return substr($format, 0, 9);
+
default:
return $format;
}
@@ -1657,40 +1744,51 @@ function date_format_date($date, $type = 'medium', $format = '', $langcode = NUL
case 'l':
$datestring .= t($date->format('l'), array(), array('context' => '', 'langcode' => $langcode));
break;
+
case 'D':
$datestring .= t($date->format('D'), array(), array('context' => '', 'langcode' => $langcode));
break;
+
case 'F':
$datestring .= t($date->format('F'), array(), array('context' => 'Long month name', 'langcode' => $langcode));
break;
+
case 'M':
$datestring .= t($date->format('M'), array(), array('langcode' => $langcode));
break;
+
case 'A':
case 'a':
$datestring .= t($date->format($c), array(), array('context' => 'ampm', 'langcode' => $langcode));
break;
+
// The timezone name translations can use t().
case 'e':
case 'T':
$datestring .= t($date->format($c));
break;
+
// Remaining date parts need no translation.
case 'O':
$datestring .= sprintf('%s%02d%02d', (date_offset_get($date) < 0 ? '-' : '+'), abs(date_offset_get($date) / 3600), abs(date_offset_get($date) % 3600) / 60);
break;
+
case 'P':
$datestring .= sprintf('%s%02d:%02d', (date_offset_get($date) < 0 ? '-' : '+'), abs(date_offset_get($date) / 3600), abs(date_offset_get($date) % 3600) / 60);
break;
+
case 'Z':
$datestring .= date_offset_get($date);
break;
+
case '\\':
$datestring .= $format[++$i];
break;
+
case 'r':
- $datestring .= date_format_date($date, 'custom', 'D, d M Y H:i:s O', $langcode);
+ $datestring .= date_format_date($date, 'custom', 'D, d M Y H:i:s O', 'en');
break;
+
default:
if (strpos('BdcgGhHiIjLmnNosStTuUwWYyz', $c) !== FALSE) {
$datestring .= $date->format($c);
@@ -1735,22 +1833,28 @@ function date_format_interval($date, $granularity = 2, $display_ago = TRUE) {
/**
* A date object for the current time.
*
- * @param object $timezone
- * (optional) Optionally force time to a specific timezone, defaults to user
- * timezone, if set, otherwise site timezone. Defaults to NULL.
+ * @param object|string|null $timezone
+ * (optional) PHP DateTimeZone object, string or NULL allowed. Optionally
+ * force time to a specific timezone, defaults to user timezone, if set,
+ * otherwise site timezone. Defaults to NULL.
*
- * @param boolean $reset [optional]
- * Static cache reset
+ * @param bool $reset
+ * (optional) Static cache reset.
*
* @return object
* The current time as a date object.
*/
function date_now($timezone = NULL, $reset = FALSE) {
+ $static_var = __FUNCTION__ . $timezone;
+ if ($timezone instanceof DateTimeZone) {
+ $static_var = __FUNCTION__ . $timezone->getName();
+ }
+
if ($reset) {
- drupal_static_reset(__FUNCTION__ . $timezone);
+ drupal_static_reset($static_var);
}
- $now = &drupal_static(__FUNCTION__ . $timezone);
+ $now = &drupal_static($static_var);
if (!isset($now)) {
$now = new DateObject('now', $timezone);
@@ -1822,7 +1926,12 @@ function date_days_in_month($year, $month) {
// Pick a day in the middle of the month to avoid timezone shifts.
$datetime = date_pad($year, 4) . '-' . date_pad($month) . '-15 00:00:00';
$date = new DateObject($datetime);
- return $date->format('t');
+ if ($date->errors) {
+ return FALSE;
+ }
+ else {
+ return $date->format('t');
+ }
}
/**
@@ -1831,7 +1940,7 @@ function date_days_in_month($year, $month) {
* @param mixed $date
* (optional) The current date object, or a date string. Defaults to NULL.
*
- * @return integer
+ * @return int
* The number of days in the year.
*/
function date_days_in_year($date = NULL) {
@@ -1860,7 +1969,7 @@ function date_days_in_year($date = NULL) {
* @param mixed $date
* (optional) The current date object, or a date string. Defaults to NULL.
*
- * @return integer
+ * @return int
* The number of ISO weeks in a year.
*/
function date_iso_weeks_in_year($date = NULL) {
@@ -1952,7 +2061,7 @@ function date_week_range($week, $year) {
// Move forwards to the last day of the week.
$max_date = clone($min_date);
- date_modify($max_date, '+7 days');
+ date_modify($max_date, '+6 days');
if (date_format($min_date, 'Y') != $year) {
$min_date = new DateObject($year . '-01-01 00:00:00');
@@ -1977,6 +2086,9 @@ function date_iso_week_range($week, $year) {
date_timezone_set($min_date, date_default_timezone_object());
// Find the first day of the first ISO week in the year.
+ // If it's already a Monday, date_modify won't add a Monday,
+ // it will remain the same day. So add a Sunday first, then a Monday.
+ date_modify($min_date, '+1 Sunday');
date_modify($min_date, '+1 Monday');
// Jump ahead to the desired week for the beginning of the week range.
@@ -1986,7 +2098,7 @@ function date_iso_week_range($week, $year) {
// Move forwards to the last day of the week.
$max_date = clone($min_date);
- date_modify($max_date, '+7 days');
+ date_modify($max_date, '+6 days');
return array($min_date, $max_date);
}
@@ -2094,7 +2206,8 @@ function date_has_time($granularity) {
if (!is_array($granularity)) {
$granularity = array();
}
- return (bool) count(array_intersect($granularity, array('hour', 'minute', 'second')));
+ $options = array('hour', 'minute', 'second');
+ return (bool) count(array_intersect($granularity, $options));
}
/**
@@ -2110,7 +2223,8 @@ function date_has_date($granularity) {
if (!is_array($granularity)) {
$granularity = array();
}
- return (bool) count(array_intersect($granularity, array('year', 'month', 'day')));
+ $options = array('year', 'month', 'day');
+ return (bool) count(array_intersect($granularity, $options));
}
/**
@@ -2128,8 +2242,10 @@ function date_part_format($part, $format) {
switch ($part) {
case 'date':
return date_limit_format($format, array('year', 'month', 'day'));
+
case 'time':
return date_limit_format($format, array('hour', 'minute', 'second'));
+
default:
return date_limit_format($format, array($part));
}
@@ -2157,7 +2273,7 @@ function date_limit_format($format, $granularity) {
$drupal_static_fast['formats'] = &drupal_static(__FUNCTION__);
}
$formats = &$drupal_static_fast['formats'];
- $format_granularity_cid = $format .'|'. implode(',', $granularity);
+ $format_granularity_cid = $format . '|' . implode(',', $granularity);
if (isset($formats[$format_granularity_cid])) {
return $formats[$format_granularity_cid];
}
@@ -2191,21 +2307,27 @@ function date_limit_format($format, $granularity) {
case 'year':
$regex[] = '([\-/\.,:]?\s?(? "$path/theme",
);
return array(
- 'date_nav_title' => $base + array('variables' => array('granularity' => NULL, 'view' => NULL, 'link' => NULL, 'format' => NULL)),
+ 'date_nav_title' => $base + array(
+ 'variables' => array(
+ 'granularity' => NULL, 'view' => NULL, 'link' => NULL, 'format' => NULL
+ ),
+ ),
'date_timezone' => $base + array('render element' => 'element'),
'date_select' => $base + array('render element' => 'element'),
'date_text' => $base + array('render element' => 'element'),
@@ -2355,7 +2495,11 @@ function date_api_theme($existing, $type, $theme, $path) {
'date_part_label_time' => $base + array('variables' => array('date_part' => NULL, 'element' => NULL)),
'date_views_filter_form' => $base + array('template' => 'date-views-filter-form', 'render element' => 'form'),
'date_calendar_day' => $base + array('variables' => array('date' => NULL)),
- 'date_time_ago' => $base + array('variables' => array('start_date' => NULL, 'end_date' => NULL, 'interval' => NULL)),
+ 'date_time_ago' => $base + array(
+ 'variables' => array(
+ 'start_date' => NULL, 'end_date' => NULL, 'interval' => NULL
+ ),
+ ),
);
}
@@ -2375,9 +2519,11 @@ function date_get_timezone($handling, $timezone = '') {
case 'date':
$timezone = !empty($timezone) ? $timezone : date_default_timezone();
break;
+
case 'utc':
$timezone = 'UTC';
break;
+
default:
$timezone = date_default_timezone();
}
@@ -2404,6 +2550,7 @@ function date_get_timezone_db($handling, $timezone = NULL) {
// These handling modes all convert to UTC before storing in the DB.
$timezone = 'UTC';
break;
+
case ('date'):
if ($timezone == NULL) {
// This shouldn't happen, since it's meaning is undefined. But we need
@@ -2411,6 +2558,7 @@ function date_get_timezone_db($handling, $timezone = NULL) {
$timezone = date_default_timezone();
}
break;
+
case ('none'):
default:
$timezone = date_default_timezone();
@@ -2465,12 +2613,12 @@ function date_order() {
* TRUE if the date range is valid, FALSE otherwise.
*/
function date_range_valid($string) {
- $matches = preg_match('@^(\-[0-9]+|[0-9]{4}):([\+|\-][0-9]+|[0-9]{4})$@', $string);
+ $matches = preg_match('@^([\+\-][0-9]+|[0-9]{4}):([\+\-][0-9]+|[0-9]{4})$@', $string);
return $matches < 1 ? FALSE : TRUE;
}
/**
- * Splits a string like -3:+3 or 2001:2010 into an array of min and max years.
+ * Splits a string like -3:+3 or 2001:2010 into an array of start and end years.
*
* Center the range around the current year, if any, but expand it far
* enough so it will pick up the year value in the field in case
@@ -2482,45 +2630,44 @@ function date_range_valid($string) {
* (optional) A date object. Defaults to NULL.
*
* @return array
- * A numerically indexed array, containing a minimum and maximum year.
+ * A numerically indexed array, containing a start and end year.
*/
function date_range_years($string, $date = NULL) {
$this_year = date_format(date_now(), 'Y');
- list($min_year, $max_year) = explode(':', $string);
+ list($start_year, $end_year) = explode(':', $string);
// Valid patterns would be -5:+5, 0:+1, 2008:2010.
- $plus_pattern = '@[\+|\-][0-9]{1,4}@';
+ $plus_pattern = '@[\+\-][0-9]{1,4}@';
$year_pattern = '@^[0-9]{4}@';
- if (!preg_match($year_pattern, $min_year, $matches)) {
- if (preg_match($plus_pattern, $min_year, $matches)) {
- $min_year = $this_year + $matches[0];
+ if (!preg_match($year_pattern, $start_year, $matches)) {
+ if (preg_match($plus_pattern, $start_year, $matches)) {
+ $start_year = $this_year + $matches[0];
}
else {
- $min_year = $this_year;
+ $start_year = $this_year;
}
}
- if (!preg_match($year_pattern, $max_year, $matches)) {
- if (preg_match($plus_pattern, $max_year, $matches)) {
- $max_year = $this_year + $matches[0];
+ if (!preg_match($year_pattern, $end_year, $matches)) {
+ if (preg_match($plus_pattern, $end_year, $matches)) {
+ $end_year = $this_year + $matches[0];
}
else {
- $max_year = $this_year;
+ $end_year = $this_year;
}
}
- // We expect the $min year to be less than the $max year.
- // Some custom values for -99:+99 might not obey that.
- if ($min_year > $max_year) {
- $temp = $max_year;
- $max_year = $min_year;
- $min_year = $temp;
- }
// If there is a current value, stretch the range to include it.
$value_year = is_object($date) ? $date->format('Y') : '';
if (!empty($value_year)) {
- $min_year = min($value_year, $min_year);
- $max_year = max($value_year, $max_year);
+ if ($start_year <= $end_year) {
+ $start_year = min($value_year, $start_year);
+ $end_year = max($value_year, $end_year);
+ }
+ else {
+ $start_year = max($value_year, $start_year);
+ $end_year = min($value_year, $end_year);
+ }
}
- return array($min_year, $max_year);
+ return array($start_year, $end_year);
}
/**
@@ -2680,6 +2827,7 @@ function date_is_all_day($string1, $string2, $granularity = 'second', $increment
|| ($hour2 == 23 && in_array($min2, array($max_minutes, 59)) && in_array($sec2, array($max_seconds, 59)))
|| ($hour1 == 0 && $hour2 == 0 && $min1 == 0 && $min2 == 0 && $sec1 == 0 && $sec2 == 0);
break;
+
case 'minute':
$min_match = $time1 == '00:00:00'
|| ($hour1 == 0 && $min1 == 0);
@@ -2687,6 +2835,7 @@ function date_is_all_day($string1, $string2, $granularity = 'second', $increment
|| ($hour2 == 23 && in_array($min2, array($max_minutes, 59)))
|| ($hour1 == 0 && $hour2 == 0 && $min1 == 0 && $min2 == 0);
break;
+
case 'hour':
$min_match = $time1 == '00:00:00'
|| ($hour1 == 0);
@@ -2694,6 +2843,7 @@ function date_is_all_day($string1, $string2, $granularity = 'second', $increment
|| ($hour2 == 23)
|| ($hour1 == 0 && $hour2 == 0);
break;
+
default:
$min_match = TRUE;
$max_match = FALSE;
@@ -2754,15 +2904,21 @@ function date_is_date($date) {
}
/**
- * This function will replace ISO values that have the pattern 9999-00-00T00:00:00
- * with a pattern like 9999-01-01T00:00:00, to match the behavior of non-ISO
- * dates and ensure that date objects created from this value contain a valid month
- * and day. Without this fix, the ISO date '2020-00-00T00:00:00' would be created as
+ * Replace specific ISO values using patterns.
+ *
+ * Function will replace ISO values that have the pattern 9999-00-00T00:00:00
+ * with a pattern like 9999-01-01T00:00:00, to match the behavior of non-ISO dates
+ * and ensure that date objects created from this value contain a valid month
+ * and day.
+ * Without this fix, the ISO date '2020-00-00T00:00:00' would be created as
* November 30, 2019 (the previous day in the previous month).
*
* @param string $iso_string
* An ISO string that needs to be made into a complete, valid date.
*
+ * @return mixed|string
+ * replaced value, or incoming value.
+ *
* @TODO Expand on this to work with all sorts of partial ISO dates.
*/
function date_make_iso_valid($iso_string) {
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api_elements.inc b/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api_elements.inc
index 57e41615..638fcda5 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api_elements.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api_elements.inc
@@ -111,20 +111,24 @@ function date_default_date($element) {
$format = DATE_FORMAT_DATETIME;
// The text and popup widgets might return less than a full datetime string.
- if (strlen($element['#default_value']) < 19) {
+ if (is_string($element['#default_value']) && strlen($element['#default_value']) < 19) {
switch (strlen($element['#default_value'])) {
case 16:
$format = 'Y-m-d H:i';
break;
+
case 13:
$format = 'Y-m-d H';
break;
+
case 10:
$format = 'Y-m-d';
break;
+
case 7:
$format = 'Y-m';
break;
+
case 4:
$format = 'Y';
break;
@@ -170,7 +174,7 @@ function date_year_range_element_process($element, &$form_state, $form) {
$element['#attached']['js'][] = drupal_get_path('module', 'date_api') . '/date_year_range.js';
$context = array(
- 'form' => $form,
+ 'form' => $form,
);
drupal_alter('date_year_range_process', $element, $form_state, $context);
@@ -256,7 +260,7 @@ function date_timezone_element_process($element, &$form_state, $form) {
}
$context = array(
- 'form' => $form,
+ 'form' => $form,
);
drupal_alter('date_timezone_process', $element, $form_state, $context);
@@ -264,7 +268,7 @@ function date_timezone_element_process($element, &$form_state, $form) {
}
/**
- * Validation for timezone input
+ * Validation for timezone input.
*
* Move the timezone value from the nested field back to the original field.
*/
@@ -307,7 +311,6 @@ function date_text_element_value_callback($element, $input = FALSE, &$form_state
*
* The exact parts displayed in the field are those in #date_granularity.
* The display of each part comes from #date_format.
- *
*/
function date_text_element_process($element, &$form_state, $form) {
if (date_hidden_element($element)) {
@@ -316,16 +319,25 @@ function date_text_element_process($element, &$form_state, $form) {
$element['#tree'] = TRUE;
$element['#theme_wrappers'] = array('date_text');
- $element['date']['#value'] = $element['#value']['date'];
+ $element['date']['#value'] = isset($element['#value']['date']) ? $element['#value']['date'] : '';
$element['date']['#type'] = 'textfield';
$element['date']['#weight'] = !empty($element['date']['#weight']) ? $element['date']['#weight'] : $element['#weight'];
$element['date']['#attributes'] = array('class' => isset($element['#attributes']['class']) ? $element['#attributes']['class'] += array('date-date') : array('date-date'));
$now = date_example_date();
$element['date']['#title'] = t('Date');
$element['date']['#title_display'] = 'invisible';
- $element['date']['#description'] = ' ' . t('Format: @date', array('@date' => date_format_date(date_example_date(), 'custom', $element['#date_format'])));
+ $element['date']['#description'] = ' ' . t('Format: @date', array(
+ '@date' => date_format_date(date_example_date(), 'custom', $element['#date_format']
+ )));
$element['date']['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
+ // Make changes if instance is set to be rendered as a regular field.
+ if (!empty($element['#instance']['widget']['settings']['no_fieldset']) && $element['#field']['cardinality'] == 1) {
+ $element['date']['#title'] = check_plain($element['#instance']['label']);
+ $element['date']['#title_display'] = $element['#title_display'];
+ $element['date']['#required'] = $element['#required'];
+ }
+
// Keep the system from creating an error message for the sub-element.
// We'll set our own message on the parent element.
// $element['date']['#required'] = $element['#required'];
@@ -341,7 +353,7 @@ function date_text_element_process($element, &$form_state, $form) {
}
$context = array(
- 'form' => $form,
+ 'form' => $form,
);
drupal_alter('date_text_process', $element, $form_state, $context);
@@ -349,12 +361,11 @@ function date_text_element_process($element, &$form_state, $form) {
}
/**
- * Validation for text input.
+ * Validation for text input.
*
* When used as a Views widget, the validation step always gets triggered,
* even with no form submission. Before form submission $element['#value']
* contains a string, after submission it contains an array.
- *
*/
function date_text_validate($element, &$form_state) {
if (date_hidden_element($element)) {
@@ -367,6 +378,11 @@ function date_text_validate($element, &$form_state) {
$input_exists = NULL;
$input = drupal_array_get_nested_value($form_state['values'], $element['#parents'], $input_exists);
+ // Trim extra spacing off user input of text fields.
+ if (isset($input['date'])) {
+ $input['date'] = trim($input['date']);
+ }
+
drupal_alter('date_text_pre_validate', $element, $form_state, $input);
$label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
@@ -421,7 +437,14 @@ function date_text_input_date($element, $input) {
* Element value callback for date_select element.
*/
function date_select_element_value_callback($element, $input = FALSE, &$form_state = array()) {
- $return = array('year' => '', 'month' => '', 'day' => '', 'hour' => '', 'minute' => '', 'second' => '');
+ $return = array(
+ 'year' => '',
+ 'month' => '',
+ 'day' => '',
+ 'hour' => '',
+ 'minute' => '',
+ 'second' => '',
+ );
$date = NULL;
if ($input !== FALSE) {
$return = $input;
@@ -431,7 +454,14 @@ function date_select_element_value_callback($element, $input = FALSE, &$form_sta
$date = date_default_date($element);
}
$granularity = date_format_order($element['#date_format']);
- $formats = array('year' => 'Y', 'month' => 'n', 'day' => 'j', 'hour' => 'H', 'minute' => 'i', 'second' => 's');
+ $formats = array(
+ 'year' => 'Y',
+ 'month' => 'n',
+ 'day' => 'j',
+ 'hour' => 'H',
+ 'minute' => 'i',
+ 'second' => 's',
+ );
foreach ($granularity as $field) {
if ($field != 'timezone') {
$return[$field] = date_is_date($date) ? $date->format($formats[$field]) : '';
@@ -449,7 +479,6 @@ function date_select_element_value_callback($element, $input = FALSE, &$form_sta
*
* The exact parts displayed in the field are those in #date_granularity.
* The display of each part comes from ['#date_settings']['format'].
- *
*/
function date_select_element_process($element, &$form_state, $form) {
if (date_hidden_element($element)) {
@@ -473,7 +502,14 @@ function date_select_element_process($element, &$form_state, $form) {
// Store a hidden value for all date parts not in the current display.
$granularity = date_format_order($element['#date_format']);
- $formats = array('year' => 'Y', 'month' => 'n', 'day' => 'j', 'hour' => 'H', 'minute' => 'i', 'second' => 's');
+ $formats = array(
+ 'year' => 'Y',
+ 'month' => 'n',
+ 'day' => 'j',
+ 'hour' => 'H',
+ 'minute' => 'i',
+ 'second' => 's',
+ );
foreach (date_nongranularity($granularity) as $field) {
if ($field != 'timezone') {
$element[$field] = array(
@@ -490,7 +526,7 @@ function date_select_element_process($element, &$form_state, $form) {
}
$context = array(
- 'form' => $form,
+ 'form' => $form,
);
drupal_alter('date_select_process', $element, $form_state, $context);
@@ -521,7 +557,7 @@ function date_parts_element($element, $date, $format) {
$sub_element = array('#granularity' => $granularity);
$order = array_flip($granularity);
- $hours_format = strpos(strtolower($element['#date_format']), 'a') ? 'g': 'G';
+ $hours_format = strpos(strtolower($element['#date_format']), 'a') ? 'g' : 'G';
$month_function = strpos($element['#date_format'], 'F') !== FALSE ? 'date_month_names' : 'date_month_names_abbr';
$count = 0;
$increment = min(intval($element['#date_increment']), 1);
@@ -539,26 +575,29 @@ function date_parts_element($element, $date, $format) {
switch ($field) {
case 'year':
$range = date_range_years($element['#date_year_range'], $date);
- $min_year = $range[0];
- $max_year = $range[1];
+ $start_year = $range[0];
+ $end_year = $range[1];
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('Y') : '';
if ($part_type == 'select') {
- $sub_element[$field]['#options'] = drupal_map_assoc(date_years($min_year, $max_year, $part_required));
+ $sub_element[$field]['#options'] = drupal_map_assoc(date_years($start_year, $end_year, $part_required));
}
break;
+
case 'month':
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('n') : '';
if ($part_type == 'select') {
$sub_element[$field]['#options'] = $month_function($part_required);
}
break;
+
case 'day':
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('j') : '';
if ($part_type == 'select') {
$sub_element[$field]['#options'] = drupal_map_assoc(date_days($part_required));
}
break;
+
case 'hour':
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format($hours_format) : '';
if ($part_type == 'select') {
@@ -566,6 +605,7 @@ function date_parts_element($element, $date, $format) {
}
$sub_element[$field]['#prefix'] = theme('date_part_hour_prefix', $element);
break;
+
case 'minute':
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('i') : '';
if ($part_type == 'select') {
@@ -573,6 +613,7 @@ function date_parts_element($element, $date, $format) {
}
$sub_element[$field]['#prefix'] = theme('date_part_minsec_prefix', $element);
break;
+
case 'second':
$sub_element[$field]['#default_value'] = is_object($date) ? $date->format('s') : '';
if ($part_type == 'select') {
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api_ical.inc b/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api_ical.inc
index 2ca484e7..4911298c 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api_ical.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api_ical.inc
@@ -181,6 +181,7 @@ function date_ical_parse($icaldatafolded = array()) {
$parent[array_pop($parents)][] = array_pop($subgroups);
}
break;
+
// Add the timezones in with their index their TZID.
case 'VTIMEZONE':
$subgroup = end($subgroups);
@@ -196,6 +197,7 @@ function date_ical_parse($icaldatafolded = array()) {
array_pop($subgroups);
array_pop($parents);
break;
+
// Do some fun stuff with durations and all_day events and then append
// to parent.
case 'VEVENT':
@@ -222,9 +224,9 @@ function date_ical_parse($icaldatafolded = array()) {
// assumes the end date is inclusive.
if (!empty($subgroup['DTEND']) && (!empty($subgroup['DTEND']['all_day']))) {
// Make the end date one day earlier.
- $date = new DateObject ($subgroup['DTEND']['datetime'] . ' 00:00:00', $subgroup['DTEND']['tz']);
+ $date = new DateObject($subgroup['DTEND']['datetime'] . ' 00:00:00', $subgroup['DTEND']['tz']);
date_modify($date, '-1 day');
- $subgroup['DTEND']['datetime'] = date_format($date, 'Y-m-d');
+ $subgroup['DTEND']['datetime'] = date_format($date, 'Y-m-d');
}
// If a start datetime is defined AND there is no definition for
// the end datetime THEN make the end datetime equal the start
@@ -239,7 +241,7 @@ function date_ical_parse($icaldatafolded = array()) {
if (!empty($subgroup['DTSTART']['all_day'])) {
$subgroup['all_day'] = TRUE;
}
- // Add this element to the parent as an array under the
+ // Add this element to the parent as an array under the.
prev($subgroups);
$parent = &$subgroups[key($subgroups)];
@@ -264,12 +266,13 @@ function date_ical_parse($icaldatafolded = array()) {
$field = !empty($matches[2]) ? $matches[2] : '';
$data = !empty($matches[3]) ? $matches[3] : '';
$parse_result = '';
+
switch ($name) {
// Keep blank lines out of the results.
case '':
break;
- // Lots of properties have date values that must be parsed out.
+ // Lots of properties have date values that must be parsed out.
case 'CREATED':
case 'LAST-MODIFIED':
case 'DTSTART':
@@ -317,9 +320,9 @@ function date_ical_parse($icaldatafolded = array()) {
$parse_result = date_ical_parse_location($field, $data);
break;
- // For all other properties, just store the property and the value.
- // This can be expanded on in the future if other properties should
- // be given special treatment.
+ // For all other properties, just store the property and the value.
+ // This can be expanded on in the future if other properties should
+ // be given special treatment.
default:
$parse_result = $data;
break;
@@ -360,7 +363,7 @@ function date_ical_parse($icaldatafolded = array()) {
* has no timezone; the ical specs say no timezone
* conversion should be done if no timezone info is
* supplied
- * @todo
+ * @todo
* Another option for dates is the format PROPERTY;VALUE=PERIOD:XXXX. The
* period may include a duration, or a date and a duration, or two dates, so
* would have to be split into parts and run through date_ical_parse_date()
@@ -401,6 +404,7 @@ function date_ical_parse_date($field, $data) {
// Date.
$datetime = date_pad($regs[1]) . '-' . date_pad($regs[2]) . '-' . date_pad($regs[3]);
break;
+
case 'DATE-TIME':
preg_match(DATE_REGEX_ICAL_DATETIME, $data, $regs);
// Date.
@@ -519,12 +523,12 @@ function date_ical_parse_duration(&$subgroup, $field = 'DURATION') {
$data = $items['DATA'];
preg_match('/^P(\d{1,4}[Y])?(\d{1,2}[M])?(\d{1,2}[W])?(\d{1,2}[D])?([T]{0,1})?(\d{1,2}[H])?(\d{1,2}[M])?(\d{1,2}[S])?/', $data, $duration);
$items['year'] = isset($duration[1]) ? str_replace('Y', '', $duration[1]) : '';
- $items['month'] = isset($duration[2]) ?str_replace('M', '', $duration[2]) : '';
- $items['week'] = isset($duration[3]) ?str_replace('W', '', $duration[3]) : '';
- $items['day'] = isset($duration[4]) ?str_replace('D', '', $duration[4]) : '';
- $items['hour'] = isset($duration[6]) ?str_replace('H', '', $duration[6]) : '';
- $items['minute'] = isset($duration[7]) ?str_replace('M', '', $duration[7]) : '';
- $items['second'] = isset($duration[8]) ?str_replace('S', '', $duration[8]) : '';
+ $items['month'] = isset($duration[2]) ? str_replace('M', '', $duration[2]) : '';
+ $items['week'] = isset($duration[3]) ? str_replace('W', '', $duration[3]) : '';
+ $items['day'] = isset($duration[4]) ? str_replace('D', '', $duration[4]) : '';
+ $items['hour'] = isset($duration[6]) ? str_replace('H', '', $duration[6]) : '';
+ $items['minute'] = isset($duration[7]) ? str_replace('M', '', $duration[7]) : '';
+ $items['second'] = isset($duration[8]) ? str_replace('S', '', $duration[8]) : '';
$start_date = array_key_exists('DTSTART', $subgroup) ? $subgroup['DTSTART']['datetime'] : date_format(date_now(), DATE_FORMAT_ISO);
$timezone = array_key_exists('DTSTART', $subgroup) ? $subgroup['DTSTART']['tz'] : variable_get('date_default_timezone');
if (empty($timezone)) {
@@ -542,7 +546,7 @@ function date_ical_parse_duration(&$subgroup, $field = 'DURATION') {
'datetime' => date_format($date2, DATE_FORMAT_DATETIME),
'all_day' => isset($subgroup['DTSTART']['all_day']) ? $subgroup['DTSTART']['all_day'] : 0,
'tz' => $timezone,
- );
+ );
$duration = date_format($date2, 'U') - date_format($date, 'U');
$subgroup['DURATION'] = array('DATA' => $data, 'DURATION' => $duration);
}
@@ -631,7 +635,6 @@ function date_ical_date($ical_date, $to_tz = FALSE) {
*
* @return string
* Escaped text
- *
*/
function date_ical_escape_text($text) {
$text = drupal_html_to_text($text);
@@ -693,14 +696,14 @@ function date_ical_escape_text($text) {
* )
*/
function date_api_ical_build_rrule($form_values) {
- $RRULE = '';
+ $rrule = '';
if (empty($form_values) || !is_array($form_values)) {
- return $RRULE;
+ return $rrule;
}
// Grab the RRULE data and put them into iCal RRULE format.
- $RRULE .= 'RRULE:FREQ=' . (!array_key_exists('FREQ', $form_values) ? 'DAILY' : $form_values['FREQ']);
- $RRULE .= ';INTERVAL=' . (!array_key_exists('INTERVAL', $form_values) ? 1 : $form_values['INTERVAL']);
+ $rrule .= 'RRULE:FREQ=' . (!array_key_exists('FREQ', $form_values) ? 'DAILY' : $form_values['FREQ']);
+ $rrule .= ';INTERVAL=' . (!array_key_exists('INTERVAL', $form_values) ? 1 : $form_values['INTERVAL']);
// Unset the empty 'All' values.
if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY'])) {
@@ -713,14 +716,14 @@ function date_api_ical_build_rrule($form_values) {
unset($form_values['BYMONTHDAY']['']);
}
- if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY']) && $BYDAY = implode(",", $form_values['BYDAY'])) {
- $RRULE .= ';BYDAY=' . $BYDAY;
+ if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY']) && $byday = implode(",", $form_values['BYDAY'])) {
+ $rrule .= ';BYDAY=' . $byday;
}
- if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH']) && $BYMONTH = implode(",", $form_values['BYMONTH'])) {
- $RRULE .= ';BYMONTH=' . $BYMONTH;
+ if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH']) && $bymonth = implode(",", $form_values['BYMONTH'])) {
+ $rrule .= ';BYMONTH=' . $bymonth;
}
- if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY']) && $BYMONTHDAY = implode(",", $form_values['BYMONTHDAY'])) {
- $RRULE .= ';BYMONTHDAY=' . $BYMONTHDAY;
+ if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY']) && $bymonthday = implode(",", $form_values['BYMONTHDAY'])) {
+ $rrule .= ';BYMONTHDAY=' . $bymonthday;
}
// The UNTIL date is supposed to always be expressed in UTC.
// The input date values may already have been converted to a date object on a
@@ -731,8 +734,17 @@ function date_api_ical_build_rrule($form_values) {
if (!is_object($form_values['UNTIL']['datetime'])) {
// If this is a date without time, give it time.
if (strlen($form_values['UNTIL']['datetime']) < 11) {
+ $granularity_options = drupal_map_assoc(array(
+ 'year',
+ 'month',
+ 'day',
+ 'hour',
+ 'minute',
+ 'second',
+ ));
+
$form_values['UNTIL']['datetime'] .= ' 23:59:59';
- $form_values['UNTIL']['granularity'] = serialize(drupal_map_assoc(array('year', 'month', 'day', 'hour', 'minute', 'second')));
+ $form_values['UNTIL']['granularity'] = serialize($granularity_options);
$form_values['UNTIL']['all_day'] = FALSE;
}
$until = date_ical_date($form_values['UNTIL'], 'UTC');
@@ -740,21 +752,21 @@ function date_api_ical_build_rrule($form_values) {
else {
$until = $form_values['UNTIL']['datetime'];
}
- $RRULE .= ';UNTIL=' . date_format($until, DATE_FORMAT_ICAL) . 'Z';
+ $rrule .= ';UNTIL=' . date_format($until, DATE_FORMAT_ICAL) . 'Z';
}
// Our form doesn't allow a value for COUNT, but it may be needed by
// modules using the API, so add it to the rule.
if (array_key_exists('COUNT', $form_values)) {
- $RRULE .= ';COUNT=' . $form_values['COUNT'];
+ $rrule .= ';COUNT=' . $form_values['COUNT'];
}
// iCal rules presume the week starts on Monday unless otherwise specified,
// so we'll specify it.
if (array_key_exists('WKST', $form_values)) {
- $RRULE .= ';WKST=' . $form_values['WKST'];
+ $rrule .= ';WKST=' . $form_values['WKST'];
}
else {
- $RRULE .= ';WKST=' . date_repeat_dow2day(variable_get('date_first_day', 0));
+ $rrule .= ';WKST=' . date_repeat_dow2day(variable_get('date_first_day', 0));
}
// Exceptions dates go last, on their own line.
@@ -765,7 +777,7 @@ function date_api_ical_build_rrule($form_values) {
foreach ($form_values['EXDATE'] as $value) {
if (!empty($value['datetime'])) {
$date = !is_object($value['datetime']) ? date_ical_date($value, 'UTC') : $value['datetime'];
- $ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z': '';
+ $ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z' : '';
if (!empty($ex_date)) {
$ex_dates[] = $ex_date;
}
@@ -773,11 +785,11 @@ function date_api_ical_build_rrule($form_values) {
}
if (!empty($ex_dates)) {
sort($ex_dates);
- $RRULE .= chr(13) . chr(10) . 'EXDATE:' . implode(',', $ex_dates);
+ $rrule .= chr(13) . chr(10) . 'EXDATE:' . implode(',', $ex_dates);
}
}
elseif (!empty($form_values['EXDATE'])) {
- $RRULE .= chr(13) . chr(10) . 'EXDATE:' . $form_values['EXDATE'];
+ $rrule .= chr(13) . chr(10) . 'EXDATE:' . $form_values['EXDATE'];
}
// Exceptions dates go last, on their own line.
@@ -785,19 +797,19 @@ function date_api_ical_build_rrule($form_values) {
$ex_dates = array();
foreach ($form_values['RDATE'] as $value) {
$date = !is_object($value['datetime']) ? date_ical_date($value, 'UTC') : $value['datetime'];
- $ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z': '';
+ $ex_date = !empty($date) ? date_format($date, DATE_FORMAT_ICAL) . 'Z' : '';
if (!empty($ex_date)) {
$ex_dates[] = $ex_date;
}
}
if (!empty($ex_dates)) {
sort($ex_dates);
- $RRULE .= chr(13) . chr(10) . 'RDATE:' . implode(',', $ex_dates);
+ $rrule .= chr(13) . chr(10) . 'RDATE:' . implode(',', $ex_dates);
}
}
elseif (!empty($form_values['RDATE'])) {
- $RRULE .= chr(13) . chr(10) . 'RDATE:' . $form_values['RDATE'];
+ $rrule .= chr(13) . chr(10) . 'RDATE:' . $form_values['RDATE'];
}
- return $RRULE;
+ return $rrule;
}
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api_sql.inc b/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api_sql.inc
index e02f0507..a95ca4ef 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api_sql.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_api/date_api_sql.inc
@@ -23,13 +23,14 @@ function date_sql_concat($array) {
switch (Database::getConnection()->databaseType()) {
case 'mysql':
return "CONCAT(" . implode(",", $array) . ")";
+
case 'pgsql':
return implode(" || ", $array);
}
}
/**
- * Helper function to do cross-database NULL replacements
+ * Helper function to do cross-database NULL replacements.
*
* @param array $array
* An array of values to test for NULL values.
@@ -61,6 +62,7 @@ function date_sql_pad($str, $size = 2, $pad = '0', $side = 'l') {
switch ($side) {
case 'r':
return "RPAD($str, $size, '$pad')";
+
default:
return "LPAD($str, $size, '$pad')";
}
@@ -69,6 +71,7 @@ function date_sql_pad($str, $size = 2, $pad = '0', $side = 'l') {
/**
* A class to manipulate date SQL.
*/
+// @codingStandardsIgnoreStart
class date_sql_handler {
var $db_type = NULL;
var $date_type = DATE_DATETIME;
@@ -86,7 +89,7 @@ class date_sql_handler {
/**
* The object constuctor.
*/
- function __construct($date_type = DATE_DATETIME, $local_timezone = NULL, $offset = '+00:00') {
+ public function __construct($date_type = DATE_DATETIME, $local_timezone = NULL, $offset = '+00:00') {
$this->db_type = Database::getConnection()->databaseType();
$this->date_type = $date_type;
$this->db_timezone = 'UTC';
@@ -97,7 +100,7 @@ class date_sql_handler {
/**
* See if the db has timezone name support.
*/
- function db_tz_support($reset = FALSE) {
+ public function db_tz_support($reset = FALSE) {
$has_support = variable_get('date_db_tz_support', -1);
if ($has_support == -1 || $reset) {
$has_support = FALSE;
@@ -108,6 +111,7 @@ class date_sql_handler {
$has_support = TRUE;
}
break;
+
case 'pgsql':
$test = db_query("SELECT '2008-02-15 12:00:00 UTC' AT TIME ZONE 'US/Central'")->fetchField();
if ($test == '2008-02-15 06:00:00') {
@@ -136,7 +140,7 @@ class date_sql_handler {
* set a fixed offset, not a timezone, so any value other than
* '+00:00' should be used with caution.
*/
- function set_db_timezone($offset = '+00:00') {
+ public function set_db_timezone($offset = '+00:00') {
static $already_set = FALSE;
$type = Database::getConnection()->databaseType();
if (!$already_set) {
@@ -144,9 +148,11 @@ class date_sql_handler {
case 'mysql':
db_query("SET @@session.time_zone = '$offset'");
break;
+
case 'pgsql':
db_query("SET TIME ZONE INTERVAL '$offset' HOUR TO MINUTE");
break;
+
case 'sqlsrv':
// Issue #1201342, This is the wrong way to set the timezone, this
// still needs to be fixed. In the meantime, commenting this out makes
@@ -161,7 +167,7 @@ class date_sql_handler {
/**
* Return timezone offset for the date being processed.
*/
- function get_offset($comp_date = NULL) {
+ public function get_offset($comp_date = NULL) {
if (!empty($this->db_timezone) && !empty($this->local_timezone)) {
if ($this->db_timezone != $this->local_timezone) {
if (empty($comp_date)) {
@@ -199,47 +205,57 @@ class date_sql_handler {
case DATE_UNIX:
$field = "FROM_UNIXTIME($field)";
break;
+
case DATE_ISO:
$field = "STR_TO_DATE($field, '%Y-%m-%dT%T')";
break;
+
case DATE_DATETIME:
break;
}
break;
+
case 'pgsql':
switch ($this->date_type) {
case DATE_UNIX:
$field = "$field::ABSTIME";
break;
+
case DATE_ISO:
$field = "TO_DATE($field, 'FMYYYY-FMMM-FMDDTFMHH24:FMMI:FMSS')";
break;
+
case DATE_DATETIME:
break;
}
break;
+
case 'sqlite':
switch ($this->date_type) {
case DATE_UNIX:
$field = "datetime($field, 'unixepoch')";
break;
+
case DATE_ISO:
case DATE_DATETIME:
$field = "datetime($field)";
break;
}
break;
+
case 'sqlsrv':
switch ($this->date_type) {
case DATE_UNIX:
$field = "DATEADD(s, $field, '19700101 00:00:00:000')";
break;
+
case DATE_ISO:
case DATE_DATETIME:
$field = "CAST($field as smalldatetime)";
break;
}
break;
+
break;
}
// Adjust the resulting value to the right timezone/offset.
@@ -254,10 +270,13 @@ class date_sql_handler {
switch ($this->db_type) {
case 'mysql':
return "ADDTIME($field, SEC_TO_TIME($offset))";
+
case 'pgsql':
- return "($field + INTERVAL '$offset SECONDS')";;
+ return "($field + INTERVAL '$offset SECONDS')";
+
case 'sqlite':
return "datetime($field, '$offset seconds')";
+
case 'sqlsrv':
return "DATEADD(second, $offset, $field)";
}
@@ -285,6 +304,7 @@ class date_sql_handler {
switch ($direction) {
case 'ADD':
return "DATE_ADD($field, INTERVAL $count $granularity)";
+
case 'SUB':
return "DATE_SUB($field, INTERVAL $count $granularity)";
}
@@ -294,6 +314,7 @@ class date_sql_handler {
switch ($direction) {
case 'ADD':
return "($field + INTERVAL '$count $granularity')";
+
case 'SUB':
return "($field - INTERVAL '$count $granularity')";
}
@@ -302,6 +323,7 @@ class date_sql_handler {
switch ($direction) {
case 'ADD':
return "datetime($field, '+$count $granularity')";
+
case 'SUB':
return "datetime($field, '-$count $granularity')";
}
@@ -352,6 +374,7 @@ class date_sql_handler {
switch ($this->db_type) {
case 'mysql':
return "CONVERT_TZ($field, $db_zone, $localzone)";
+
case 'pgsql':
// WITH TIME ZONE assumes the date is using the system
// timezone, which should have been set to UTC.
@@ -395,6 +418,7 @@ class date_sql_handler {
);
$format = strtr($format, $replace);
return "DATE_FORMAT($field, '$format')";
+
case 'pgsql':
$replace = array(
'Y' => 'YYYY',
@@ -421,6 +445,7 @@ class date_sql_handler {
);
$format = strtr($format, $replace);
return "TO_CHAR($field, '$format')";
+
case 'sqlite':
$replace = array(
// 4 digit year number.
@@ -460,6 +485,7 @@ class date_sql_handler {
);
$format = strtr($format, $replace);
return "strftime('$format', $field)";
+
case 'sqlsrv':
$replace = array(
// 4 digit year number.
@@ -528,18 +554,25 @@ class date_sql_handler {
switch (strtoupper($extract_type)) {
case 'DATE':
return $field;
+
case 'YEAR':
return "EXTRACT(YEAR FROM($field))";
+
case 'MONTH':
return "EXTRACT(MONTH FROM($field))";
+
case 'DAY':
return "EXTRACT(DAY FROM($field))";
+
case 'HOUR':
return "EXTRACT(HOUR FROM($field))";
+
case 'MINUTE':
return "EXTRACT(MINUTE FROM($field))";
+
case 'SECOND':
return "EXTRACT(SECOND FROM($field))";
+
// ISO week number for date.
case 'WEEK':
switch ($this->db_type) {
@@ -547,6 +580,7 @@ class date_sql_handler {
// WEEK using arg 3 in MySQl should return the same value as
// Postgres EXTRACT.
return "WEEK($field, 3)";
+
case 'pgsql':
return "EXTRACT(WEEK FROM($field))";
}
@@ -556,6 +590,7 @@ class date_sql_handler {
// MySQL returns 1 for Sunday through 7 for Saturday, PHP date
// functions and Postgres use 0 for Sunday and 6 for Saturday.
return "INTEGER(DAYOFWEEK($field) - 1)";
+
case 'pgsql':
return "EXTRACT(DOW FROM($field))";
}
@@ -563,6 +598,7 @@ class date_sql_handler {
switch ($this->db_type) {
case 'mysql':
return "DAYOFYEAR($field)";
+
case 'pgsql':
return "EXTRACT(DOY FROM($field))";
}
@@ -775,8 +811,7 @@ class date_sql_handler {
}
/**
- * Create a complete datetime value out of an
- * incomplete array of selected values.
+ * Create a complete date/time value out of an incomplete array of values.
*
* For example, array('year' => 2008, 'month' => 05) will fill
* in the day, hour, minute and second with the earliest possible
@@ -795,9 +830,11 @@ class date_sql_handler {
case 'empty_min':
case 'min':
return date_format($dates[0], 'Y-m-d H:i:s');
+
case 'empty_max':
case 'max':
return date_format($dates[1], 'Y-m-d H:i:s');
+
default:
return;
}
@@ -840,7 +877,7 @@ class date_sql_handler {
}
/**
- * A function to test the validity of various date parts
+ * A function to test the validity of various date parts.
*/
function part_is_valid($value, $type) {
if (!preg_match('/^[0-9]*$/', $value)) {
@@ -856,16 +893,19 @@ class date_sql_handler {
return FALSE;
}
break;
+
case 'month':
if ($value < 0 || $value > 12) {
return FALSE;
}
break;
+
case 'day':
if ($value < 0 || $value > 31) {
return FALSE;
}
break;
+
case 'week':
if ($value < 0 || $value > 53) {
return FALSE;
@@ -890,26 +930,36 @@ class date_sql_handler {
$formats['display'] = 'Y';
$formats['sql'] = 'Y';
break;
+
case 'month':
$formats['display'] = date_limit_format($short, array('year', 'month'));
$formats['sql'] = 'Y-m';
break;
+
case 'day':
- $formats['display'] = date_limit_format($short, array('year', 'month', 'day'));
+ $args = array('year', 'month', 'day');
+ $formats['display'] = date_limit_format($short, $args);
$formats['sql'] = 'Y-m-d';
break;
+
case 'hour':
- $formats['display'] = date_limit_format($short, array('year', 'month', 'day', 'hour'));
+ $args = array('year', 'month', 'day', 'hour');
+ $formats['display'] = date_limit_format($short, $args);
$formats['sql'] = 'Y-m-d\TH';
break;
+
case 'minute':
- $formats['display'] = date_limit_format($short, array('year', 'month', 'day', 'hour', 'minute'));
+ $args = array('year', 'month', 'day', 'hour', 'minute');
+ $formats['display'] = date_limit_format($short, $args);
$formats['sql'] = 'Y-m-d\TH:i';
break;
+
case 'second':
- $formats['display'] = date_limit_format($short, array('year', 'month', 'day', 'hour', 'minute', 'second'));
+ $args = array('year', 'month', 'day', 'hour', 'minute', 'second');
+ $formats['display'] = date_limit_format($short, $args);
$formats['sql'] = 'Y-m-d\TH:i:s';
break;
+
case 'week':
$formats['display'] = 'F j Y (W)';
$formats['sql'] = 'Y-\WW';
@@ -927,7 +977,7 @@ class date_sql_handler {
'#type' => 'radios',
'#default_value' => $granularity,
'#options' => $this->date_parts(),
- );
+ );
return $form;
}
@@ -1030,7 +1080,6 @@ class date_sql_handler {
$direction = $results[1];
$count = $results[2];
$item = $results[3];
-
$replace = array(
'now' => '@',
'+' => 'P',
@@ -1051,14 +1100,27 @@ class date_sql_handler {
'second' => 'S',
' ' => '',
' ' => '',
- );
- $prefix = in_array($item, array('hours', 'hour', 'minutes', 'minute', 'seconds', 'second')) ? 'T' : '';
- return $prefix . strtr($direction, $replace) . $count . strtr($item, $replace);
+ );
+ $args = array('hours', 'hour', 'minutes', 'minute', 'seconds', 'second');
+ if (in_array($item, $args)) {
+ $prefix = 'T';
+ }
+ else {
+ $prefix = '';
+ }
+ $return = $prefix;
+ $return .= strtr($direction, $replace);
+ $return .= $count;
+ $return .= strtr($item, $replace);
+
+ return $return;
}
/**
- * Use the parsed values from the ISO argument to determine the
- * granularity of this period.
+ * Granularity arguments handler.
+ *
+ * Use the parsed values from the ISO argument
+ * to determine the granularity of this period.
*/
function arg_granularity($arg) {
$granularity = '';
@@ -1137,8 +1199,9 @@ class date_sql_handler {
}
return array($min_date, $max_date);
}
- // Intercept invalid info and fall back to the current date.
+ // Intercept invalid info and fall back to the current date.
$now = date_now();
return array($now, $now);
}
}
+// @codingStandardsIgnoreEnd
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_api/theme/theme.inc b/profiles/commerce_kickstart/modules/contrib/date/date_api/theme/theme.inc
index 032e3e93..0a57ecd0 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_api/theme/theme.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_api/theme/theme.inc
@@ -194,6 +194,7 @@ function theme_date_calendar_day($variables) {
function theme_date_time_ago($variables) {
$start_date = $variables['start_date'];
$end_date = $variables['end_date'];
+ $use_end_date = isset($variables['use_end_date']) ? $variables['use_end_date'] : false;
$interval = !empty($variables['interval']) ? $variables['interval'] : 2;
$display = isset($variables['interval_display']) ? $variables['interval_display'] : 'time ago';
@@ -202,28 +203,43 @@ function theme_date_time_ago($variables) {
return;
}
+ // We use the end date only when the option is checked.
+ if ($use_end_date){
+ $date = date_format($end_date, DATE_FORMAT_UNIX);
+ }
+ else {
+ $date = date_format($start_date, DATE_FORMAT_UNIX);
+ }
+
// Time to compare dates to.
+
$now = date_format(date_now(), DATE_FORMAT_UNIX);
- $start = date_format($start_date, DATE_FORMAT_UNIX);
- // will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence)
- $time_diff = $now - $start;
+ // Will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence).
+ $time_diff = $now - $date;
// Uses the same options used by Views format_interval.
switch ($display) {
case 'raw time ago':
return format_interval($time_diff, $interval);
+
case 'time ago':
return t('%time ago', array('%time' => format_interval($time_diff, $interval)));
+
case 'raw time hence':
return format_interval(-$time_diff, $interval);
+
case 'time hence':
return t('%time hence', array('%time' => format_interval(-$time_diff, $interval)));
+
case 'raw time span':
return ($time_diff < 0 ? '-' : '') . format_interval(abs($time_diff), $interval);
+
case 'inverse time span':
return ($time_diff > 0 ? '-' : '') . format_interval(abs($time_diff), $interval);
+
case 'time span':
return t(($time_diff < 0 ? '%time hence' : '%time ago'), array('%time' => format_interval(abs($time_diff), $interval)));
+
}
}
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_context/date_context.info b/profiles/commerce_kickstart/modules/contrib/date/date_context/date_context.info
index 1d8a551d..97cb8c9d 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_context/date_context.info
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_context/date_context.info
@@ -8,9 +8,9 @@ dependencies[] = context
files[] = date_context.module
files[] = plugins/date_context_date_condition.inc
-; Information added by Drupal.org packaging script on 2014-07-29
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
core = "7.x"
project = "date"
-datestamp = "1406653438"
+datestamp = "1491562090"
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_context/date_context.module b/profiles/commerce_kickstart/modules/contrib/date/date_context/date_context.module
index 44e975ac..9b568e15 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_context/date_context.module
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_context/date_context.module
@@ -1,5 +1,8 @@
execute()
@@ -8,8 +11,6 @@
* Cache the date processing, perhaps cache the formatted, timezone-adjusted
* date strings for each entity (would have to be cached differently for each
* timezone, based on the tz_handling method for the date).
- *
- * Add an option to set/not set the context on forms vs views.
*/
/**
@@ -22,7 +23,7 @@ function date_context_context_node_condition_alter($node, $op) {
}
/**
- * Implements hook_context_plugins()
+ * Implements hook_context_plugins().
*/
function date_context_context_plugins() {
$plugins = array();
@@ -38,7 +39,7 @@ function date_context_context_plugins() {
}
/**
- * Implements hook_context_registry()
+ * Implements hook_context_registry().
*/
function date_context_context_registry() {
return array(
@@ -51,4 +52,3 @@ function date_context_context_registry() {
),
);
}
-
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_context/plugins/date_context_date_condition.inc b/profiles/commerce_kickstart/modules/contrib/date/date_context/plugins/date_context_date_condition.inc
index 573b0354..97c18b47 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_context/plugins/date_context_date_condition.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_context/plugins/date_context_date_condition.inc
@@ -1,10 +1,20 @@
$field) {
@@ -15,10 +25,13 @@ class date_context_date_condition extends context_condition_node {
return $values;
}
- function options_form($context) {
+ /**
+ * {@inheritdoc}
+ */
+ public function options_form($context) {
$defaults = $this->fetch_from_context($context, 'options');
$options = array(
- '<' => t('Is less than'),
+ '<' => t('Is less than'),
'<=' => t('Is less than or equal to'),
'>=' => t('Is greater than or equal to'),
'>' => t('Is greater than'),
@@ -27,6 +40,8 @@ class date_context_date_condition extends context_condition_node {
'empty' => t('Is empty'),
'not empty' => t('Is not Empty'),
);
+ $dependency_options = array('<', '<=', '>', '>=', '=', '!=');
+
$form['operation'] = array(
'#title' => t('Operation'),
'#type' => 'select',
@@ -41,12 +56,15 @@ class date_context_date_condition extends context_condition_node {
'#description' => t("The value the field should contain to meet the condition. This can either be an absolute date in ISO format (YYYY-MM-DDTHH:MM:SS) or a relative string like '12AM today'. Examples: 2011-12-31T00:00:00, now, now +1 day, 12AM today, Monday next week. More examples of relative date formats in the PHP documentation.", array('@relative_format' => 'http://www.php.net/manual/en/datetime.formats.relative.php')),
'#default_value' => isset($defaults['value']) ? $defaults['value'] : '',
'#process' => array('ctools_dependent_process'),
- '#dependency' => array('edit-conditions-plugins-date-context-date-condition-options-operation' => array('<', '<=', '>', '>=', '=', '!=')),
+ '#dependency' => array('edit-conditions-plugins-date-context-date-condition-options-operation' => $dependency_options),
);
return $form;
}
- function execute($entity, $op) {
+ /**
+ * {@inheritdoc}
+ */
+ public function execute($entity, $op) {
if (in_array($op, array('view', 'form'))) {
foreach ($this->get_contexts() as $context) {
$options = $this->fetch_from_context($context, 'options');
@@ -91,32 +109,37 @@ class date_context_date_condition extends context_condition_node {
str_replace('now', 'today', $options['value']);
$date = date_create($options['value'], date_default_timezone_object());
$compdate = $date->format(DATE_FORMAT_DATETIME);
- switch($options['operation']) {
+ switch ($options['operation']) {
case '=':
if ($date2 >= $compdate && $date1 <= $compdate) {
$this->condition_met($context, $field_name);
}
break;
+
case '>':
if ($date1 > $compdate) {
$this->condition_met($context, $field_name);
}
break;
+
case '>=':
if ($date1 >= $compdate) {
$this->condition_met($context, $field_name);
}
break;
+
case '<':
if ($date2 < $compdate) {
$this->condition_met($context, $field_name);
}
break;
+
case '<=':
if ($date2 <= $compdate) {
$this->condition_met($context, $field_name);
}
break;
+
case '!=':
if ($date1 < $compdate || $date2 > $compdate) {
$this->condition_met($context, $field_name);
@@ -130,3 +153,4 @@ class date_context_date_condition extends context_condition_node {
}
}
}
+// @codingStandardsIgnoreEnd
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_elements.inc b/profiles/commerce_kickstart/modules/contrib/date/date_elements.inc
index 6908d967..656d4998 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_elements.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_elements.inc
@@ -40,7 +40,6 @@
*
* - In the field's submission processing, the new date values, which are in
* the local timezone, are converted back to their UTC values and stored.
- *
*/
function date_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $base) {
@@ -75,7 +74,7 @@ function date_field_widget_form(&$form, &$form_state, $field, $instance, $langco
// The repeating values will be re-generated when the repeat widget form is validated.
// At this point we can't tell if this form element is going to be hidden by #access, and we're going to
// lose all but the first value by doing this, so store the original values in case we need to replace them later.
- if (!empty($field['settings']['repeat'])) {
+ if (!empty($field['settings']['repeat']) && module_exists('date_repeat_field')) {
if ($delta == 0) {
$form['#after_build'][] = 'date_repeat_after_build';
$form_state['storage']['repeat_fields'][$field_name] = array_merge($form['#parents'], array($field_name));
@@ -87,7 +86,7 @@ function date_field_widget_form(&$form, &$form_state, $field, $instance, $langco
}
module_load_include('inc', 'date_api', 'date_api_elements');
- $timezone = date_get_timezone($field['settings']['tz_handling'], isset($items[0]['timezone']) ? $items[0]['timezone'] : date_default_timezone());
+ $timezone = date_get_timezone($field['settings']['tz_handling'], isset($items[$delta]['timezone']) ? $items[$delta]['timezone'] : date_default_timezone());
// TODO see if there's a way to keep the timezone element from ever being
// nested as array('timezone' => 'timezone' => value)). After struggling
@@ -122,7 +121,13 @@ function date_field_widget_form(&$form, &$form_state, $field, $instance, $langco
'#weight' => $instance['widget']['weight'] + 1,
'#attributes' => array('class' => array('date-no-float')),
'#date_label_position' => $instance['widget']['settings']['label_position'],
- );
+ );
+ }
+
+ // Make changes if instance is set to be rendered as a regular field.
+ if (!empty($instance['widget']['settings']['no_fieldset'])) {
+ $element['#title'] = check_plain($instance['label']);
+ $element['#theme_wrappers'] = ($field['cardinality'] == 1) ? array('date_form_element') : array();
}
return $element;
@@ -148,6 +153,7 @@ function date_local_date($item, $timezone, $field, $instance, $part = 'value') {
// @TODO Figure out how to replace date_fuzzy_datetime() function.
// Special case for ISO dates to create a valid date object for formatting.
// Is this still needed?
+ // @codingStandardsIgnoreStart
/*
if ($field['type'] == DATE_ISO) {
$value = date_fuzzy_datetime($value);
@@ -157,6 +163,7 @@ function date_local_date($item, $timezone, $field, $instance, $part = 'value') {
$value = date_convert($value, $field['type'], DATE_DATETIME, $db_timezone);
}
*/
+ // @codingStandardsIgnoreEnd
$date = new DateObject($value, date_get_timezone_db($field['settings']['tz_handling']));
$date->limitGranularity($field['settings']['granularity']);
@@ -193,8 +200,7 @@ function date_default_value($field, $instance, $langcode) {
}
/**
- * Helper function for the date default value callback to set
- * either 'value' or 'value2' to its default value.
+ * Helper function for the date default value callback to set either 'value' or 'value2' to its default value.
*/
function date_default_value_part($item, $field, $instance, $langcode, $part = 'value') {
$timezone = date_get_timezone($field['settings']['tz_handling']);
@@ -241,7 +247,6 @@ function date_default_value_part($item, $field, $instance, $langcode, $part = 'v
* Process an individual date element.
*/
function date_combo_element_process($element, &$form_state, $form) {
-
if (date_hidden_element($element)) {
// A hidden value for a new entity that had its end date set to blank
// will not get processed later to populate the end date, so set it here.
@@ -296,6 +301,7 @@ function date_combo_element_process($element, &$form_state, $form) {
// Blank out the end date for optional end dates that match the start date,
// except when this is a new node that has default values that should be honored.
if (!$date_is_default && $field['settings']['todate'] != 'required'
+ && is_array($element['#default_value'])
&& !empty($element['#default_value'][$to_field])
&& $element['#default_value'][$to_field] == $element['#default_value'][$from_field]) {
unset($element['#default_value'][$to_field]);
@@ -329,10 +335,13 @@ function date_combo_element_process($element, &$form_state, $form) {
'#date_increment' => $instance['widget']['settings']['increment'],
'#date_year_range' => $instance['widget']['settings']['year_range'],
'#date_label_position' => $instance['widget']['settings']['label_position'],
- );
+ );
- $description = !empty($element['#description']) ? t($element['#description']) : '';
- unset($element['#description']);
+ // Date repeat is a multiple value field. So the description is removed from
+ // the single element earlier. Let's get it back.
+ if (isset($element['show_repeat_settings']) && !empty($element['value']['#instance']['description'])) {
+ $element['#description'] = $element['value']['#instance']['description'];
+ }
// Give this element the right type, using a Date API
// or a Date Popup element type.
@@ -347,11 +356,13 @@ function date_combo_element_process($element, &$form_state, $form) {
$element['#attached']['js'][] = drupal_get_path('module', 'date') . '/date.js';
$element[$from_field]['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
break;
+
case 'date_popup':
$element[$from_field]['#type'] = 'date_popup';
$element[$from_field]['#theme_wrappers'] = array('date_popup');
$element[$from_field]['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
break;
+
default:
$element[$from_field]['#type'] = 'date_text';
$element[$from_field]['#theme_wrappers'] = array('date_text');
@@ -375,18 +386,17 @@ function date_combo_element_process($element, &$form_state, $form) {
$element[$to_field]['#prefix'] = '';
// Users with JS enabled will never see initially blank values for the end
// date (see Drupal.date.EndDateHandler()), so hide the message for them.
- $description .= ' ' . t("Empty 'End date' values will use the 'Start date' values.") . '';
- $element['#fieldset_description'] = $description;
+ $element['#description'] .= ' ' . t("Empty 'End date' values will use the 'Start date' values.") . '';
if ($field['settings']['todate'] == 'optional') {
$element[$to_field]['#states'] = array(
'visible' => array(
- 'input[name="' . $show_id . '"]' => array('checked' => TRUE),
- ));
+ 'input[name="' . $show_id . '"]' => array(
+ 'checked' => TRUE,
+ ),
+ ),
+ );
}
}
- else {
- $element[$from_field]['#description'] = $description;
- }
// Create label for error messages that make sense in multiple values
// and when the title field is left blank.
@@ -404,16 +414,27 @@ function date_combo_element_process($element, &$form_state, $form) {
$element[$from_field]['#date_title'] = t('@field_name', array('@field_name' => $instance['label']));
}
+ // Make changes if instance is set to be rendered as a regular field.
+ if (!empty($instance['widget']['settings']['no_fieldset'])) {
+ unset($element[$from_field]['#description']);
+ if (!empty($field['settings']['todate']) && isset($element['#description'])) {
+ $element['#description'] .= ' ' . t("Empty 'End date' values will use the 'Start date' values.") . '';
+ }
+ }
+
$context = array(
- 'field' => $field,
- 'instance' => $instance,
- 'form' => $form,
+ 'field' => $field,
+ 'instance' => $instance,
+ 'form' => $form,
);
drupal_alter('date_combo_process', $element, $form_state, $context);
return $element;
}
+/**
+ * Empty a date element.
+ */
function date_element_empty($element, &$form_state) {
$item = array();
$item['value'] = NULL;
@@ -428,6 +449,7 @@ function date_element_empty($element, &$form_state) {
/**
* Validate and update a combo element.
+ *
* Don't try this if there were errors before reaching this point.
*/
function date_combo_validate($element, &$form_state) {
@@ -444,9 +466,19 @@ function date_combo_validate($element, &$form_state) {
$delta = $element['#delta'];
$langcode = $element['#language'];
+ // Related issue: https://drupal.org/node/2279831.
+ if (!is_array($element['#field_parents'])) {
+ $element['#field_parents'] = array();
+ }
$form_values = drupal_array_get_nested_value($form_state['values'], $element['#field_parents']);
$form_input = drupal_array_get_nested_value($form_state['input'], $element['#field_parents']);
+ // Programmatically calling drupal_submit_form() does not always add the date
+ // combo to $form_state['input'].
+ if (empty($form_input[$field_name]) && !empty($form_values[$field_name])) {
+ form_set_value($element, $element['#date_items'], $form_state);
+ return;
+ }
// If the whole field is empty and that's OK, stop now.
if (empty($form_input[$field_name]) && !$element['#required']) {
return;
@@ -519,11 +551,7 @@ function date_combo_validate($element, &$form_state) {
return;
}
}
- // Don't look for further errors if errors are already flagged
- // because otherwise we'll show errors on the nested elements
- // more than once.
- elseif (!form_get_errors()) {
-
+ else {
$timezone = !empty($item[$tz_field]) ? $item[$tz_field] : $element['#date_timezone'];
$timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
$element[$from_field]['#date_timezone'] = $timezone;
@@ -598,7 +626,10 @@ function date_combo_validate($element, &$form_state) {
}
}
}
- if (!empty($errors)) {
+ // Don't show further errors if errors are already flagged
+ // because otherwise we'll show errors on the nested elements
+ // more than once.
+ if (!form_get_errors() && !empty($errors)) {
if ($field['cardinality']) {
form_error($element, t('There are errors in @field_name value #@delta:', array('@field_name' => $instance['label'], '@delta' => $delta + 1)) . theme('item_list', array('items' => $errors)));
}
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_migrate/date_migrate.info b/profiles/commerce_kickstart/modules/contrib/date/date_migrate/date_migrate.info
index 69012711..41e416a3 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_migrate/date_migrate.info
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_migrate/date_migrate.info
@@ -4,9 +4,9 @@ core = 7.x
package = Date/Time
hidden = TRUE
-; Information added by Drupal.org packaging script on 2014-07-29
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
core = "7.x"
project = "date"
-datestamp = "1406653438"
+datestamp = "1491562090"
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_migrate/date_migrate_example/date_migrate_example.info b/profiles/commerce_kickstart/modules/contrib/date/date_migrate/date_migrate_example/date_migrate_example.info
index 7223b763..ba07220d 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_migrate/date_migrate_example/date_migrate_example.info
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_migrate/date_migrate_example/date_migrate_example.info
@@ -20,9 +20,9 @@ package = "Features"
project = "date_migrate_example"
version = "7.x-2.0"
-; Information added by Drupal.org packaging script on 2014-07-29
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
core = "7.x"
project = "date"
-datestamp = "1406653438"
+datestamp = "1491562090"
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_migrate/date_migrate_example/date_migrate_example.migrate.inc b/profiles/commerce_kickstart/modules/contrib/date/date_migrate/date_migrate_example/date_migrate_example.migrate.inc
index e11dea66..216e1c54 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_migrate/date_migrate_example/date_migrate_example.migrate.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_migrate/date_migrate_example/date_migrate_example.migrate.inc
@@ -47,8 +47,8 @@ class DateExampleMigration extends XMLMigration {
$xml_folder = drupal_get_path('module', 'date_migrate_example');
$items_url = $xml_folder . '/date_migrate_example.xml';
$item_xpath = '/source_data/item';
- $item_ID_xpath = 'id';
- $items_class = new MigrateItemsXML($items_url, $item_xpath, $item_ID_xpath);
+ $item_id_xpath = 'id';
+ $items_class = new MigrateItemsXML($items_url, $item_xpath, $item_id_xpath);
$this->source = new MigrateSourceMultiItems($items_class, $fields);
$this->destination = new MigrateDestinationNode('date_migrate_example');
@@ -78,7 +78,7 @@ class DateExampleMigration extends XMLMigration {
$this->addFieldMapping('field_datestamp_range:to', 'datestamp_range_to');
// You can specify a timezone to be applied to all values going into the
- // field (Tokyo is UTC+9, no DST)
+ // field (Tokyo is UTC+9, no DST).
$this->addFieldMapping('field_datetime', 'datetime')
->xpath('datetime');
$this->addFieldMapping('field_datetime:timezone')
@@ -107,25 +107,25 @@ class DateExampleMigration extends XMLMigration {
// The date range field can have multiple values.
$current_row->date_range_from = array();
foreach ($current_row->xml->date_range as $range) {
- $current_row->date_range_from[] = (string)$range->from[0];
- $current_row->date_range_to[] = (string)$range->to[0];
+ $current_row->date_range_from[] = (string) $range->from[0];
+ $current_row->date_range_to[] = (string) $range->to[0];
}
- $current_row->datestamp_range_from =
- (string) $current_row->xml->datestamp_range->from[0];
- $current_row->datestamp_range_to =
- (string) $current_row->xml->datestamp_range->to[0];
-
- $current_row->datetime_range_from =
- (string) $current_row->xml->datetime_range->from[0];
- $current_row->datetime_range_to =
- (string) $current_row->xml->datetime_range->to[0];
- $current_row->datetime_range_timezone =
- (string) $current_row->xml->datetime_range->timezone[0];
-
- $current_row->date_repeat =
- (string) $current_row->xml->date_repeat->date[0];
- $current_row->date_repeat_rrule =
- (string) $current_row->xml->date_repeat->rule[0];
+ $current_row->datestamp_range_from
+ = (string) $current_row->xml->datestamp_range->from[0];
+ $current_row->datestamp_range_to
+ = (string) $current_row->xml->datestamp_range->to[0];
+
+ $current_row->datetime_range_from
+ = (string) $current_row->xml->datetime_range->from[0];
+ $current_row->datetime_range_to
+ = (string) $current_row->xml->datetime_range->to[0];
+ $current_row->datetime_range_timezone
+ = (string) $current_row->xml->datetime_range->timezone[0];
+
+ $current_row->date_repeat
+ = (string) $current_row->xml->date_repeat->date[0];
+ $current_row->date_repeat_rrule
+ = (string) $current_row->xml->date_repeat->rule[0];
}
}
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_popup/date_popup.info b/profiles/commerce_kickstart/modules/contrib/date/date_popup/date_popup.info
index 271e1c68..41945a63 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_popup/date_popup.info
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_popup/date_popup.info
@@ -7,9 +7,9 @@ configure = admin/config/date/date_popup
stylesheets[all][] = themes/datepicker.1.7.css
-; Information added by Drupal.org packaging script on 2014-07-29
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
core = "7.x"
project = "date"
-datestamp = "1406653438"
+datestamp = "1491562090"
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_popup/date_popup.install b/profiles/commerce_kickstart/modules/contrib/date/date_popup/date_popup.install
index 790a514a..e13a4f5a 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_popup/date_popup.install
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_popup/date_popup.install
@@ -5,6 +5,7 @@
* Install, update and uninstall functions for the Date Popup module.
*/
+// @codingStandardsIgnoreStart
/**
* Implements hook_install().
*/
@@ -17,6 +18,7 @@ function date_popup_install() {
function date_popup_uninstall() {
}
+// @codingStandardsIgnoreEnd
/**
* Implements hook_enable().
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_popup/date_popup.js b/profiles/commerce_kickstart/modules/contrib/date/date_popup/date_popup.js
index 1847f84f..f38dcb59 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_popup/date_popup.js
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_popup/date_popup.js
@@ -1,62 +1,73 @@
/**
* Attaches the calendar behavior to all required fields
*/
-(function ($) {
-Drupal.behaviors.date_popup = {
- attach: function (context) {
- for (var id in Drupal.settings.datePopup) {
- $('#'+ id).bind('focus', Drupal.settings.datePopup[id], function(e) {
- if (!$(this).hasClass('date-popup-init')) {
- var datePopup = e.data;
- // Explicitely filter the methods we accept.
- switch (datePopup.func) {
- case 'datepicker':
- $(this)
- .datepicker(datePopup.settings)
- .addClass('date-popup-init')
- $(this).click(function(){
- $(this).focus();
+(function($) {
+ function makeFocusHandler(e) {
+ if (!$(this).hasClass('date-popup-init')) {
+ var datePopup = e.data;
+ // Explicitely filter the methods we accept.
+ switch (datePopup.func) {
+ case 'datepicker':
+ $(this)
+ .datepicker(datePopup.settings)
+ .addClass('date-popup-init');
+ $(this).click(function(){
+ $(this).focus();
+ });
+ if (datePopup.settings.syncEndDate) {
+ $('.start-date-wrapper').each(function(){
+ var start_date_wrapper = this;
+ $(this).find('input:eq(0)').change(function(){
+ $(start_date_wrapper).next('.end-date-wrapper').find('input:eq(0)').val($(this).val());
+ });
});
- break;
+ }
+ break;
- case 'timeEntry':
- $(this)
- .timeEntry(datePopup.settings)
- .addClass('date-popup-init')
- $(this).click(function(){
- $(this).focus();
- });
- break;
- case 'timepicker':
- // Translate the PHP date format into the style the timepicker uses.
- datePopup.settings.timeFormat = datePopup.settings.timeFormat
- // 12-hour, leading zero,
- .replace('h', 'hh')
- // 12-hour, no leading zero.
- .replace('g', 'h')
- // 24-hour, leading zero.
- .replace('H', 'HH')
- // 24-hour, no leading zero.
- .replace('G', 'H')
- // AM/PM.
- .replace('A', 'p')
- // Minutes with leading zero.
- .replace('i', 'mm')
- // Seconds with leading zero.
- .replace('s', 'ss');
+ case 'timeEntry':
+ $(this)
+ .timeEntry(datePopup.settings)
+ .addClass('date-popup-init');
+ $(this).click(function(){
+ $(this).focus();
+ });
+ break;
- datePopup.settings.startTime = new Date(datePopup.settings.startTime);
- $(this)
- .timepicker(datePopup.settings)
- .addClass('date-popup-init');
- $(this).click(function(){
- $(this).focus();
- });
- break;
- }
+ case 'timepicker':
+ // Translate the PHP date format into the style the timepicker uses.
+ datePopup.settings.timeFormat = datePopup.settings.timeFormat
+ // 12-hour, leading zero,
+ .replace('h', 'hh')
+ // 12-hour, no leading zero.
+ .replace('g', 'h')
+ // 24-hour, leading zero.
+ .replace('H', 'HH')
+ // 24-hour, no leading zero.
+ .replace('G', 'H')
+ // AM/PM.
+ .replace('A', 'p')
+ // Minutes with leading zero.
+ .replace('i', 'mm')
+ // Seconds with leading zero.
+ .replace('s', 'ss');
+
+ datePopup.settings.startTime = new Date(datePopup.settings.startTime);
+ $(this)
+ .timepicker(datePopup.settings)
+ .addClass('date-popup-init');
+ $(this).click(function(){
+ $(this).focus();
+ });
+ break;
}
- });
+ }
}
- }
-};
+
+ Drupal.behaviors.date_popup = {
+ attach: function (context) {
+ for (var id in Drupal.settings.datePopup) {
+ $('#'+ id).bind('focus', Drupal.settings.datePopup[id], makeFocusHandler);
+ }
+ }
+ };
})(jQuery);
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_popup/date_popup.module b/profiles/commerce_kickstart/modules/contrib/date/date_popup/date_popup.module
index a2d0ebb1..a03132e9 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_popup/date_popup.module
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_popup/date_popup.module
@@ -16,7 +16,6 @@
* If no time elements are included in the format string, only the date
* textfield will be created. If no date elements are included in the format
* string, only the time textfield, will be created.
- *
*/
/**
@@ -44,7 +43,7 @@ function date_popup_add() {
/**
* Get the location of the Willington Vega timepicker library.
*
- * @return
+ * @return string
* The location of the library, or FALSE if the library isn't installed.
*/
function date_popup_get_wvega_path() {
@@ -94,9 +93,11 @@ function date_popup_library() {
}
/**
- * Create a unique CSS id name and output a single inline JS block for
- * each startup function to call and settings array to pass it. This
- * used to create a unique CSS class for each unique combination of
+ * Create a unique CSS id name and output a single inline JS block.
+ *
+ * For each startup function to call and settings array to pass it.
+ *
+ * This used to create a unique CSS class for each unique combination of
* function and settings, but using classes requires a DOM traversal
* and is much slower than an id lookup. The new approach returns to
* requiring a duplicate copy of the settings/code for every element
@@ -104,17 +105,20 @@ function date_popup_library() {
* putting the ids for each unique function/settings combo into
* Drupal.settings and searching for each listed id.
*
- * @param $pfx
+ * @param string $id
* The CSS class prefix to search the DOM for.
* TODO : unused ?
- * @param $func
- * The jQuery function to invoke on each DOM element containing the
- * returned CSS class.
- * @param $settings
+ *
+ * @param string $func
+ * The jQuery function to invoke on each DOM element
+ * containing the returned CSS class.
+ *
+ * @param array $settings
* The settings array to pass to the jQuery function.
+ *
* @returns
- * The CSS id to assign to the element that should have
- * $func($settings) invoked on it.
+ * The CSS id to assign to the element that should have $func($settings)
+ * invoked on it.
*/
function date_popup_js_settings_id($id, $func, $settings) {
static $js_added = FALSE;
@@ -123,14 +127,15 @@ function date_popup_js_settings_id($id, $func, $settings) {
// Make sure popup date selector grid is in correct year.
if (!empty($settings['yearRange'])) {
$parts = explode(':', $settings['yearRange']);
- // Set the default date to 0 or the lowest bound if the date ranges do not include the current year
- // Necessary for the datepicker to render and select dates correctly
- $defaultDate = ($parts[0] > 0 || 0 > $parts[1]) ? $parts[0] : 0;
- $settings += array('defaultDate' => (string) $defaultDate . 'y');
+ // Set the default date to 0 or the lowest bound if
+ // the date ranges do not include the current year.
+ // Necessary for the datepicker to render and select dates correctly.
+ $default_date = ($parts[0] > 0 || 0 > $parts[1]) ? $parts[0] : 0;
+ $settings += array('defaultDate' => (string) $default_date . 'y');
}
if (!$js_added) {
- drupal_add_js(drupal_get_path('module', 'date_popup') .'/date_popup.js');
+ drupal_add_js(drupal_get_path('module', 'date_popup') . '/date_popup.js');
$js_added = TRUE;
}
@@ -140,29 +145,35 @@ function date_popup_js_settings_id($id, $func, $settings) {
$id_count[$id] = 0;
}
-// It looks like we need the additional id_count for this to
-// work correctly when there are multiple values.
-// $return_id = "$id-$func-popup";
- $return_id = "$id-$func-popup-". $id_count[$id]++;
+ // It looks like we need the additional id_count for this to
+ // work correctly when there are multiple values.
+ // $return_id = "$id-$func-popup";
+ $return_id = "$id-$func-popup-" . $id_count[$id]++;
$js_settings['datePopup'][$return_id] = array(
'func' => $func,
- 'settings' => $settings
+ 'settings' => $settings,
);
drupal_add_js($js_settings, 'setting');
return $return_id;
}
+/**
+ * Date popup theme handler.
+ */
function date_popup_theme() {
return array(
- 'date_popup' => array('render element' => 'element'),
- );
+ 'date_popup' => array(
+ 'render element' => 'element',
+ ),
+ );
}
/**
* Implements hook_element_info().
*
* Set the #type to date_popup and fill the element #default_value with
- * a date adjusted to the proper local timezone in datetime format (YYYY-MM-DD HH:MM:SS).
+ * a date adjusted to the proper local timezone in datetime format
+ * (YYYY-MM-DD HH:MM:SS).
*
* The element will create two textfields, one for the date and one for the
* time. The date textfield will include a jQuery popup calendar date picker,
@@ -218,20 +229,32 @@ function date_popup_element_info() {
return $type;
}
+/**
+ * Date popup date granularity.
+ */
function date_popup_date_granularity($element) {
$granularity = date_format_order($element['#date_format']);
return array_intersect($granularity, array('month', 'day', 'year'));
}
+/**
+ * Date popup time granularity.
+ */
function date_popup_time_granularity($element) {
$granularity = date_format_order($element['#date_format']);
return array_intersect($granularity, array('hour', 'minute', 'second'));
}
+/**
+ * Date popup date format.
+ */
function date_popup_date_format($element) {
return (date_limit_format($element['#date_format'], date_popup_date_granularity($element)));
}
+/**
+ * Date popup time format.
+ */
function date_popup_time_format($element) {
return date_popup_format_to_popup_time(date_limit_format($element['#date_format'], date_popup_time_granularity($element)), $element['#timepicker']);
}
@@ -239,6 +262,7 @@ function date_popup_time_format($element) {
/**
* Element value callback for date_popup element.
*/
+// @codingStandardsIgnoreStart
function date_popup_element_value_callback($element, $input = FALSE, &$form_state) {
$granularity = date_format_order($element['#date_format']);
$has_time = date_has_time($granularity);
@@ -266,9 +290,11 @@ function date_popup_element_value_callback($element, $input = FALSE, &$form_stat
return $return;
}
+// @codingStandardsIgnoreEnd
/**
* Javascript popup element processing.
+ *
* Add popup attributes to $element.
*/
function date_popup_element_process($element, &$form_state, $form) {
@@ -284,7 +310,9 @@ function date_popup_element_process($element, &$form_state, $form) {
if (!empty($element['#ajax'])) {
$element['#ajax'] += array(
- 'trigger_as' => array('name' =>$element['#name']),
+ 'trigger_as' => array(
+ 'name' => $element['#name'],
+ ),
'event' => 'change',
);
}
@@ -292,6 +320,18 @@ function date_popup_element_process($element, &$form_state, $form) {
$element['date'] = date_popup_process_date_part($element);
$element['time'] = date_popup_process_time_part($element);
+ // Make changes if instance is set to be rendered as a regular field.
+ if (!empty($element['#instance']['widget']['settings']['no_fieldset']) && $element['#field']['cardinality'] == 1) {
+ if (!empty($element['date']) && empty($element['time'])) {
+ $element['date']['#title'] = check_plain($element['#instance']['label']);
+ $element['date']['#required'] = $element['#required'];
+ }
+ elseif (empty($element['date']) && !empty($element['time'])) {
+ $element['time']['#title'] = check_plain($element['#instance']['label']);
+ $element['time']['#required'] = $element['#required'];
+ }
+ }
+
if (isset($element['#element_validate'])) {
array_push($element['#element_validate'], 'date_popup_validate');
}
@@ -300,7 +340,7 @@ function date_popup_element_process($element, &$form_state, $form) {
}
$context = array(
- 'form' => $form,
+ 'form' => $form,
);
drupal_alter('date_popup_process', $element, $form_state, $context);
@@ -313,13 +353,22 @@ function date_popup_element_process($element, &$form_state, $form) {
function date_popup_process_date_part(&$element) {
$granularity = date_format_order($element['#date_format']);
$date_granularity = date_popup_date_granularity($element);
- if (empty($date_granularity)) return array();
+ if (empty($date_granularity)) {
+ return array();
+ }
// The datepicker can't handle zero or negative values like 0:+1
// even though the Date API can handle them, so rework the value
// we pass to the datepicker to use defaults it can accept (such as +0:+1)
// date_range_string() adds the necessary +/- signs to the range string.
$this_year = date_format(date_now(), 'Y');
+ // When used as a Views exposed filter widget, $element['#value'] contains an array instead an string.
+ // Fill the 'date' string in this case.
+ $mock = NULL;
+ $callback_values = date_popup_element_value_callback($element, FALSE, $mock);
+ if (!isset($element['#value']['date']) && isset($callback_values['date'])) {
+ $element['#value']['date'] = $callback_values['date'];
+ }
$date = '';
if (!empty($element['#value']['date'])) {
$date = new DateObject($element['#value']['date'], $element['#date_timezone'], date_popup_date_format($element));
@@ -336,37 +385,49 @@ function date_popup_process_date_part(&$element) {
'closeAtTop' => FALSE,
'speed' => 'immediate',
'firstDay' => intval(variable_get('date_first_day', 0)),
- //'buttonImage' => base_path() . drupal_get_path('module', 'date_api') ."/images/calendar.png",
- //'buttonImageOnly' => TRUE,
+ // 'buttonImage' => base_path()
+ // . drupal_get_path('module', 'date_api') ."/images/calendar.png",
+ // 'buttonImageOnly' => TRUE,
'dateFormat' => date_popup_format_to_popup(date_popup_date_format($element), 'datepicker'),
'yearRange' => $year_range,
// Custom setting, will be expanded in Drupal.behaviors.date_popup()
'fromTo' => isset($fromto),
);
+ if (!empty($element['#instance'])) {
+ $settings['syncEndDate'] = $element['#instance']['settings']['default_value2'] == 'sync';
+ }
+
// Create a unique id for each set of custom settings.
$id = date_popup_js_settings_id($element['#id'], 'datepicker', $settings);
- // Manually build this element and set the value - this will prevent corrupting
- // the parent value
+ // Manually build this element and set the value -
+ // this will prevent corrupting the parent value.
$parents = array_merge($element['#parents'], array('date'));
$sub_element = array(
'#type' => 'textfield',
'#title' => theme('date_part_label_date', array('part_type' => 'date', 'element' => $element)),
'#title_display' => $element['#date_label_position'] == 'above' ? 'before' : 'invisible',
- '#default_value' => $element['#value']['date'],
+ '#default_value' => date_format_date($date, 'custom', date_popup_date_format($element)),
'#id' => $id,
'#input' => FALSE,
'#size' => !empty($element['#size']) ? $element['#size'] : 20,
'#maxlength' => !empty($element['#maxlength']) ? $element['#maxlength'] : 30,
'#attributes' => $element['#attributes'],
'#parents' => $parents,
- '#name' => array_shift($parents) . '['. implode('][', $parents) .']',
+ '#name' => array_shift($parents) . '[' . implode('][', $parents) . ']',
'#ajax' => !empty($element['#ajax']) ? $element['#ajax'] : FALSE,
);
$sub_element['#value'] = $sub_element['#default_value'];
- // TODO, figure out exactly when we want this description. In many places it is not desired.
- $sub_element['#description'] = ' '. t('E.g., @date', array('@date' => date_format_date(date_example_date(), 'custom', date_popup_date_format($element))));
+ // TODO, figure out exactly when we want this description.
+ // In many places it is not desired.
+ $sub_element['#description'] = ' ' . t('E.g., @date', array(
+ '@date' => date_format_date(
+ date_example_date(),
+ 'custom',
+ date_popup_date_format($element)
+ ),
+ ));
return $sub_element;
}
@@ -377,7 +438,17 @@ function date_popup_process_date_part(&$element) {
function date_popup_process_time_part(&$element) {
$granularity = date_format_order($element['#date_format']);
$has_time = date_has_time($granularity);
- if (empty($has_time)) return array();
+ if (empty($has_time)) {
+ return array();
+ }
+
+ // When used as a Views exposed filter widget, $element['#value'] contains an array instead an string.
+ // Fill the 'time' string in this case.
+ $mock = NULL;
+ $callback_values = date_popup_element_value_callback($element, FALSE, $mock);
+ if (!isset($element['#value']['time']) && isset($callback_values['time'])) {
+ $element['#value']['time'] = $callback_values['time'];
+ }
switch ($element['#timepicker']) {
case 'default':
@@ -385,10 +456,14 @@ function date_popup_process_time_part(&$element) {
$settings = array(
'show24Hours' => strpos($element['#date_format'], 'H') !== FALSE ? TRUE : FALSE,
'showSeconds' => (in_array('second', $granularity) ? TRUE : FALSE),
- 'timeSteps' => array(1, intval($element['#date_increment']), (in_array('second', $granularity) ? $element['#date_increment'] : 0)),
+ 'timeSteps' => array(
+ 1,
+ intval($element['#date_increment']),
+ (in_array('second', $granularity) ? $element['#date_increment'] : 0),
+ ),
'spinnerImage' => '',
'fromTo' => isset($fromto),
- );
+ );
if (strpos($element['#date_format'], 'a') !== FALSE) {
// Then we are using lowercase am/pm.
$settings['ampmNames'] = array('am', 'pm');
@@ -397,14 +472,17 @@ function date_popup_process_time_part(&$element) {
$settings['ampmPrefix'] = ' ';
}
break;
+
case 'wvega':
$func = 'timepicker';
- $time_granularity = array_intersect($granularity, array('hour', 'minute', 'second'));
+ $grans = array('hour', 'minute', 'second');
+ $time_granularity = array_intersect($granularity, $grans);
$format = date_popup_format_to_popup_time(date_limit_format($element['#date_format'], $time_granularity), 'wvega');
+ $default_value = isset($element['#default_value']) ? $element['#default_value'] : '';
// The first value in the dropdown list should be the same as the element
// default_value, but it needs to be in JS format (i.e. milliseconds since
// the epoch).
- $start_time = new DateObject($element['#default_value'], $element['#date_timezone'], DATE_FORMAT_DATETIME);
+ $start_time = new DateObject($default_value, $element['#date_timezone'], DATE_FORMAT_DATETIME);
date_increment_round($start_time, $element['#date_increment']);
$start_time = $start_time->format(DATE_FORMAT_UNIX) * 1000;
$settings = array(
@@ -414,6 +492,7 @@ function date_popup_process_time_part(&$element) {
'scrollbar' => TRUE,
);
break;
+
default:
$func = '';
$settings = array();
@@ -423,8 +502,8 @@ function date_popup_process_time_part(&$element) {
// Create a unique id for each set of custom settings.
$id = date_popup_js_settings_id($element['#id'], $func, $settings);
- // Manually build this element and set the value - this will prevent corrupting
- // the parent value
+ // Manually build this element and set the value -
+ // this will prevent corrupting the parent value.
$parents = array_merge($element['#parents'], array('time'));
$sub_element = array(
'#type' => 'textfield',
@@ -436,16 +515,22 @@ function date_popup_process_time_part(&$element) {
'#maxlength' => 10,
'#attributes' => $element['#attributes'],
'#parents' => $parents,
- '#name' => array_shift($parents) . '['. implode('][', $parents) .']',
+ '#name' => array_shift($parents) . '[' . implode('][', $parents) . ']',
'#ajax' => !empty($element['#ajax']) ? $element['#ajax'] : FALSE,
);
$sub_element['#value'] = $sub_element['#default_value'];
- // TODO, figure out exactly when we want this description. In many places it is not desired.
+ // TODO, figure out exactly when we want this description.
+ // In many places it is not desired.
$example_date = date_now();
date_increment_round($example_date, $element['#date_increment']);
- $sub_element['#description'] = t('E.g., @date', array('@date' => date_format_date($example_date, 'custom', date_popup_time_format($element))));
+ $sub_element['#description'] = t('E.g., @date', array(
+ '@date' => date_format_date(
+ $example_date,
+ 'custom',
+ date_popup_time_format($element)
+ )));
return ($sub_element);
}
@@ -456,7 +541,6 @@ function date_popup_process_time_part(&$element) {
* When used as a Views widget, the validation step always gets triggered,
* even with no form submission. Before form submission $element['#value']
* contains a string, after submission it contains an array.
- *
*/
function date_popup_validate($element, &$form_state) {
@@ -473,6 +557,11 @@ function date_popup_validate($element, &$form_state) {
$input_exists = NULL;
$input = drupal_array_get_nested_value($form_state['values'], $element['#parents'], $input_exists);
+ // If the date is a string, it is not considered valid and can cause problems
+ // later on, so just exit out now.
+ if (is_string($input)) {
+ return;
+ }
drupal_alter('date_popup_pre_validate', $element, $form_state, $input);
@@ -481,16 +570,22 @@ function date_popup_validate($element, &$form_state) {
$time_granularity = date_popup_time_granularity($element);
$has_time = date_has_time($granularity);
- $label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
- $label = t($label);
-
+ // @codingStandardsIgnoreStart
+ $label = '';
+ if (!empty($element['#date_title'])) {
+ $label = t($element['#date_title']);
+ }
+ elseif (!empty($element['#title'])) {
+ $label = t($element['#title']);
+ }
+ // @codingStandardsIgnoreEnd
$date = date_popup_input_date($element, $input);
// If the date has errors, display them.
// If something was input but there is no date, the date is invalid.
// If the field is empty and required, set error message and return.
$error_field = implode('][', $element['#parents']);
- if (empty($date) || !empty($date->errors)) {
+ if ((empty($element['#value']['date']) && empty($element['#value']['time'])) || !empty($date->errors)) {
if (is_object($date) && !empty($date->errors)) {
$message = t('The value input for field %field is invalid:', array('%field' => $label));
$message .= ' ' . implode(' ', $date->errors);
@@ -517,13 +612,15 @@ function date_popup_validate($element, &$form_state) {
/**
* Helper function for extracting a date value out of user input.
*
- * @param autocomplete
+ * @param bool $auto_complete
* Should we add a time value to complete the date if there is no time?
* Useful anytime the time value is optional.
*/
function date_popup_input_date($element, $input, $auto_complete = FALSE) {
if (empty($input) || !is_array($input) || !array_key_exists('date', $input) || empty($input['date'])) {
- return NULL;
+ //check if there is no time associated in the input variable. This is the exception scenario where the user has entered only time and not date.
+ if(empty($input['time']))
+ return NULL;
}
date_popup_add();
$granularity = date_format_order($element['#date_format']);
@@ -532,9 +629,14 @@ function date_popup_input_date($element, $input, $auto_complete = FALSE) {
$format = date_popup_date_format($element);
$format .= $has_time ? ' ' . date_popup_time_format($element) : '';
- $datetime = $input['date'];
- $datetime .= $has_time ? ' ' . $input['time'] : '';
+ //check if date is empty, if yes, then leave it blank.
+ $datetime = !empty($input['date']) ? trim($input['date']) : '';
+ $datetime .= $has_time ? ' ' . trim($input['time']) : '';
$date = new DateObject($datetime, $element['#date_timezone'], $format);
+ //if the variable is time only then set TimeOnly to TRUE
+ if(empty($input['date']) && !empty($input['time']) ){
+ $date->timeOnly = 'TRUE';
+ }
if (is_object($date)) {
$date->limitGranularity($granularity);
if ($date->validGranularity($granularity, $flexible)) {
@@ -552,7 +654,7 @@ function date_popup_time_formats($with_seconds = FALSE) {
return array(
'H:i:s',
'h:i:sA',
- );
+ );
}
/**
@@ -561,8 +663,17 @@ function date_popup_time_formats($with_seconds = FALSE) {
* TODO Remove any formats not supported by the widget, if any.
*/
function date_popup_formats() {
- $formats = str_replace('i', 'i:s', array_keys(system_get_date_formats('short')));
+ // Load short date formats.
+ $formats = system_get_date_formats('short');
+
+ // Load custom date formats.
+ if ($formats_custom = system_get_date_formats('custom')) {
+ $formats = array_merge($formats, $formats_custom);
+ }
+
+ $formats = str_replace('i', 'i:s', array_keys($formats));
$formats = drupal_map_assoc($formats);
+
return $formats;
}
@@ -570,7 +681,8 @@ function date_popup_formats() {
* Recreate a date format string so it has the values popup expects.
*
* @param string $format
- * a normal date format string, like Y-m-d
+ * A normal date format string, like Y-m-d
+ *
* @return string
* A format string in popup format, like YMD-, for the
* earlier 'calendar' version, or m/d/Y for the later 'datepicker'
@@ -588,15 +700,34 @@ function date_popup_format_to_popup($format) {
* Recreate a time format string so it has the values popup expects.
*
* @param string $format
- * a normal time format string, like h:i (a)
+ * A normal time format string, like h:i (a)
+ *
* @return string
- * a format string that the popup can accept like h:i a
+ * A format string that the popup can accept like h:i a
*/
function date_popup_format_to_popup_time($format, $timepicker = NULL) {
if (empty($format)) {
$format = 'H:i';
}
- $format = str_replace(array('/', '-', ' .', ',', 'F', 'M', 'l', 'z', 'w', 'W', 'd', 'j', 'm', 'n', 'y', 'Y'), '', $format);
+ $symbols = array(
+ '/',
+ '-',
+ ' .',
+ ',',
+ 'F',
+ 'M',
+ 'l',
+ 'z',
+ 'w',
+ 'W',
+ 'd',
+ 'j',
+ 'm',
+ 'n',
+ 'y',
+ 'Y',
+ );
+ $format = str_replace($symbols, '', $format);
$format = strtr($format, date_popup_timepicker_format_replacements($timepicker));
return $format;
}
@@ -605,9 +736,10 @@ function date_popup_format_to_popup_time($format, $timepicker = NULL) {
* Reconstruct popup format string into normal format string.
*
* @param string $format
- * a string in popup format, like YMD-
+ * A string in popup format, like YMD-
+ *
* @return string
- * a normal date format string, like Y-m-d
+ * A normal date format string, like Y-m-d
*/
function date_popup_popup_to_format($format) {
$replace = array_flip(date_popup_datepicker_format_replacements());
@@ -621,22 +753,21 @@ function date_popup_popup_to_format($format) {
* This function returns a map of format replacements required to change any
* input format into one that the given timepicker can support.
*
- * @param $timepicker
+ * @param string $timepicker
* The time entry plugin being used: either 'wvega' or 'default'.
- * @return
+ *
+ * @return array
* A map of replacements.
*/
function date_popup_timepicker_format_replacements($timepicker = 'default') {
switch ($timepicker) {
case 'wvega':
- return array(
- 'a' => 'A', // The wvega timepicker only supports uppercase AM/PM.
- );
+ // The wvega timepicker only supports uppercase AM/PM.
+ return array('a' => 'A');
+
default:
- return array(
- 'G' => 'H', // The default timeEntry plugin requires leading zeros.
- 'g' => 'h',
- );
+ // The default timeEntry plugin requires leading zeros.
+ return array('G' => 'H', 'g' => 'h');
}
}
@@ -645,16 +776,16 @@ function date_popup_timepicker_format_replacements($timepicker = 'default') {
*/
function date_popup_datepicker_format_replacements() {
return array(
- 'd' => 'dd',
- 'j' => 'd',
- 'l' => 'DD',
- 'D' => 'D',
- 'm' => 'mm',
- 'n' => 'm',
- 'F' => 'MM',
- 'M' => 'M',
- 'Y' => 'yy',
- 'y' => 'y',
+ 'd' => 'dd',
+ 'j' => 'd',
+ 'l' => 'DD',
+ 'D' => 'D',
+ 'm' => 'mm',
+ 'n' => 'm',
+ 'F' => 'MM',
+ 'M' => 'M',
+ 'Y' => 'yy',
+ 'y' => 'y',
);
}
@@ -667,16 +798,26 @@ function theme_date_popup($vars) {
$element = $vars['element'];
$attributes = !empty($element['#wrapper_attributes']) ? $element['#wrapper_attributes'] : array('class' => array());
$attributes['class'][] = 'container-inline-date';
- // If there is no description, the floating date elements need some extra padding below them.
+ // If there is no description, the floating date
+ // elements need some extra padding below them.
$wrapper_attributes = array('class' => array('date-padding'));
if (empty($element['date']['#description'])) {
$wrapper_attributes['class'][] = 'clearfix';
}
- // Add an wrapper to mimic the way a single value field works, for ease in using #states.
+ // Add an wrapper to mimic the way a single value field works,
+ // for ease in using #states.
if (isset($element['#children'])) {
- $element['#children'] = '
' . $element['#children'] . '
';
+ $element['#children'] = '
' . $element['#children'] . '
';
}
- return '
' . theme('form_element', $element) . '
';
+ return '
' . theme('form_element', $element) . '
';
+}
+
+/**
+ * Implements hook_date_field_instance_settings_form_alter().
+ */
+function date_popup_date_field_instance_settings_form_alter(&$form, $context) {
+ // Add an extra option to sync the end date with the start date.
+ $form['default_value2']['#options']['sync'] = t('Sync with start date');
}
/**
@@ -707,8 +848,8 @@ function date_popup_settings() {
'#type' => 'select',
'#options' => array(
'default' => t('Use default jQuery timepicker'),
- 'wvega' => t('Use dropdown timepicker'),
- 'none' => t('Manual time entry, no jQuery timepicker')
+ 'wvega' => t('Use dropdown timepicker'),
+ 'none' => t('Manual time entry, no jQuery timepicker'),
),
'#title' => t('Timepicker'),
'#default_value' => variable_get('date_popup_timepicker', $preferred_timepicker),
@@ -734,7 +875,7 @@ function date_popup_settings() {
}
EOM;
- $form['#suffix'] = t('
The Date Popup calendar includes some css for IE6 that breaks css validation. Since IE 6 is now superceded by IE 7, 8, and 9, the special css for IE 6 has been removed from the regular css used by the Date Popup. If you find you need that css after all, you can add it back in your theme. Look at the way the Garland theme adds special IE-only css in in its page.tpl.php file. The css you need is:
') .'
' . $css .'
';
+ $form['#suffix'] = t('
The Date Popup calendar includes some css for IE6 that breaks css validation. Since IE 6 is now superceded by IE 7, 8, and 9, the special css for IE 6 has been removed from the regular css used by the Date Popup. If you find you need that css after all, you can add it back in your theme. Look at the way the Garland theme adds special IE-only css in in its page.tpl.php file. The css you need is:
',
);
- $YEARLY_on_the_BYDAY_of_BYMONTH['BYMONTH'] = array(
+ $yearly_on_the_byday_of_bymonth['BYMONTH'] = array(
'#type' => 'checkboxes',
'#title' => t('Bymonth', array(), array('context' => 'Date repeat')),
'#title_display' => 'invisible',
- '#default_value' => !empty($rrule['BYMONTH']) && $rrule['FREQ'] === 'YEARLY' && $YEARLY_day_month_default === 'BYDAY_BYMONTH' ? $rrule['BYMONTH'] : array(),
+ '#default_value' => !empty($rrule['BYMONTH']) && $rrule['FREQ'] === 'YEARLY' && $yearly_day_month_default === 'BYDAY_BYMONTH' ? $rrule['BYMONTH'] : array(),
'#options' => date_month_names_abbr(TRUE),
'#attributes' => array('class' => array('container-inline')),
'#multiple' => TRUE,
@@ -465,13 +470,13 @@ function _date_repeat_rrule_process($element, &$form_state, $form) {
),
),
'#attributes' => array('class' => array('date-repeat-radios clearfix')),
- '#default_value' => $YEARLY_day_month_default,
+ '#default_value' => $yearly_day_month_default,
'#options' => array(
'BYMONTHDAY_BYMONTH' => t('On day ... of ...'),
'BYDAY_BYMONTH' => t('On the ... of ...'),
),
- 'BYMONTHDAY_BYMONTH_child' => $YEARLY_on_day_BYMONTHDAY_of_BYMONTH,
- 'BYDAY_BYMONTH_child' => $YEARLY_on_the_BYDAY_of_BYMONTH,
+ 'BYMONTHDAY_BYMONTH_child' => $yearly_on_day_bymonthday_of_bymonth,
+ 'BYDAY_BYMONTH_child' => $yearly_on_the_byday_of_bymonth,
'#div_classes' => array(
'date-repeat-radios-item date-clear clearfix bymonthday-bymonth',
'date-repeat-radios-item date-clear clearfix byday-bymonth',
@@ -482,7 +487,7 @@ function _date_repeat_rrule_process($element, &$form_state, $form) {
$count_form_element = array(
'#type' => 'textfield',
'#title' => t('Count', array(), array('context' => 'Date repeat')),
- '#default_value' => $COUNT,
+ '#default_value' => $count,
'#element_validate' => array('element_validate_integer_positive'),
'#attributes' => array('placeholder' => array('#')),
'#prefix' => $prefix,
@@ -499,21 +504,26 @@ function _date_repeat_rrule_process($element, &$form_state, $form) {
'#type' => $element['#date_repeat_widget'],
'#title' => t('Until', array(), array('context' => 'Date repeat')),
'#title_display' => 'invisible',
- '#default_value' => $UNTIL,
- '#date_format' => !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
+ '#default_value' => $until,
+ '#date_format' => !empty($element['#date_format']) ?
+ date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
'#date_timezone' => $timezone,
'#date_text_parts' => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
'#date_year_range' => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
- '#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
+ '#date_label_position' => !empty($element['#date_label_position']) ?
+ $element['#date_label_position'] : 'within',
'#date_flexible' => 0,
),
'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
'all_day' => array('#type' => 'hidden', '#value' => 1),
- 'granularity' => array('#type' => 'hidden', '#value' => serialize(array('year', 'month', 'day'))),
+ 'granularity' => array(
+ '#type' => 'hidden',
+ '#value' => serialize(array('year', 'month', 'day')),
+ ),
);
$range_of_repeat_default = 'COUNT';
- if (!empty($UNTIL)) {
+ if (!empty($until)) {
$range_of_repeat_default = 'UNTIL';
}
$element['range_of_repeat'] = array(
@@ -528,7 +538,7 @@ function _date_repeat_rrule_process($element, &$form_state, $form) {
":input[name=\"{$element['#name']}[FREQ]\"]" => array('value' => 'NONE'),
),
),
- '#default_value' => $range_of_repeat_default,
+ '#default_value' => $range_of_repeat_default,
'#options' => array(
'COUNT' => t('Count'),
'UNTIL' => t('Until'),
@@ -544,7 +554,8 @@ function _date_repeat_rrule_process($element, &$form_state, $form) {
$parents = $element['#array_parents'];
$instance = implode('-', $parents);
- // Make sure this will work right either in the normal form or in an ajax callback from the 'Add more' button.
+ // Make sure this will work right either in the normal
+ // form or in an ajax callback from the 'Add more' button.
if (empty($form_state['num_exceptions'][$instance])) {
$form_state['num_exceptions'][$instance] = count($exceptions);
}
@@ -576,33 +587,48 @@ function _date_repeat_rrule_process($element, &$form_state, $form) {
),
),
);
- for ($i = 0; $i < max($form_state['num_exceptions'][$instance], 1) ; $i++) {
- $EXCEPT = '';
+ for ($i = 0; $i < max($form_state['num_exceptions'][$instance], 1); $i++) {
+ $except = '';
if (!empty($exceptions[$i]['datetime'])) {
$ex_date = new DateObject($exceptions[$i]['datetime'], $exceptions[$i]['tz']);
date_timezone_set($ex_date, timezone_open($timezone));
- $EXCEPT = date_format($ex_date, DATE_FORMAT_DATETIME);
+ $except = date_format($ex_date, DATE_FORMAT_DATETIME);
+ }
+ $date_format = 'Y-m-d';
+ if (!empty($element['#date_format'])) {
+ $grans = array('year', 'month', 'day');
+ $date_format = date_limit_format($element['#date_format'], $grans);
}
$element['exceptions']['EXDATE'][$i] = array(
'#tree' => TRUE,
'datetime' => array(
'#name' => 'exceptions|' . $instance,
'#type' => $element['#date_repeat_widget'],
- '#default_value' => $EXCEPT,
- '#date_timezone' => !empty($element['#date_timezone']) ? $element['#date_timezone'] : date_default_timezone(),
- '#date_format' => !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
+ '#default_value' => $except,
+ '#date_timezone' => !empty($element['#date_timezone']) ?
+ $element['#date_timezone'] : date_default_timezone(),
+ '#date_format' => $date_format,
'#date_text_parts' => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
'#date_year_range' => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
'#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
'#date_flexible' => 0,
- ),
- 'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
- 'all_day' => array('#type' => 'hidden', '#value' => 1),
- 'granularity' => array('#type' => 'hidden', '#value' => serialize(array('year', 'month', 'day'))),
- );
+ ),
+ 'tz' => array(
+ '#type' => 'hidden',
+ '#value' => $element['#date_timezone'],
+ ),
+ 'all_day' => array(
+ '#type' => 'hidden',
+ '#value' => 1,
+ ),
+ 'granularity' => array(
+ '#type' => 'hidden',
+ '#value' => serialize(array('year', 'month', 'day')),
+ ),
+ );
}
- // collect additions in the same way as exceptions - implements RDATE.
+ // Collect additions in the same way as exceptions - implements RDATE.
if (empty($form_state['num_additions'][$instance])) {
$form_state['num_additions'][$instance] = count($additions);
}
@@ -634,30 +660,45 @@ function _date_repeat_rrule_process($element, &$form_state, $form) {
),
),
);
- for ($i = 0; $i < max($form_state['num_additions'][$instance], 1) ; $i++) {
- $RDATE = '';
+ for ($i = 0; $i < max($form_state['num_additions'][$instance], 1); $i++) {
+ $r_date = '';
if (!empty($additions[$i]['datetime'])) {
$rdate = new DateObject($additions[$i]['datetime'], $additions[$i]['tz']);
date_timezone_set($rdate, timezone_open($timezone));
- $RDATE = date_format($rdate, DATE_FORMAT_DATETIME);
+ $r_date = date_format($rdate, DATE_FORMAT_DATETIME);
+ }
+ $date_format = 'Y-m-d';
+ if (!empty($element['#date_format'])) {
+ $grans = array('year', 'month', 'day');
+ $date_format = date_limit_format($element['#date_format'], $grans);
}
$element['additions']['RDATE'][$i] = array(
'#tree' => TRUE,
'datetime' => array(
'#type' => $element['#date_repeat_widget'],
'#name' => 'additions|' . $instance,
- '#default_value' => $RDATE,
- '#date_timezone' => !empty($element['#date_timezone']) ? $element['#date_timezone'] : date_default_timezone(),
- '#date_format' => !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
+ '#default_value' => $r_date,
+ '#date_timezone' => !empty($element['#date_timezone']) ?
+ $element['#date_timezone'] : date_default_timezone(),
+ '#date_format' => $date_format,
'#date_text_parts' => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
'#date_year_range' => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
'#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
'#date_flexible' => 0,
- ),
- 'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
- 'all_day' => array('#type' => 'hidden', '#value' => 1),
- 'granularity' => array('#type' => 'hidden', '#value' => serialize(array('year', 'month', 'day'))),
- );
+ ),
+ 'tz' => array(
+ '#type' => 'hidden',
+ '#value' => $element['#date_timezone'],
+ ),
+ 'all_day' => array(
+ '#type' => 'hidden',
+ '#value' => 1,
+ ),
+ 'granularity' => array(
+ '#type' => 'hidden',
+ '#value' => serialize(array('year', 'month', 'day')),
+ ),
+ );
}
$element['exceptions']['exceptions_add'] = array(
@@ -687,6 +728,9 @@ function _date_repeat_rrule_process($element, &$form_state, $form) {
return $element;
}
+/**
+ * Add callback to date repeat.
+ */
function date_repeat_add_exception_callback($form, &$form_state) {
$parents = $form_state['triggering_element']['#array_parents'];
$button_key = array_pop($parents);
@@ -694,6 +738,9 @@ function date_repeat_add_exception_callback($form, &$form_state) {
return $element;
}
+/**
+ * Add addition callback to date repeat.
+ */
function date_repeat_add_addition_callback($form, &$form_state) {
$parents = $form_state['triggering_element']['#array_parents'];
$button_key = array_pop($parents);
@@ -701,6 +748,9 @@ function date_repeat_add_addition_callback($form, &$form_state) {
return $element;
}
+/**
+ * Add exception to date repeat.
+ */
function date_repeat_add_exception($form, &$form_state) {
$parents = $form_state['triggering_element']['#array_parents'];
$instance = implode('-', array_slice($parents, 0, count($parents) - 2));
@@ -708,6 +758,9 @@ function date_repeat_add_exception($form, &$form_state) {
$form_state['rebuild'] = TRUE;
}
+/**
+ * Add addition to date repeat.
+ */
function date_repeat_add_addition($form, &$form_state) {
$parents = $form_state['triggering_element']['#array_parents'];
$instance = implode('-', array_slice($parents, 0, count($parents) - 2));
@@ -723,8 +776,14 @@ function date_repeat_merge($form_values, $element) {
return $form_values;
}
if (array_key_exists('exceptions', $form_values) || array_key_exists('additions', $form_values)) {
- if (!array_key_exists('exceptions', $form_values)) $form_values['exceptions'] = array();
- if (!array_key_exists('additions', $form_values)) $form_values['additions'] = array();
+ if (!array_key_exists('exceptions', $form_values)) {
+ $form_values['exceptions'] = array();
+ }
+
+ if (!array_key_exists('additions', $form_values)) {
+ $form_values['additions'] = array();
+ }
+
$form_values = array_merge($form_values, (array) $form_values['exceptions'], (array) $form_values['additions']);
unset($form_values['exceptions']);
unset($form_values['additions']);
@@ -738,18 +797,22 @@ function date_repeat_merge($form_values, $element) {
case 'INTERVAL':
$form_values['INTERVAL'] = $form_values['daily']['INTERVAL_child'];
break;
+
case 'every_weekday':
$form_values['BYDAY'] = array('MO', 'TU', 'WE', 'TH', 'FR');
break;
+
case 'every_mo_we_fr':
$form_values['BYDAY'] = array('MO', 'WE', 'FR');
break;
+
case 'every_tu_th':
$form_values['BYDAY'] = array('TU', 'TH');
break;
}
}
break;
+
case 'WEEKLY':
if (array_key_exists('weekly', $form_values)) {
$form_values = array_merge($form_values, (array) $form_values['weekly']);
@@ -758,12 +821,14 @@ function date_repeat_merge($form_values, $element) {
}
}
break;
+
case 'MONTHLY':
if (array_key_exists('monthly', $form_values)) {
switch ($form_values['monthly']['day_month']) {
case 'BYMONTHDAY_BYMONTH':
$form_values['monthly'] = array_merge($form_values['monthly'], (array) $form_values['monthly']['BYMONTHDAY_BYMONTH_child']);
break;
+
case 'BYDAY_BYMONTH':
$form_values['monthly']['BYDAY_BYMONTH_child']['BYDAY'] = $form_values['monthly']['BYDAY_BYMONTH_child']['BYDAY_COUNT'] . $form_values['monthly']['BYDAY_BYMONTH_child']['BYDAY_DAY'];
$form_values['monthly'] = array_merge($form_values['monthly'], (array) $form_values['monthly']['BYDAY_BYMONTH_child']);
@@ -783,12 +848,14 @@ function date_repeat_merge($form_values, $element) {
}
}
break;
+
case 'YEARLY':
if (array_key_exists('yearly', $form_values)) {
switch ($form_values['yearly']['day_month']) {
case 'BYMONTHDAY_BYMONTH':
$form_values['yearly'] = array_merge($form_values['yearly'], (array) $form_values['yearly']['BYMONTHDAY_BYMONTH_child']);
break;
+
case 'BYDAY_BYMONTH':
$form_values['yearly']['BYDAY_BYMONTH_child']['BYDAY'] = $form_values['yearly']['BYDAY_BYMONTH_child']['BYDAY_COUNT'] . $form_values['yearly']['BYDAY_BYMONTH_child']['BYDAY_DAY'];
$form_values['yearly'] = array_merge($form_values['yearly'], (array) $form_values['yearly']['BYDAY_BYMONTH_child']);
@@ -808,6 +875,7 @@ function date_repeat_merge($form_values, $element) {
}
}
break;
+
default:
break;
}
@@ -823,6 +891,7 @@ function date_repeat_merge($form_values, $element) {
case 'COUNT':
$form_values['COUNT'] = $form_values['count_child'];
break;
+
case 'UNTIL':
$form_values['UNTIL'] = $form_values['until_child'];
break;
@@ -832,14 +901,23 @@ function date_repeat_merge($form_values, $element) {
unset($form_values['count_child']);
unset($form_values['until_child']);
- if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY'])) unset($form_values['BYDAY']['']);
- if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH'])) unset($form_values['BYMONTH']['']);
- if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY'])) unset($form_values['BYMONTHDAY']['']);
+ if (array_key_exists('BYDAY', $form_values) && is_array($form_values['BYDAY'])) {
+ unset($form_values['BYDAY']['']);
+ }
+
+ if (array_key_exists('BYMONTH', $form_values) && is_array($form_values['BYMONTH'])) {
+ unset($form_values['BYMONTH']['']);
+ }
+
+ if (array_key_exists('BYMONTHDAY', $form_values) && is_array($form_values['BYMONTHDAY'])) {
+ unset($form_values['BYMONTHDAY']['']);
+ }
if (array_key_exists('UNTIL', $form_values) && is_array($form_values['UNTIL']['datetime'])) {
$function = $element['#date_repeat_widget'] . '_input_date';
$until_element = $element;
- $until_element['#date_format'] = !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d';
+ $until_element['#date_format'] = !empty($element['#date_format']) ?
+ date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d';
$date = $function($until_element, $form_values['UNTIL']['datetime']);
$form_values['UNTIL']['datetime'] = is_object($date) ? $date->format(DATE_FORMAT_DATETIME) : '';
}
@@ -849,9 +927,14 @@ function date_repeat_merge($form_values, $element) {
if (array_key_exists('EXDATE', $form_values) && is_array($form_values['EXDATE'])) {
$function = $element['#date_repeat_widget'] . '_input_date';
$exdate_element = $element;
+ $date_format = 'Y-m-d';
+ if (!empty($element['#date_format'])) {
+ $grans = array('year', 'month', 'day');
+ $date_format = date_limit_format($element['#date_format'], $grans);
+ }
foreach ($form_values['EXDATE'] as $delta => $value) {
if (is_array($value['datetime'])) {
- $exdate_element['#date_format'] = !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d';
+ $exdate_element['#date_format'] = $date_format;
$date = $function($exdate_element, $form_values['EXDATE'][$delta]['datetime']);
$form_values['EXDATE'][$delta]['datetime'] = is_object($date) ? $date->format(DATE_FORMAT_DATETIME) : '';
}
@@ -864,9 +947,14 @@ function date_repeat_merge($form_values, $element) {
if (array_key_exists('RDATE', $form_values) && is_array($form_values['RDATE'])) {
$function = $element['#date_repeat_widget'] . '_input_date';
$rdate_element = $element;
+ $date_format = 'Y-m-d';
+ if (!empty($element['#date_format'])) {
+ $grans = array('year', 'month', 'day');
+ $date_format = date_limit_format($element['#date_format'], $grans);
+ }
foreach ($form_values['RDATE'] as $delta => $value) {
if (is_array($value['datetime'])) {
- $rdate_element['#date_format'] = !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d';
+ $rdate_element['#date_format'] = $date_format;
$date = $function($rdate_element, $form_values['RDATE'][$delta]['datetime']);
$form_values['RDATE'][$delta]['datetime'] = is_object($date) ? $date->format(DATE_FORMAT_DATETIME) : '';
}
@@ -910,7 +998,7 @@ function date_repeat_rrule_validate($element, &$form_state) {
}
/**
- * Theme the exception list as a table so the buttons line up
+ * Theme the exception list as a table so the buttons line up.
*/
function theme_date_repeat_current_exceptions($vars) {
$rows = $vars['rows'];
@@ -920,11 +1008,14 @@ function theme_date_repeat_current_exceptions($vars) {
$rows_info[] = array(drupal_render($value['action']), drupal_render($value['display']));
}
}
- return theme('table', array('header' => array(t('Delete'), t('Current exceptions')), 'rows' => $rows_info));
+ return theme('table', array(
+ 'header' => array(t('Delete'), t('Current exceptions')),
+ 'rows' => $rows_info)
+ );
}
- /**
- * Theme the exception list as a table so the buttons line up
+/**
+ * Theme the exception list as a table so the buttons line up.
*/
function theme_date_repeat_current_additions($rows = array()) {
$rows_info = array();
@@ -933,7 +1024,10 @@ function theme_date_repeat_current_additions($rows = array()) {
$rows_info[] = array(drupal_render($value['action']), drupal_render($value['display']));
}
}
- return theme('table', array('header' => array(t('Delete'), t('Current additions')), 'rows' => $rows_info));
+ return theme('table', array(
+ 'header' => array(t('Delete'), t('Current additions')),
+ 'rows' => $rows_info)
+ );
}
/**
@@ -943,7 +1037,13 @@ function theme_date_repeat_rrule($vars) {
$element = $vars['element'];
$id = drupal_html_id('repeat-settings-fieldset');
$parents = $element['#parents'];
- $selector = "{$parents[0]}[{$parents[1]}][{$parents[2]}][show_repeat_settings]";
+
+ $selector = $parents[0];
+ for ($i = 1; $i < count($parents) - 1; $i++) {
+ $selector .= '[' . $parents[$i] . ']';
+ }
+ $selector .= '[show_repeat_settings]';
+
$fieldset = array(
'#type' => 'item',
'#title' => t('Repeat settings'),
@@ -960,6 +1060,9 @@ function theme_date_repeat_rrule($vars) {
return drupal_render($fieldset);
}
+/**
+ * Filter non zero values.
+ */
function date_repeat_filter_non_zero_value($value) {
return $value !== 0;
}
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_repeat/tests/date_repeat_form.test b/profiles/commerce_kickstart/modules/contrib/date/date_repeat/tests/date_repeat_form.test
index 0c5460ba..22d65296 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_repeat/tests/date_repeat_form.test
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_repeat/tests/date_repeat_form.test
@@ -25,7 +25,7 @@ class DateRepeatFormTestCase extends DrupalWebTestCase {
// Create and log in our privileged user.
$this->privileged_user = $this->drupalCreateUser(array(
- 'administer content types', 'administer nodes', 'bypass node access', 'view date repeats'
+ 'administer content types', 'administer nodes', 'bypass node access', 'view date repeats', 'administer fields'
));
$this->drupalLogin($this->privileged_user);
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_repeat_field/date_repeat_field.devel_generate.inc b/profiles/commerce_kickstart/modules/contrib/date/date_repeat_field/date_repeat_field.devel_generate.inc
index 3880e8b4..51c3708b 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_repeat_field/date_repeat_field.devel_generate.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_repeat_field/date_repeat_field.devel_generate.inc
@@ -1,5 +1,5 @@
'Repeats',
- 'page callback' => 'date_repeat_field_page',
- 'page arguments' => array($entity_type, $count),
- 'access callback' => 'date_repeat_field_show',
- 'access arguments' => array($entity_type, $count),
- 'type' => MENU_LOCAL_TASK,
- 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+ 'title' => 'Repeats',
+ 'page callback' => 'date_repeat_field_page',
+ 'page arguments' => array($entity_type, $count),
+ 'access callback' => 'date_repeat_field_show',
+ 'access arguments' => array($entity_type, $count),
+ 'type' => MENU_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
);
}
}
@@ -91,13 +91,13 @@ function date_repeat_field_menu() {
else {
$path = $entity_type . '/%' . $entity_type;
$items[$path . '/repeats'] = array(
- 'title' => 'Repeats',
- 'page callback' => 'date_repeat_field_page',
- 'page arguments' => array($entity_type, 1),
- 'access callback' => 'date_repeat_field_show',
- 'access arguments' => array($entity_type, 1),
- 'type' => MENU_LOCAL_TASK,
- 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+ 'title' => 'Repeats',
+ 'page callback' => 'date_repeat_field_page',
+ 'page arguments' => array($entity_type, 1),
+ 'access callback' => 'date_repeat_field_show',
+ 'access arguments' => array($entity_type, 1),
+ 'type' => MENU_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
);
}
}
@@ -108,10 +108,12 @@ function date_repeat_field_menu() {
* Implements hook_permission().
*/
function date_repeat_field_permission() {
- return array('view date repeats' => array(
- 'title' => t('View Repeating Dates'),
- 'description' => t('Allow user to see a page with all the times a date repeats.'),
- ));
+ return array(
+ 'view date repeats' => array(
+ 'title' => t('View Repeating Dates'),
+ 'description' => t('Allow user to see a page with all the times a date repeats.'),
+ ),
+ );
}
/**
@@ -195,6 +197,9 @@ function date_repeat_field_bundles() {
return $values;
}
+/**
+ * Check field is repeat.
+ */
function date_is_repeat_field($field, $instance = NULL) {
if (is_string($field)) {
$field = field_info_field($field);
@@ -215,7 +220,7 @@ function date_is_repeat_field($field, $instance = NULL) {
}
}
-/*
+/**
* Implements hook_date_field_insert_alter().
*/
function date_repeat_field_date_field_insert_alter(&$items, $context) {
@@ -239,7 +244,7 @@ function date_repeat_field_date_field_insert_alter(&$items, $context) {
}
}
-/*
+/**
* Implements hook_date_field_update_alter().
*/
function date_repeat_field_date_field_update_alter(&$items, $context) {
@@ -279,6 +284,13 @@ function date_repeat_field_field_widget_form_alter(&$element, &$form_state, $con
'#suffix' => '',
'#default_value' => isset($items[$delta]['rrule']) && !empty($items[$delta]['rrule']) ? 1 : 0,
);
+
+ // Make changes if instance is set to be rendered as a regular field.
+ if (!empty($instance['widget']['settings']['no_fieldset'])) {
+ $element['#title'] = check_plain($instance['label']);
+ $element['#description'] = field_filter_xss($instance['description']);
+ $element['#theme_wrappers'] = array('date_form_element');
+ }
}
}
}
@@ -340,13 +352,14 @@ function date_repeat_field_widget_validate($element, &$form_state) {
// The RRULE has already been created by this point, so go back
// to the posted values to see if this was filled out.
$error_field_base = implode('][', $element['#parents']);
- $error_field_until = $error_field_base . '][rrule][until_child][datetime][';
+ $error_field_until = $error_field_base . '][rrule][until_child][datetime][';
if (!empty($item['rrule']) && $rrule_values['range_of_repeat'] === 'UNTIL' && empty($rrule_values['UNTIL']['datetime'])) {
switch ($instance['widget']['type']) {
case 'date_text':
case 'date_popup':
form_set_error($error_field_until . 'date', t("Missing value in 'Range of repeat'. (UNTIL).", array(), array('context' => 'Date repeat')));
break;
+
case 'date_select':
form_set_error($error_field_until . 'year', t("Missing value in 'Range of repeat': Year (UNTIL)", array(), array('context' => 'Date repeat')));
form_set_error($error_field_until . 'month', t("Missing value in 'Range of repeat': Month (UNTIL)", array(), array('context' => 'Date repeat')));
@@ -382,8 +395,9 @@ function date_repeat_field_widget_validate($element, &$form_state) {
// We only collect a date for UNTIL, but we need it to be inclusive,
// so force it to a full datetime element at the last possible second of the day.
if (!empty($rrule_values['UNTIL'])) {
+ $gran = array('year', 'month', 'day', 'hour', 'minute', 'second');
$rrule_values['UNTIL']['datetime'] .= ' 23:59:59';
- $rrule_values['UNTIL']['granularity'] = serialize(drupal_map_assoc(array('year', 'month', 'day', 'hour', 'minute', 'second')));
+ $rrule_values['UNTIL']['granularity'] = serialize(drupal_map_assoc($gran));
$rrule_values['UNTIL']['all_day'] = 0;
}
$value = date_repeat_build_dates($rrule, $rrule_values, $field, $item);
@@ -418,9 +432,10 @@ function date_repeat_after_build(&$element, &$form_state) {
* Pass in either the RRULE or the $form_values array for the RRULE,
* whichever is missing will be created when needed.
*/
+// @codingStandardsIgnoreStart
function date_repeat_build_dates($rrule = NULL, $rrule_values = NULL, $field, $item) {
-
- include_once(DRUPAL_ROOT . '/' . drupal_get_path('module', 'date_api') . '/date_api_ical.inc');
+// @codingStandardsIgnoreEnd
+ include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'date_api') . '/date_api_ical.inc';
$field_name = $field['field_name'];
if (empty($rrule)) {
@@ -497,8 +512,9 @@ function date_repeat_build_dates($rrule = NULL, $rrule_values = NULL, $field, $i
'offset2' => date_offset_get($date_end),
'timezone' => $timezone,
'rrule' => $rrule,
- );
+ );
}
+
return $value;
}
@@ -681,9 +697,8 @@ function date_repeat_field_date_field_widget_settings_form_alter(&$form, $contex
'#title' => t('Repeat display', array(), array('context' => 'Date repeat')),
'#description' => t("Should the repeat options form start out expanded or collapsed? Set to 'Collapsed' to make those options less obtrusive.", array(), array('context' => 'Date repeat')),
'#fieldset' => 'date_format',
- );
+ );
}
-
}
/**
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_tools/date_tools.change_type.inc b/profiles/commerce_kickstart/modules/contrib/date/date_tools/date_tools.change_type.inc
index cad2cafd..041c5dea 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_tools/date_tools.change_type.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_tools/date_tools.change_type.inc
@@ -28,10 +28,14 @@ function date_tools_change_type_form() {
// Get the available date fields.
foreach ($fields as $field_name => $field) {
if ($field['type'] == 'date' || $field['type'] == 'datestamp' || $field['type'] == 'datetime') {
- $date_options[$labels[$field['type']]][$field_name] = t('Field @label (@field_name)', array('@label' => $field['widget']['label'], '@field_name' => $field_name, '@type' => $labels[$field['type']]));
+ $date_options[$labels[$field['type']]][$field_name] = t('Field @label (@field_name)', array(
+ '@label' => $field['widget']['label'],
+ '@field_name' => $field_name,
+ '@type' => $labels[$field['type']]
+ ));
}
}
- if (sizeof($date_options) < 1) {
+ if (count($date_options) < 1) {
drupal_set_message(t('There are no date fields in this database.'));
return $form;
}
@@ -142,26 +146,31 @@ function date_tools_change_type_form_submit($form, &$form_state) {
case 'datestamp':
$new_columns[] = $date_handler->sql_format('U', $db_field) . ' AS ' . $info['column'];
break;
+
case 'datetime':
$new_columns[] = $date_handler->sql_format('Y-m-d H:i:s', $db_field) . ' AS ' . $info['column'];
break;
}
break;
+
case 'datestamp':
switch ($new_type) {
case 'date':
$new_columns[] = $date_handler->sql_format('Y-m-d/TH:i:s', $db_field) . ' AS ' . $info['column'];
break;
+
case 'datetime':
$new_columns[] = $date_handler->sql_format('Y-m-d H:i:s', $db_field) . ' AS ' . $info['column'];
break;
}
break;
+
case 'datetime':
switch ($new_type) {
case 'date':
$new_columns[] = $date_handler->sql_format('Y-m-d/TH:i:s', $db_field) . ' AS ' . $info['column'];
break;
+
case 'datestamp':
$new_columns[] = $date_handler->sql_format('U', $db_field) . ' AS ' . $info['column'];
break;
@@ -178,5 +187,9 @@ function date_tools_change_type_form_submit($form, &$form_state) {
db_query($sql);
db_query("DROP TABLE {" . $temp_table . "}");
- drupal_set_message(t('The field @field_name has been changed from @old_type to @new_type.', array('@field_name' => $field['widget']['label'], '@old_type' => $labels[$old_type], '@new_type' => $labels[$new_type])));
+ drupal_set_message(t('The field @field_name has been changed from @old_type to @new_type.', array(
+ '@field_name' => $field['widget']['label'],
+ '@old_type' => $labels[$old_type],
+ '@new_type' => $labels[$new_type]
+ )));
}
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_tools/date_tools.info b/profiles/commerce_kickstart/modules/contrib/date/date_tools/date_tools.info
index dbcff7d9..04bfb03f 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_tools/date_tools.info
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_tools/date_tools.info
@@ -6,9 +6,9 @@ core = 7.x
configure = admin/config/date/tools
files[] = tests/date_tools.test
-; Information added by Drupal.org packaging script on 2014-07-29
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
core = "7.x"
project = "date"
-datestamp = "1406653438"
+datestamp = "1491562090"
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_tools/date_tools.module b/profiles/commerce_kickstart/modules/contrib/date/date_tools/date_tools.module
index a7ac5f1e..997808df 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_tools/date_tools.module
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_tools/date_tools.module
@@ -31,7 +31,7 @@ function date_tools_help($section, $arg) {
*/
function date_tools_permission() {
return array(
- 'administer date tools' => array(
+ 'administer date tools' => array(
'title' => t('Administer date tools'),
),
);
@@ -68,6 +68,7 @@ function date_tools_menu() {
'file' => 'date_tools.wizard.inc',
);
+ // @codingStandardsIgnoreStart
/**
$items['admin/config/date/tools/change'] = array(
'title' => 'Change type',
@@ -79,18 +80,18 @@ function date_tools_menu() {
'file' => 'date_tools.change_type.inc',
);
*/
+ // @codingStandardsIgnoreEnd
return $items;
}
/**
- * Main Date Tools page
+ * Main Date Tools page.
*/
function date_tools_page() {
$content = '';
- $content .= t('Dates and calendars can be complicated to set up. The !date_wizard makes it easy to create a simple date content type and related calendar. ', array('!date_wizard' => l(t('Date wizard'), 'admin/config/date/tools/date_wizard')));
-
+ $content .= t('Dates and calendars can be complicated to set up. The !date_wizard makes it easy to create a simple date content type and related calendar.', array('!date_wizard' => l(t('Date wizard'), 'admin/config/date/tools/date_wizard')));
return $content;
}
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_tools/date_tools.wizard.inc b/profiles/commerce_kickstart/modules/contrib/date/date_tools/date_tools.wizard.inc
index 14bc2759..94a130a4 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_tools/date_tools.wizard.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_tools/date_tools.wizard.inc
@@ -6,6 +6,8 @@
*/
/**
+ * Implements hook_form().
+ *
* @todo.
*/
function date_tools_wizard_form() {
@@ -59,7 +61,10 @@ function date_tools_wizard_form() {
$form['field']['repeat'] = array(
'#type' => 'select',
'#default_value' => 0,
- '#options' => array(0 => t('No'), 1 => t('Yes')),
+ '#options' => array(
+ 0 => t('No'),
+ 1 => t('Yes'),
+ ),
'#title' => t('Show repeating date options'),
'#access' => module_exists('date_repeat_field'),
);
@@ -72,7 +77,11 @@ function date_tools_wizard_form() {
$form['field']['advanced']['todate'] = array(
'#type' => 'select',
'#default_value' => 'optional',
- '#options' => array('' => t('Never'), 'optional' => t('Optional'), 'required' => t('Required')),
+ '#options' => array(
+ '' => t('Never'),
+ 'optional' => t('Optional'),
+ 'required' => t('Required'),
+ ),
'#title' => t('End Date'),
'#description' => t("Display a matching second date field as a 'End date'."),
);
@@ -106,7 +115,10 @@ function date_tools_wizard_form() {
$form['calendar'] = array(
'#type' => 'select',
'#default_value' => module_exists('calendar'),
- '#options' => array(0 => t('No'), 1 => t('Yes')),
+ '#options' => array(
+ 0 => t('No'),
+ 1 => t('Yes'),
+ ),
'#title' => t('Create a calendar for this date field'),
'#access' => module_exists('calendar'),
);
@@ -119,13 +131,26 @@ function date_tools_wizard_form() {
}
/**
+ * Form validate.
+ *
* @todo.
*/
function date_tools_wizard_form_validate(&$form, &$form_state) {
$bundle = $form_state['values']['bundle'];
$field_name = 'field_' . $form_state['values']['field_name'];
- $existing_type = db_query("SELECT type FROM {node_type} WHERE type=:bundle", array(':bundle' => $bundle))->fetchField();
- $existing_instance = db_query("SELECT field_name FROM {field_config_instance} WHERE field_name=:field_name AND bundle=:bundle AND entity_type=:entity_type", array(':field_name' => $field_name, ':bundle' => $bundle, ':entity_type' => 'node'))->fetchField();
+
+ $args = array(
+ ':field_name' => $field_name,
+ ':bundle' => $bundle,
+ ':entity_type' => 'node',
+ );
+
+ $query = "SELECT type FROM {node_type} WHERE type=:bundle";
+ $existing_type = db_query($query, array(':bundle' => $args[':bundle']))->fetchField();
+
+ $query = "SELECT field_name FROM {field_config_instance} WHERE field_name=:field_name AND bundle=:bundle AND entity_type=:entity_type";
+ $existing_instance = db_query($query, $args)->fetchField();
+
if ($existing_type) {
drupal_set_message(t('This content type name already exists, adding new field to existing content type.'));
}
@@ -147,6 +172,8 @@ function date_tools_wizard_form_validate(&$form, &$form_state) {
}
/**
+ * Form submit.
+ *
* @todo.
*/
function date_tools_wizard_form_submit(&$form, &$form_state) {
@@ -161,6 +188,8 @@ function date_tools_wizard_form_submit(&$form, &$form_state) {
}
/**
+ * Wizard build.
+ *
* @todo.
*/
function date_tools_wizard_build($form_values) {
@@ -201,7 +230,7 @@ function date_tools_wizard_build($form_values) {
'timezone_db' => date_get_timezone_db($tz_handling),
'repeat' => $repeat,
'todate' => !empty($todate) ? $todate : 'optional',
- ),
+ ),
);
$instance = array(
'entity_type' => 'node',
@@ -275,6 +304,8 @@ function date_tools_wizard_build($form_values) {
}
/**
+ * Includes handler.
+ *
* @todo.
*/
function date_tools_wizard_include() {
@@ -285,6 +316,8 @@ function date_tools_wizard_include() {
}
/**
+ * Implements hook_field_types().
+ *
* @todo.
*/
function date_tools_wizard_field_types() {
@@ -296,6 +329,7 @@ function date_tools_wizard_field_types() {
}
/**
+ * Implements hook_widget_types().
* @todo.
*/
function date_tools_wizard_widget_types() {
@@ -309,6 +343,8 @@ function date_tools_wizard_widget_types() {
}
/**
+ * Tz handler.
+ *
* @todo.
*/
function date_tools_wizard_tz_handling() {
@@ -317,6 +353,8 @@ function date_tools_wizard_tz_handling() {
}
/**
+ * Create date tools wizard content type.
+ *
* @todo.
*/
function date_tools_wizard_create_content_type($name, $bundle, $description, $type_settings = array()) {
@@ -332,8 +370,7 @@ function date_tools_wizard_create_content_type($name, $bundle, $description, $ty
'body_label' => 'Body',
'min_word_count' => '0',
'help' => '',
- 'node_options' =>
- array(
+ 'node_options' => array(
'status' => 1,
'promote' => 1,
'sticky' => 0,
@@ -374,8 +411,10 @@ function date_tools_wizard_create_content_type($name, $bundle, $description, $ty
'weight' => -4,
'module' => 'text',
),
- 'settings' => array('display_summary' => TRUE),
- 'display' => array(
+ 'settings' => array(
+ 'display_summary' => TRUE,
+ ),
+ 'display' => array(
'default' => array(
'label' => 'hidden',
'type' => 'text_default',
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_tools/tests/date_tools.test b/profiles/commerce_kickstart/modules/contrib/date/date_tools/tests/date_tools.test
index 47c05642..07af4a3d 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_tools/tests/date_tools.test
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_tools/tests/date_tools.test
@@ -28,7 +28,7 @@ class DateToolsTestCase extends DrupalWebTestCase {
// Create and log in our privileged user.
$this->privileged_user = $this->drupalCreateUser(
- array('administer content types', 'administer nodes', 'bypass node access', 'administer date tools')
+ array('administer content types', 'administer nodes', 'bypass node access', 'administer date tools', 'administer fields')
);
$this->drupalLogin($this->privileged_user);
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_views/date_views.info b/profiles/commerce_kickstart/modules/contrib/date/date_views/date_views.info
index 0f2d7ec3..68b32cc2 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_views/date_views.info
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_views/date_views.info
@@ -12,9 +12,9 @@ files[] = includes/date_views_filter_handler_simple.inc
files[] = includes/date_views.views.inc
files[] = includes/date_views_plugin_pager.inc
-; Information added by Drupal.org packaging script on 2014-07-29
-version = "7.x-2.8"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
core = "7.x"
project = "date"
-datestamp = "1406653438"
+datestamp = "1491562090"
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_views/date_views.install b/profiles/commerce_kickstart/modules/contrib/date/date_views/date_views.install
index c9697b2d..e1d2e3ef 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_views/date_views.install
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_views/date_views.install
@@ -28,3 +28,27 @@ function date_views_uninstall() {
variable_del('date_views_week_format_with_year');
variable_del('date_views_week_format_without_year');
}
+
+/**
+ * Set default date views variables.
+ */
+function date_views_update_7200() {
+ if (!variable_get('date_views_month_format_with_year', FALSE)) {
+ variable_set('date_views_month_format_with_year', 'F Y');
+ }
+ if (!variable_get('date_views_month_format_without_year', FALSE)) {
+ variable_set('date_views_month_format_without_year', 'F');
+ }
+ if (!variable_get('date_views_day_format_with_year', FALSE)) {
+ variable_set('date_views_day_format_with_year', 'l, F j, Y');
+ }
+ if (!variable_get('date_views_day_format_without_year', FALSE)) {
+ variable_set('date_views_day_format_without_year', 'l, F j');
+ }
+ if (!variable_get('date_views_week_format_with_year', FALSE)) {
+ variable_set('date_views_week_format_with_year', 'F j, Y');
+ }
+ if (!variable_get('date_views_week_format_without_year', FALSE)) {
+ variable_set('date_views_week_format_without_year', 'F j');
+ }
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_views/date_views.module b/profiles/commerce_kickstart/modules/contrib/date/date_views/date_views.module
index 04bad091..c050e56e 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_views/date_views.module
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_views/date_views.module
@@ -1,5 +1,9 @@
'Configure settings for date views.',
'page callback' => 'drupal_get_form',
'page arguments' => array('date_views_settings'),
- 'access arguments' => array('administer site configuration '),
+ 'access arguments' => array('administer site configuration'),
'type' => MENU_LOCAL_TASK,
);
@@ -86,13 +90,30 @@ function date_views_theme() {
'file' => 'theme.inc',
'path' => "$path/theme",
);
- return array(
- 'date_nav_title' => $base + array('variables' => array('granularity' => NULL, 'view' => NULL, 'link' => NULL, 'format' => NULL)),
- 'date_views_filter_form' => $base + array('template' => 'date-views-filter-form', 'render element' => 'form'),
- 'date_calendar_day' => $base + array('variables' => array('date' => NULL)),
+ return array(
+ 'date_nav_title' => $base + array(
+ 'variables' => array(
+ 'granularity' => NULL,
+ 'view' => NULL,
+ 'link' => NULL,
+ 'format' => NULL,
+ ),
+ ),
+ 'date_views_filter_form' => $base + array(
+ 'template' => 'date-views-filter-form',
+ 'render element' => 'form',
+ ),
+ 'date_calendar_day' => $base + array(
+ 'variables' => array(
+ 'date' => NULL,
+ ),
+ ),
'date_views_pager' => $base + array(
- 'variables' => array('plugin' => NULL, 'input' => NULL),
+ 'variables' => array(
+ 'plugin' => NULL,
+ 'input' => NULL,
+ ),
// Register a pattern so that it can work like all views templates.
'pattern' => 'date_views_pager__',
'template' => 'date-views-pager',
@@ -100,6 +121,9 @@ function date_views_theme() {
);
}
+/**
+ * Implements hook_views_api().
+ */
function date_views_views_api() {
return array(
'api' => 3,
@@ -119,7 +143,7 @@ function date_views_views_fetch_fields($base, $type) {
}
/**
- * Identify all potential date/timestamp fields and cache the data.
+ * Identify all potential date/timestamp fields and cache the data.
*/
function date_views_fields($base = 'node', $reset = FALSE) {
static $fields = array();
@@ -141,8 +165,8 @@ function date_views_fields($base = 'node', $reset = FALSE) {
/**
* Implements hook_date_views_entities().
- * Map extra Views tables to the entity that holds its date fields,
- * needed for Views tables other than the primary tables identified in entity_info().
+ *
+ * Map extra Views tables to the entity that holds its date fields, needed for Views tables other than the primary tables identified in entity_info().
*/
function date_views_date_views_extra_tables() {
return array(
@@ -151,14 +175,13 @@ function date_views_date_views_extra_tables() {
}
/**
- * Helper function to map entity types to the Views base table they use,
- * to make it easier to infer the entity type from a base table.
+ * Helper function to map entity types to the Views base table they use, to make it easier to infer the entity type from a base table.
+ *
+ * Views has a new handler called views_handler_field_entity() that loads entities.
*
- * Views has a new handler called views_handler_field_entity() that loads
- * entities, and you can use something like the following to get the
- * entity type from a view, but not all our base tables contain the
- * entity information we need, (i.e. revisions) so it won't work here
- * and we resort to creating information from entity_get_info().
+ * And you can use something like the following to get the entity type from a view, but not all our base tables contain the entity information we need, (i.e. revisions).
+ *
+ * So it won't work here and we resort to creating information from entity_get_info().
*
* // A method to get the entity type for a base table.
* $table_data = views_fetch_data($base_table);
@@ -193,11 +216,7 @@ function date_views_base_tables() {
/**
* Implements hook_date_views_fields().
*
- * All modules that create custom fields that use the
- * 'views_handler_field_date' handler can provide
- * additional information here about the type of
- * date they create so the date can be used by
- * the Date API views date argument and date filter.
+ * All modules that create custom fields that use the 'views_handler_field_date' handler can provide additional information here about the type of date they create so the date can be used by the Date API views date argument and date filter.
*/
function date_views_date_views_fields($field) {
$values = array(
@@ -263,12 +282,15 @@ function date_pager_url($view, $date_type = NULL, $date_arg = NULL, $force_view_
case 'year':
$args[$pos] = date_pad($view->date_info->year, 4);
break;
+
case 'week':
$args[$pos] = date_pad($view->date_info->year, 4) . '-W' . date_pad($view->date_info->week);
break;
+
case 'day':
$args[$pos] = date_pad($view->date_info->year, 4) . '-' . date_pad($view->date_info->month) . '-' . date_pad($view->date_info->day);
break;
+
default:
$args[$pos] = date_pad($view->date_info->year, 4) . '-' . date_pad($view->date_info->month);
break;
@@ -298,9 +320,14 @@ function date_pager_url($view, $date_type = NULL, $date_arg = NULL, $force_view_
// if they use exposed filters.
return url($view->get_url($args), array(
'query' => date_views_querystring($view),
- 'absolute' => $absolute));
+ 'absolute' => $absolute,
+ )
+ );
}
+/**
+ * Identifier of a date block.
+ */
function date_block_identifier($view) {
if (!empty($view->block_identifier)) {
return $view->block_identifier;
@@ -311,12 +338,9 @@ function date_block_identifier($view) {
/**
* Implements hook_field_views_data_alter().
*
- * Create a Views field for each date column we care about
- * to supplement the generic 'entity_id' and 'revision_id'
- * fields that are automatically created.
+ * Create a Views field for each date column we care about to supplement the generic 'entity_id' and 'revision_id' fields that are automatically created.
*
- * Also use friendlier labels to distinguish the start date
- * and end date in listings (for fields that use both).
+ * Also use friendlier labels to distinguish the start date and end date in listings (for fields that use both).
*/
function date_views_field_views_data_alter(&$result, $field, $module) {
if ($module == 'date') {
@@ -336,8 +360,8 @@ function date_views_field_views_data_alter(&$result, $field, $module) {
$result[$table][$column]['field']['is date'] = TRUE;
// Not sure yet if we still need a custom field handler in D7 now that custom formatters are available.
// Might still need it to handle grouping of multiple value dates.
- //$result[$table][$column]['field']['handler'] = 'date_handler_field_date';
- //$result[$table][$column]['field']['add fields to query'] = TRUE;
+ // $result[$table][$column]['field']['handler'] = 'date_handler_field_date';
+ // $result[$table][$column]['field']['add fields to query'] = TRUE;
}
// For filters, arguments, and sorts, determine if this column is for
@@ -395,12 +419,25 @@ function date_views_field_views_data_alter(&$result, $field, $module) {
// translatable string. This is a hack to get it to appear right
// before 'end date' in the listing (i.e., in a non-alphabetical,
// but more user friendly, order).
- $result[$table][$column]['title'] = t('@label - start date (!name)', array('@label' => $label, '!name' => $field['field_name']));
- $result[$table][$column]['title short'] = t('@label - start date', array('@label' => $label));
+ $result[$table][$column]['title'] = t('@label - start date (!name)', array(
+ '@label' => $label,
+ '!name' => $field['field_name'],
+ ));
+ $result[$table][$column]['title short'] = t('@label - start date', array(
+ '@label' => $label,
+ ));
break;
+
case 'value2':
- $result[$table][$column]['title'] = t('@label - end date (!name:!column)', array('@label' => $label, '!name' => $field['field_name'], '!column' => $this_column));
- $result[$table][$column]['title short'] = t('@label - end date:!column', array('@label' => $label, '!column' => $this_column));
+ $result[$table][$column]['title'] = t('@label - end date (!name:!column)', array(
+ '@label' => $label,
+ '!name' => $field['field_name'],
+ '!column' => $this_column,
+ ));
+ $result[$table][$column]['title short'] = t('@label - end date:!column', array(
+ '@label' => $label,
+ '!column' => $this_column,
+ ));
break;
}
}
@@ -421,18 +458,15 @@ function date_views_form_views_ui_edit_form_alter(&$form, &$form_state, $form_id
}
/**
- * The instanceof function makes this work for any handler that was derived
- * from 'views_handler_filter_date' or 'views_handler_argument_date',
- * which includes core date fields like the node updated field.
+ * The instanceof function makes this work for any handler that was derived from 'views_handler_filter_date' or 'views_handler_argument_date', which includes core date fields like the node updated field.
*
- * The test for $handler->min_date tells us that this is an argument that
- * not only is derived from the views date handler but also has been processed
- * by the Date Views filter or argument code.
-*/
+ * The test for $handler->min_date tells us that this is an argument that not only is derived from the views date handler but also has been processed by the Date Views filter or argument code.
+ */
function date_views_handler_is_date($handler, $type = 'argument') {
switch ($type) {
case 'filter':
return $handler instanceof views_handler_filter_date && !empty($handler->min_date);
+
case 'argument':
return $handler instanceof views_handler_argument_date && !empty($handler->min_date);
}
@@ -441,8 +475,8 @@ function date_views_handler_is_date($handler, $type = 'argument') {
/**
* Validation hook for exposed filters that use the select widget.
- * This is to ensure the the user completes all parts of the date
- * not just some parts. Only needed for the select widget.
+ *
+ * This is to ensure the the user completes all parts of the date not just some parts. Only needed for the select widget.
*/
function date_views_select_validate(&$form, &$form_state) {
// If there are no values just return.
@@ -453,7 +487,7 @@ function date_views_select_validate(&$form, &$form_state) {
$filled = array();
$value = drupal_array_get_nested_value($form_state['input'], $form['#parents']);
foreach ($granularity as $part) {
- if (!empty($value['value'][$part])) {
+ if (isset($value['value']) && is_numeric($value['value'][$part])) {
$filled[] = $part;
}
}
@@ -464,18 +498,23 @@ function date_views_select_validate(&$form, &$form_state) {
case 'year':
form_error($form['value'][$part], t('Please choose a year.'), $form_state);
break;
+
case 'month':
form_error($form['value'][$part], t('Please choose a month.'), $form_state);
break;
+
case 'day':
form_error($form['value'][$part], t('Please choose a day.'), $form_state);
break;
+
case 'hour':
form_error($form['value'][$part], t('Please choose an hour.'), $form_state);
break;
+
case 'minute':
form_error($form['value'][$part], t('Please choose a minute.'), $form_state);
break;
+
case 'second':
form_error($form['value'][$part], t('Please choose a second.'), $form_state);
break;
@@ -487,8 +526,7 @@ function date_views_select_validate(&$form, &$form_state) {
/**
* Implements hook_date_formatter_view_alter().
*
- * If we are displaying a date from a view, see if we have information about
- * which multiple value to display. If so, set the date_id in the entity.
+ * If we are displaying a date from a view, see if we have information about which multiple value to display. If so, set the date_id in the entity.
*/
function date_views_date_formatter_pre_view_alter(&$entity, &$variables) {
// Some views have no row index.
@@ -501,4 +539,4 @@ function date_views_date_formatter_pre_view_alter(&$entity, &$variables) {
$entity->date_id = 'date.' . $date_item->$date_id . '.' . $field['field_name'] . '.' . $date_item->$date_delta . '.0';
}
}
-}
\ No newline at end of file
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_plugin_display_attachment.inc b/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_plugin_display_attachment.inc
index 94371f76..779f4d1f 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_plugin_display_attachment.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_plugin_display_attachment.inc
@@ -1,6 +1,7 @@
'date_views', // This just tells our themes are elsewhere.
+ // This just tells our themes are elsewhere.
+ 'module' => 'date_views',
'display' => array(
// Display plugin for date navigation.
'date_nav' => array(
@@ -83,7 +85,7 @@ function date_views_views_plugins() {
}
/**
- * Implements hook_views_data()
+ * Implements hook_views_data().
*/
function date_views_views_data() {
$data = array();
@@ -95,12 +97,12 @@ function date_views_views_data() {
$data[$base_table]['date_argument'] = array(
'group' => t('Date'),
'title' => t('Date (!base_table)', array('!base_table' => $base_table)),
- 'help' => t('Filter any Views !base_table date field by a date argument, using any common ISO date/period format (i.e. YYYY, YYYY-MM, YYYY-MM-DD, YYYY-W99, YYYY-MM-DD--P3M, P90D, etc). ', array('!base_table' => $base_table)),
+ 'help' => t('Filter any Views !base_table date field by a date argument, using any common ISO date/period format (i.e. YYYY, YYYY-MM, YYYY-MM-DD, YYYY-W99, YYYY-MM-DD--P3M, P90D, etc).', array('!base_table' => $base_table)),
'argument' => array(
'handler' => 'date_views_argument_handler',
'empty field name' => t('Undated'),
'is date' => TRUE,
- //'skip base' => $base_table,
+ // 'skip base' => $base_table,
),
);
// The flexible date filter.
@@ -112,7 +114,7 @@ function date_views_views_data() {
'handler' => 'date_views_filter_handler',
'empty field name' => t('Undated'),
'is date' => TRUE,
- //'skip base' => $base_table,
+ // 'skip base' => $base_table,
),
);
}
@@ -140,8 +142,9 @@ function date_views_views_data_alter(&$data) {
}
/**
- * Central function for setting up the right timezone values
- * in the SQL date handler.
+ * Central function for setting up the right timezone values.
+ *
+ * In the SQL date handler.
*
* The date handler will use this information to decide if the
* database value needs a timezone conversion.
@@ -152,30 +155,45 @@ function date_views_views_data_alter(&$data) {
*/
function date_views_set_timezone(&$date_handler, &$view, $field) {
switch ($field['tz_handling']) {
- case 'date' :
+ case 'date':
$date_handler->db_timezone = 'UTC';
$date_handler->local_timezone_field = $field['timezone_field'];
$date_handler->offset_field = $field['offset_field'];
break;
+
case 'none':
$date_handler->db_timezone = date_default_timezone();
$date_handler->local_timezone = date_default_timezone();
break;
+
case 'utc':
$date_handler->db_timezone = 'UTC';
$date_handler->local_timezone = 'UTC';
break;
- default :
+
+ default:
$date_handler->db_timezone = 'UTC';
$date_handler->local_timezone = date_default_timezone();
break;
}
}
+/**
+ * Helper function to generate a query string.
+ *
+ * @param object $view
+ * A View object.
+ *
+ * @param array $extra_params
+ * An extra parameters.
+ *
+ * @return null/string
+ * Return a query or NULL.
+ */
function date_views_querystring($view, $extra_params = array()) {
$query_params = array_merge($_GET, $extra_params);
// Allow NULL params to be removed from the query string.
- foreach ($extra_params AS $key => $value) {
+ foreach ($extra_params as $key => $value) {
if (!isset($value)) {
unset($query_params[$key]);
}
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_argument_handler.inc b/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_argument_handler.inc
index 61aeafc1..20eedff0 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_argument_handler.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_argument_handler.inc
@@ -3,12 +3,14 @@
* @file
* Date API views argument handler.
* This argument combines multiple date arguments into a single argument
- * where all fields are controlled by the same date and can be combined with either AND or OR.
+ * where all fields are controlled by the same date and can be combined
+ * with either AND or OR.
*/
/**
* Date API argument handler.
*/
+// @codingStandardsIgnoreStart
class date_views_argument_handler extends date_views_argument_handler_simple {
/**
@@ -198,3 +200,4 @@ class date_views_argument_handler extends date_views_argument_handler_simple {
}
}
+// @codingStandardsIgnoreEnd
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_argument_handler_simple.inc b/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_argument_handler_simple.inc
index 35f88e00..2839b959 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_argument_handler_simple.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_argument_handler_simple.inc
@@ -7,11 +7,13 @@
/**
* Date API argument handler.
*/
+// @codingStandardsIgnoreStart
class date_views_argument_handler_simple extends views_handler_argument_date {
/**
- * Get granularity and use it to create the formula and a format
- * for the results.
+ * Get granularity.
+ *
+ * Use it to create the formula and a format for the results.
*/
function init(&$view, &$options) {
parent::init($view, $options);
@@ -29,12 +31,14 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
$this->date_handler->local_timezone = date_get_timezone($field['settings']['tz_handling']);
}
$this->date_handler->granularity = $this->options['granularity'];
- // This value needs to be initialized so it exists even if the query doesn't run.
+ // This value needs to be initialized so
+ // it exists even if the query doesn't run.
$this->date_handler->placeholders = array();
$this->format = $this->date_handler->views_formats($this->date_handler->granularity, 'display');
$this->sql_format = $this->date_handler->views_formats($this->date_handler->granularity, 'sql');
- // $this->arg_format is the format the parent date handler will use to create a default argument.
+ // $this->arg_format is the format the parent date
+ // handler will use to create a default argument.
$this->arg_format = $this->format();
// Identify the base table for this field.
@@ -43,6 +47,9 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
}
+ /**
+ * {@inheritdoc}
+ */
function format() {
if (!empty($this->options['granularity'])) {
return $this->date_handler->views_formats($this->options['granularity']);
@@ -53,8 +60,9 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
}
/**
- * Set the empty argument value to the current date,
- * formatted appropriately for this argument.
+ * Set the empty argument value to the current date.
+ *
+ * Formatted appropriately for this argument.
*/
function get_default_argument($raw = FALSE) {
$is_default = FALSE;
@@ -85,6 +93,7 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
$options = parent::option_definition();
$options['year_range'] = array('default' => '-3:+3');
$options['granularity'] = array('default' => 'month');
+ $options['granularity_reset'] = array('default' => FALSE);
$options['default_argument_type']['default'] = 'date';
$options['add_delta'] = array('default' => '');
$options['use_fromto'] = array('default' => '');
@@ -116,7 +125,9 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
'#attributes' => array('class' => array('dependent-options')),
'#states' => array(
'visible' => array(
- ':input[name="options[default_action]"]' => array('value' => 'summary')
+ ':input[name="options[default_action]"]' => array(
+ 'value' => 'summary',
+ ),
),
),
);
@@ -129,23 +140,37 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
'#attributes' => array('class' => array('dependent-options')),
'#states' => array(
'visible' => array(
- ':input[name="options[title_format]"]' => array('value' => 'custom')
+ ':input[name="options[title_format]"]' => array(
+ 'value' => 'custom',
+ ),
),
),
);
+ // Get default granularity options
$options = $this->date_handler->date_parts();
- unset($options['second'], $options['minute']);
- $options += array('week' => t('Week', array(), array('context' => 'datetime')));
+ // Add the 'week' option.
+ $options += array(
+ 'week' => t('Week', array(), array(
+ 'context' => 'datetime',
+ )),
+ );
+
$form['granularity'] = array(
'#title' => t('Granularity'),
'#type' => 'radios',
'#options' => $options,
'#default_value' => $this->options['granularity'],
- '#multiple' => TRUE,
'#description' => t("Select the type of date value to be used in defaults, summaries, and navigation. For example, a granularity of 'month' will set the default date to the current month, summarize by month in summary views, and link to the next and previous month when using date navigation."),
);
+ $form['granularity_reset'] = array(
+ '#title' => t('Use granularity from argument value'),
+ '#type' => 'checkbox',
+ '#default_value' => $this->options['granularity_reset'],
+ '#description' => t("If the granularity of argument value is different from selected, use it from argument value."),
+ );
+
$form['year_range'] = array(
'#title' => t('Date year range'),
'#type' => 'textfield',
@@ -172,16 +197,18 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
'#default_value' => $this->options['add_delta'],
'#options' => array('' => t('No'), 'yes' => t('Yes')),
'#description' => t('Add an identifier to the view to show which multiple value date fields meet the filter criteria. Note: This option may introduce duplicate values into the view. Required when using multiple value fields in a Calendar or any time you want the node view of multiple value dates to display only the values that match the view filters.'),
- // Only let mere mortals tweak this setting for multi-value fields
+ // Only let mere mortals tweak this setting for multi-value fields.
'#access' => $access,
);
-
}
+ /**
+ * {@inheritdoc}
+ */
function options_validate(&$form, &$form_state) {
// It is very important to call the parent function here:
parent::options_validate($form, $form_state);
- if (!preg_match('/^(?:\-[0-9]{1,4}|[0-9]{4}):(?:[\+|\-][0-9]{1,4}|[0-9]{4})$/', $form_state['values']['options']['year_range'])) {
+ if (!preg_match('/^(?:\-[0-9]{1,4}|[0-9]{4}):(?:[\+\-][0-9]{1,4}|[0-9]{4})$/', $form_state['values']['options']['year_range'])) {
form_error($form['year_range'], t('Date year range must be in the format -9:+9, 2005:2010, -9:2010, or 2005:+9'));
}
}
@@ -209,14 +236,15 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
$format = !empty($this->options['title_format_custom']) && !empty($this->options['title_format_custom']) ? $this->options['title_format_custom'] : $this->date_handler->views_formats($this->options['granularity'], 'display');
$range = $this->date_handler->arg_range($this->argument);
return date_format_date($range[0], 'custom', $format);
- }
+ }
/**
- * Provide the argument to use to link from the summary to the next level;
- * this will be called once per row of a summary, and used as part of
+ * Provide the argument to use to link from the summary to the next level.
+ *
+ * This will be called once per row of a summary, and used as part of
* $view->get_url().
*
- * @param $data
+ * @param object $data
* The query results for the row.
*/
function summary_argument($data) {
@@ -234,10 +262,11 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
*/
function summary_query() {
- // @TODO The summary values are computed by the database. Unless the database has
- // built-in timezone handling it will use a fixed offset, which will not be
- // right for all dates. The only way I can see to make this work right is to
- // store the offset for each date in the database so it can be added to the base
+ // @TODO The summary values are computed by the database.
+ // Unless the database has built-in timezone handling it will use
+ // a fixed offset, which will not be right for all dates.
+ // The only way I can see to make this work right is to store the offset
+ // for each date in the database so it can be added to the base
// date value before the database formats the result. Because this is a huge
// architectural change, it won't go in until we start a new branch.
$this->formula = $this->date_handler->sql_format($this->sql_format, $this->date_handler->sql_field("***table***.$this->real_field"));
@@ -245,7 +274,8 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
// Now that our table is secure, get our formula.
$formula = $this->get_formula();
- // Add the field, give it an alias that does NOT match the actual field name or grouping won't work right.
+ // Add the field, give it an alias that does NOT match the actual
+ // field name or grouping won't work right.
$this->base_alias = $this->name_alias = $this->query->add_field(NULL, $formula, $this->field . '_summary');
$this->query->set_count_field(NULL, $formula, $this->field);
@@ -254,20 +284,22 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
/**
* Inject a test for valid date range before the regular query.
+ *
* Override the parent query to be able to control the $group.
*/
function query($group_by = FALSE) {
- // @TODO Not doing anything with $group_by yet, need to figure out what has to be done.
+ // @TODO Not doing anything with $group_by yet,
+ // need to figure out what has to be done.
if ($this->date_forbid()) {
return;
}
// See if we need to reset granularity based on an argument value.
- // Make sure we don't try to reset to some bogus value if someone has typed in an unexpected argument.
- $granularity = $this->date_handler->arg_granularity($this->argument);
- if (!empty($granularity)) {
+ // Make sure we don't try to reset to some bogus value if someone has
+ // typed in an unexpected argument.
+ if ($this->options['granularity_reset'] && $granularity = $this->date_handler->arg_granularity($this->argument)) {
$this->date_handler->granularity = $granularity;
$this->format = $this->date_handler->views_formats($this->date_handler->granularity, 'display');
$this->sql_format = $this->date_handler->views_formats($this->date_handler->granularity, 'sql');
@@ -276,7 +308,8 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
$this->ensure_my_table();
$group = !empty($this->options['date_group']) ? $this->options['date_group'] : 0;
- // If requested, add the delta field to the view so we can later find the value that matched our query.
+ // If requested, add the delta field to the view so
+ // we can later find the value that matched our query.
if (!empty($this->options['add_delta']) && (substr($this->real_field, -6) == '_value' || substr($this->real_field, -7) == '_value2')) {
$this->query->add_field($this->table_alias, 'delta');
$real_field_name = str_replace(array('_value', '_value2'), '', $this->real_field);
@@ -291,7 +324,8 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
$view_max_placeholder = $this->placeholder();
$this->date_handler->placeholders = array($view_min_placeholder => $view_min, $view_max_placeholder => $view_max);
- // Are we comparing this field only or the Start/End date range to the view criteria?
+ // Are we comparing this field only or the Start/End date range
+ // to the view criteria?
if (!empty($this->options['use_fromto'])) {
// The simple case, match the field to the view range.
@@ -302,10 +336,14 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
}
else {
- // Look for the intersection of the range of the date field with the range of the view.
- // Get the Start/End values for this field. Retrieve using the original table name.
- // Swap the current table name (adjusted for relationships) into the query.
- // @TODO We may be able to use Views substitutions here, investigate that later.
+ // Look for the intersection of the range
+ // of the date field with the range of the view.
+ // Get the Start/End values for this field.
+ // Retrieve using the original table name.
+ // Swap the current table name (adjusted for relationships)
+ // into the query.
+ // @TODO We may be able to use Views substitutions here,
+ // investigate that later.
$fields = date_views_fields($this->base_table);
$fields = $fields['name'];
$fromto = $fields[$this->original_table . '.' . $this->real_field]['fromto'];
@@ -321,7 +359,10 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
}
/**
- * Add a callback to determine if we have moved outside the valid date range for this argument.
+ * Add a callback.
+ *
+ * To determine if we have moved outside
+ * the valid date range for this argument.
*/
function date_forbid() {
if (empty($this->argument)) {
@@ -343,3 +384,4 @@ class date_views_argument_handler_simple extends views_handler_argument_date {
}
}
+// @codingStandardsIgnoreEnd
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_fields.inc b/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_fields.inc
index a002b088..d497ef60 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_fields.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_fields.inc
@@ -5,13 +5,11 @@
*/
/**
- * Identify all potential date/timestamp fields.
+ * Identify all potential date/timestamp fields.
*
- * @return
- * array with fieldname, type, and table.
- * @see
- * date_views_date_views_fields() which implements
- * the hook_date_views_fields() for the core date fields.
+ * @return array
+ * An array with fieldname, type, and table.
+ * @see date_views_date_views_fields()
*/
function _date_views_fields($base = 'node') {
@@ -60,7 +58,7 @@ function _date_views_fields($base = 'node') {
$handler = views_get_handler($table_name, $field_name, 'filter');
$handler_name = $handler->definition['handler'];
- // We don't care about anything but date handlers
+ // We don't care about anything but date handlers.
if (empty($handler->definition['is date'])) {
continue;
}
@@ -72,14 +70,17 @@ function _date_views_fields($base = 'node') {
$field = field_info_field($handler->definition['field_name']);
$is_field = TRUE;
switch ($field['type']) {
- case 'date':
+ case 'date':
$sql_type = DATE_ISO;
break;
+
case 'datestamp':
break;
+
case 'datetime':
$sql_type = DATE_DATETIME;
break;
+
default:
// If this is not a date field, nothing more to do.
continue;
@@ -88,7 +89,8 @@ function _date_views_fields($base = 'node') {
$revision = in_array($base, array('node_revision')) ? FIELD_LOAD_REVISION : FIELD_LOAD_CURRENT;
$db_info = date_api_database_info($field, $revision);
$name = $table_name . "." . $field_name;
- $granularity = !empty($field['granularity']) ? $field['granularity'] : array('year', 'month', 'day', 'hour', 'minute', 'second');
+ $grans = array('year', 'month', 'day', 'hour', 'minute', 'second');
+ $granularity = !empty($field['granularity']) ? $field['granularity'] : $grans;
$fromto = array(
$table_name . '.' . $db_info['columns'][$table_name]['value'],
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_filter_handler.inc b/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_filter_handler.inc
index 0cfc7fcc..ae6944ee 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_filter_handler.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_filter_handler.inc
@@ -3,9 +3,11 @@
* @file
* A flexible, configurable date filter.
* This filter combines multiple date filters into a single filter
- * where all fields are controlled by the same date and can be combined with either AND or OR.
+ * where all fields are controlled by the same date and can be combined
+ * with either AND or OR.
*/
+// @codingStandardsIgnoreStart
class date_views_filter_handler extends date_views_filter_handler_simple {
function init(&$view, &$options) {
parent::init($view, $options);
@@ -40,6 +42,32 @@ class date_views_filter_handler extends date_views_filter_handler_simple {
$this->date_combine_conditions('op_contains');
}
+ function op_empty($field) {
+ $this->get_query_fields();
+ if (empty($this->query_fields)) {
+ return;
+ }
+
+ // Add each condition to the custom filter group.
+ foreach ((array) $this->query_fields as $query_field) {
+ $field = $query_field['field'];
+ $this->date_handler = $query_field['date_handler'];
+
+ // Respect relationships when determining the table alias.
+ if ($field['table_name'] != $this->table || !empty($this->relationship)) {
+ $this->related_table_alias = $this->query->ensure_table($field['table_name'], $this->relationship);
+ }
+ else {
+ $this->related_table_alias = NULL;
+ }
+
+ $table_alias = !empty($this->related_table_alias) ? $this->related_table_alias : $field['table_name'];
+ $field_name = $table_alias . '.' . $field['field_name'];
+
+ parent::op_empty($field_name);
+ }
+ }
+
/**
* Combines multiple date WHERE expressions into a single WHERE expression.
*
@@ -64,6 +92,9 @@ class date_views_filter_handler extends date_views_filter_handler_simple {
if ($field['table_name'] != $this->table || !empty($this->relationship)) {
$this->related_table_alias = $this->query->ensure_table($field['table_name'], $this->relationship);
}
+ else {
+ $this->related_table_alias = NULL;
+ }
$table_alias = !empty($this->related_table_alias) ? $this->related_table_alias : $field['table_name'];
$field_name = $table_alias . '.' . $field['field_name'];
@@ -179,3 +210,4 @@ class date_views_filter_handler extends date_views_filter_handler_simple {
}
}
}
+// @codingStandardsIgnoreEnd
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_filter_handler_simple.inc b/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_filter_handler_simple.inc
index d41f30b6..4fa4c409 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_filter_handler_simple.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_filter_handler_simple.inc
@@ -1,9 +1,11 @@
$operator_values);
}
if (!isset($form_state['input'][$identifier][$prefix])) {
- $form_state['input'][$identifier][$prefix] = $this->value[$prefix];
+ // Ensure these exist.
+ foreach ($granularity as $key) {
+ $form_state['input'][$identifier][$prefix][$key] = NULL;
+ }
}
}
else {
@@ -530,3 +535,4 @@ class date_views_filter_handler_simple extends views_handler_filter_date {
}
}
+// @codingStandardsIgnoreEnd
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_plugin_pager.inc b/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_plugin_pager.inc
index f9594a72..1addd200 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_plugin_pager.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_views/includes/date_views_plugin_pager.inc
@@ -2,50 +2,74 @@
/**
* @file
* Date pager.
- * Works with a Date argument, the argument filters the view and the pager provides back/next navigation.
+ * Works with a Date argument, the argument filters
+ * the view and the pager provides back/next navigation.
*
* USER NOTES:
*
* To use this, add a pager to a view, and choose the option to 'Page by date'.
* There are several settings:
- * - The pager id: Set an id to be used as the identifier in the url for pager values, defaults to 'date'.
- * - Pager position: Choose whether to display the date pager above, below, or both above and below the content.
- * - Link format: Choose whether the pager links will be in the simple 'calendar/2011-12' format or the
- * more complex 'calendar/?date=2011-12' pager format. The second one is more likely to work correctly
- * if the pager is used in blocks and panels.
+ * - The pager id: Set an id to be used as the identifier
+ * in the url for pager values, defaults to 'date'.
+ * - Pager position: Choose whether to display the date
+ * pager above, below, or both above and below the content.
+ * - Link format: Choose whether the pager links will be in t
+ * he simple 'calendar/2011-12' format or the
+ * more complex 'calendar/?date=2011-12' pager format.
+ * The second one is more likely to work correctly
+ * if the pager is used in blocks and panels.
*
- * The pager works in combination with a Date argument and it will use the date fields and granularity
- * set in that argument to create its back/next links. If the view has no Date argument, the pager can
- * do nothing. The argument can either be a 'Date' argument that lets you select one or more date fields
- * in the argument, or the simple 'Content' argument for an individual date field. It must be an
+ * The pager works in combination with a Date argument
+ * and it will use the date fields and granularity
+ * set in that argument to create its back/next links.
+ * If the view has no Date argument, the pager can
+ * do nothing. The argument can either be a 'Date' argument
+ * that lets you select one or more date fields
+ * in the argument, or the simple 'Content' argument for an
+ * individual date field. It must be an
* argument that uses the date argument handler.
*
* DEVELOPER NOTES
*
- * The pager could technically create a query of its own rather than depending on the date argument to
- * set the query, but it has only a limited set of tools to work with because it is a plugin, not a handler:
- * it has no knowledge about relationships, it cannot use the ensure_my_table() function,
- * plugins are not even invoked in pre_query(), so can't do anything there.
+ * The pager could technically create a query of its own rather
+ * than depending on the date argument to
+ * set the query, but it has only a limited set of tools to work
+ * with because it is a plugin, not a handler:
+ * it has no knowledge about relationships, it cannot use the
+ * ensure_my_table() function, plugins are not even invoked in pre_query(),
+ * so can't do anything there.
*
- * My conclusion was that the date pager simply is not powerful enough to create its own queries for
- * date fields, which require very complex queries. Instead, we can combine this with a date argument and
- * let the argument create the query and let the pager just provide the back/next links. If there is no
+ * My conclusion was that the date pager simply
+ * is not powerful enough to create its own queries for
+ * date fields, which require very complex queries.
+ * Instead, we can combine this with a date argument and
+ * let the argument create the query and let the pager
+ * just provide the back/next links. If there is no
* date argument, the pager will do nothing.
*
- * There are still other problems. The pager is not even initialized until after all the handlers
- * have created their queries, so it has no chance to alter values ahead of that. And the argument
- * has no knowledge of the pager, so it can't check for pager values before the query is created.
+ * There are still other problems. The pager is not even
+ * initialized until after all the handlers
+ * have created their queries, so it has no chance
+ * to alter values ahead of that. And the argument
+ * has no knowledge of the pager, so it can't check
+ * for pager values before the query is created.
*
- * The solution used here is to let the argument create the original query. The pager query
- * runs after that, so the pager checks to see if there is a pager value that needs to be used in the query.
- * The date argument has identified the placeholders it used in the query. So if a change is needed,
- * we can swap the pager value into the query created by the date argument and adjust the
- * $view->date_info values set by the argument accordingly so the theme will pick up the new information.
+ * The solution used here is to let the argument create
+ * the original query. The pager query
+ * runs after that, so the pager checks to see
+ * if there is a pager value that needs to be used in the query.
+ * The date argument has identified the placeholders
+ * it used in the query. So if a change is needed,
+ * we can swap the pager value into the query created
+ * by the date argument and adjust the
+ * $view->date_info values set by the argument accordingly
+ * so the theme will pick up the new information.
*/
/**
* Example plugin to handle paging by month.
*/
+// @codingStandardsIgnoreStart
class date_views_plugin_pager extends views_plugin_pager {
/**
@@ -79,6 +103,7 @@ class date_views_plugin_pager extends views_plugin_pager {
$options['link_format'] = array('default' => 'pager');
$options['date_argument'] = array('default' => 'Unknown');
$options['granularity'] = array('default' => 'Unknown');
+ $options['skip_empty_pages'] = array('default' => FALSE);
return $options;
}
@@ -110,6 +135,12 @@ class date_views_plugin_pager extends views_plugin_pager {
'#default_value' => $this->options['link_format'],
'#required' => TRUE,
);
+ $form['skip_empty_pages'] = array(
+ '#title' => t('Skip empty pages'),
+ '#type' => 'checkbox',
+ '#description' => t('When selected, the pager will not display pages with no result for the given date. This causes a slight performance degradation because two additional queries need to be executed.'),
+ '#default_value' => $this->options['skip_empty_pages'],
+ );
$form['date_argument']['#type'] = 'hidden';
$form['date_argument']['#value'] = $this->options['date_argument'];
$form['granularity']['#type'] = 'hidden';
@@ -150,13 +181,7 @@ class date_views_plugin_pager extends views_plugin_pager {
// Reset values set by argument if pager requires it.
if (!empty($value)) {
- $argument->argument = $value;
- $argument->date_range = $argument->date_handler->arg_range($value);
- $argument->min_date = $argument->date_range[0];
- $argument->max_date = $argument->date_range[1];
- // $argument->is_default works correctly for normal arguments, but does not
- // work correctly if we are swapping in a new value from the pager.
- $argument->is_default = FALSE;
+ $this->set_argument_value($argument, $value);
}
// The pager value might move us into a forbidden range, so test it.
@@ -164,13 +189,102 @@ class date_views_plugin_pager extends views_plugin_pager {
$this->view->build_info['fail'] = TRUE;
return;
}
-
- if (empty($this->view->date_info)) $this->view->date_info = new stdClass();
+ // Write date_info to store information to be used
+ // in the theming functions.
+ if (empty($this->view->date_info)) {
+ $this->view->date_info = new stdClass();
+ }
$this->view->date_info->granularity = $argument->date_handler->granularity;
$format = $this->view->date_info->granularity == 'week' ? DATE_FORMAT_DATETIME : $argument->sql_format;
$this->view->date_info->placeholders = isset($argument->placeholders) ? $argument->placeholders : $argument->date_handler->placeholders;
$this->view->date_info->date_arg = $argument->argument;
$this->view->date_info->date_arg_pos = $i;
+ $this->view->date_info->limit = $argument->limit;
+ $this->view->date_info->url = $this->view->get_url();
+ $this->view->date_info->pager_id = $this->options['date_id'];
+ $this->view->date_info->date_pager_position = $this->options['pager_position'];
+ $this->view->date_info->date_pager_format = $this->options['link_format'];
+ $this->view->date_info->skip_empty_pages = $this->options['skip_empty_pages'] == 1;
+ // Execute two additional queries to find
+ // the previous and next page with values.
+ if ($this->view->date_info->skip_empty_pages) {
+ $q = clone $argument->query;
+ $field = $argument->table_alias . '.' . $argument->real_field;
+ $fieldsql = $date_handler->sql_field($field);
+ $fieldsql = $date_handler->sql_format($format, $fieldsql);
+ $q->clear_fields();
+ $q->orderby = array();
+ $q->set_distinct(TRUE, TRUE);
+ // Date limits of this argument.
+ $datelimits = $argument->date_handler->arg_range($argument->limit[0] . '--' . $argument->limit[1]);
+ // Find the first two dates between the minimum date
+ // and the upper bound of the current value.
+ $q->add_orderby(NULL, $fieldsql, 'DESC', 'date');
+ $this->set_argument_placeholders($this->view->date_info->placeholders, $datelimits[0], $argument->max_date, $q, $format);
+
+ $compiledquery = $q->query();
+ $compiledquery->range(0, 2);
+ $results = $compiledquery->execute()->fetchCol(0);
+
+ $prevdate = array_shift($results);
+ $prevdatealt = array_shift($results);
+ // Find the first two dates between the lower bound
+ // of the current value and the maximum date.
+ $q->add_orderby(NULL, $fieldsql, 'ASC', 'date');
+ $this->set_argument_placeholders($this->view->date_info->placeholders, $argument->min_date, $datelimits[1], $q, $format);
+
+ $compiledquery = $q->query();
+ $compiledquery->range(0, 2);
+ $results = $compiledquery->execute()->fetchCol(0);
+
+ $nextdate = array_shift($results);
+ $nextdatealt = array_shift($results);
+
+ // Set the default value of the query to $prevfirst or $nextfirst
+ // when there is no value and $prevsecond or $nextsecond is set.
+ if (empty($value)) {
+ // @Todo find out which of $prevdate or $nextdate is closest to the
+ // default argument date value and choose that one.
+ if ($prevdate && $prevdatealt) {
+ $this->set_argument_value($argument, $prevdate);
+ $value = $prevdate;
+ $prevdate = $prevdatealt;
+ // If the first next date is the same as the first previous date,
+ // move to the following next date.
+ if ($value == $nextdate) {
+ $nextdate = $nextdatealt;
+ $nextdatealt = NULL;
+ }
+ }
+ elseif ($nextdate && $nextdatealt) {
+ $this->set_argument_value($argument, $nextdate);
+ $value = $nextdate;
+ $nextdate = $nextdatealt;
+ // If the first previous date is the same as the first next date,
+ // move to the following previous date.
+ if ($value == $prevdate) {
+ $prevdate = $prevdatealt;
+ $prevdatealt = NULL;
+ }
+ }
+ }
+ else {
+ // $prevdate and $nextdate are the same as $value, so move to
+ // the next values.
+ $prevdate = $prevdatealt;
+ $nextdate = $nextdatealt;
+ }
+
+ $this->view->date_info->prev_date = $prevdate ? new DateObject($prevdate, NULL, $format) : NULL;
+ $this->view->date_info->next_date = $nextdate ? new DateObject($nextdate, NULL, $format) : NULL;
+ }
+ else {
+ $this->view->date_info->prev_date = clone($argument->min_date);
+ date_modify($this->view->date_info->prev_date, '-1 ' . $argument->date_handler->granularity);
+ $this->view->date_info->next_date = clone($argument->min_date);
+ date_modify($this->view->date_info->next_date, '+1 ' . $argument->date_handler->granularity);
+ }
+ // Write the date_info properties that depend on the current value.
$this->view->date_info->year = date_format($argument->min_date, 'Y');
$this->view->date_info->month = date_format($argument->min_date, 'n');;
$this->view->date_info->day = date_format($argument->min_date, 'j');
@@ -178,11 +292,6 @@ class date_views_plugin_pager extends views_plugin_pager {
$this->view->date_info->date_range = $argument->date_range;
$this->view->date_info->min_date = $argument->min_date;
$this->view->date_info->max_date = $argument->max_date;
- $this->view->date_info->limit = $argument->limit;
- $this->view->date_info->url = $this->view->get_url();
- $this->view->date_info->pager_id = $this->options['date_id'];
- $this->view->date_info->date_pager_position = $this->options['pager_position'];
- $this->view->date_info->date_pager_format = $this->options['link_format'];
}
$i++;
}
@@ -191,20 +300,33 @@ class date_views_plugin_pager extends views_plugin_pager {
// If there is pager input and the argument has set the placeholders,
// swap the pager value in for the placeholder set by the argument.
if (!empty($value) && !empty($this->view->date_info->placeholders)) {
- $placeholders = $this->view->date_info->placeholders;
- $count = count($placeholders);
- foreach ($this->view->query->where as $group => $data) {
- foreach ($data['conditions'] as $delta => $condition) {
- if (array_key_exists('value', $condition) && is_array($condition['value'])) {
- foreach ($condition['value'] as $placeholder => $placeholder_value) {
- if (array_key_exists($placeholder, $placeholders)) {
- // If we didn't get a match, this is a > $min < $max query that uses the view
- // min and max dates as placeholders.
- $date = ($count == 2) ? $this->view->date_info->min_date : $this->view->date_info->max_date;
- $next_placeholder = array_shift($placeholders);
- $this->view->query->where[$group]['conditions'][$delta]['value'][$placeholder] = $date->format($format);
- $count--;
- }
+ $this->set_argument_placeholders($this->view->date_info->placeholders, $this->view->date_info->min_date, $this->view->date_info->max_date, $this->view->query, $format);
+ }
+ }
+
+ function set_argument_value($argument, $value) {
+ $argument->argument = $value;
+ $argument->date_range = $argument->date_handler->arg_range($value);
+ $argument->min_date = $argument->date_range[0];
+ $argument->max_date = $argument->date_range[1];
+ // $argument->is_default works correctly for normal arguments, but does not
+ // work correctly if we are swapping in a new value from the pager.
+ $argument->is_default = FALSE;
+ }
+
+ function set_argument_placeholders($placeholders, $mindate, $maxdate, $query, $format) {
+ $count = count($placeholders);
+ foreach ($query->where as $group => $data) {
+ foreach ($data['conditions'] as $delta => $condition) {
+ if (array_key_exists('value', $condition) && is_array($condition['value'])) {
+ foreach ($condition['value'] as $placeholder => $placeholder_value) {
+ if (array_key_exists($placeholder, $placeholders)) {
+ // If we didn't get a match, this is a > $min < $max query that uses the view
+ // min and max dates as placeholders.
+ $date = ($count == 2) ? $mindate : $maxdate;
+ $next_placeholder = array_shift($placeholders);
+ $query->where[$group]['conditions'][$delta]['value'][$placeholder] = $date->format($format);
+ $count--;
}
}
}
@@ -230,4 +352,5 @@ class date_views_plugin_pager extends views_plugin_pager {
$pager_theme = views_theme_functions('date_views_pager', $this->view, $this->display);
return theme($pager_theme, array('plugin' => $this, 'input' => $input));
}
-}
\ No newline at end of file
+}
+// @codingStandardsIgnoreEnd
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_views/theme/date-views-pager.tpl.php b/profiles/commerce_kickstart/modules/contrib/date/date_views/theme/date-views-pager.tpl.php
index b12c2e1c..ac8cfb4e 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_views/theme/date-views-pager.tpl.php
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_views/theme/date-views-pager.tpl.php
@@ -27,8 +27,10 @@
* be used in the l() function, including rel=nofollow.
*/
?>
-
-
diff --git a/profiles/commerce_kickstart/modules/contrib/date/date_views/theme/theme.inc b/profiles/commerce_kickstart/modules/contrib/date/date_views/theme/theme.inc
index 8c42a527..7ca03f3a 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/date_views/theme/theme.inc
+++ b/profiles/commerce_kickstart/modules/contrib/date/date_views/theme/theme.inc
@@ -4,6 +4,7 @@
* @file
* Theme files for Date Pager.
*/
+
/**
* Jump in and move the pager.
*/
@@ -15,9 +16,11 @@ function date_views_preprocess_views_view(&$vars) {
$vars['header'] .= $vars['pager'];
$vars['pager'] = '';
break;
+
case 'both':
$vars['header'] .= $vars['pager'];
break;
+
default:
// Already on the bottom.
}
@@ -66,28 +69,37 @@ function template_preprocess_date_views_pager(&$vars) {
}
if (empty($date_info->hide_nav)) {
- $prev_date = clone($min_date);
- date_modify($prev_date, '-1 ' . $granularity);
- $next_date = clone($min_date);
- date_modify($next_date, '+1 ' . $granularity);
- $format = array('year' => 'Y', 'month' => 'Y-m', 'day' => 'Y-m-d');
- switch ($granularity) {
- case 'week':
- $next_week = date_week(date_format($next_date, 'Y-m-d'));
- $prev_week = date_week(date_format($prev_date, 'Y-m-d'));
- $next_arg = date_format($next_date, 'o-\W') . date_pad($next_week);
- $prev_arg = date_format($prev_date, 'o-\W') . date_pad($prev_week);
- break;
- default:
- $next_arg = date_format($next_date, $format[$granularity]);
- $prev_arg = date_format($prev_date, $format[$granularity]);
+ $prev_date = $date_info->prev_date;
+ $next_date = $date_info->next_date;
+
+ $format = array('year' => 'Y', 'month' => 'Y-m', 'day' => 'Y-m-d', 'hour' => 'Y-m-d\TH');
+ if (!empty($prev_date)) {
+ switch ($granularity) {
+ case 'week':
+ $prev_week = date_week(date_format($prev_date, 'Y-m-d'));
+ $prev_arg = date_format($prev_date, 'o-\W') . date_pad($prev_week);
+ break;
+ default:
+ $prev_arg = date_format($prev_date, $format[$granularity]);
+ }
+ $prev_path = str_replace($date_info->date_arg, $prev_arg, $date_info->url);
+ $prev_args[$pos] = $prev_arg;
+ $vars['prev_url'] = date_pager_url($view, NULL, $prev_arg);
}
- $next_path = str_replace($date_info->date_arg, $next_arg, $date_info->url);
- $prev_path = str_replace($date_info->date_arg, $prev_arg, $date_info->url);
- $next_args[$pos] = $next_arg;
- $prev_args[$pos] = $prev_arg;
- $vars['next_url'] = date_pager_url($view, NULL, $next_arg);
- $vars['prev_url'] = date_pager_url($view, NULL, $prev_arg);
+ if (!empty($next_date)) {
+ switch ($granularity) {
+ case 'week':
+ $next_week = date_week(date_format($next_date, 'Y-m-d'));
+ $next_arg = date_format($next_date, 'o-\W') . date_pad($next_week);
+ break;
+ default:
+ $next_arg = date_format($next_date, $format[$granularity]);
+ }
+ $next_path = str_replace($date_info->date_arg, $next_arg, $date_info->url);
+ $next_args[$pos] = $next_arg;
+ $vars['next_url'] = date_pager_url($view, NULL, $next_arg);
+ }
+
$vars['next_options'] = $vars['prev_options'] = array();
}
else {
@@ -117,14 +129,17 @@ function template_preprocess_date_views_pager(&$vars) {
$prev_title = t('Navigate to previous year');
$next_title = t('Navigate to next year');
break;
+
case 'month':
$prev_title = t('Navigate to previous month');
$next_title = t('Navigate to next month');
break;
+
case 'week':
$prev_title = t('Navigate to previous week');
$next_title = t('Navigate to next week');
break;
+
case 'day':
$prev_title = t('Navigate to previous day');
$next_title = t('Navigate to next day');
@@ -157,34 +172,44 @@ function template_preprocess_date_views_pager(&$vars) {
}
/**
- * Theme the calendar title
+ * Theme the calendar title.
*/
function theme_date_nav_title($params) {
+ $title = '';
$granularity = $params['granularity'];
$view = $params['view'];
$date_info = $view->date_info;
$link = !empty($params['link']) ? $params['link'] : FALSE;
$format = !empty($params['format']) ? $params['format'] : NULL;
- $format_with_year = variable_get('date_views_' . $granularity . 'format_with_year', 'l, F j, Y');
- $format_without_year = variable_get('date_views_' . $granularity . 'format_without_year', 'l, F j');
+ $format_with_year = variable_get('date_views_' . $granularity . '_format_with_year', 'l, F j, Y');
+ $format_without_year = variable_get('date_views_' . $granularity . '_format_without_year', 'l, F j');
switch ($granularity) {
case 'year':
$title = $date_info->year;
$date_arg = $date_info->year;
break;
+
case 'month':
$format = !empty($format) ? $format : (empty($date_info->mini) ? $format_with_year : $format_without_year);
$title = date_format_date($date_info->min_date, 'custom', $format);
$date_arg = $date_info->year . '-' . date_pad($date_info->month);
break;
+
case 'day':
$format = !empty($format) ? $format : (empty($date_info->mini) ? $format_with_year : $format_without_year);
$title = date_format_date($date_info->min_date, 'custom', $format);
- $date_arg = $date_info->year . '-' . date_pad($date_info->month) . '-' . date_pad($date_info->day);
+ $date_arg = $date_info->year;
+ $date_arg .= '-';
+ $date_arg .= date_pad($date_info->month);
+ $date_arg .= '-';
+ $date_arg .= date_pad($date_info->day);
break;
+
case 'week':
$format = !empty($format) ? $format : (empty($date_info->mini) ? $format_with_year : $format_without_year);
- $title = t('Week of @date', array('@date' => date_format_date($date_info->min_date, 'custom', $format)));
+ $title = t('Week of @date', array(
+ '@date' => date_format_date($date_info->min_date, 'custom', $format),
+ ));
$date_arg = $date_info->year . '-W' . date_pad($date_info->week);
break;
}
diff --git a/profiles/commerce_kickstart/modules/contrib/date/tests/date_api.test b/profiles/commerce_kickstart/modules/contrib/date/tests/date_api.test
index f50020c1..03c9081b 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/tests/date_api.test
+++ b/profiles/commerce_kickstart/modules/contrib/date/tests/date_api.test
@@ -132,11 +132,11 @@ class DateAPITestCase extends DrupalWebTestCase {
// Test week range with calendar weeks.
variable_set('date_first_day', 0);
variable_set('date_api_use_iso8601', FALSE);
- $expected = '2008-01-27 to 2008-02-03';
+ $expected = '2008-01-27 to 2008-02-02';
$result = date_week_range(5, 2008);
$value = $result[0]->format(DATE_FORMAT_DATE) . ' to ' . $result[1]->format(DATE_FORMAT_DATE);
$this->assertEqual($expected, $value, "Test calendar date_week_range(5, 2008): should be $expected, found $value.");
- $expected = '2009-01-25 to 2009-02-01';
+ $expected = '2009-01-25 to 2009-01-31';
$result = date_week_range(5, 2009);
$value = $result[0]->format(DATE_FORMAT_DATE) . ' to ' . $result[1]->format(DATE_FORMAT_DATE);
$this->assertEqual($expected, $value, "Test calendar date_week_range(5, 2009): should be $expected, found $value.");
@@ -144,11 +144,11 @@ class DateAPITestCase extends DrupalWebTestCase {
// And now with ISO weeks.
variable_set('date_first_day', 1);
variable_set('date_api_use_iso8601', TRUE);
- $expected = '2008-01-28 to 2008-02-04';
+ $expected = '2008-01-28 to 2008-02-03';
$result = date_week_range(5, 2008);
$value = $result[0]->format(DATE_FORMAT_DATE) . ' to ' . $result[1]->format(DATE_FORMAT_DATE);
$this->assertEqual($expected, $value, "Test ISO date_week_range(5, 2008): should be $expected, found $value.");
- $expected = '2009-01-26 to 2009-02-02';
+ $expected = '2009-01-26 to 2009-02-01';
$result = date_week_range(5, 2009);
$value = $result[0]->format(DATE_FORMAT_DATE) . ' to ' . $result[1]->format(DATE_FORMAT_DATE);
$this->assertEqual($expected, $value, "Test ISO date_week_range(5, 2009): should be $expected, found $value.");
@@ -393,9 +393,31 @@ class DateAPITestCase extends DrupalWebTestCase {
$input = '23 abc 2012';
$timezone = NULL;
$format = 'd M Y';
- $date = new dateObject($input, $timezone, $format);
+ $date = @new dateObject($input, $timezone, $format);
$this->assertNotEqual(count($date->errors), 0, '23 abc 2012 should be an invalid date');
+ // Test Granularity.
+ $input = '2005-06-01 10:30:45';
+ $timezone = NULL;
+ $format = 'Y-m-d H:i:s';
+
+ $date = new dateObject($input, $timezone, $format);
+ $date->removeGranularity('hour');
+ $date->removeGranularity('second');
+ $date->removeGranularity('minute');
+
+ $value = $date->format($format);
+ $expected = '2005-06-01';
+ $this->assertEqual($expected, $value, "The date with removed granularity should be $expected, found $value.");
+
+ $date->addGranularity('hour');
+ $date->addGranularity('second');
+ $date->addGranularity('minute');
+
+ $value = $date->format($format);
+ $expected = '2005-06-01 10:30:45';
+
+ $this->assertEqual($expected, $value, "The date with added granularity should be $expected, found $value.");
}
/**
diff --git a/profiles/commerce_kickstart/modules/contrib/date/tests/date_field.test b/profiles/commerce_kickstart/modules/contrib/date/tests/date_field.test
index b2a45a0d..b8aad594 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/tests/date_field.test
+++ b/profiles/commerce_kickstart/modules/contrib/date/tests/date_field.test
@@ -16,7 +16,7 @@ abstract class DateFieldBasic extends DrupalWebTestCase {
// Create and log in our privileged user.
$this->privileged_user = $this->drupalCreateUser(
- array('administer content types', 'administer nodes', 'bypass node access', 'administer date tools')
+ array('administer content types', 'administer nodes', 'bypass node access', 'administer date tools', 'administer fields')
);
$this->drupalLogin($this->privileged_user);
@@ -52,7 +52,7 @@ abstract class DateFieldBasic extends DrupalWebTestCase {
$repeat = !empty($repeat) ? $repeat : 0;
$todate = !empty($todate) ? $todate : 'optional';
$widget_type = !empty($widget_type) ? $widget_type : 'date_select';
- $tz_handling = !empty($tz_handing) ? $tz_handling : 'site';
+ $tz_handling = !empty($tz_handling) ? $tz_handling : 'site';
$granularity = !empty($granularity) ? $granularity : array('year', 'month', 'day', 'hour', 'minute');
$year_range = !empty($year_range) ? $year_range : '2010:+1';
$input_format = !empty($input_format) ? $input_format : date_default_format($widget_type);
@@ -151,6 +151,123 @@ abstract class DateFieldBasic extends DrupalWebTestCase {
}
+ /**
+ * Creates a date field from an array of settings values.
+ *
+ * All values have defaults, only need to specify values that need to be
+ * different.
+ */
+ protected function createMultiDateField($values = array()) {
+ extract($values);
+
+ $field_name = !empty($field_name) ? $field_name : 'field_test';
+ $entity_type = !empty($entity_type) ? $entity_type : 'node';
+ $bundle = !empty($bundle) ? $bundle : 'story';
+ $label = !empty($label) ? $label : 'Test';
+ $field_type = !empty($field_type) ? $field_type : 'datetime';
+ $repeat = !empty($repeat) ? $repeat : 0;
+ $todate = !empty($todate) ? $todate : 'optional';
+ $widget_type = !empty($widget_type) ? $widget_type : 'date_select';
+ $this->verbose(!empty($tz_handling));
+ $tz_handling = !empty($tz_handling) ? $tz_handling : 'site';
+ $granularity = !empty($granularity) ? $granularity : array('year', 'month', 'day', 'hour', 'minute');
+ $year_range = !empty($year_range) ? $year_range : '2010:+1';
+ $input_format = !empty($input_format) ? $input_format : date_default_format($widget_type);
+ $input_format_custom = !empty($input_format_custom) ? $input_format_custom : '';
+ $text_parts = !empty($text_parts) ? $text_parts : array();
+ $increment = !empty($increment) ? $increment : 15;
+ $default_value = !empty($default_value) ? $default_value : 'now';
+ $default_value2 = !empty($default_value2) ? $default_value2 : 'blank';
+ $default_format = !empty($default_format) ? $default_format : 'long';
+ $cache_enabled = !empty($cache_enabled);
+ $cache_count = !empty($cache_count) ? $cache_count : 4;
+ $cardinality = !empty($cardinality) ? $cardinality : 1;
+
+ $field = array(
+ 'field_name' => $field_name,
+ 'type' => $field_type,
+ 'cardinality' => $cardinality,
+ 'settings' => array(
+ 'granularity' => $granularity,
+ 'tz_handling' => $tz_handling,
+ 'timezone_db' => date_get_timezone_db($tz_handling),
+ 'repeat' => $repeat,
+ 'todate' => $todate,
+ 'cache_enabled' => $cache_enabled,
+ 'cache_count' => $cache_count,
+ ),
+ );
+ $instance = array(
+ 'entity_type' => $entity_type,
+ 'field_name' => $field_name,
+ 'label' => $label,
+ 'bundle' => $bundle,
+ // Move the date right below the title.
+ 'weight' => -4,
+ 'widget' => array(
+ 'type' => $widget_type,
+ // Increment for minutes and seconds, can be 1, 5, 10, 15, or 30.
+ 'settings' => array(
+ 'increment' => $increment,
+ // The number of years to go back and forward in drop-down year
+ // selectors.
+ 'year_range' => $year_range,
+ 'input_format' => $input_format,
+ 'input_format_custom' => $input_format_custom,
+ 'text_parts' => $text_parts,
+ 'label_position' => 'above',
+ 'repeat_collapsed' => 0,
+ ),
+ 'weight' => -4,
+ ),
+ 'settings' => array(
+ 'default_value' => $default_value,
+ 'default_value2' => $default_value2,
+ ),
+ );
+
+ $instance['display'] = array(
+ 'default' => array(
+ 'label' => 'above',
+ 'type' => 'date_default',
+ 'settings' => array(
+ 'format_type' => $default_format,
+ 'show_repeat_rule' => 'show',
+ 'multiple_number' => '',
+ 'multiple_from' => '',
+ 'multiple_to' => '',
+ 'fromto' => 'both',
+ ),
+ 'module' => 'date',
+ 'weight' => 0 ,
+ ),
+ 'teaser' => array(
+ 'label' => 'above',
+ 'type' => 'date_default',
+ 'weight' => 0,
+ 'settings' => array(
+ 'format_type' => $default_format,
+ 'show_repeat_rule' => 'show',
+ 'multiple_number' => '',
+ 'multiple_from' => '',
+ 'multiple_to' => '',
+ 'fromto' => 'both',
+ ),
+ 'module' => 'date',
+ ),
+ );
+
+ $field = field_create_field($field);
+ $instance = field_create_instance($instance);
+
+ field_info_cache_clear(TRUE);
+ field_cache_clear(TRUE);
+
+ // Look at how the field got configured.
+ $this->drupalGet("admin/structure/types/manage/$bundle/fields/$field_name");
+ $this->drupalGet("admin/structure/types/manage/$bundle/display");
+ }
+
/**
* @todo.
*/
diff --git a/profiles/commerce_kickstart/modules/contrib/date/tests/date_form.test b/profiles/commerce_kickstart/modules/contrib/date/tests/date_form.test
new file mode 100644
index 00000000..56b89e43
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/date/tests/date_form.test
@@ -0,0 +1,30 @@
+ t('Date Form test'),
+ 'description' => t('Test Date form functions.') ,
+ 'group' => t('Date'),
+ );
+ }
+
+ public function setUp() {
+ // Load the date_api module.
+ parent::setUp('date_test');
+ }
+
+ /**
+ * Tests rendering of a date element in a form.
+ */
+ public function testDateForm() {
+ $this->drupalGet('date-test/form');
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/date/tests/date_migrate.test b/profiles/commerce_kickstart/modules/contrib/date/tests/date_migrate.test
index cdde115f..ec2ae7d8 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/tests/date_migrate.test
+++ b/profiles/commerce_kickstart/modules/contrib/date/tests/date_migrate.test
@@ -18,6 +18,7 @@ class DateMigrateExampleUnitTest extends DrupalWebTestCase {
'name' => 'Date Migration',
'description' => 'Test migration into date fields',
'group' => 'Date',
+ 'dependencies' => array('migrate', 'features'),
);
}
diff --git a/profiles/commerce_kickstart/modules/contrib/date/tests/date_test/date_test.info b/profiles/commerce_kickstart/modules/contrib/date/tests/date_test/date_test.info
new file mode 100644
index 00000000..2f265fa7
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/date/tests/date_test/date_test.info
@@ -0,0 +1,14 @@
+name = "Date module tests"
+description = "Support module for date related testing."
+package = Date/Time
+version = VERSION
+core = 7.x
+hidden = TRUE
+dependencies[] = date
+
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
+core = "7.x"
+project = "date"
+datestamp = "1491562090"
+
diff --git a/profiles/commerce_kickstart/modules/contrib/date/tests/date_test/date_test.module b/profiles/commerce_kickstart/modules/contrib/date/tests/date_test/date_test.module
new file mode 100644
index 00000000..18540891
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/date/tests/date_test/date_test.module
@@ -0,0 +1,40 @@
+ 'Test form with date element',
+ 'description' => "Form with date element to make form related tests",
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('date_test_sample_form'),
+ 'access arguments' => array('access content'),
+ 'type' => MENU_CALLBACK,
+ );
+ return $items;
+}
+
+/**
+ * Form callback. Generates a test form with date elements.
+ */
+function date_test_sample_form($form, &$form_state) {
+ $form['date_test_select'] = array(
+ '#type' => 'date_select',
+ '#title' => t('Sample from'),
+ '#date_format' => 'H:i:s a',
+ '#default_value' => array(
+ 'hour' => 7,
+ 'minute' => 0,
+ 'second' => 0,
+ 'ampm' => 'am'
+ ),
+ );
+
+ return $form;
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/date/tests/date_timezone.test b/profiles/commerce_kickstart/modules/contrib/date/tests/date_timezone.test
index ddbdcef9..9f2905a2 100644
--- a/profiles/commerce_kickstart/modules/contrib/date/tests/date_timezone.test
+++ b/profiles/commerce_kickstart/modules/contrib/date/tests/date_timezone.test
@@ -16,6 +16,16 @@ class DateTimezoneTestCase extends DateFieldBasic {
);
}
+ public function setUp() {
+ parent::setUp();
+ // Set the timezone explicitly. Otherwise the site's default timezone is
+ // used, which defaults to the server timezone when installing Drupal. This
+ // depends on the environment and is therefore uncertain.
+ // The Australia/Sydney timezone is chosen so all tests are run using an
+ // edge case scenario (UTC+10 and DST).
+ variable_set('date_default_timezone', 'Australia/Sydney');
+ }
+
/**
* @todo.
*/
@@ -23,7 +33,7 @@ class DateTimezoneTestCase extends DateFieldBasic {
// Create a date fields with combinations of various timezone handling and
// granularity.
foreach (array('date', 'datestamp', 'datetime') as $field_type) {
- foreach (array('site', 'none', 'date', 'user', 'utc') as $tz_handling) {
+ foreach (array('site', 'none', 'date', 'user', 'utc', 'Europe/Dublin') as $tz_handling) {
foreach (array('year', 'month', 'day', 'hour', 'minute', 'second') as $max_granularity) {
// Skip invalid combinations.
if (in_array($max_granularity, array('year', 'month', 'day')) && $tz_handling != 'none') {
@@ -50,6 +60,111 @@ class DateTimezoneTestCase extends DateFieldBasic {
}
}
+ /**
+ * Validates timezone handling with a multi-value date field.
+ */
+ public function testMultiUserTimezone() {
+ // Create date fields with combinations of various types and granularity
+ // using the "Date's Timezone" strategy.
+ $field_type = 'datetime';
+ $tz_handling = 'date';
+ $max_granularity = 'minute';
+
+ // Create date field
+ $field_name = "field_test";
+ $label = 'Test';
+ $options = array(
+ 'label' => $label,
+ 'widget_type' => 'date_text',
+ 'field_name' => $field_name,
+ 'field_type' => $field_type,
+ 'input_format' => 'custom',
+ 'input_format_custom' => 'm/d/Y - H:i:s T',
+ 'cardinality' => 3,
+ 'tz_handling' => $tz_handling,
+ );
+ $this->createMultiDateField($options);
+
+ // Submit a date field form with multiple values
+ $this->dateMultiValueForm($field_name, $field_type, $max_granularity, $tz_handling);
+
+
+ $this->deleteDateField($label);
+ }
+
+ /**
+ * Tests the submission of a date field's widget form when using unlimited
+ * cardinality
+ */
+ public function dateMultiValueForm($field_name, $field_type, $max_granularity, $tz_handling) {
+ variable_set('date_format_long', 'D, m/d/Y - H:i:s T');
+
+ $edit = array();
+ $should_be = array();
+ $edit['title'] = $this->randomName(8);
+ $timezones = array('America/Chicago', 'America/Los_Angeles', 'America/New_York');
+
+ switch ($max_granularity) {
+ case 'hour':
+ $edit[$field_name . '[und][0][value][date]'] = '10/07/2010 - 10:30';
+ $edit[$field_name . '[und][0][timezone][timezone]'] = 'America/Chicago';
+ $should_be[0] = 'Thu, 10/07/2010 - 10 CDT';
+
+ $edit[$field_name . '[und][1][value][date]'] = '10/07/2010 - 10:30';
+ $edit[$field_name . '[und][1][timezone][timezone]'] = 'America/Los_Angeles';
+ $should_be[1] = 'Thu, 10/07/2010 - 10 PDT';
+
+ $edit[$field_name . '[und][2][value][date]'] = '10/07/2010 - 10:30';
+ $edit[$field_name . '[und][2][timezone][timezone]'] = 'America/New_York';
+ $should_be[2] = 'Thu, 10/07/2010 - 10 EDT';
+
+ break;
+ case 'minute':
+ $edit[$field_name . '[und][0][value][date]'] = '10/07/2010 - 10:30';
+ $edit[$field_name . '[und][0][timezone][timezone]'] = 'America/Chicago';
+ $should_be[0] = 'Thu, 10/07/2010 - 10:30 CDT';
+
+ $edit[$field_name . '[und][1][value][date]'] = '10/07/2010 - 10:30';
+ $edit[$field_name . '[und][1][timezone][timezone]'] = 'America/Los_Angeles';
+ $should_be[1] = 'Thu, 10/07/2010 - 10:30 PDT';
+
+ $edit[$field_name . '[und][2][value][date]'] = '10/07/2010 - 10:30';
+ $edit[$field_name . '[und][2][timezone][timezone]'] = 'America/New_York';
+ $should_be[2] = 'Thu, 10/07/2010 - 10:30 EDT';
+
+ break;
+ case 'second':
+ $edit[$field_name . '[und][0][value][date]'] = '10/07/2010 - 10:30';
+ $edit[$field_name . '[und][0][timezone][timezone]'] = 'America/Chicago';
+ $should_be[0] = 'Thu, 10/07/2010 - 10:30:30 CDT';
+
+ $edit[$field_name . '[und][1][value][date]'] = '10/07/2010 - 10:30';
+ $edit[$field_name . '[und][1][timezone][timezone]'] = 'America/Los_Angeles';
+ $should_be[1] = 'Thu, 10/07/2010 - 10:30:30 PDT';
+
+ $edit[$field_name . '[und][2][value][date]'] = '10/07/2010 - 10:30';
+ $edit[$field_name . '[und][2][timezone][timezone]'] = 'America/New_York';
+ $should_be[2] = 'Thu, 10/07/2010 - 10:30:30 EDT';
+ break;
+ }
+
+ $this->drupalPost('node/add/story', $edit, t('Save'));
+ $this->assertText($edit['title'], "Node has been created");
+
+ foreach ($should_be as $assertion) {
+ $this->assertText($assertion, "Found the correct date for a $field_type field using $max_granularity granularity with $tz_handling timezone handling.");
+ }
+
+ // Goto the edit page and save the node again.
+ $node = $this->drupalGetNodeByTitle($edit['title']);
+ $this->drupalGet('node/' . $node->nid . '/edit');
+
+ // Re-assert the proper date timezones.
+ foreach ($timezones as $key => $timezone) {
+ $this->assertOptionSelected('edit-field-test-und-' . $key . '-timezone-timezone', $timezone, "Found the correct timezone $timezone for a $field_type field using $max_granularity granularity with $tz_handling timezone handling.");
+ }
+ }
+
/**
* @todo.
*/
@@ -77,17 +192,32 @@ class DateTimezoneTestCase extends DateFieldBasic {
case 'hour':
$edit[$field_name . '[und][0][value][date]'] = '10/07/2010 - 10';
$edit[$field_name . '[und][0][value2][date]'] = '10/07/2010 - 11';
- $should_be = 'Thu, 10/07/2010 - 10 to Thu, 10/07/2010 - 11';
+ if ($tz_handling == 'utc') {
+ $should_be = 'Thu, 10/07/2010 - 21 to Thu, 10/07/2010 - 22';
+ }
+ else {
+ $should_be = 'Thu, 10/07/2010 - 10 to Thu, 10/07/2010 - 11';
+ }
break;
case 'minute':
$edit[$field_name . '[und][0][value][date]'] = '10/07/2010 - 10:30';
$edit[$field_name . '[und][0][value2][date]'] = '10/07/2010 - 11:30';
- $should_be = 'Thu, 10/07/2010 - 10:30 to 11:30';
+ if ($tz_handling == 'utc') {
+ $should_be = 'Thu, 10/07/2010 - 21:30 to 22:30';
+ }
+ else {
+ $should_be = 'Thu, 10/07/2010 - 10:30 to 11:30';
+ }
break;
case 'second':
$edit[$field_name . '[und][0][value][date]'] = '10/07/2010 - 10:30:30';
$edit[$field_name . '[und][0][value2][date]'] = '10/07/2010 - 11:30:30';
- $should_be = 'Thu, 10/07/2010 - 10:30:30 to 11:30:30';
+ if ($tz_handling == 'utc') {
+ $should_be = 'Thu, 10/07/2010 - 21:30:30 to 22:30:30';
+ }
+ else {
+ $should_be = 'Thu, 10/07/2010 - 10:30:30 to 11:30:30';
+ }
break;
}
$this->drupalPost('node/add/story', $edit, t('Save'));
diff --git a/profiles/commerce_kickstart/modules/contrib/date/tests/date_views_pager.test b/profiles/commerce_kickstart/modules/contrib/date/tests/date_views_pager.test
new file mode 100644
index 00000000..4f5dd97d
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/date/tests/date_views_pager.test
@@ -0,0 +1,129 @@
+ 'Date views pager skipping test',
+ 'description' => "Views date pager, option to skip empty pages test",
+ 'group' => 'Date',
+ );
+ }
+
+ /**
+ * Test setup actions.
+ */
+ public function setUp() {
+ // Load the 'date_views', 'views', 'views_ui', 'ctools' modules.
+ parent::setUp('date_views', 'views', 'views_ui', 'ctools');
+ // Set required permissions.
+ $permissions = array('administer views', 'administer site configuration');
+ // Create admin user and login.
+ $admin_user = $this->drupalCreateUser($permissions);
+ $this->drupalLogin($admin_user);
+
+ // Create a new view for test.
+ $view = new view();
+ $view->name = 'test_date_pager';
+ $view->description = '';
+ $view->tag = 'default';
+ $view->base_table = 'node';
+ $view->human_name = 'test_date_pager';
+ $view->core = 7;
+ $view->api_version = '3.0';
+ $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+
+ /* Display: Master */
+ $handler = $view->new_display('default', 'Master', 'default');
+ $handler->display->display_options['title'] = 'test_date_pager';
+ $handler->display->display_options['use_more_always'] = FALSE;
+ $handler->display->display_options['access']['type'] = 'perm';
+ $handler->display->display_options['cache']['type'] = 'none';
+ $handler->display->display_options['query']['type'] = 'views_query';
+ $handler->display->display_options['exposed_form']['type'] = 'basic';
+ $handler->display->display_options['pager']['type'] = 'date_views_pager';
+ $handler->display->display_options['pager']['options']['skip_empty_pages'] = 1;
+ $handler->display->display_options['style_plugin'] = 'default';
+ $handler->display->display_options['row_plugin'] = 'node';
+ /* Field: Content: Title */
+ $handler->display->display_options['fields']['title']['id'] = 'title';
+ $handler->display->display_options['fields']['title']['table'] = 'node';
+ $handler->display->display_options['fields']['title']['field'] = 'title';
+ $handler->display->display_options['fields']['title']['label'] = '';
+ $handler->display->display_options['fields']['title']['alter']['word_boundary'] = FALSE;
+ $handler->display->display_options['fields']['title']['alter']['ellipsis'] = FALSE;
+ /* Sort criterion: Content: Post date */
+ $handler->display->display_options['sorts']['created']['id'] = 'created';
+ $handler->display->display_options['sorts']['created']['table'] = 'node';
+ $handler->display->display_options['sorts']['created']['field'] = 'created';
+ $handler->display->display_options['sorts']['created']['order'] = 'DESC';
+ /* Contextual filter: Date: Date (node) */
+ $handler->display->display_options['arguments']['date_argument']['id'] = 'date_argument';
+ $handler->display->display_options['arguments']['date_argument']['table'] = 'node';
+ $handler->display->display_options['arguments']['date_argument']['field'] = 'date_argument';
+ $handler->display->display_options['arguments']['date_argument']['default_action'] = 'default';
+ $handler->display->display_options['arguments']['date_argument']['default_argument_type'] = 'date';
+ $handler->display->display_options['arguments']['date_argument']['summary']['format'] = 'default_summary';
+ $handler->display->display_options['arguments']['date_argument']['granularity'] = 'hour';
+ $handler->display->display_options['arguments']['date_argument']['date_fields'] = array(
+ 'node.created' => 'node.created',
+ );
+ /* Filter criterion: Content: Published */
+ $handler->display->display_options['filters']['status']['id'] = 'status';
+ $handler->display->display_options['filters']['status']['table'] = 'node';
+ $handler->display->display_options['filters']['status']['field'] = 'status';
+ $handler->display->display_options['filters']['status']['value'] = 1;
+ $handler->display->display_options['filters']['status']['group'] = 1;
+ $handler->display->display_options['filters']['status']['expose']['operator'] = FALSE;
+
+ /* Display: Page */
+ $handler = $view->new_display('page', 'Page', 'page_1');
+ $handler->display->display_options['path'] = 'test_date_pager';
+
+ $view->save();
+ }
+
+ /**
+ * Test pager skipping.
+ */
+ public function testPagerSkipping() {
+ // Go to view admin page.
+ $this->drupalGet('admin/structure/views/view/display/test_date_pager/edit');
+ // Go to pager options.
+ $this->drupalGet('admin/structure/views/nojs/display/test_date_pager/default/pager_options');
+ // Check if "Skip empty pages" text - exist.
+ $this->assertText('Skip empty pages');
+ // Check if field and it's value is correct.
+ $this->assertFieldByName('pager_options[skip_empty_pages]', '1');
+ // Go back to view admin page.
+ $this->drupalGet('admin/structure/views/view/display/test_date_pager/edit');
+ // Check if pager on empty page are gone.
+ $this->assertNoText('« Prev', 'Previous pager does not exist');
+ $this->assertNoText('Next »', 'Next pager does not exist');
+ }
+
+ /**
+ * Test the view page has no PHP warnings.
+ */
+ public function testPagerWarning() {
+ $this->drupalCreateNode(array('type' => 'blog'));
+ // Set pager to skip empty pages.
+ $edit = array(
+ 'pager_options[skip_empty_pages]' => FALSE,
+ );
+ $this->drupalPost('admin/structure/views/nojs/display/test_date_pager/default/pager_options', $edit, t('Apply'));
+ // Save the view.
+ $this->drupalPost('admin/structure/views/view/test_date_pager/edit', array(), t('Save'));
+
+ // Visit view page. This will throw error, if any PHP warnings or errors.
+ $this->drupalGet('test_date_pager');
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/date/tests/date_views_popup.test b/profiles/commerce_kickstart/modules/contrib/date/tests/date_views_popup.test
new file mode 100644
index 00000000..e3d4306d
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/date/tests/date_views_popup.test
@@ -0,0 +1,106 @@
+ 'Date Views - Popup Test',
+ 'description' => 'Tests date popup in Views',
+ 'group' => 'Date',
+ );
+ }
+
+ /**
+ * Test setup actions.
+ */
+ public function setUp() {
+ parent::setUp();
+ // Load the 'date_popup', 'date_views', 'views', 'views_ui', 'ctools' modules.
+ $modules = array('date_popup', 'date_views', 'views', 'views_ui', 'ctools');
+ $success = module_enable($modules, TRUE);
+ $this->assertTrue($success, t('Enabled modules: %modules', array('%modules' => implode(', ', $modules))));
+
+ // Reset/rebuild all data structures after enabling the modules.
+ $this->resetAll();
+
+ // Create a date field.
+ $field_name = "field_test_date_popup";
+ $label = 'Test';
+ $options = array(
+ 'label' => 'Test',
+ 'widget_type' => 'date_popup',
+ 'field_name' => $field_name,
+ 'field_type' => 'datetime',
+ 'input_format' => 'm/d/Y - H:i',
+ );
+ $this->createDateField($options);
+
+ // Set required permissions.
+ $permissions = array('administer views', 'administer site configuration');
+ // Create admin user and login.
+ $admin_user = $this->drupalCreateUser($permissions);
+ $this->drupalLogin($admin_user);
+
+ // Create the view.
+ $view = new view();
+ $view->name = 'test_date_popup';
+ $view->description = '';
+ $view->tag = 'default';
+ $view->base_table = 'node';
+ $view->human_name = 'Test date_popup';
+ $view->core = 7;
+ $view->api_version = '3.0';
+ $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+
+ /* Display: Master */
+ $handler = $view->new_display('default', 'Master', 'default');
+ $handler->display->display_options['title'] = 'test_date_popup_page';
+ $handler->display->display_options['use_more_always'] = FALSE;
+ $handler->display->display_options['access']['type'] = 'perm';
+ $handler->display->display_options['cache']['type'] = 'none';
+ $handler->display->display_options['query']['type'] = 'views_query';
+ $handler->display->display_options['exposed_form']['type'] = 'basic';
+ $handler->display->display_options['pager']['type'] = 'none';
+ $handler->display->display_options['pager']['options']['offset'] = '0';
+ $handler->display->display_options['style_plugin'] = 'default';
+ $handler->display->display_options['row_plugin'] = 'node';
+ /* Field: Content: Title */
+ $handler->display->display_options['fields']['title']['id'] = 'title';
+ $handler->display->display_options['fields']['title']['table'] = 'node';
+ $handler->display->display_options['fields']['title']['field'] = 'title';
+ $handler->display->display_options['fields']['title']['label'] = '';
+ $handler->display->display_options['fields']['title']['alter']['word_boundary'] = FALSE;
+ $handler->display->display_options['fields']['title']['alter']['ellipsis'] = FALSE;
+ /* Filter criterion: Content: test_date_popup (field_test_date_popup) */
+ $handler->display->display_options['filters']['field_test_date_popup_value']['id'] = 'field_test_date_popup_value';
+ $handler->display->display_options['filters']['field_test_date_popup_value']['table'] = 'field_data_field_test_date_popup';
+ $handler->display->display_options['filters']['field_test_date_popup_value']['field'] = 'field_test_date_popup_value';
+ $handler->display->display_options['filters']['field_test_date_popup_value']['exposed'] = TRUE;
+ $handler->display->display_options['filters']['field_test_date_popup_value']['expose']['operator_id'] = 'field_test_date_popup_value_op';
+ $handler->display->display_options['filters']['field_test_date_popup_value']['expose']['label'] = 'test_date_popup (field_test_date_popup)';
+ $handler->display->display_options['filters']['field_test_date_popup_value']['expose']['operator'] = 'field_test_date_popup_value_op';
+ $handler->display->display_options['filters']['field_test_date_popup_value']['expose']['identifier'] = 'field_test_date_popup_value';
+ $handler->display->display_options['filters']['field_test_date_popup_value']['form_type'] = 'date_popup';
+
+ /* Display: Page */
+ $handler = $view->new_display('page', 'Page', 'page');
+ $handler->display->display_options['path'] = 'test-date-popup';
+
+ $view->save();
+ }
+
+ /**
+ * Test date popup.
+ */
+ public function testDatePopup() {
+ // Go to view page.
+ $this->drupalGet('test-date-popup');
+ }
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/README.txt b/profiles/commerce_kickstart/modules/contrib/entity/README.txt
index ed048e42..745dd7fe 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/README.txt
+++ b/profiles/commerce_kickstart/modules/contrib/entity/README.txt
@@ -11,7 +11,15 @@ entity CRUD controller, which helps simplifying the creation of new entity types
This is an API module. You only need to enable it if a module depends on it or
you are interested in using it for development.
-This README is for interested developers. If you are not interested in
+Advanced usage:
+---------------
+You can optimize cache clearing performance by setting the variable
+'entity_rebuild_on_flush' to FALSE. This skips rebuilding of feature
+components and exported entities during cache flushing. Instead, it is triggered
+by the features module only; e.g., when features are reverted.
+
+
+The README below is for interested developers. If you are not interested in
developing, you may stop reading now.
--------------------------------------------------------------------------------
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/ctools/relationships/entity_property.inc b/profiles/commerce_kickstart/modules/contrib/entity/ctools/relationships/entity_property.inc
new file mode 100644
index 00000000..6869146f
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/entity/ctools/relationships/entity_property.inc
@@ -0,0 +1,153 @@
+ t('Entity property or field (via Entity Metadata Wrapper)'),
+ 'description' => t('Creates any kind of context for entity properties and fields.'),
+ 'context' => 'entity_entity_property_context',
+ 'required context' => new ctools_context_required(t('Entity'), 'entity'),
+ 'edit form' => 'entity_entity_property_edit_form',
+ 'edit form validate' => 'entity_entity_property_edit_form_validate',
+ 'defaults' => array(
+ 'selector' => '',
+ 'target_context' => 'entity',
+ 'concatenator' => ','
+ ),
+);
+
+/**
+ * Return a new context based on an existing context.
+ */
+function entity_entity_property_context($context, $conf) {
+ $plugin = $conf['name'];
+
+ // If unset it wants a generic, unfilled context, which is just NULL.
+ if (empty($context->data)) {
+ return ctools_context_create_empty(isset($conf['target_context']) ? $conf['target_context'] : 'entity', NULL);
+ }
+
+ list($part1, $entity_type) = explode(':', $context->plugin);
+
+ if (isset($context->data) && $entity = $context->data) {
+ // Apply the selector.
+ $wrapper = entity_metadata_wrapper($entity_type, $entity);
+ $parts = explode(':', $conf['selector']);
+
+ try {
+ foreach ($parts as $part) {
+ if (!($wrapper instanceof EntityStructureWrapper || $wrapper instanceof EntityListWrapper)) {
+ $wrapper = NULL;
+ $value = NULL;
+ continue;
+ }
+ $wrapper = $wrapper->get($part);
+ }
+ }
+ catch (EntityMetadataWrapperException $e) {
+ $wrapper = NULL;
+ $value = NULL;
+ }
+
+ if (isset($wrapper)) {
+ $value = $wrapper->value();
+ }
+
+ // Massage list values.
+ if ($wrapper instanceof EntityListWrapper) {
+ $value = $wrapper[0]->value();
+ $argument = implode($conf['concatenator'], $wrapper->value(array('identifier' => TRUE)));
+ }
+ elseif ($wrapper instanceof EntityDrupalWrapper) {
+ $argument = $wrapper->getIdentifier();
+ }
+
+ // Bail out if we were unable to retrieve the value.
+ if (!isset($value)) {
+ return ctools_context_create_empty(isset($conf['target_context']) ? $conf['target_context'] : 'entity', NULL);
+ }
+
+ $context = ctools_context_create($conf['target_context'], $value);
+ // Provide a suiting argument if context is used as argument.
+ if (isset($argument)) {
+ $context->argument = $argument;
+ }
+ return $context;
+ }
+}
+
+function entity_entity_property_edit_form($form, &$form_state) {
+ $conf = $form_state['conf'];
+
+ $form['selector'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Data selector'),
+ '#description' => t('Any valid data selector, e.g. "title" to select a node\'s title, or "field_tags:1" to select the second tag.'),
+ '#default_value' => $conf['selector'],
+ '#required' => TRUE,
+ );
+ $form['concatenator'] = array(
+ '#title' => t('Concatenator (if multiple)'),
+ '#type' => 'select',
+ '#options' => array(',' => ', (AND)', '+' => '+ (OR)'),
+ '#default_value' => $conf['concatenator'],
+ '#prefix' => '
',
+ '#suffix' => '
',
+ '#description' => t("When the resulting value is multiple valued and the context is passed on to a view as argument, the value can be concatenated in the form of 1+2+3 (for OR) or 1,2,3 (for AND)."),
+ );
+ return $form;
+}
+
+function entity_entity_property_edit_form_validate($form, &$form_state) {
+ $context_key = $form_state['values']['context'];
+ $context = $form_state['contexts'][$context_key];
+ $entity_type = $context->type[2];
+
+ try {
+ $all_properties = entity_get_all_property_info($entity_type);
+ $wrapper = entity_metadata_wrapper($entity_type, NULL, array('property info' => $all_properties));
+ $parts = explode(':', $form_state['values']['selector']);
+ foreach ($parts as $part) {
+ if (!($wrapper instanceof EntityStructureWrapper || $wrapper instanceof EntityListWrapper)) {
+ form_set_error('selector', t('Unable to apply the data selector part %key.'. array('%key' => $part)));
+ continue;
+ }
+ $wrapper = $wrapper->get($part);
+ }
+ $type = entity_entity_property_map_data_type($wrapper->type());
+ $form_state['conf']['target_context'] = $type;
+ }
+ catch (EntityMetadataWrapperException $e) {
+ form_set_error('selector', t('Unable to apply the data selector on entity type %type. @reason', array('@reason' => $e->getMessage(), '%type' => $entity_type)));
+ }
+
+ // Auto-generate a sane identifier.
+ if ($form_state['values']['identifier'] == $form['identifier']['#default_value']) {
+ $form_state['values']['identifier'] = 'Entity property ' . $entity_type . ':' . check_plain($form_state['values']['selector']);
+ }
+}
+
+/**
+ * Maps an entity-property data type to ctools types.
+ */
+function entity_entity_property_map_data_type($type) {
+ // Remove list<> wrappers from types.
+ while ($item_type = entity_property_list_extract_type($type)) {
+ $type = $item_type;
+ }
+ // Massage data type of entites to c
+ if (entity_get_info($type)) {
+ $type = "entity:$type";
+ }
+ if ($type == 'text') {
+ $type = 'string';
+ }
+ return $type;
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/entity.features.inc b/profiles/commerce_kickstart/modules/contrib/entity/entity.features.inc
index e266aaf5..0ec3e618 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/entity.features.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entity/entity.features.inc
@@ -7,6 +7,12 @@
/**
* Returns the configured entity features controller.
+ *
+ * @param string $type
+ * The entity type to get the controller for.
+ *
+ * @return EntityDefaultFeaturesController
+ * The configured entity features controller.
*/
function entity_features_get_controller($type) {
$static = &drupal_static(__FUNCTION__);
@@ -85,6 +91,7 @@ class EntityDefaultFeaturesController {
$fields = field_info_instances($this->info['bundle of'], $entity->{$this->bundleKey});
foreach ($fields as $name => $field) {
$pipe['field'][] = "{$field['entity_type']}-{$field['bundle']}-{$field['field_name']}";
+ $pipe['field_instance'][] = "{$field['entity_type']}-{$field['bundle']}-{$field['field_name']}";
}
}
}
@@ -125,9 +132,7 @@ class EntityDefaultFeaturesController {
*/
function revert($module = NULL) {
if ($defaults = features_get_default($this->type, $module)) {
- foreach ($defaults as $name => $entity) {
- entity_delete($this->type, $name);
- }
+ entity_delete_multiple($this->type, array_keys($defaults));
}
}
}
@@ -146,6 +151,8 @@ function entity_features_api() {
}
/**
+ * Implements hook_features_export_options().
+ *
* Features component callback.
*/
function entity_features_export_options($a1, $a2 = NULL) {
@@ -157,6 +164,8 @@ function entity_features_export_options($a1, $a2 = NULL) {
}
/**
+ * Implements hook_features_export().
+ *
* Features component callback.
*/
function entity_features_export($data, &$export, $module_name = '', $entity_type) {
@@ -164,6 +173,8 @@ function entity_features_export($data, &$export, $module_name = '', $entity_type
}
/**
+ * Implements hook_features_export_render().
+ *
* Features component callback.
*/
function entity_features_export_render($module, $data, $export = NULL, $entity_type) {
@@ -171,8 +182,23 @@ function entity_features_export_render($module, $data, $export = NULL, $entity_t
}
/**
+ * Implements hook_features_revert().
+ *
* Features component callback.
*/
function entity_features_revert($module = NULL, $entity_type) {
return entity_features_get_controller($entity_type)->revert($module);
}
+
+/**
+ * Implements hook_features_post_restore().
+ *
+ * Rebuild all defaults when a features rebuild is triggered - even the ones not
+ * handled by features itself.
+ */
+function entity_features_post_restore($op, $items = array()) {
+ if ($op == 'rebuild') {
+ // Use features rebuild to rebuild the features independent exports too.
+ entity_defaults_rebuild();
+ }
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/entity.info b/profiles/commerce_kickstart/modules/contrib/entity/entity.info
index ff88ce54..0b865a04 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/entity.info
+++ b/profiles/commerce_kickstart/modules/contrib/entity/entity.info
@@ -25,9 +25,9 @@ files[] = views/handlers/entity_views_handler_field_uri.inc
files[] = views/handlers/entity_views_handler_relationship_by_bundle.inc
files[] = views/handlers/entity_views_handler_relationship.inc
files[] = views/plugins/entity_views_plugin_row_entity_view.inc
-; Information added by Drupal.org packaging script on 2015-02-25
-version = "7.x-1.6"
+; Information added by Drupal.org packaging script on 2018-02-14
+version = "7.x-1.9"
core = "7.x"
project = "entity"
-datestamp = "1424876582"
+datestamp = "1518620551"
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/entity.install b/profiles/commerce_kickstart/modules/contrib/entity/entity.install
index f6f8cc2f..118820b8 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/entity.install
+++ b/profiles/commerce_kickstart/modules/contrib/entity/entity.install
@@ -13,6 +13,14 @@ function entity_enable() {
entity_entitycache_installed_modules();
}
+/**
+ * Implements hook_uninstall().
+ */
+function entity_uninstall() {
+ // Delete variables.
+ variable_del('entity_rebuild_on_flush');
+}
+
/**
* The entity API modules have been merged into a single module.
*/
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/entity.module b/profiles/commerce_kickstart/modules/contrib/entity/entity.module
index d4a882cd..da0acf69 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/entity.module
+++ b/profiles/commerce_kickstart/modules/contrib/entity/entity.module
@@ -184,8 +184,17 @@ function entity_ui_entity_page_view($entity) {
* Gets the page title for the passed operation.
*/
function entity_ui_get_page_title($op, $entity_type, $entity = NULL) {
- module_load_include('inc', 'entity', 'includes/entity.ui');
- $label = entity_label($entity_type, $entity);
+ if (isset($entity)) {
+ module_load_include('inc', 'entity', 'includes/entity.ui');
+ $label = entity_label($entity_type, $entity);
+ list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+ }
+ else {
+ $info = entity_get_info($entity_type);
+ $label = $info['label'];
+ $bundle = NULL;
+ }
+
switch ($op) {
case 'view':
return $label;
@@ -200,12 +209,7 @@ function entity_ui_get_page_title($op, $entity_type, $entity = NULL) {
case 'export':
return t('Export @label', array('@label' => $label));
}
- if (isset($entity)) {
- list(, , $bundle) = entity_extract_ids($entity_type, $entity);
- }
- else {
- $bundle = NULL;
- }
+
return entity_ui_get_action_title($op, $entity_type, $bundle);
}
@@ -600,7 +604,7 @@ function entity_id($entity_type, $entity) {
* content language of the current request.
* @param $page
* (optional) If set will control if the entity is rendered: if TRUE
- * the entity will be rendered without its title, so that it can be embeded
+ * the entity will be rendered without its title, so that it can be embedded
* in another context. If FALSE the entity will be displayed with its title
* in a mode suitable for lists.
* If unset, the page mode will be enabled if the current path is the URI
@@ -1076,16 +1080,18 @@ function entity_flush_caches() {
// case of enabling or disabling modules we already rebuild defaults in
// entity_modules_enabled() and entity_modules_disabled(), so we do not need
// to do it again.
- if (current_path() != 'admin/modules/list/confirm') {
+ // Also check if rebuilding on cache flush is explicitly disabled.
+ if (current_path() != 'admin/modules/list/confirm' && variable_get('entity_rebuild_on_flush', TRUE)) {
entity_defaults_rebuild();
}
// Care about entitycache tables.
if (module_exists('entitycache')) {
$tables = array();
- foreach (entity_crud_get_info() as $entity_type => $entity_info) {
- if (isset($entity_info['module']) && !empty($entity_info['entity cache'])) {
- $tables[] = 'cache_entity_' . $entity_type;
+ $tables_created = variable_get('entity_cache_tables_created');
+ if (is_array($tables_created)) {
+ foreach ($tables_created as $module => $entity_cache_tables) {
+ $tables = array_merge($tables, $entity_cache_tables);
}
}
return $tables;
@@ -1372,7 +1378,7 @@ function entity_get_extra_fields_controller($type = NULL) {
* Returns a property wrapper for the given data.
*
* If an entity is wrapped, the wrapper can be used to retrieve further wrappers
- * for the entitity properties. For that the wrapper support chaining, e.g. you
+ * for the entity properties. For that the wrapper support chaining, e.g. you
* can use a node wrapper to get the node authors mail address:
*
* @code
@@ -1563,7 +1569,7 @@ function _entity_info_add_metadata(&$entity_info) {
* Implements hook_ctools_plugin_directory().
*/
function entity_ctools_plugin_directory($module, $plugin) {
- if ($module == 'ctools' && $plugin == 'content_types') {
- return 'ctools/content_types';
+ if ($module == 'ctools') {
+ return "ctools/$plugin";
}
}
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/entity.test b/profiles/commerce_kickstart/modules/contrib/entity/entity.test
index 03c2551a..fd8cea12 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/entity.test
+++ b/profiles/commerce_kickstart/modules/contrib/entity/entity.test
@@ -1342,6 +1342,74 @@ class EntityMetadataNodeRevisionAccessTestCase extends DrupalWebTestCase {
}
}
+/**
+ * Tests basic entity_access() functionality for taxonomy terms.
+ */
+class EntityMetadataTaxonomyAccessTestCase extends EntityWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Entity Metadata Taxonomy Access',
+ 'description' => 'Test entity_access() for taxonomy terms',
+ 'group' => 'Entity API',
+ );
+ }
+
+ /**
+ * Asserts entity_access() correctly grants or denies access.
+ */
+ function assertTaxonomyMetadataAccess($ops, $term, $account) {
+ foreach ($ops as $op => $result) {
+ $msg = t("entity_access() returns @result with operation '@op'.", array('@result' => $result ? 'TRUE' : 'FALSE', '@op' => $op));
+ $access = entity_access($op, 'taxonomy_term', $term, $account);
+ $this->assertEqual($result, $access, $msg);
+ }
+ }
+
+ /**
+ * @inheritdoc
+ */
+ function setUp() {
+ parent::setUp('entity', 'taxonomy');
+ // Clear permissions for authenticated users.
+ db_delete('role_permission')
+ ->condition('rid', DRUPAL_AUTHENTICATED_RID)
+ ->execute();
+ }
+
+ /**
+ * Runs basic tests for entity_access() function.
+ */
+ function testTaxonomyMetadataAccess() {
+ $vocab = $this->createVocabulary();
+ $term = entity_property_values_create_entity('taxonomy_term', array(
+ 'name' => $this->randomName(),
+ 'vocabulary' => $vocab,
+ ))->save()->value();
+ // Clear permissions static cache to get new taxonomy permissions.
+ drupal_static_reset('checkPermissions');
+
+ // Check assignment of view permissions.
+ $user1 = $this->drupalCreateUser(array('access content'));
+ $this->assertTaxonomyMetadataAccess(array('create' => FALSE, 'view' => TRUE, 'update' => FALSE, 'delete' => FALSE), $term, $user1);
+
+ // Check assignment of edit permissions.
+ $user2 = $this->drupalCreateUser(array('edit terms in ' . $vocab->vid));
+ $this->assertTaxonomyMetadataAccess(array('create' => FALSE, 'view' => FALSE, 'update' => TRUE, 'delete' => FALSE), $term, $user2);
+
+ // Check assignment of delete permissions.
+ $user3 = $this->drupalCreateUser(array('delete terms in ' . $vocab->vid));
+ $this->assertTaxonomyMetadataAccess(array('create' => FALSE, 'view' => FALSE, 'update' => FALSE, 'delete' => TRUE), $term, $user3);
+
+ // Check assignment of view, edit, delete permissions.
+ $user4 = $this->drupalCreateUser(array('access content', 'edit terms in ' . $vocab->vid, 'delete terms in ' . $vocab->vid));
+ $this->assertTaxonomyMetadataAccess(array('create' => FALSE, 'view' => TRUE, 'update' => TRUE, 'delete' => TRUE), $term, $user4);
+
+ // Check assignment of administration permissions.
+ $user5 = $this->drupalCreateUser(array('administer taxonomy'));
+ $this->assertTaxonomyMetadataAccess(array('create' => TRUE, 'view' => TRUE, 'update' => TRUE, 'delete' => TRUE), $term, $user5);
+ }
+}
+
/**
* Tests provided entity property info of the core modules.
*/
@@ -1466,6 +1534,7 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase {
$book = array('bid' => $node->nid, 'plid' => $node->book['mlid']);
$node2 = $this->drupalCreateNode(array('type' => 'book', 'book' => $book));
$node3 = $this->drupalCreateNode(array('type' => 'page'));
+ $node4 = $this->drupalCreateNode(array('type' => 'book', 'book' => array('bid' => 0, 'plid' => -1)));
// Test whether the properties work.
$wrapper = entity_metadata_wrapper('node', $node2);
@@ -1477,6 +1546,10 @@ class EntityMetadataIntegrationTestCase extends EntityWebTestCase {
$wrapper = entity_metadata_wrapper('node', $node3);
$this->assertEmpty($wrapper, 'book');
$this->assertEmptyArray($wrapper, 'book_ancestors');
+
+ // Test a book node which is not contained in a hierarchy.
+ $wrapper = entity_metadata_wrapper('node', $node4);
+ $this->assertEmptyArray($wrapper, 'book_ancestors');
}
/**
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/entity_token.info b/profiles/commerce_kickstart/modules/contrib/entity/entity_token.info
index b579ced1..c59c6502 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/entity_token.info
+++ b/profiles/commerce_kickstart/modules/contrib/entity/entity_token.info
@@ -5,9 +5,9 @@ files[] = entity_token.tokens.inc
files[] = entity_token.module
dependencies[] = entity
-; Information added by Drupal.org packaging script on 2015-02-25
-version = "7.x-1.6"
+; Information added by Drupal.org packaging script on 2018-02-14
+version = "7.x-1.9"
core = "7.x"
project = "entity"
-datestamp = "1424876582"
+datestamp = "1518620551"
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.controller.inc b/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.controller.inc
index f675a63a..5e86b529 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.controller.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.controller.inc
@@ -107,7 +107,7 @@ interface EntityAPIControllerInterface extends DrupalEntityControllerInterface {
* content language of the current request.
* @param $page
* (optional) If set will control if the entity is rendered: if TRUE
- * the entity will be rendered without its title, so that it can be embeded
+ * the entity will be rendered without its title, so that it can be embedded
* in another context. If FALSE the entity will be displayed with its title
* in a mode suitable for lists.
* If unset, the page mode will be enabled if the current path is the URI
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.inc b/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.inc
index be24499d..2f504f36 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.inc
@@ -5,6 +5,168 @@
* Provides a base class for entities.
*/
+/**
+ * Interface for class based entities.
+ */
+interface EntityInterface {
+
+ /**
+ * Returns the internal, numeric identifier.
+ *
+ * Returns the numeric identifier, even if the entity type has specified a
+ * name key. In the latter case, the numeric identifier is supposed to be used
+ * when dealing generically with entities or internally to refer to an entity,
+ * i.e. in a relational database. If unsure, use Entity:identifier().
+ */
+ public function internalIdentifier();
+
+ /**
+ * Returns the entity identifier, i.e. the entities name or numeric id.
+ *
+ * @return
+ * The identifier of the entity. If the entity type makes use of a name key,
+ * the name is returned, else the numeric id.
+ *
+ * @see entity_id()
+ */
+ public function identifier();
+
+ /**
+ * Returns the info of the type of the entity.
+ *
+ * @see entity_get_info()
+ */
+ public function entityInfo();
+
+ /**
+ * Returns the type of the entity.
+ */
+ public function entityType();
+
+ /**
+ * Returns the bundle of the entity.
+ *
+ * @return
+ * The bundle of the entity. Defaults to the entity type if the entity type
+ * does not make use of different bundles.
+ */
+ public function bundle();
+
+ /**
+ * Returns the EntityMetadataWrapper of the entity.
+ *
+ * @return EntityDrupalWrapper
+ * An EntityMetadataWrapper containing the entity.
+ */
+ public function wrapper();
+
+ /**
+ * Returns the label of the entity.
+ *
+ * Modules may alter the label by specifying another 'label callback' using
+ * hook_entity_info_alter().
+ *
+ * @see entity_label()
+ */
+ public function label();
+
+ /**
+ * Returns the uri of the entity just as entity_uri().
+ *
+ * Modules may alter the uri by specifying another 'uri callback' using
+ * hook_entity_info_alter().
+ *
+ * @see entity_uri()
+ */
+ public function uri();
+
+ /**
+ * Checks if the entity has a certain exportable status.
+ *
+ * @param $status
+ * A status constant, i.e. one of ENTITY_CUSTOM, ENTITY_IN_CODE,
+ * ENTITY_OVERRIDDEN or ENTITY_FIXED.
+ *
+ * @return bool
+ * For exportable entities TRUE if the entity has the status, else FALSE.
+ * In case the entity is not exportable, NULL is returned.
+ *
+ * @see entity_has_status()
+ */
+ public function hasStatus($status);
+
+ /**
+ * Permanently saves the entity.
+ *
+ * @see entity_save()
+ */
+ public function save();
+
+ /**
+ * Permanently deletes the entity.
+ *
+ * @see entity_delete()
+ */
+ public function delete();
+
+ /**
+ * Exports the entity.
+ *
+ * @see entity_export()
+ */
+ public function export($prefix = '');
+
+ /**
+ * Generate an array for rendering the entity.
+ *
+ * @see entity_view()
+ */
+ public function view($view_mode = 'full', $langcode = NULL, $page = NULL);
+
+ /**
+ * Builds a structured array representing the entity's content.
+ *
+ * @see entity_build_content()
+ */
+ public function buildContent($view_mode = 'full', $langcode = NULL);
+
+ /**
+ * Gets the raw, translated value of a property or field.
+ *
+ * Supports retrieving field translations as well as i18n string translations.
+ *
+ * Note that this returns raw data values, which might not reflect what
+ * has been declared for hook_entity_property_info() as no 'getter callbacks'
+ * are invoked or no referenced entities are loaded. For retrieving values
+ * reflecting the property info make use of entity metadata wrappers, see
+ * entity_metadata_wrapper().
+ *
+ * @param $property
+ * The name of the property to return; e.g., 'title'.
+ * @param $langcode
+ * (optional) The language code of the language to which the value should
+ * be translated. If set to NULL, the default display language is being
+ * used.
+ *
+ * @return
+ * The raw, translated property value; or the raw, un-translated value if no
+ * translation is available.
+ *
+ * @todo Implement an analogous setTranslation() method for updating.
+ */
+ public function getTranslation($property, $langcode = NULL);
+
+ /**
+ * Checks whether the entity is the default revision.
+ *
+ * @return Boolean
+ *
+ * @see entity_revision_is_default()
+ */
+ public function isDefaultRevision();
+
+}
+
/**
* A common class for entities.
*
@@ -25,7 +187,7 @@
* public $count = 0;
* @endcode
*/
-class Entity {
+class Entity implements EntityInterface {
protected $entityType;
protected $entityInfo;
@@ -34,9 +196,7 @@ class Entity {
protected $wrapper;
/**
- * Creates a new entity.
- *
- * @see entity_create()
+ * {@inheritdoc}
*/
public function __construct(array $values = array(), $entityType = NULL) {
if (empty($entityType)) {
@@ -61,62 +221,42 @@ class Entity {
}
/**
- * Returns the internal, numeric identifier.
- *
- * Returns the numeric identifier, even if the entity type has specified a
- * name key. In the latter case, the numeric identifier is supposed to be used
- * when dealing generically with entities or internally to refer to an entity,
- * i.e. in a relational database. If unsure, use Entity:identifier().
+ * {@inheritdoc}
*/
public function internalIdentifier() {
return isset($this->{$this->idKey}) ? $this->{$this->idKey} : NULL;
}
/**
- * Returns the entity identifier, i.e. the entities name or numeric id.
- *
- * @return
- * The identifier of the entity. If the entity type makes use of a name key,
- * the name is returned, else the numeric id.
- *
- * @see entity_id()
+ * {@inheritdoc}
*/
public function identifier() {
return isset($this->{$this->nameKey}) ? $this->{$this->nameKey} : NULL;
}
/**
- * Returns the info of the type of the entity.
- *
- * @see entity_get_info()
+ * {@inheritdoc}
*/
public function entityInfo() {
return $this->entityInfo;
}
/**
- * Returns the type of the entity.
+ * {@inheritdoc}
*/
public function entityType() {
return $this->entityType;
}
/**
- * Returns the bundle of the entity.
- *
- * @return
- * The bundle of the entity. Defaults to the entity type if the entity type
- * does not make use of different bundles.
+ * {@inheritdoc}
*/
public function bundle() {
return !empty($this->entityInfo['entity keys']['bundle']) ? $this->{$this->entityInfo['entity keys']['bundle']} : $this->entityType;
}
/**
- * Returns the EntityMetadataWrapper of the entity.
- *
- * @return EntityDrupalWrapper
- * An EntityMetadataWrapper containing the entity.
+ * {@inheritdoc}
*/
public function wrapper() {
if (empty($this->wrapper)) {
@@ -130,12 +270,7 @@ class Entity {
}
/**
- * Returns the label of the entity.
- *
- * Modules may alter the label by specifying another 'label callback' using
- * hook_entity_info_alter().
- *
- * @see entity_label()
+ * {@inheritdoc}
*/
public function label() {
// If the default label flag is enabled, this is being invoked recursively.
@@ -165,12 +300,7 @@ class Entity {
}
/**
- * Returns the uri of the entity just as entity_uri().
- *
- * Modules may alter the uri by specifying another 'uri callback' using
- * hook_entity_info_alter().
- *
- * @see entity_uri()
+ * {@inheritdoc}
*/
public function uri() {
if (isset($this->entityInfo['uri callback']) && $this->entityInfo['uri callback'] == 'entity_class_uri') {
@@ -188,17 +318,7 @@ class Entity {
}
/**
- * Checks if the entity has a certain exportable status.
- *
- * @param $status
- * A status constant, i.e. one of ENTITY_CUSTOM, ENTITY_IN_CODE,
- * ENTITY_OVERRIDDEN or ENTITY_FIXED.
- *
- * @return
- * For exportable entities TRUE if the entity has the status, else FALSE.
- * In case the entity is not exportable, NULL is returned.
- *
- * @see entity_has_status()
+ * {@inheritdoc}
*/
public function hasStatus($status) {
if (!empty($this->entityInfo['exportable'])) {
@@ -207,18 +327,14 @@ class Entity {
}
/**
- * Permanently saves the entity.
- *
- * @see entity_save()
+ * {@inheritdoc}
*/
public function save() {
return entity_get_controller($this->entityType)->save($this);
}
/**
- * Permanently deletes the entity.
- *
- * @see entity_delete()
+ * {@inheritdoc}
*/
public function delete() {
$id = $this->identifier();
@@ -228,55 +344,28 @@ class Entity {
}
/**
- * Exports the entity.
- *
- * @see entity_export()
+ * {@inheritdoc}
*/
public function export($prefix = '') {
return entity_get_controller($this->entityType)->export($this, $prefix);
}
/**
- * Generate an array for rendering the entity.
- *
- * @see entity_view()
+ * {@inheritdoc}
*/
public function view($view_mode = 'full', $langcode = NULL, $page = NULL) {
return entity_get_controller($this->entityType)->view(array($this), $view_mode, $langcode, $page);
}
/**
- * Builds a structured array representing the entity's content.
- *
- * @see entity_build_content()
+ * {@inheritdoc}
*/
public function buildContent($view_mode = 'full', $langcode = NULL) {
return entity_get_controller($this->entityType)->buildContent($this, $view_mode, $langcode);
}
/**
- * Gets the raw, translated value of a property or field.
- *
- * Supports retrieving field translations as well as i18n string translations.
- *
- * Note that this returns raw data values, which might not reflect what
- * has been declared for hook_entity_property_info() as no 'getter callbacks'
- * are invoked or no referenced entities are loaded. For retrieving values
- * reflecting the property info make use of entity metadata wrappers, see
- * entity_metadata_wrapper().
- *
- * @param $property_name
- * The name of the property to return; e.g., 'title'.
- * @param $langcode
- * (optional) The language code of the language to which the value should
- * be translated. If set to NULL, the default display language is being
- * used.
- *
- * @return
- * The raw, translated property value; or the raw, un-translated value if no
- * translation is available.
- *
- * @todo Implement an analogous setTranslation() method for updating.
+ * {@inheritdoc}
*/
public function getTranslation($property, $langcode = NULL) {
$all_info = entity_get_all_property_info($this->entityType);
@@ -296,11 +385,7 @@ class Entity {
}
/**
- * Checks whether the entity is the default revision.
- *
- * @return Boolean
- *
- * @see entity_revision_is_default()
+ * {@inheritdoc}
*/
public function isDefaultRevision() {
if (!empty($this->entityInfo['entity keys']['revision'])) {
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.property.inc b/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.property.inc
index 38e4fd7b..e8714e67 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.property.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.property.inc
@@ -69,7 +69,7 @@ function entity_property_info_defaults() {
* (optiona) The entity type to return properties for.
*
* @return
- * An array of info about properties. If the type is ommitted, all known
+ * An array of info about properties. If the type is omitted, all known
* properties are returned.
*/
function entity_get_all_property_info($entity_type = NULL) {
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.ui.inc b/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.ui.inc
index 1826da40..24e3c2b9 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.ui.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.ui.inc
@@ -127,8 +127,8 @@ class EntityDefaultUIController {
* Use per bundle form ids if possible, such that easy per bundle alterations
* are supported too.
*
- * Note that for performance reasons, this method is only invoked for forms,
- * which receive the entity_type as first argument. Thus any forms added, must
+ * Note that for performance reasons, this method is invoked only for forms
+ * which receive the entity_type as first argument. Thus any forms added must
* follow that pattern.
*
* @see entity_forms()
@@ -645,7 +645,7 @@ function entity_ui_operation_form($form, &$form_state, $entity_type, $entity, $o
*/
function entity_ui_main_form_defaults($form, &$form_state, $entity = NULL, $op = NULL) {
// Now equals entity_ui_form_defaults() but is still here to keep backward
- // compatability.
+ // compatibility.
return entity_ui_form_defaults($form, $form_state, $form_state['entity_type'], $entity, $op);
}
@@ -760,7 +760,7 @@ function entity_ui_validate_machine_name($element, &$form_state) {
function theme_entity_ui_overview_item($variables) {
$output = $variables['url'] ? l($variables['label'], $variables['url']['path'], $variables['url']['options']) : check_plain($variables['label']);
if ($variables['name']) {
- $output .= ' (' . t('Machine name') . ': ' . check_plain($variables['name']) . ')';
+ $output .= ' (' . t('Machine name') . ': ' . check_plain($variables['name']) . ')';
}
return $output;
}
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.wrapper.inc b/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.wrapper.inc
index 06b89adf..860d2c33 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.wrapper.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entity/includes/entity.wrapper.inc
@@ -119,7 +119,11 @@ abstract class EntityMetadataWrapper {
*/
public function set($value) {
if (!$this->validate($value)) {
- throw new EntityMetadataWrapperException('Invalid data value given. Be sure it matches the required data type and format.');
+ throw new EntityMetadataWrapperException(t('Invalid data value given. Be sure it matches the required data type and format. Value at !location: !value.', array(
+ // An exception's message is output through check_plain().
+ '!value' => is_array($value) || is_object($value) ? var_export($value, TRUE) : $value,
+ '!location' => $this->debugIdentifierLocation(),
+ )));
}
$this->clear();
$this->data = $value;
@@ -231,6 +235,21 @@ abstract class EntityMetadataWrapper {
return !empty($this->info['parent']) ? $this->info['parent']->propertyAccess($this->info['name'], $op, $account) : TRUE;
}
+ /**
+ * Returns a string to use to identify this wrapper in error messages.
+ *
+ * @return
+ * A string that identifies this wrapper and its chain of ancestors, of the
+ * form 'grandparentidentifier->parentidentifier->identifier'.
+ */
+ public function debugIdentifierLocation() {
+ $debug = $this->info['name'];
+ if (isset($this->info['parent'])) {
+ $debug = $this->info['parent']->debugIdentifierLocation() . '->' . $debug;
+ }
+ return $debug;
+ }
+
/**
* Prepare for serializiation.
*/
@@ -734,7 +753,11 @@ class EntityDrupalWrapper extends EntityStructureWrapper {
*/
public function set($value) {
if (!$this->validate($value)) {
- throw new EntityMetadataWrapperException('Invalid data value given. Be sure it matches the required data type and format.');
+ throw new EntityMetadataWrapperException(t('Invalid data value given. Be sure it matches the required data type and format. Value at !location: !value.', array(
+ // An exception's message is output through check_plain().
+ '!value' => is_array($value) || is_object($value) ? var_export($value, TRUE) : $value,
+ '!location' => $this->debugIdentifierLocation(),
+ )));
}
if ($this->info['type'] == 'entity' && $value === $this) {
// Nothing to do.
@@ -821,7 +844,12 @@ class EntityDrupalWrapper extends EntityStructureWrapper {
}
else {
// This is not a property, so fallback on entity access.
- return $this->entityAccess($op == 'edit' ? 'update' : 'view', $account);
+ if ($op == 'edit') {
+ // If the operation is "edit" determine if its actually a "create" for
+ // new un-saved entities, or an "update" for existing ones.
+ return $this->entityAccess($this->getIdentifier() ? 'update' : 'create', $account);
+ }
+ return $this->entityAccess('view', $account);
}
}
@@ -909,6 +937,27 @@ class EntityDrupalWrapper extends EntityStructureWrapper {
}
}
+ /**
+ * Returns a string to use to identify this wrapper in error messages.
+ */
+ public function debugIdentifierLocation() {
+ // An entity wrapper can be at the top of the chain or a part of it.
+ if (isset($this->info['name'])) {
+ // This wrapper is part of a chain, eg in the position node->author.
+ // Return the name.
+ $debug = $this->info['name'];
+ }
+ else {
+ // This is a wrapper for an actual entity: return its type and id.
+ $debug = $this->info['type'] . '(' . $this->getIdentifier() . ')';
+ }
+
+ if (isset($this->info['parent'])) {
+ $debug = $this->info['parent']->debugIdentifierLocation() . '->' . $debug;
+ }
+ return $debug;
+ }
+
/**
* Prepare for serializiation.
*/
@@ -1067,7 +1116,7 @@ class EntityListWrapper extends EntityMetadataWrapper implements IteratorAggrega
*/
public function getIterator() {
// In case there is no data available, just iterate over the first item.
- return new EntityMetadataWrapperIterator($this, $this->dataAvailable() ? array_keys(parent::value()) : array(0));
+ return new EntityMetadataWrapperIterator($this, ($this->dataAvailable() && is_array(parent::value())) ? array_keys(parent::value()) : array(0));
}
/**
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/modules/callbacks.inc b/profiles/commerce_kickstart/modules/contrib/entity/modules/callbacks.inc
index 26f802e6..ee156ab3 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/modules/callbacks.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entity/modules/callbacks.inc
@@ -29,7 +29,7 @@ function entity_metadata_book_get_properties($node, array $options, $name, $enti
case 'book_ancestors':
$ancestors = array();
- while (!empty($node->book['plid'])) {
+ while (!empty($node->book['plid']) && $node->book['plid'] != -1) {
$link = book_link_load($node->book['plid']);
array_unshift($ancestors, $link['nid']);
$node = node_load($link['nid']);
@@ -670,9 +670,11 @@ function entity_metadata_field_file_validate_item($items, $context) {
function entity_metadata_no_hook_node_access($op, $node = NULL, $account = NULL) {
// First deal with the case where a $node is provided.
if (isset($node)) {
- if ($op == 'create') {
+ if (empty($node->vid) && in_array($op, array('create', 'update'))) {
+ // This is a new node or the original node.
if (isset($node->type)) {
- return node_access($op, $node->type, $account);
+ $op = empty($node->nid) || !empty($node->is_new) ? 'create' : 'update';
+ return node_access($op, $op == 'create' ? $node->type : $node, $account);
}
else {
throw new EntityMalformedException('Permission to create a node was requested but no node type was given.');
@@ -796,14 +798,35 @@ function entity_metadata_comment_properties_access($op, $property, $entity = NUL
* Access callback for the taxonomy entities.
*/
function entity_metadata_taxonomy_access($op, $entity = NULL, $account = NULL, $entity_type = NULL) {
- if ($entity_type == 'taxonomy_vocabulary') {
- return user_access('administer taxonomy', $account);
- }
- if (isset($entity) && $op == 'update' && !isset($account) && taxonomy_term_edit_access($entity)) {
+ // If user has administer taxonomy permission then no further checks.
+ if (user_access('administer taxonomy', $account)) {
return TRUE;
}
- if (user_access('administer taxonomy', $account) || user_access('access content', $account) && $op == 'view') {
- return TRUE;
+ switch ($op) {
+ case "view":
+ if (user_access('access content', $account)) {
+ return TRUE;
+ }
+ break;
+ case "update":
+ if ($entity_type == 'taxonomy_term') {
+ return user_access("edit terms in $entity->vid", $account);
+ }
+ break;
+ case "create":
+ if ($entity_type == 'taxonomy_term') {
+ // Check for taxonomy_access_fix contrib module which adds additional
+ // permissions to create new terms in a given vocabulary.
+ if (function_exists('taxonomy_access_fix_access')) {
+ return taxonomy_access_fix_access('add terms', $entity->vocabulary_machine_name);
+ }
+ }
+ break;
+ case "delete":
+ if ($entity_type == 'taxonomy_term') {
+ return user_access("delete terms in $entity->vid", $account);
+ }
+ break;
}
return FALSE;
}
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/modules/node.info.inc b/profiles/commerce_kickstart/modules/contrib/entity/modules/node.info.inc
index 3512d9a0..f146a7e8 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/modules/node.info.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entity/modules/node.info.inc
@@ -163,4 +163,10 @@ function entity_metadata_node_entity_property_info_alter(&$info) {
'auto creation' => 'entity_property_create_array',
'field' => TRUE,
);
+
+ // Make it a list if cardinality is not 1.
+ $field_body = field_info_field('body');
+ if (isset($field_body) && $field_body['cardinality'] != 1) {
+ $info['node']['properties']['body']['type'] = 'list';
+ }
}
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/tests/entity_feature.info b/profiles/commerce_kickstart/modules/contrib/entity/tests/entity_feature.info
index 80d2a908..524fdfaf 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/tests/entity_feature.info
+++ b/profiles/commerce_kickstart/modules/contrib/entity/tests/entity_feature.info
@@ -6,9 +6,9 @@ files[] = entity_feature.module
dependencies[] = entity_test
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-02-25
-version = "7.x-1.6"
+; Information added by Drupal.org packaging script on 2018-02-14
+version = "7.x-1.9"
core = "7.x"
project = "entity"
-datestamp = "1424876582"
+datestamp = "1518620551"
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/tests/entity_test.info b/profiles/commerce_kickstart/modules/contrib/entity/tests/entity_test.info
index d34326c9..b7cceabf 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/tests/entity_test.info
+++ b/profiles/commerce_kickstart/modules/contrib/entity/tests/entity_test.info
@@ -7,9 +7,9 @@ files[] = entity_test.install
dependencies[] = entity
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-02-25
-version = "7.x-1.6"
+; Information added by Drupal.org packaging script on 2018-02-14
+version = "7.x-1.9"
core = "7.x"
project = "entity"
-datestamp = "1424876582"
+datestamp = "1518620551"
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/tests/entity_test.module b/profiles/commerce_kickstart/modules/contrib/entity/tests/entity_test.module
index 55855688..727797ae 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/tests/entity_test.module
+++ b/profiles/commerce_kickstart/modules/contrib/entity/tests/entity_test.module
@@ -2,7 +2,7 @@
/**
* @file
- * Test moduel for the entity API.
+ * Test module for the entity API.
*/
/**
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/tests/entity_test_i18n.info b/profiles/commerce_kickstart/modules/contrib/entity/tests/entity_test_i18n.info
index 8adf04af..4ca048af 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/tests/entity_test_i18n.info
+++ b/profiles/commerce_kickstart/modules/contrib/entity/tests/entity_test_i18n.info
@@ -5,9 +5,9 @@ dependencies[] = i18n_string
package = Multilingual - Internationalization
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-02-25
-version = "7.x-1.6"
+; Information added by Drupal.org packaging script on 2018-02-14
+version = "7.x-1.9"
core = "7.x"
project = "entity"
-datestamp = "1424876582"
+datestamp = "1518620551"
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/theme/entity.theme.inc b/profiles/commerce_kickstart/modules/contrib/entity/theme/entity.theme.inc
index 9238dfdb..fc0ba7c1 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/theme/entity.theme.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entity/theme/entity.theme.inc
@@ -80,9 +80,12 @@ function template_preprocess_entity_property(&$variables, $hook) {
);
// Populate the content with sensible defaults.
- if (!isset($variables['content'])) {
+ if (!isset($element['#content'])) {
$variables['content'] = entity_property_default_render_value_by_type($element['#entity_wrapped']->{$element['#property_name']});
}
+ else {
+ $variables['content'] = $element['#content'];
+ }
}
/**
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/views/entity.views.inc b/profiles/commerce_kickstart/modules/contrib/entity/views/entity.views.inc
index 59ebaa48..a0179c0c 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/views/entity.views.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entity/views/entity.views.inc
@@ -605,6 +605,28 @@ class EntityDefaultViewsController {
);
break;
+ case 'duration':
+ $return += $description + array(
+ 'field' => array(
+ 'real field' => $views_field_name,
+ 'handler' => 'entity_views_handler_field_duration',
+ 'click sortable' => TRUE,
+ ),
+ 'sort' => array(
+ 'real field' => $views_field_name,
+ 'handler' => 'views_handler_sort',
+ ),
+ 'filter' => array(
+ 'real field' => $views_field_name,
+ 'handler' => 'views_handler_filter_numeric',
+ ),
+ 'argument' => array(
+ 'real field' => $views_field_name,
+ 'handler' => 'views_handler_argument_numeric',
+ ),
+ );
+ break;
+
case 'uri':
$return += $description + array(
'field' => array(
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/views/handlers/entity_views_field_handler_helper.inc b/profiles/commerce_kickstart/modules/contrib/entity/views/handlers/entity_views_field_handler_helper.inc
index 0077f4a3..6bb4fbff 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/views/handlers/entity_views_field_handler_helper.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entity/views/handlers/entity_views_field_handler_helper.inc
@@ -18,7 +18,7 @@ class EntityFieldHandlerHelper {
* Provide appropriate default options for a handler.
*/
public static function option_definition($handler) {
- if (entity_property_list_extract_type($handler->definition['type'])) {
+ if (isset($handler->definition['type']) && entity_property_list_extract_type($handler->definition['type'])) {
$options['list']['contains']['mode'] = array('default' => 'collapse');
$options['list']['contains']['separator'] = array('default' => ', ');
$options['list']['contains']['type'] = array('default' => 'ul');
@@ -32,7 +32,7 @@ class EntityFieldHandlerHelper {
* Provide an appropriate default option form for a handler.
*/
public static function options_form($handler, &$form, &$form_state) {
- if (entity_property_list_extract_type($handler->definition['type'])) {
+ if (isset($handler->definition['type']) && entity_property_list_extract_type($handler->definition['type'])) {
$form['list']['mode'] = array(
'#type' => 'select',
'#title' => t('List handling'),
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/views/handlers/entity_views_handler_area_entity.inc b/profiles/commerce_kickstart/modules/contrib/entity/views/handlers/entity_views_handler_area_entity.inc
index f3746942..0c5b7143 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/views/handlers/entity_views_handler_area_entity.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entity/views/handlers/entity_views_handler_area_entity.inc
@@ -40,7 +40,7 @@ class entity_views_handler_area_entity extends views_handler_area {
$form['entity_id'] = array(
'#type' => 'textfield',
'#title' => t('Entity id'),
- '#description' => t('Choose the entity you want to display in the area.'),
+ '#description' => t('Choose the entity you want to display in the area. To render an entity given by a contextual filter use "%1" for the first argument, "%2" for the second, etc.'),
'#default_value' => $this->options['entity_id'],
);
@@ -105,6 +105,9 @@ class entity_views_handler_area_entity extends views_handler_area {
* Render an entity using the view mode.
*/
public function render_entity($entity_type, $entity_id, $view_mode) {
+ $tokens = $this->get_render_tokens();
+ // Replace argument tokens in entity id.
+ $entity_id = strtr($entity_id, $tokens);
if (!empty($entity_type) && !empty($entity_id) && !empty($view_mode)) {
$entity = entity_load_single($entity_type, $entity_id);
if (!empty($this->options['bypass_access']) || entity_access('view', $entity_type, $entity)) {
@@ -117,4 +120,31 @@ class entity_views_handler_area_entity extends views_handler_area {
return '';
}
}
+
+ /**
+ * Get the 'render' tokens to use for advanced rendering.
+ *
+ * This runs through all of the fields and arguments that
+ * are available and gets their values. This will then be
+ * used in one giant str_replace().
+ */
+ function get_render_tokens() {
+ $tokens = array();
+ if (!empty($this->view->build_info['substitutions'])) {
+ $tokens = $this->view->build_info['substitutions'];
+ }
+ $count = 0;
+ foreach ($this->view->display_handler->get_handlers('argument') as $arg => $handler) {
+ $token = '%' . ++$count;
+ if (!isset($tokens[$token])) {
+ $tokens[$token] = '';
+ }
+ // Use strip tags as there should never be HTML in the path.
+ // However, we need to preserve special characters like " that
+ // were removed by check_plain().
+ $tokens['%' . $count] = $handler->argument;
+ }
+
+ return $tokens;
+ }
}
diff --git a/profiles/commerce_kickstart/modules/contrib/entity/views/plugins/entity_views_plugin_row_entity_view.inc b/profiles/commerce_kickstart/modules/contrib/entity/views/plugins/entity_views_plugin_row_entity_view.inc
index db72b5f5..5e738a8c 100644
--- a/profiles/commerce_kickstart/modules/contrib/entity/views/plugins/entity_views_plugin_row_entity_view.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entity/views/plugins/entity_views_plugin_row_entity_view.inc
@@ -88,6 +88,9 @@ class entity_views_plugin_row_entity_view extends views_plugin_row {
public function render($values) {
if ($entity = $this->get_value($values)) {
+ // Add the view object as views_plugin_row_node_view::render() would.
+ // Otherwise the views theme suggestions won't work properly.
+ $entity->view = $this->view;
$render = $this->rendered_content[entity_id($this->entity_type, $entity)];
return drupal_render($render);
}
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/LICENSE.txt b/profiles/commerce_kickstart/modules/contrib/entityreference/LICENSE.txt
old mode 100755
new mode 100644
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/PATCHES.txt b/profiles/commerce_kickstart/modules/contrib/entityreference/PATCHES.txt
deleted file mode 100644
index 70a44c35..00000000
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/PATCHES.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-The following patches have been applied to this project:
-- http://drupal.org/files/1580348-universal-formatters-17.patch
-
-This file was automatically generated by Drush Make (http://drupal.org/project/drush).
\ No newline at end of file
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.devel_generate.inc b/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.devel_generate.inc
index f6ab0144..fab46dda 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.devel_generate.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.devel_generate.inc
@@ -19,9 +19,13 @@ function _entityreference_devel_generate($object, $field, $instance, $bundle) {
// Get all the entity that are referencable here.
$referencable_entity = entityreference_get_selection_handler($field, $instance)->getReferencableEntities();
if (is_array($referencable_entity) && !empty($referencable_entity)) {
- // Get a random key.
- foreach ($referencable_entity as $type => $eids) {
- $object_field['target_id'] = array_rand($eids);
+ // $referencable_entity is keyed by bundle type.
+ $random_bundle = array_rand($referencable_entity);
+ if (!empty($random_bundle)) {
+ $target_id = array_rand($referencable_entity[$random_bundle]);
+ if (!empty($referencable_entity[$random_bundle][$target_id])) {
+ $object_field['target_id'] = $target_id;
+ }
}
}
return $object_field;
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.feeds.inc b/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.feeds.inc
index 3f641415..3da1479c 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.feeds.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.feeds.inc
@@ -125,10 +125,15 @@ function entityreference_feeds_set_target($source, $entity, $target, $value) {
break;
case 'label':
$options = $handler->getReferencableEntities($value, '=');
- $options = reset($options);
- $etids = array_keys($options);
- // Use the first matching entity.
- $entity_id = reset($etids);
+ if ($options) {
+ $options = reset($options);
+ $etids = array_keys($options);
+ // Use the first matching entity.
+ $entity_id = reset($etids);
+ }
+ else {
+ $entity_id = NULL;
+ }
break;
}
/*
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.info b/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.info
index d6348ef5..5b2a0f74 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.info
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.info
@@ -1,18 +1,23 @@
name = Entity Reference
description = Provides a field that can reference other entities.
-core = 7.x
package = Fields
+core = 7.x
+
dependencies[] = entity
dependencies[] = ctools
+test_dependencies[] = feeds
+test_dependencies[] = views
+
; Migrate handler.
files[] = entityreference.migrate.inc
-; Our plugins interfaces and abstract implementations.
+; Plugins interfaces and abstract implementations.
files[] = plugins/selection/abstract.inc
files[] = plugins/selection/views.inc
files[] = plugins/behavior/abstract.inc
+; Views integration.
files[] = views/entityreference_plugin_display.inc
files[] = views/entityreference_plugin_style.inc
files[] = views/entityreference_plugin_row_fields.inc
@@ -22,10 +27,11 @@ files[] = tests/entityreference.handlers.test
files[] = tests/entityreference.taxonomy.test
files[] = tests/entityreference.admin.test
files[] = tests/entityreference.feeds.test
+files[] = tests/entityreference.entity_translation.test
-; Information added by packaging script on 2013-11-20
-version = "7.x-1.1"
+; Information added by Drupal.org packaging script on 2017-08-16
+version = "7.x-1.5"
core = "7.x"
project = "entityreference"
-datestamp = "1384973110"
+datestamp = "1502895850"
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.install b/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.install
index 4e248efd..ce610185 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.install
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.install
@@ -41,6 +41,7 @@ function entityreference_field_schema($field) {
}
// Invoke the behaviors to allow them to change the schema.
+ module_load_include('module', 'entityreference');
foreach (entityreference_get_behavior_handlers($field) as $handler) {
$handler->schema_alter($schema, $field);
}
@@ -161,4 +162,29 @@ function entityreference_update_7002() {
'not null' => TRUE,
));
}
-}
\ No newline at end of file
+}
+
+/**
+ * Implements hook_update_N().
+ *
+ * Remove duplicate rows in the taxonomy_index table.
+ */
+function entityreference_update_7100() {
+ if (db_table_exists('taxonomy_index')) {
+ if (db_table_exists('taxonomy_index_tmp')) {
+ db_drop_table('taxonomy_index_tmp');
+ }
+
+ $tx_schema = drupal_get_schema('taxonomy_index');
+ db_create_table('taxonomy_index_tmp', $tx_schema);
+ $select = db_select('taxonomy_index', 'tx');
+ $select->fields('tx', array('nid', 'tid'));
+ $select->groupBy('tx.nid');
+ $select->groupBy('tx.tid');
+ $select->addExpression('MAX(sticky)', 'sticky');
+ $select->addExpression('MAX(created)', 'created');
+ db_insert('taxonomy_index_tmp')->from($select)->execute();
+ db_drop_table('taxonomy_index');
+ db_rename_table('taxonomy_index_tmp', 'taxonomy_index');
+ }
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.migrate.inc b/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.migrate.inc
index 0e95bf0a..35737b52 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.migrate.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.migrate.inc
@@ -1,12 +1,11 @@
'target_id',
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.module b/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.module
index 2c026ac3..c0c9f58f 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.module
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/entityreference.module
@@ -1,5 +1,12 @@
array(
+ 'variables' => array('label' => NULL, 'item' => NULL, 'settings' => NULL, 'uri' => NULL),
+ ),
+ 'entityreference_entity_id' => array(
+ 'variables' => array('item' => NULL, 'settings' => NULL),
+ ),
+ );
+}
+
/**
* Implements hook_menu().
*/
@@ -163,7 +184,7 @@ function entityreference_get_behavior_handlers($field, $instance = NULL) {
/**
* Get the behavior handler for a given entityreference field and instance.
*
- * @param $handler
+ * @param $behavior
* The behavior handler name.
*/
function _entityreference_get_behavior_handler($behavior) {
@@ -220,13 +241,15 @@ function entityreference_field_validate($entity_type, $entity, $field, $instance
if ($ids) {
$valid_ids = entityreference_get_selection_handler($field, $instance, $entity_type, $entity)->validateReferencableEntities(array_keys($ids));
- $invalid_entities = array_diff_key($ids, array_flip($valid_ids));
- if ($invalid_entities) {
- foreach ($invalid_entities as $id => $delta) {
- $errors[$field['field_name']][$langcode][$delta][] = array(
- 'error' => 'entityreference_invalid_entity',
- 'message' => t('The referenced entity (@type: @id) is invalid.', array('@type' => $field['settings']['target_type'], '@id' => $id)),
- );
+ if (!empty($valid_ids)) {
+ $invalid_entities = array_diff_key($ids, array_flip($valid_ids));
+ if ($invalid_entities) {
+ foreach ($invalid_entities as $id => $delta) {
+ $errors[$field['field_name']][$langcode][$delta][] = array(
+ 'error' => 'entityreference_invalid_entity',
+ 'message' => t('The referenced entity (@type: @id) is invalid.', array('@type' => $field['settings']['target_type'], '@id' => $id)),
+ );
+ }
}
}
}
@@ -398,6 +421,9 @@ function entityreference_field_settings_form($field, $instance, $has_data) {
return $form;
}
+/**
+ * Callback for custom element processing.
+ */
function _entityreference_field_settings_process($form, $form_state) {
$field = isset($form_state['entityreference']['field']) ? $form_state['entityreference']['field'] : $form['#field'];
$instance = isset($form_state['entityreference']['instance']) ? $form_state['entityreference']['instance'] : $form['#instance'];
@@ -479,11 +505,17 @@ function _entityreference_field_settings_process($form, $form_state) {
return $form;
}
+/**
+ * Custom callback for ajax processing.
+ */
function _entityreference_field_settings_ajax_process($form, $form_state) {
_entityreference_field_settings_ajax_process_element($form, $form);
return $form;
}
+/**
+ * Helper function for custom ajax processing.
+ */
function _entityreference_field_settings_ajax_process_element(&$element, $main_form) {
if (isset($element['#ajax']) && $element['#ajax'] === TRUE) {
$element['#ajax'] = array(
@@ -498,6 +530,9 @@ function _entityreference_field_settings_ajax_process_element(&$element, $main_f
}
}
+/**
+ * Custom callback for element processing.
+ */
function _entityreference_form_process_merge_parent($element) {
$parents = $element['#parents'];
array_pop($parents);
@@ -505,11 +540,17 @@ function _entityreference_form_process_merge_parent($element) {
return $element;
}
+/**
+ * Helper function to remove blank elements.
+ */
function _entityreference_element_validate_filter(&$element, &$form_state) {
$element['#value'] = array_filter($element['#value']);
form_set_value($element, $element['#value'], $form_state);
}
+/**
+ * Implements hook_validate().
+ */
function _entityreference_field_settings_validate($form, &$form_state) {
// Store the new values in the form state.
$field = $form['#field'];
@@ -545,6 +586,9 @@ function entityreference_field_instance_settings_form($field, $instance) {
return $form;
}
+/**
+ * Implements hook_field_settings_form().
+ */
function _entityreference_field_instance_settings_form($form, $form_state) {
$field = isset($form_state['entityreference']['field']) ? $form_state['entityreference']['field'] : $form['#field'];
$instance = isset($form_state['entityreference']['instance']) ? $form_state['entityreference']['instance'] : $form['#instance'];
@@ -562,6 +606,9 @@ function _entityreference_field_instance_settings_form($form, $form_state) {
return $form;
}
+/**
+ * Implements hook_validate().
+ */
function _entityreference_field_instance_settings_validate($form, &$form_state) {
// Store the new values in the form state.
$instance = $form['#instance'];
@@ -793,7 +840,7 @@ function entityreference_query_entityreference_alter(QueryAlterableInterface $qu
function entityreference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
// Ensure that the entity target type exists before displaying the widget.
$entity_info = entity_get_info($field['settings']['target_type']);
- if (empty($entity_info)){
+ if (empty($entity_info)) {
return;
}
$entity_type = $instance['entity_type'];
@@ -818,7 +865,9 @@ function entityreference_field_widget_form(&$form, &$form_state, $field, $instan
// Build an array of entities ID.
foreach ($items as $item) {
- $entity_ids[] = $item['target_id'];
+ if (isset($item['target_id'])) {
+ $entity_ids[] = $item['target_id'];
+ }
}
// Load those entities and loop through them to extract their labels.
@@ -879,6 +928,9 @@ function entityreference_field_widget_form(&$form, &$form_state, $field, $instan
}
}
+/**
+ * Implements hook_validate().
+ */
function _entityreference_autocomplete_validate($element, &$form_state, $form) {
// If a value was entered into the autocomplete...
$value = '';
@@ -903,6 +955,9 @@ function _entityreference_autocomplete_validate($element, &$form_state, $form) {
form_set_value($element, $value, $form_state);
}
+/**
+ * Implements hook_validate().
+ */
function _entityreference_autocomplete_tags_validate($element, &$form_state, $form) {
$value = array();
// If a value was entered into the autocomplete...
@@ -949,7 +1004,8 @@ function entityreference_field_widget_error($element, $error) {
* The entity type.
* @param $bundle_name
* The bundle name.
- * @return
+ *
+ * @return bool
* True if user can access this menu item.
*/
function entityreference_autocomplete_access_callback($type, $field_name, $entity_type, $bundle_name) {
@@ -981,10 +1037,11 @@ function entityreference_autocomplete_access_callback($type, $field_name, $entit
*/
function entityreference_autocomplete_callback($type, $field_name, $entity_type, $bundle_name, $entity_id = '', $string = '') {
// If the request has a '/' in the search text, then the menu system will have
- // split it into multiple arguments and $string will only be a partial. We want
- // to make sure we recover the intended $string.
+ // split it into multiple arguments and $string will only be a partial.
+ // We want to make sure we recover the intended $string.
$args = func_get_args();
- // Shift off the $type, $field_name, $entity_type, $bundle_name, and $entity_id args.
+ // Shift off the $type, $field_name, $entity_type,
+ // $bundle_name, and $entity_id args.
array_shift($args);
array_shift($args);
array_shift($args);
@@ -1020,6 +1077,7 @@ function entityreference_autocomplete_callback($type, $field_name, $entity_type,
*/
function entityreference_autocomplete_callback_get_matches($type, $field, $instance, $entity_type, $entity_id = '', $string = '') {
$matches = array();
+ $prefix = '';
$entity = NULL;
if ($entity_id !== 'NULL') {
@@ -1034,7 +1092,8 @@ function entityreference_autocomplete_callback_get_matches($type, $field, $insta
$handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);
if ($type == 'tags') {
- // The user enters a comma-separated list of tags. We only autocomplete the last tag.
+ // The user enters a comma-separated list of tags.
+ // We only autocomplete the last tag.
$tags_typed = drupal_explode_tags($string);
$tag_last = drupal_strtolower(array_pop($tags_typed));
if (!empty($tag_last)) {
@@ -1043,19 +1102,22 @@ function entityreference_autocomplete_callback_get_matches($type, $field, $insta
}
else {
// The user enters a single tag.
- $prefix = '';
$tag_last = $string;
}
if (isset($tag_last)) {
// Get an array of matching entities.
$entity_labels = $handler->getReferencableEntities($tag_last, $instance['widget']['settings']['match_operator'], 10);
-
+ $denied_label = t(ENTITYREFERENCE_DENIED);
// Loop through the products and convert them into autocomplete output.
foreach ($entity_labels as $values) {
foreach ($values as $entity_id => $label) {
+ // Never autocomplete entities that aren't accessible.
+ if ($label == $denied_label) {
+ continue;
+ }
$key = "$label ($entity_id)";
- // Strip things like starting/trailing white spaces, line breaks and tags.
+ // Strip starting/trailing white spaces, line breaks and tags.
$key = preg_replace('/\s\s+/', ' ', str_replace("\n", '', trim(decode_entities(strip_tags($key)))));
// Names containing commas or quotes must be wrapped in quotes.
if (strpos($key, ',') !== FALSE || strpos($key, '"') !== FALSE) {
@@ -1069,7 +1131,7 @@ function entityreference_autocomplete_callback_get_matches($type, $field, $insta
drupal_json_output($matches);
}
-/**
+ /**
* Introspects field and instance settings, and determines the correct settings
* for the functioning of the formatter.
*
@@ -1106,6 +1168,7 @@ function entityreference_field_formatter_info() {
'field types' => array('entityreference'),
'settings' => array(
'link' => FALSE,
+ 'bypass_access' => FALSE,
),
),
'entityreference_entity_id' => array(
@@ -1120,6 +1183,7 @@ function entityreference_field_formatter_info() {
'settings' => array(
'view_mode' => 'default',
'links' => TRUE,
+ 'use_content_language' => TRUE,
),
),
);
@@ -1132,8 +1196,16 @@ function entityreference_field_formatter_settings_form($field, $instance, $view_
$display = $instance['display'][$view_mode];
$settings = $display['settings'];
$field_type_settings = entityreference_field_type_settings($field);
+ $element = array();
if ($display['type'] == 'entityreference_label') {
+ $element['bypass_access'] = array(
+ '#title' => t('Show entity labels regardless of user access'),
+ '#description' => t("All entities in the field will be shown, without checking them for access. If the 'Link' setting is also enabled, an entity which the user does not have access to view will show without a link."),
+ '#type' => 'checkbox',
+ '#default_value' => $settings['bypass_access'],
+ );
+
$element['link'] = array(
'#title' => t('Link label to the referenced entity'),
'#type' => 'checkbox',
@@ -1163,6 +1235,12 @@ function entityreference_field_formatter_settings_form($field, $instance, $view_
'#title' => t('Show links'),
'#default_value' => $settings['links'],
);
+
+ $element['use_content_language'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use current content language'),
+ '#default_value' => $settings['use_content_language'],
+ );
}
return $element;
@@ -1180,6 +1258,7 @@ function entityreference_field_formatter_settings_summary($field, $instance, $vi
if ($display['type'] == 'entityreference_label') {
$summary[] = $settings['link'] ? t('Link to the referenced entity') : t('No link');
+ $summary[] = $settings['bypass_access'] ? t('Show labels regardless of access') : t('Respect entity access for label visibility');
}
if ($display['type'] == 'entityreference_entity_view') {
@@ -1190,6 +1269,7 @@ function entityreference_field_formatter_settings_summary($field, $instance, $vi
}
$summary[] = t('Rendered as @mode', array('@mode' => $view_mode_label));
$summary[] = !empty($settings['links']) ? t('Display links') : t('Do not display links');
+ $summary[] = !empty($settings['use_content_language']) ? t('Use current content language') : t('Use field language');
}
return implode(' ', $summary);
@@ -1226,7 +1306,7 @@ function entityreference_field_formatter_prepare_view($entity_type, $entities, $
foreach ($items[$id] as $delta => $item) {
// Check whether the referenced entity could be loaded.
- if (isset($target_entities[$item[$column]])) {
+ if (isset($target_entities[$item[$column]]) && isset($target_entities[$item[$column]])) {
// Replace the instance value with the term data.
$items[$id][$delta]['entity'] = $target_entities[$item[$column]];
// Check whether the user has access to the referenced entity.
@@ -1258,38 +1338,74 @@ function entityreference_field_formatter_view($entity_type, $entity, $field, $in
$target_type = $field_type_settings['entity_type'];
$column = $field_type_settings['column'];
- // Rebuild the items list to contain only those with access.
- foreach ($items as $key => $item) {
- if (empty($item['access'])) {
- unset($items[$key]);
- }
- }
-
switch ($display['type']) {
case 'entityreference_label':
$handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);
foreach ($items as $delta => $item) {
- $label = $handler->getLabel($item['entity']);
- // If the link is to be displayed and the entity has a uri, display a link.
- // Note the assignment ($url = ) here is intended to be an assignment.
- if ($display['settings']['link'] && ($uri = entity_uri($target_type, $item['entity']))) {
- $result[$delta] = array('#markup' => l($label, $uri['path'], $uri['options']));
+ // Skip an item that is not accessible, unless we're allowing output of
+ // entity labels without considering access.
+ if (empty($item['access']) && !$display['settings']['bypass_access']) {
+ continue;
}
- else {
- $result[$delta] = array('#markup' => check_plain($label));
+
+ // Calling EntityReferenceHandler::getLabel() would make a repeated,
+ // wasteful call to entity_access().
+ $label = entity_label($field['settings']['target_type'], $item['entity']);
+
+ // Check if the settings and access allow a link to be displayed.
+ $display_link = $display['settings']['link'] && $item['access'];
+
+ $uri = NULL;
+
+ // If the link is allowed and the entity has a uri, display a link.
+ if ($display_link) {
+ $uri = entity_uri($target_type, $item['entity']);
}
+
+ $result[$delta] = array(
+ '#theme' => 'entityreference_label',
+ '#label' => $label,
+ '#item' => $item,
+ '#uri' => $uri,
+ '#settings' => array(
+ 'display' => $display['settings'],
+ 'field' => $field['settings'],
+ ),
+ );
}
break;
case 'entityreference_entity_id':
foreach ($items as $delta => $item) {
- $result[$delta] = array('#markup' => check_plain($item[$column]));
+ // Skip an item that is not accessible.
+ if (empty($item['access'])) {
+ continue;
+ }
+
+ $result[$delta] = array(
+ '#theme' => 'entityreference_entity_id',
+ '#item' => $item,
+ '#settings' => array(
+ 'display' => $display['settings'],
+ 'field' => $field['settings'],
+ ),
+ );
}
break;
case 'entityreference_entity_view':
+ $target_langcode = $langcode;
+ if (!empty($settings['use_content_language']) && !empty($GLOBALS['language_content']->language)) {
+ $target_langcode = $GLOBALS['language_content']->language;
+ }
+
foreach ($items as $delta => $item) {
+ // Skip an item that is not accessible.
+ if (empty($item['access'])) {
+ continue;
+ }
+
// Protect ourselves from recursive rendering.
static $depth = 0;
$depth++;
@@ -1297,9 +1413,9 @@ function entityreference_field_formatter_view($entity_type, $entity, $field, $in
throw new EntityReferenceRecursiveRenderingException(t('Recursive rendering detected when rendering entity @entity_type(@entity_id). Aborting rendering.', array('@entity_type' => $target_type, '@entity_id' => $item[$column])));
}
- $entity = clone $item['entity'];
- unset($entity->content);
- $result[$delta] = entity_view($target_type, array($item[$column] => $entity), $settings['view_mode'], $langcode, FALSE);
+ $target_entity = clone $item['entity'];
+ unset($target_entity->content);
+ $result[$delta] = entity_view($target_type, array($item[$column] => $target_entity), $settings['view_mode'], $target_langcode, FALSE);
if (empty($settings['links']) && isset($result[$delta][$target_type][$column]['links'])) {
$result[$delta][$target_type][$item[$column]]['links']['#access'] = FALSE;
@@ -1326,3 +1442,44 @@ function entityreference_views_api() {
'path' => drupal_get_path('module', 'entityreference') . '/views',
);
}
+
+/**
+ * Theme label.
+ *
+ * @ingroup themeable.
+ */
+function theme_entityreference_label($vars) {
+ $label = $vars['label'];
+ $settings = $vars['settings'];
+ $item = $vars['item'];
+ $uri = $vars['uri'];
+
+ $output = '';
+
+ // If the link is to be displayed and the entity has a uri, display a link.
+ // Note the assignment ($url = ) here is intended to be an assignment.
+ if ($settings['display']['link'] && isset($uri['path'])) {
+ $output .= l($label, $uri['path'], $uri['options']);
+ }
+ else {
+ $output .= check_plain($label);
+ }
+
+ return $output;
+}
+
+/**
+ * Theme entity_id
+ *
+ * @ingroup themeable.
+ */
+function theme_entityreference_entity_id($vars) {
+ $settings = $vars['settings'];
+ $item = $vars['item'];
+
+ $output = '';
+
+ $output = check_plain($item['target_id']);
+
+ return $output;
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/examples/entityreference_behavior_example/entityreference_behavior_example.info b/profiles/commerce_kickstart/modules/contrib/entityreference/examples/entityreference_behavior_example/entityreference_behavior_example.info
index 88ad7b5d..70bcc4f2 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/examples/entityreference_behavior_example/entityreference_behavior_example.info
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/examples/entityreference_behavior_example/entityreference_behavior_example.info
@@ -4,9 +4,9 @@ core = 7.x
package = Fields
dependencies[] = entityreference
-; Information added by packaging script on 2013-11-20
-version = "7.x-1.1"
+; Information added by Drupal.org packaging script on 2017-08-16
+version = "7.x-1.5"
core = "7.x"
project = "entityreference"
-datestamp = "1384973110"
+datestamp = "1502895850"
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/plugins/behavior/EntityReferenceBehavior_TaxonomyIndex.class.php b/profiles/commerce_kickstart/modules/contrib/entityreference/plugins/behavior/EntityReferenceBehavior_TaxonomyIndex.class.php
index 43ac693f..075b54d7 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/plugins/behavior/EntityReferenceBehavior_TaxonomyIndex.class.php
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/plugins/behavior/EntityReferenceBehavior_TaxonomyIndex.class.php
@@ -144,18 +144,20 @@ protected function buildNodeIndex($node) {
// already inserted in taxonomy_build_node_index().
$tid_all = array_diff($tid_all, $original_tid_all);
- // Insert index entries for all the node's terms.
+ // Insert index entries for all the node's terms, preventing duplicates.
if (!empty($tid_all)) {
- $query = db_insert('taxonomy_index')->fields(array('nid', 'tid', 'sticky', 'created'));
foreach ($tid_all as $tid) {
- $query->values(array(
+ $row = array(
'nid' => $node->nid,
'tid' => $tid,
'sticky' => $sticky,
'created' => $node->created,
- ));
+ );
+ $query = db_merge('taxonomy_index')
+ ->key($row)
+ ->fields($row);
+ $query->execute();
}
- $query->execute();
}
}
}
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/plugins/selection/EntityReference_SelectionHandler_Generic.class.php b/profiles/commerce_kickstart/modules/contrib/entityreference/plugins/selection/EntityReference_SelectionHandler_Generic.class.php
index 444a74cc..6ec28a4b 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/plugins/selection/EntityReference_SelectionHandler_Generic.class.php
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/plugins/selection/EntityReference_SelectionHandler_Generic.class.php
@@ -208,7 +208,11 @@ public function validateReferencableEntities(array $ids) {
* Implements EntityReferenceHandler::validateAutocompleteInput().
*/
public function validateAutocompleteInput($input, &$element, &$form_state, $form) {
- $entities = $this->getReferencableEntities($input, '=', 6);
+ $bundled_entities = $this->getReferencableEntities($input, '=', 6);
+ $entities = array();
+ foreach($bundled_entities as $entities_list) {
+ $entities += $entities_list;
+ }
if (empty($entities)) {
// Error if there are no entities available for a required field.
form_error($element, t('There are no entities matching "%value"', array('%value' => $input)));
@@ -305,7 +309,7 @@ protected function reAlterQuery(SelectQueryInterface $query, $tag, $base_table)
*/
public function getLabel($entity) {
$target_type = $this->field['settings']['target_type'];
- return entity_access('view', $target_type, $entity) ? entity_label($target_type, $entity) : t('- Restricted access -');
+ return entity_access('view', $target_type, $entity) ? entity_label($target_type, $entity) : t(ENTITYREFERENCE_DENIED);
}
/**
@@ -339,9 +343,11 @@ public function ensureBaseTable(SelectQueryInterface $query) {
// Join the known base-table.
$target_type = $this->field['settings']['target_type'];
$entity_info = entity_get_info($target_type);
+ $target_type_base_table = $entity_info['base table'];
$id = $entity_info['entity keys']['id'];
+
// Return the alias of the table.
- return $query->innerJoin($target_type, NULL, "%alias.$id = $alias.entity_id");
+ return $query->innerJoin($target_type_base_table, NULL, "%alias.$id = $alias.entity_id");
}
}
@@ -543,7 +549,7 @@ public function getReferencableEntities($match = NULL, $match_operator = 'CONTAI
if ($vocabulary = taxonomy_vocabulary_machine_name_load($bundle)) {
if ($terms = taxonomy_get_tree($vocabulary->vid, 0, NULL, TRUE)) {
foreach ($terms as $term) {
- $options[$vocabulary->machine_name][$term->tid] = str_repeat('-', $term->depth) . check_plain($term->name);
+ $options[$vocabulary->machine_name][$term->tid] = str_repeat('-', $term->depth) . check_plain(entity_label('taxonomy_term', $term));
}
}
}
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/plugins/selection/EntityReference_SelectionHandler_Views.class.php b/profiles/commerce_kickstart/modules/contrib/entityreference/plugins/selection/EntityReference_SelectionHandler_Views.class.php
index 1b036a7d..cbed33b1 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/plugins/selection/EntityReference_SelectionHandler_Views.class.php
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/plugins/selection/EntityReference_SelectionHandler_Views.class.php
@@ -9,12 +9,13 @@ class EntityReference_SelectionHandler_Views implements EntityReference_Selectio
* Implements EntityReferenceHandler::getInstance().
*/
public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
- return new EntityReference_SelectionHandler_Views($field, $instance);
+ return new EntityReference_SelectionHandler_Views($field, $instance, $entity);
}
- protected function __construct($field, $instance) {
+ protected function __construct($field, $instance, $entity) {
$this->field = $field;
$this->instance = $instance;
+ $this->entity = $entity;
}
/**
@@ -52,13 +53,32 @@ public static function settingsForm($field, $instance) {
);
$default = !empty($view_settings['args']) ? implode(', ', $view_settings['args']) : '';
+ $description = t('Provide a comma separated list of arguments to pass to the view.') . ' ' . t('This field supports tokens.');
+
+ if (!module_exists('token')) {
+ $description .= ' ' . t('Install the token module to get more tokens and display available once.', array('@url' => 'http://drupal.org/project/token'));
+ }
+
$form['view']['args'] = array(
'#type' => 'textfield',
'#title' => t('View arguments'),
'#default_value' => $default,
'#required' => FALSE,
- '#description' => t('Provide a comma separated list of arguments to pass to the view.'),
+ '#description' => $description,
+ '#maxlength' => '512',
);
+ if (module_exists('token')) {
+ // Get the token type for the entity type our field is in (a type 'taxonomy_term' has a 'term' type token).
+ $info = entity_get_info($instance['entity_type']);
+
+ $form['view']['tokens'] = array(
+ '#theme' => 'token_tree',
+ '#token_types' => array($info['token type']),
+ '#global_types' => TRUE,
+ '#click_insert' => TRUE,
+ '#dialog' => TRUE,
+ );
+ }
}
else {
$form['view']['no_view_help'] = array(
@@ -84,6 +104,7 @@ protected function initializeView($match = NULL, $match_operator = 'CONTAINS', $
return FALSE;
}
$this->view->set_display($display_name);
+ $this->view->pre_execute();
// Make sure the query is not cached.
$this->view->is_cacheable = FALSE;
@@ -104,7 +125,7 @@ protected function initializeView($match = NULL, $match_operator = 'CONTAINS', $
*/
public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
$display_name = $this->field['settings']['handler_settings']['view']['display_name'];
- $args = $this->field['settings']['handler_settings']['view']['args'];
+ $args = $this->handleArgs($this->field['settings']['handler_settings']['view']['args']);
$result = array();
if ($this->initializeView($match, $match_operator, $limit)) {
// Get the results.
@@ -133,12 +154,14 @@ function countReferencableEntities($match = NULL, $match_operator = 'CONTAINS')
function validateReferencableEntities(array $ids) {
$display_name = $this->field['settings']['handler_settings']['view']['display_name'];
- $args = $this->field['settings']['handler_settings']['view']['args'];
+ $args = $this->handleArgs($this->field['settings']['handler_settings']['view']['args']);
$result = array();
if ($this->initializeView(NULL, 'CONTAINS', 0, $ids)) {
// Get the results.
$entities = $this->view->execute_display($display_name, $args);
- $result = array_keys($entities);
+ if (!empty($entities)) {
+ $result = array_keys($entities);
+ }
}
return $result;
}
@@ -164,6 +187,49 @@ public function entityFieldQueryAlter(SelectQueryInterface $query) {
}
+ /**
+ * Handles arguments for views.
+ *
+ * Replaces tokens using token_replace().
+ *
+ * @param array $args
+ * Usually $this->field['settings']['handler_settings']['view']['args'].
+ *
+ * @return array
+ * The arguments to be send to the View.
+ */
+ protected function handleArgs($args) {
+ if (!module_exists('token')) {
+ return $args;
+ }
+
+ // Parameters for token_replace().
+ $data = array();
+ $options = array('clear' => TRUE);
+
+ if ($entity = $this->entity) {
+ // D7 HACK: For new entities, entity and revision id are not set. This leads to
+ // * token replacement emitting PHP warnings
+ // * views choking on empty arguments
+ // We workaround this by filling in '0' for these IDs
+ // and use a clone to leave no traces of our unholy doings.
+ $info = entity_get_info($this->instance['entity_type']);
+ if (!isset($entity->{$info['entity keys']['id']})) {
+ $entity = clone $entity;
+ $entity->{$info['entity keys']['id']} = '0';
+ if (!empty($info['entity keys']['revision'])) {
+ $entity->{$info['entity keys']['revision']} = '0';
+ }
+ }
+
+ $data[$info['token type']] = $entity;
+ }
+ // Replace tokens for each argument.
+ foreach ($args as $key => $arg) {
+ $args[$key] = token_replace($arg, $data, $options);
+ }
+ return $args;
+ }
}
function entityreference_view_settings_validate($element, &$form_state, $form) {
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/plugins/selection/abstract.inc b/profiles/commerce_kickstart/modules/contrib/entityreference/plugins/selection/abstract.inc
index 1d2ea0d3..a4805b1f 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/plugins/selection/abstract.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/plugins/selection/abstract.inc
@@ -21,8 +21,9 @@ interface EntityReference_SelectionHandler {
* Return a list of referencable entities.
*
* @return
- * An array of referencable entities, which keys are entity ids and
- * values (safe HTML) labels to be displayed to the user.
+ * A nested array of entities, the first level is keyed by the
+ * entity bundle, which contains an array of entity labels (safe HTML),
+ * keyed by the entity ID.
*/
public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0);
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/tests/entityreference.admin.test b/profiles/commerce_kickstart/modules/contrib/entityreference/tests/entityreference.admin.test
index 9a121198..ec78e7bc 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/tests/entityreference.admin.test
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/tests/entityreference.admin.test
@@ -21,7 +21,7 @@ class EntityReferenceAdminTestCase extends DrupalWebTestCase {
parent::setUp(array('field_ui', 'entity', 'ctools', 'entityreference'));
// Create test user.
- $this->admin_user = $this->drupalCreateUser(array('access content', 'administer content types'));
+ $this->admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer fields'));
$this->drupalLogin($this->admin_user);
// Create content type, with underscores.
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/tests/entityreference.feeds.test b/profiles/commerce_kickstart/modules/contrib/entityreference/tests/entityreference.feeds.test
index 4dc1901f..32248cc0 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/tests/entityreference.feeds.test
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/tests/entityreference.feeds.test
@@ -17,6 +17,7 @@ class FeedsMapperFieldTestCase extends DrupalWebTestCase{
'name' => 'Feeds integration (field mapper)',
'description' => 'Test Feeds Mapper support for fields.',
'group' => 'Entity Reference',
+ 'dependencies' => array('feeds'),
);
}
@@ -28,10 +29,6 @@ class FeedsMapperFieldTestCase extends DrupalWebTestCase{
module_enable(array('entityreference_feeds_test'), TRUE);
$this->resetAll();
- if (!module_exists('feeds')) {
- return;
- }
-
$permissions[] = 'access content';
$permissions[] = 'administer site configuration';
$permissions[] = 'administer content types';
@@ -157,10 +154,6 @@ class FeedsMapperFieldTestCase extends DrupalWebTestCase{
* Basic test loading a double entry CSV file.
*/
public function test() {
- if (!module_exists('feeds')) {
- return;
- }
-
$this->drupalLogin($this->admin_user);
$this->drupalGet('admin/structure/types/manage/article/fields');
$this->assertText('Ref - entity ID', t('Found Entity reference field %field.', array('%field' => 'field_er_id')));
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/tests/entityreference.handlers.test b/profiles/commerce_kickstart/modules/contrib/entityreference/tests/entityreference.handlers.test
index b88e1069..1367b44a 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/tests/entityreference.handlers.test
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/tests/entityreference.handlers.test
@@ -194,6 +194,21 @@ class EntityReferenceHandlersTestCase extends DrupalWebTestCase {
),
);
$this->assertReferencable($field, $referencable_tests, 'Node handler (admin)');
+
+ // Verify autocomplete input validation.
+ $handler = entityreference_get_selection_handler($field);
+ $element = array(
+ '#parents' => array('element_name'),
+ );
+ $form_state = array();
+ $form = array();
+ $value = $handler->validateAutocompleteInput($nodes['published1']->title, $element, $form_state, $form);
+ $this->assertEqual($value, $nodes['published1']->nid);
+
+ $invalid_input = $this->randomName();
+ $value = $handler->validateAutocompleteInput($invalid_input, $element, $form_state, $form);
+ $this->assertNull($value);
+ $this->assertEqual(form_get_error($element), t('There are no entities matching "%value"', array('%value' => $invalid_input)));
}
/**
@@ -256,7 +271,7 @@ class EntityReferenceHandlersTestCase extends DrupalWebTestCase {
),
'result' => array(
'user' => array(
- $users['admin']->uid => '- Restricted access -',
+ $users['admin']->uid => ENTITYREFERENCE_DENIED,
$users['non_admin']->uid => $user_labels['non_admin'],
),
),
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/tests/entityreference.taxonomy.test b/profiles/commerce_kickstart/modules/contrib/entityreference/tests/entityreference.taxonomy.test
index 6e4afb78..94b3f568 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/tests/entityreference.taxonomy.test
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/tests/entityreference.taxonomy.test
@@ -112,4 +112,52 @@ class EntityReferenceTaxonomyTestCase extends DrupalWebTestCase {
$this->assertFalse(taxonomy_select_nodes(1));
}
+ /**
+ * Add a second ER field from node/article to taxonomy.
+ *
+ * This should not cause {taxonomy_index} to receive duplicate entries.
+ */
+ protected function setupForIndexDuplicates() {
+ // Create an entity reference field.
+ $field = array(
+ 'entity_types' => array('node'),
+ 'settings' => array(
+ 'handler' => 'base',
+ 'target_type' => 'taxonomy_term',
+ 'handler_settings' => array(
+ 'target_bundles' => array(),
+ ),
+ ),
+ 'field_name' => 'field_entityreference_term2',
+ 'type' => 'entityreference',
+ );
+ $field = field_create_field($field);
+ $instance = array(
+ 'field_name' => 'field_entityreference_term2',
+ 'bundle' => 'article',
+ 'entity_type' => 'node',
+ );
+
+ // Enable the taxonomy-index behavior.
+ $instance['settings']['behaviors']['taxonomy-index']['status'] = TRUE;
+ field_create_instance($instance);
+ }
+
+ /**
+ * Make sure the index only contains one entry for a given node->term
+ * reference, even when multiple ER fields link from the node bundle to terms.
+ */
+ public function testIndexDuplicates() {
+ // Extra setup for this test: add another ER field on this content type.
+ $this->setupForIndexDuplicates();
+
+ // Assert node insert with reference to term in first field.
+ $tid = 1;
+ $settings = array();
+ $settings['type'] = 'article';
+ $settings['field_entityreference_term'][LANGUAGE_NONE][0]['target_id'] = $tid;
+ $node = $this->drupalCreateNode($settings);
+
+ $this->assertEqual(taxonomy_select_nodes($tid), array($node->nid));
+ }
}
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/tests/modules/entityreference_feeds_test/entityreference_feeds_test.info b/profiles/commerce_kickstart/modules/contrib/entityreference/tests/modules/entityreference_feeds_test/entityreference_feeds_test.info
index 311ae3f4..5bbf9b6f 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/tests/modules/entityreference_feeds_test/entityreference_feeds_test.info
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/tests/modules/entityreference_feeds_test/entityreference_feeds_test.info
@@ -8,9 +8,9 @@ dependencies[] = feeds
dependencies[] = feeds_ui
dependencies[] = entityreference
-; Information added by packaging script on 2013-11-20
-version = "7.x-1.1"
+; Information added by Drupal.org packaging script on 2017-08-16
+version = "7.x-1.5"
core = "7.x"
project = "entityreference"
-datestamp = "1384973110"
+datestamp = "1502895850"
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/views/entityreference_plugin_display.inc b/profiles/commerce_kickstart/modules/contrib/entityreference/views/entityreference_plugin_display.inc
index f13e88a8..cca36509 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/views/entityreference_plugin_display.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/views/entityreference_plugin_display.inc
@@ -81,8 +81,9 @@ class entityreference_plugin_display extends views_plugin_display {
$field = $this->view->query->fields[$this->view->field[$field_alias]->field_alias];
}
else {
- $this->view->query->add_field($this->view->field[$field_alias]->options['table'], $this->view->field[$field_alias]->real_field, $this->view->field[$field_alias]->options['field'], array());
- $field = $this->view->query->fields[$this->view->field[$field_alias]->options['field']];
+ $field_table = $this->view->query->ensure_table($this->view->field[$field_alias]->table, $this->view->field[$field_alias]->relationship);
+ $this->view->query->add_field($field_table, $this->view->field[$field_alias]->real_field, $this->view->field[$field_alias]->field, array());
+ $field = $this->view->query->fields[$this->view->field[$field_alias]->field];
}
// Add an OR condition for the field
$conditions->condition($field['table'] . '.' . $field['field'], $value, 'LIKE');
diff --git a/profiles/commerce_kickstart/modules/contrib/entityreference/views/entityreference_plugin_style.inc b/profiles/commerce_kickstart/modules/contrib/entityreference/views/entityreference_plugin_style.inc
index fadaa9ee..b72a2357 100644
--- a/profiles/commerce_kickstart/modules/contrib/entityreference/views/entityreference_plugin_style.inc
+++ b/profiles/commerce_kickstart/modules/contrib/entityreference/views/entityreference_plugin_style.inc
@@ -26,7 +26,7 @@ class entityreference_plugin_style extends views_plugin_style {
'#title' => t('Search fields'),
'#options' => $options,
'#required' => TRUE,
- '#default_value' => $this->options['search_fields'],
+ '#default_value' => isset($this->options['search_fields']) ? $this->options['search_fields'] : array(),
'#description' => t('Select the field(s) that will be searched when using the autocomplete widget.'),
'#weight' => -3,
);
diff --git a/profiles/commerce_kickstart/modules/contrib/eva/eva-display-entity-view.tpl.php b/profiles/commerce_kickstart/modules/contrib/eva/eva-display-entity-view.tpl.php
index a0317bf9..cd6ab11f 100755
--- a/profiles/commerce_kickstart/modules/contrib/eva/eva-display-entity-view.tpl.php
+++ b/profiles/commerce_kickstart/modules/contrib/eva/eva-display-entity-view.tpl.php
@@ -39,6 +39,12 @@
+
+
+
+
+
+
diff --git a/profiles/commerce_kickstart/modules/contrib/eva/eva.info b/profiles/commerce_kickstart/modules/contrib/eva/eva.info
index aafbd193..0967cc4a 100644
--- a/profiles/commerce_kickstart/modules/contrib/eva/eva.info
+++ b/profiles/commerce_kickstart/modules/contrib/eva/eva.info
@@ -6,9 +6,9 @@ package = Views
files[] = eva_plugin_display_entity.inc
-; Information added by drupal.org packaging script on 2012-07-31
-version = "7.x-1.2"
+; Information added by Drupal.org packaging script on 2016-08-08
+version = "7.x-1.3"
core = "7.x"
project = "eva"
-datestamp = "1343701935"
+datestamp = "1470619440"
diff --git a/profiles/commerce_kickstart/modules/contrib/eva/eva.module b/profiles/commerce_kickstart/modules/contrib/eva/eva.module
index 25cf5b4e..5de36e1e 100755
--- a/profiles/commerce_kickstart/modules/contrib/eva/eva.module
+++ b/profiles/commerce_kickstart/modules/contrib/eva/eva.module
@@ -14,24 +14,32 @@ function eva_views_api() {
/**
- * Implements hook_content_extra_fields().
+ * Implements hook_field_extra_fields().
*/
function eva_field_extra_fields() {
$extras = array();
$views = eva_get_views();
-
+
foreach ($views as $entity => $data) {
foreach ($data as $view) {
- foreach ($view['bundles'] as $bundle) {
+ if (!empty($view['bundles'])) {
+ $bundles = $view['bundles'];
+ }
+ // If no bundles are set, apply to all bundles.
+ else {
+ $entity_info = entity_get_info($entity);
+ $bundles = array_keys($entity_info['bundles']);
+ }
+ foreach ($bundles as $bundle) {
$extras[$entity][$bundle]['display'][$view['name'] . '_' . $view['display']] = array(
- 'label' => (empty($view['title'])) ? $view['name'] : $view['title'],
- 'description' => $view['title'],
+ 'label' => (empty($view['title'])) ? $view['name'] : $view['title'],
+ 'description' => $view['title'],
'weight' => 10,
);
// Provide a separate extra field for the exposed form if there is any.
- if ($view['exposed form']) {
+ if (!empty($view['exposed form']) && !empty($view['exposed form split'])) {
$extras[$entity][$bundle]['display'][$view['name'] . '_' . $view['display'] . '_' . 'form'] = array(
- 'label' => ((empty($view['title'])) ? $view['name'] : $view['title']) . ' (' . t('Exposed form') . ')',
+ 'label' => ((empty($view['title'])) ? $view['name'] : $view['title']) . ' (' . t('Exposed form') . ')',
'description' => t('The exposed filter form of the view.'),
'weight' => 9,
);
@@ -49,22 +57,21 @@ function eva_field_extra_fields() {
* This is a terrible, terrible hack that should not be necessary; taxonomy and
* some other entity types use fields, but don't implement hook_entity_view().
* We have to ALTER those entity types after they're built. For the time being,
- * we'll use a list of special cases to trigger this special handling.
+ * we'll use a list of special cases to trigger this special handling.
*/
function eva_entity_view_alter(&$build, $type) {
$view_mode = $build['#view_mode'];
- $language = $build['#language'];
- $entity_data = entity_get_info($type);
- $entity = _eva_extract_entity_from_build($build);
+ if (!$entity = _eva_extract_entity_from_build($build, $type)) {
+ return;
+ }
$entity_ids = entity_extract_ids($type, $entity);
- $settings = field_view_mode_settings($type, $entity_ids[2]);
$fields = field_extra_fields_get_display($type, $entity_ids[2], $view_mode);
$views = eva_get_views($type);
foreach ($views as $info) {
- $longname = $info['name'] .'_'. $info['display'];
+ $longname = $info['name'] . '_' . $info['display'];
if (isset($fields[$longname]) && $fields[$longname]['visible']) {
if ($view = views_get_view($info['name'])) {
$view->set_display($info['display']);
@@ -93,17 +100,18 @@ function eva_entity_view_alter(&$build, $type) {
}
/**
- * Get a list of views and displays attached to speficic entities.
+ * Gets a list of views and displays attached to specific entities.
*
* This function will cache its results into the views cache, so it gets
* cleared by Views appropriately.
*
- * @param $type
- * The entity type we want to retrieve views for. If NULL is
- * specified, views for all entity types will be returned.
- * @param $reset
- * Force a rebuild of the data.
- * @return
+ * @param string|null $type
+ * (optional) The entity type we want to retrieve views for. If NULL is
+ * specified, views for all entity types will be returned. Defaults to NULL.
+ * @param bool $reset
+ * (optional) Force a rebuild of the data. Defaults to FALSE.
+ *
+ * @return array
* An array of view name/display name values, or an empty array().
*/
function eva_get_views($type = NULL, $reset = FALSE) {
@@ -111,7 +119,7 @@ function eva_get_views($type = NULL, $reset = FALSE) {
if (!isset($used_views) || $reset) {
views_include('cache');
-
+
// If we're not resetting, check the Views cache.
if (!$reset) {
$cache = views_cache_get("eva");
@@ -122,6 +130,7 @@ function eva_get_views($type = NULL, $reset = FALSE) {
// If it's still empty rebuild it.
if (!isset($used_views)) {
+ $used_views = array();
// Trigger a rebuild of the views object cache, which may not be fully loaded.
ctools_include('export');
ctools_export_load_object_reset('views_view');
@@ -139,6 +148,7 @@ function eva_get_views($type = NULL, $reset = FALSE) {
'display' => $display_id,
'bundles' => $view->display_handler->get_option('bundles'),
'exposed form' => $view->display_handler->uses_exposed(),
+ 'exposed form split' => $view->display_handler->get_option('exposed_form_as_field'),
);
$view->destroy();
}
@@ -162,23 +172,27 @@ function eva_get_views($type = NULL, $reset = FALSE) {
* entities, and contrib entities based on EntityAPI all store their junk in
* different slots of the build array. See http://drupal.org/node/1170198.
*
- * @param $build
- * The token string defined by the view.
- * @param $entity_data
- * The token type.
+ * @param array $build
+ * The build array as passed to hook_entity_view_alter().
+ * @param string $entity_type
+ * (optional) The entity type. Defaults to NULL.
*
- * I hate you, Milkman Dan.
+ * @return object|bool
+ * Either the entity object, or FALSE if it cannot be found.
*/
-function _eva_extract_entity_from_build($build) {
+function _eva_extract_entity_from_build($build, $entity_type = NULL) {
// EntityAPI often sticks stuff in here.
if (!empty($build['#entity'])) {
return $build['#entity'];
}
-
+
// Other entities stick them here!
elseif (!empty($build['#' . $build['#entity_type']])) {
return $build['#' . $build['#entity_type']];
}
+ elseif ($entity_type && !empty($build['#' . $entity_type])) {
+ return $build['#' . $entity_type];
+ }
// Some entities are naughty.
elseif ($build['#entity_type'] == 'user') {
@@ -194,13 +208,14 @@ function _eva_extract_entity_from_build($build) {
/**
* Get view arguments array from string that contains tokens
*
- * @param $string
+ * @param string $string
* The token string defined by the view.
- * @param $type
+ * @param string $type
* The token type.
- * @param $object
+ * @param object $object
* The object being used for replacement data (typically a node).
- * @return
+ *
+ * @return array
* An array of argument values.
*
* @todo: security?
diff --git a/profiles/commerce_kickstart/modules/contrib/eva/eva.theme.inc b/profiles/commerce_kickstart/modules/contrib/eva/eva.theme.inc
index d60caf2c..b64c0db6 100755
--- a/profiles/commerce_kickstart/modules/contrib/eva/eva.theme.inc
+++ b/profiles/commerce_kickstart/modules/contrib/eva/eva.theme.inc
@@ -10,6 +10,7 @@ function template_preprocess_eva_display_entity_view(&$vars) {
$view = $vars['view'];
$display = $view->display_handler;
$vars['title'] = $display->get_option('show_title') ? filter_xss_admin($view->get_title()) : '';
+ $vars['exposed_form_as_field'] = $display->get_option('exposed_form_as_field');
}
function template_process_eva_display_entity_view(&$vars) {
diff --git a/profiles/commerce_kickstart/modules/contrib/eva/eva_plugin_display_entity.inc b/profiles/commerce_kickstart/modules/contrib/eva/eva_plugin_display_entity.inc
index ae7366e4..906a0c00 100755
--- a/profiles/commerce_kickstart/modules/contrib/eva/eva_plugin_display_entity.inc
+++ b/profiles/commerce_kickstart/modules/contrib/eva/eva_plugin_display_entity.inc
@@ -12,6 +12,7 @@ class eva_plugin_display_entity extends views_plugin_display {
$options['argument_mode'] = array('default' => 'id');
$options['default_argument'] = array('default' => '');
$options['show_title'] = 0;
+ $options['exposed_form_as_field'] = 0;
return $options;
}
@@ -51,7 +52,7 @@ class eva_plugin_display_entity extends views_plugin_display {
$options['bundles'] = array(
'category' => 'entity_view',
'title' => t('Bundles'),
- 'value' => empty($bundle_names) ? t('None') : implode(', ', $bundle_names),
+ 'value' => empty($bundle_names) ? t('All') : implode(', ', $bundle_names),
);
$argument_mode = $this->get_option('argument_mode');
@@ -67,6 +68,12 @@ class eva_plugin_display_entity extends views_plugin_display {
'value' => $this->get_option('show_title') ? t('Yes') : t('No'),
);
+ $options['exposed_form_as_field'] = array(
+ 'category' => 'entity_view',
+ 'title' => t('Exposed Form as Field'),
+ 'value' => $this->get_option('exposed_form_as_field') ? t('Yes') : t('No'),
+ );
+
if (module_exists('token')) {
// We must load token values here to show them on the options form.
drupal_add_js(drupal_get_path('module', 'token') . '/token.js');
@@ -81,12 +88,13 @@ class eva_plugin_display_entity extends views_plugin_display {
function options_form(&$form, &$form_state) {
// It is very important to call the parent function here:
parent::options_form($form, $form_state);
-
+
$entity_info = entity_get_info();
$entity_type = $this->get_option('entity_type');
switch ($form_state['section']) {
case 'entity_type':
+ $entity_names = array();
foreach ($entity_info as $type => $info) {
if (!empty($info['view modes'])) {
$entity_names[$type] = $info['label'];
@@ -104,13 +112,14 @@ class eva_plugin_display_entity extends views_plugin_display {
break;
case 'bundles':
+ $options = array();
foreach ($entity_info[$entity_type]['bundles'] as $bundle => $info) {
$options[$bundle] = $info['label'];
}
$form['#title'] .= t('Bundles');
$form['bundles'] = array(
'#type' => 'checkboxes',
- '#title' => t("Attach this display to the following bundles"),
+ '#title' => t("Attach this display to the following bundles. If no bundles are selected, the display will be attached to all."),
'#options' => $options,
'#default_value' => $this->get_option('bundles'),
);
@@ -138,7 +147,7 @@ class eva_plugin_display_entity extends views_plugin_display {
'#collapsible' => TRUE,
'#states' => array(
'visible' => array(
- 'input:[name=argument_mode]' => array('value' => 'token'),
+ ':input[name=argument_mode]' => array('value' => 'token'),
),
),
);
@@ -166,6 +175,14 @@ class eva_plugin_display_entity extends views_plugin_display {
'#default_value' => $this->get_option('show_title'),
);
break;
+ case 'exposed_form_as_field':
+ $form['#title'] .= t('Exposed Form as Field');
+ $form['exposed_form_as_field'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Split off Exposed Form as Separate Field'),
+ '#default_value' => $this->get_option('exposed_form_as_field'),
+ '#description' => t('Check this box to have a separate field for this view\'s exposed form on the "Manage Display" tab'),
+ );
}
}
@@ -185,7 +202,7 @@ class eva_plugin_display_entity extends views_plugin_display {
// only one on the new type, we can select it automatically. Otherwise
// we need to wipe the options and start over.
$new_entity_info = entity_get_info($new_entity);
-
+
$new_bundle_keys = array_keys($new_entity_info['bundles']);
$new_bundles = array();
if (count($new_bundle_keys) == 1) {
@@ -209,6 +226,10 @@ class eva_plugin_display_entity extends views_plugin_display {
case 'show_title':
$this->set_option('show_title', $form_state['values']['show_title']);
break;
+ case 'exposed_form_as_field':
+ $this->set_option('exposed_form_as_field', $form_state['values']['exposed_form_as_field']);
+ break;
+
}
}
@@ -219,12 +240,6 @@ class eva_plugin_display_entity extends views_plugin_display {
if (empty($entity_type)) {
$errors[] = t('Display @display must have an entity type selected.', array('@display' => $this->display->display_title));
}
-
- $bundles = $this->get_option('bundles');
- if (empty($bundles)) {
- $errors[] = t('Display @display must have at least one bundle selected.', array('@display' => $this->display->display_title));
- }
-
return $errors;
}
@@ -239,7 +254,7 @@ class eva_plugin_display_entity extends views_plugin_display {
$entity = $this->view->current_entity;
$entity_type = $this->view->display_handler->get_option('entity_type');
$entity_info = entity_get_info($entity_type);
-
+
$arg_mode = $this->view->display_handler->get_option('argument_mode');
if ($arg_mode == 'token') {
if ($token_string = $this->view->display_handler->get_option('default_argument')) {
@@ -250,7 +265,7 @@ class eva_plugin_display_entity extends views_plugin_display {
foreach ($token_values as $key => $value) {
$new_args[$key] = $value;
}
-
+
$this->view->args = $new_args;
}
}
@@ -289,4 +304,5 @@ class eva_plugin_display_entity extends views_plugin_display {
return $data;
}
}
+
}
diff --git a/profiles/commerce_kickstart/modules/contrib/facetapi/PATCHES.txt b/profiles/commerce_kickstart/modules/contrib/facetapi/PATCHES.txt
index 345b3534..cb079ae1 100644
--- a/profiles/commerce_kickstart/modules/contrib/facetapi/PATCHES.txt
+++ b/profiles/commerce_kickstart/modules/contrib/facetapi/PATCHES.txt
@@ -2,4 +2,4 @@ The following patches have been applied to this project:
- https://drupal.org/files/1616518-term_remove_link-24.patch
- https://www.drupal.org/files/issues/notice_undefined-2378693-3.patch
-This file was automatically generated by Drush Make (http://drupal.org/project/drush).
\ No newline at end of file
+This file was automatically generated by Drush Make (http://drupal.org/project/drush).
diff --git a/profiles/commerce_kickstart/modules/contrib/features/PATCHES.txt b/profiles/commerce_kickstart/modules/contrib/features/PATCHES.txt
index e29b9b98..69da25f6 100644
--- a/profiles/commerce_kickstart/modules/contrib/features/PATCHES.txt
+++ b/profiles/commerce_kickstart/modules/contrib/features/PATCHES.txt
@@ -1,6 +1,5 @@
The following patches have been applied to this project:
- http://drupal.org/files/issues/features-fix-modules-enabled-2143765-1.patch
- https://www.drupal.org/files/issues/ignore_hidden_modules-2479803-1.patch
-- https://www.drupal.org/files/issues/2534138-field-base-exception-catch-1.patch
-This file was automatically generated by Drush Make (http://drupal.org/project/drush).
\ No newline at end of file
+This file was automatically generated by Drush Make (http://drupal.org/project/drush).
diff --git a/profiles/commerce_kickstart/modules/contrib/features/features.admin.inc b/profiles/commerce_kickstart/modules/contrib/features/features.admin.inc
index 8360e974..46752c89 100644
--- a/profiles/commerce_kickstart/modules/contrib/features/features.admin.inc
+++ b/profiles/commerce_kickstart/modules/contrib/features/features.admin.inc
@@ -88,6 +88,12 @@ function features_settings_form($form, $form_state) {
'#default_value' => variable_get('features_rebuild_on_flush', TRUE),
'#description' => t('If you have a large site with many features, you may experience lag on full cache clear. If disabled, features will rebuild only when viewing the features list or saving the modules list.'),
);
+ $form['general']['features_rebuild_modules_page'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Rebuild features on accessing modules list page'),
+ '#default_value' => variable_get('features_rebuild_modules_page', FALSE),
+ '#description' => t('If you have a large site with many features, you may experience lag on accessing the modules administration page. If disabled, features will not rebuild when viewing the modules list.'),
+ );
return system_settings_form($form);
}
@@ -109,7 +115,7 @@ function features_export_form($form, $form_state, $feature = NULL) {
$feature_name = !empty($feature->name) ? $feature->name : '';
$form = array(
- '#attributes' => array('class' => array('features-export-form')),
+ '#attributes' => array('class' => array('features-export-form', 'clearfix')),
'#feature' => isset($feature) ? $feature : NULL,
);
$form['info'] = array(
@@ -756,7 +762,7 @@ function features_export_form_rebuild($form, &$form_state) {
function features_export_components_json($feature_name) {
module_load_include('inc', 'features', 'features.export');
- $export = array();
+ $export = array('features' => array());
if (!empty($_POST['items'])) {
$excluded = (!empty($_POST['excluded'])) ? $_POST['excluded'] : array();
$stub = array();
@@ -1143,7 +1149,7 @@ function features_admin_form($form, $form_state) {
// As of 7.0 beta 2 it matters where the "vertical_tabs" element lives on the
// the array. We add it late, but at the beginning of the array because that
// keeps us away from trouble.
- $form = array('packages' => array('#type' => 'vertical_tabs')) + $form;
+ $form = array_merge(array('packages' => array('#type' => 'vertical_tabs')), $form);
$form['buttons'] = array(
'#theme' => 'features_form_buttons',
@@ -1328,7 +1334,7 @@ function features_form_submit(&$form, &$form_state) {
// page callback rather than as part of the submit handler as some modules
// have includes/other directives of importance in hooks that have already
// been called in this page load.
- $form_state['redirect'] = 'admin/structure/features/cleanup/clear';
+ $form_state['redirect'] = array('admin/structure/features/cleanup', array('query' => array('token' => drupal_get_token())));
$features = $form['#features'];
if (!empty($features)) {
@@ -1352,21 +1358,19 @@ function features_form_rebuild() {
}
/**
- * Form for clearing cache after enabling a feature.
+ * Callback for clearing cache after enabling a feature.
*/
-function features_cleanup_form($form, $form_state, $cache_clear = FALSE) {
- // Clear caches if we're getting a post-submit redirect that requests it.
- if ($cache_clear) {
+function features_cleanup() {
+ if (!empty($_GET['token']) && drupal_valid_token($_GET['token'])) {
drupal_flush_all_caches();
-
// The following functions need to be run because drupal_flush_all_caches()
// runs rebuilds in the wrong order. The node type cache is rebuilt *after*
// the menu is rebuilt, meaning that the menu tree is stale in certain
// circumstances after drupal_flush_all_caches(). We rebuild again.
menu_rebuild();
- }
-
drupal_goto('admin/structure/features');
+ }
+ return MENU_NOT_FOUND;
}
/**
diff --git a/profiles/commerce_kickstart/modules/contrib/features/features.api.php b/profiles/commerce_kickstart/modules/contrib/features/features.api.php
index 6a13b0c1..d7c7edec 100644
--- a/profiles/commerce_kickstart/modules/contrib/features/features.api.php
+++ b/profiles/commerce_kickstart/modules/contrib/features/features.api.php
@@ -42,7 +42,7 @@
* are declared "dynamically" or are part of a family of components.
*
* 'alter_type': What type of alter hook this hook uses. 'normal' is called
- * after the main hook is called. 'inline' is embeded within the default hook
+ * after the main hook is called. 'inline' is embedded within the default hook
* and may not be implemented by some default hooks.
* 'none' is no alter hook exists. Defaults to 'normal'
*
@@ -310,7 +310,7 @@ function hook_features_pipe_COMPONENT_alter(&$pipe, $data, $export) {
* The module being exported contained in $export['module_name'].
*/
function hook_features_pipe_alter(&$pipe, $data, $export) {
- if ($export['component'] == 'node' && in_array($data, 'my-node-type')) {
+ if ($export['component'] == 'node' && in_array('my-node-type', $data)) {
$pipe['dependencies'][] = 'mymodule';
}
}
diff --git a/profiles/commerce_kickstart/modules/contrib/features/features.drush.inc b/profiles/commerce_kickstart/modules/contrib/features/features.drush.inc
index 6fdbc263..696825d6 100644
--- a/profiles/commerce_kickstart/modules/contrib/features/features.drush.inc
+++ b/profiles/commerce_kickstart/modules/contrib/features/features.drush.inc
@@ -32,6 +32,12 @@ function features_drush_command() {
),
'drupal dependencies' => array('features'),
'aliases' => array('fl', 'features'),
+ 'outputformat' => array(
+ 'default' => 'table',
+ 'pipe-format' => 'list',
+ 'field-labels' => array('name' => 'Name', 'feature' => 'Feature', 'status' => 'Status', 'version' => 'Version', 'state' => 'State'),
+ 'output-data-type' => 'format-table',
+ ),
);
$items['features-export'] = array(
'description' => "Export a feature from your site into a module.",
@@ -207,12 +213,12 @@ function drush_features_list() {
}
module_load_include('inc', 'features', 'features.export');
- $rows = array(array(dt('Name'), dt('Feature'), dt('Status'), dt('Version'), dt('State')));
// Sort the Features list before compiling the output.
$features = features_get_features(NULL, TRUE);
ksort($features);
+ $rows = array();
foreach ($features as $k => $m) {
switch (features_get_storage($m->name)) {
case FEATURES_DEFAULT:
@@ -230,16 +236,19 @@ function drush_features_list() {
($m->status == 0 && ($status == 'all' || $status == 'disabled')) ||
($m->status == 1 && ($status == 'all' || $status == 'enabled'))
) {
- $rows[] = array(
- $m->info['name'],
- $m->name,
- $m->status ? dt('Enabled') : dt('Disabled'),
- $m->info['version'],
- $storage
+ $rows[$k] = array(
+ 'name' => $m->info['name'],
+ 'feature' => $m->name,
+ 'status' => $m->status ? dt('Enabled') : dt('Disabled'),
+ 'version' => $m->info['version'],
+ 'state' => $storage
);
}
}
- drush_print_table($rows, TRUE);
+ if (version_compare(DRUSH_VERSION, '6.0', '<')) {
+ drush_print_table($rows, TRUE);
+ }
+ return $rows;
}
/**
@@ -337,8 +346,13 @@ function _drush_features_component_filter($all_components, $patterns = array(),
// Rewrite * to %. Let users use both as wildcard.
$pattern = strtr($pattern, array('*' => '%'));
$sources = array();
- $source_pattern = strtok($pattern, ':');
- $component_pattern = strtok(':');
+ if (strpos($pattern, ':') !== FALSE) {
+ list($source_pattern, $component_pattern) = explode(':', $pattern, 2);
+ }
+ else {
+ $source_pattern = $pattern;
+ $component_pattern = '';
+ }
// If source is empty, use a pattern.
if ($source_pattern == '') {
$source_pattern = '%';
@@ -607,9 +621,18 @@ function _drush_features_export($info, $module_name = NULL, $directory = NULL) {
drush_op('mkdir', $directory);
}
if (is_dir($directory)) {
+ // Ensure that the export will be created in the English language.
+ // The export language must be set before flushing caches as that can
+ // result into translatables being statically cached.
+ $language = _features_export_language();
+
drupal_flush_all_caches();
$export = _drush_features_generate_export($info, $module_name);
$files = features_export_render($export, $module_name, TRUE);
+
+ // Restore the language
+ _features_export_language($language);
+
// Copy any files if _files key is there.
if (!empty($files['_files'])) {
foreach ($files['_files'] as $file_name => $file_info) {
@@ -685,7 +708,7 @@ function _drush_features_generate_export(&$info, &$module_name) {
}
else {
// Split version number parts.
- $pattern = '/([0-9]-[a-z]+([0-9])+)/';
+ $pattern = '/([0-9]-[a-z]+([0-9]+))/';
$matches = array();
preg_match($pattern, $version_minor, $matches);
$number = array_pop($matches);
@@ -797,7 +820,7 @@ function drush_features_revert() {
}
}
else {
- drush_features_list();
+ drush_print_table(drush_features_list());
return;
}
}
@@ -851,7 +874,7 @@ function drush_features_revert_all() {
*/
function drush_features_diff() {
if (!$args = func_get_args()) {
- drush_features_list();
+ drush_print_table(drush_features_list());
return;
}
$module = $args[0];
diff --git a/profiles/commerce_kickstart/modules/contrib/features/features.export.inc b/profiles/commerce_kickstart/modules/contrib/features/features.export.inc
index 5cf2a8c8..5045b131 100644
--- a/profiles/commerce_kickstart/modules/contrib/features/features.export.inc
+++ b/profiles/commerce_kickstart/modules/contrib/features/features.export.inc
@@ -46,7 +46,7 @@ function features_populate($info, $module_name) {
*/
function _features_populate($pipe, &$export, $module_name = '', $reset = FALSE) {
// Ensure that the export will be created in the english language.
- _features_set_export_language();
+ $language = _features_export_language();
if ($reset) {
drupal_static_reset(__FUNCTION__);
@@ -92,6 +92,7 @@ function _features_populate($pipe, &$export, $module_name = '', $reset = FALSE)
}
}
}
+ _features_export_language($language);
return $export;
}
@@ -843,6 +844,13 @@ function features_get_default($component, $module_name = NULL, $alter = TRUE, $r
/**
* Get a map of components to their providing modules.
+ *
+ * @param string $component
+ * @param string $attribute
+ * @param callable $callback
+ * @param bool $reset
+ *
+ * @return array|bool
*/
function features_get_default_map($component, $attribute = NULL, $callback = NULL, $reset = FALSE) {
$map = &drupal_static(__FUNCTION__, array());
@@ -891,6 +899,9 @@ function features_get_default_map($component, $attribute = NULL, $callback = NUL
* Retrieve an array of features/components and their current states.
*/
function features_get_component_states($features = array(), $rebuild_only = TRUE, $reset = FALSE) {
+ // Ensure that the export will be created in the English language.
+ $language = _features_export_language();
+
if ($reset) {
drupal_static_reset(__FUNCTION__);
}
@@ -901,7 +912,7 @@ function features_get_component_states($features = array(), $rebuild_only = TRUE
// Retrieve only rebuildable components if requested.
features_include();
- $components = array_keys(features_get_components());
+ $components = array_keys(features_get_components(NULL, NULL, $reset));
if ($rebuild_only) {
foreach ($components as $k => $component) {
if (!features_hook($component, 'features_rebuild')) {
@@ -984,6 +995,9 @@ function features_get_component_states($features = array(), $rebuild_only = TRUE
foreach ($return as $k => $v) {
$return[$k] = array_intersect_key($return[$k], array_flip($components));
}
+
+ _features_export_language($language);
+
return $return;
}
@@ -1006,17 +1020,14 @@ function _features_linetrim($code) {
* @param bool $remove_empty if set, remove null or empty values for assoc arrays.
*/
function features_sanitize(&$array, $component = NULL, $remove_empty = TRUE) {
- // make a deep copy of data to prevent problems when removing recursion later.
- $array = unserialize(serialize($array));
+ $array = features_remove_recursion($array);
if (isset($component)) {
$ignore_keys = _features_get_ignore_keys($component);
// remove keys to be ignored
- // doing this now allows us to better control which recursive parts are removed
if (count($ignore_keys)) {
_features_remove_ignores($array, $ignore_keys);
}
}
- features_remove_recursion($array);
_features_sanitize($array, $remove_empty);
}
@@ -1069,81 +1080,45 @@ function _features_is_assoc($array) {
/**
* Removes recursion from an object or array.
*
- * @param $item
- * An object or array passed by reference.
- */
-function features_remove_recursion(&$item) {
- $uniqid = __FUNCTION__ . mt_rand(); // use of uniqid() here impacts performance
- $stack = array();
- return _features_remove_recursion($item, $stack, $uniqid);
-}
-
-/**
- * Helper to removes recursion from an object/array.
+ * Taken from https://code.google.com/p/formaldehyde/source/browse/trunk/formaldehyde.php
+ * Also used in node_export module
*
- * @param $item
- * An object or array passed by reference.
+ * @param $o mixed
+ * @return mixed
+ * returns a copy of the object or array with recursion removed
*/
-function _features_remove_recursion(&$object, &$stack = array(), $uniqid) {
- if ((is_object($object) || is_array($object)) && $object) {
- $in_stack = FALSE;
- foreach ($stack as &$item) {
- if (_features_is_ref_to($object, $item, $uniqid)) {
- $in_stack = TRUE;
- break;
- }
- }
- unset($item);
-
- if (!$in_stack) {
- $stack[] = $object;
- foreach ($object as $key => &$subobject) {
- if (_features_remove_recursion($subobject, $stack, $uniqid)) {
- if (is_object($object)) {
- unset($object->$key);
- }
- else {
- unset($object[$key]);
- }
+function features_remove_recursion($o) {
+ static $replace;
+ if (!isset($replace)) {
+ $replace = create_function(
+ '$m',
+ '$r="\x00{$m[1]}ecursion_features";return \'s:\'.strlen($r.$m[2]).\':"\'.$r.$m[2].\'";\';'
+ );
+ }
+ if (is_array($o) || is_object($o)) {
+ $re = '#(r|R):([0-9]+);#';
+ $serialize = serialize($o);
+ if (preg_match($re, $serialize)) {
+ $last = $pos = 0;
+ while (false !== ($pos = strpos($serialize, 's:', $pos))) {
+ $chunk = substr($serialize, $last, $pos - $last);
+ if (preg_match($re, $chunk)) {
+ $length = strlen($chunk);
+ $chunk = preg_replace_callback($re, $replace, $chunk);
+ $serialize = substr($serialize, 0, $last) . $chunk . substr($serialize, $last + ($pos - $last));
+ $pos += strlen($chunk) - $length;
}
+ $pos += 2;
+ $last = strpos($serialize, ':', $pos);
+ $length = substr($serialize, $pos, $last - $pos);
+ $last += 4 + $length;
+ $pos = $last;
}
- unset($subobject);
- }
- else {
- return TRUE;
+ $serialize = substr($serialize, 0, $last) . preg_replace_callback($re, $replace, substr($serialize, $last));
+ $o = unserialize($serialize);
}
}
- return FALSE;
-}
-
-/**
- * Helper function in determining equality of arrays. Credit to http://stackoverflow.com/a/4263181
- *
- * @see _features_remove_recursion()
- *
- * @param $a
- * object a
- * @param $b
- * object b
- * @return bool
- *
- */
-function _features_is_ref_to(&$a, &$b, $uniqid) {
- if (is_object($a) && is_object($b)) {
- return ($a === $b);
- }
-
- $temp_a = $a;
- $temp_b = $b;
-
- $b = $uniqid;
-
- if ($a === $uniqid) $return = true;
- else $return = false;
-
- $a = $temp_a;
- $b = $temp_b;
- return $return;
+ return $o;
}
/**
@@ -1162,7 +1137,7 @@ function _features_remove_ignores(&$item, $ignore_keys, $level = -1) {
if (!is_array($item) && !is_object($item)) {
return;
}
- foreach ($item as $key => $value) {
+ foreach ($item as $key => &$value) {
if (isset($ignore_keys[$key]) && ($ignore_keys[$key] == $level)) {
if ($is_object) {
unset($item->$key);
@@ -1175,6 +1150,7 @@ function _features_remove_ignores(&$item, $ignore_keys, $level = -1) {
_features_remove_ignores($value, $ignore_keys, $level+1);
}
}
+ unset($value);
}
/**
diff --git a/profiles/commerce_kickstart/modules/contrib/features/features.info b/profiles/commerce_kickstart/modules/contrib/features/features.info
index e18cc8f1..d28a617b 100644
--- a/profiles/commerce_kickstart/modules/contrib/features/features.info
+++ b/profiles/commerce_kickstart/modules/contrib/features/features.info
@@ -3,12 +3,16 @@ description = "Provides feature management for Drupal."
core = 7.x
package = "Features"
files[] = tests/features.test
+test_dependencies[] = image
+test_dependencies[] = strongarm
+test_dependencies[] = taxonomy
+test_dependencies[] = views
configure = admin/structure/features/settings
-; Information added by Drupal.org packaging script on 2015-06-24
-version = "7.x-2.6"
+; Information added by Drupal.org packaging script on 2016-04-18
+version = "7.x-2.10"
core = "7.x"
project = "features"
-datestamp = "1435165997"
+datestamp = "1461011641"
diff --git a/profiles/commerce_kickstart/modules/contrib/features/features.module b/profiles/commerce_kickstart/modules/contrib/features/features.module
index 94e00830..c489dfbc 100644
--- a/profiles/commerce_kickstart/modules/contrib/features/features.module
+++ b/profiles/commerce_kickstart/modules/contrib/features/features.module
@@ -84,8 +84,7 @@ function features_menu() {
$items['admin/structure/features/cleanup'] = array(
'title' => 'Cleanup',
'description' => 'Clear cache after enabling/disabling a feature.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('features_cleanup_form', 4),
+ 'page callback' => 'features_cleanup',
'type' => MENU_CALLBACK,
'file' => 'features.admin.inc',
'weight' => 1,
@@ -128,7 +127,7 @@ function features_menu() {
'description' => 'Display components of a feature.',
'page callback' => 'drupal_get_form',
'page arguments' => array('features_admin_components', 3),
- 'load arguments' => array(3, TRUE),
+ 'load arguments' => array(TRUE),
'access callback' => 'user_access',
'access arguments' => array('administer features'),
'type' => MENU_CALLBACK,
@@ -147,7 +146,7 @@ function features_menu() {
'description' => 'Recreate an existing feature.',
'page callback' => 'drupal_get_form',
'page arguments' => array('features_export_form', 3),
- 'load arguments' => array(3, TRUE),
+ 'load arguments' => array(TRUE),
'access callback' => 'user_access',
'access arguments' => array('administer features'),
'type' => MENU_LOCAL_TASK,
@@ -160,7 +159,7 @@ function features_menu() {
'description' => 'Compare default and current feature.',
'page callback' => 'features_feature_diff',
'page arguments' => array(3, 5),
- 'load arguments' => array(3, TRUE),
+ 'load arguments' => array(TRUE),
'access callback' => 'features_access_override_actions',
'access arguments' => array(3),
'type' => MENU_LOCAL_TASK,
@@ -173,7 +172,7 @@ function features_menu() {
'description' => 'Lock a feature or components.',
'page callback' => 'features_admin_lock',
'page arguments' => array(3, 5, 6),
- 'load arguments' => array(3, TRUE, TRUE),
+ 'load arguments' => array(TRUE),
'access arguments' => array('administer features'),
'type' => MENU_CALLBACK,
'file' => 'features.admin.inc',
@@ -183,7 +182,7 @@ function features_menu() {
'description' => 'Javascript status call back.',
'page callback' => 'features_feature_status',
'page arguments' => array(3),
- 'load arguments' => array(3, TRUE),
+ 'load arguments' => array(TRUE),
'access callback' => 'user_access',
'access arguments' => array('administer features'),
'type' => MENU_CALLBACK,
@@ -278,7 +277,11 @@ function features_flush_caches() {
features_get_modules(NULL, TRUE);
}
}
- return array('cache_features');
+
+ if (db_table_exists('cache_features')) {
+ return array('cache_features');
+ }
+ return array();
}
/**
@@ -515,7 +518,7 @@ function features_load_feature($name, $reset = FALSE) {
* Return a module 'object' including .info information.
*
* @param $name
- * The name of the module to retrieve information for. If ommitted,
+ * The name of the module to retrieve information for. If omitted,
* an array of all available modules will be returned.
* @param $reset
* Whether to reset the cache.
@@ -757,9 +760,9 @@ function features_get_info($type = 'module', $name = NULL, $reset = FALSE) {
$cache->data = $data;
}
if (!empty($name)) {
- return !empty($cache->data[$type][$name]) ? clone $cache->data[$type][$name] : array();
+ return !empty($cache->data[$type][$name]) ? clone $cache->data[$type][$name] : FALSE;
}
- return !empty($cache->data[$type]) ? $cache->data[$type] : array();
+ return !empty($cache->data[$type]) ? $cache->data[$type] : FALSE;
}
/**
@@ -910,7 +913,7 @@ function features_access_override_actions($feature) {
features_include();
module_load_include('inc', 'features', 'features.export');
- $access[$feature->name] = in_array(features_get_storage($feature->name), array(FEATURES_OVERRIDDEN, FEATURES_NEEDS_REVIEW)) && user_access('administer features');
+ $access[$feature->name] = in_array(features_get_storage($feature->name), array(FEATURES_DEFAULT, FEATURES_OVERRIDDEN, FEATURES_NEEDS_REVIEW));
}
return $access[$feature->name];
}
@@ -921,7 +924,9 @@ function features_access_override_actions($feature) {
* Implements hook_form_alter() for system_modules form().
*/
function features_form_system_modules_alter(&$form) {
- features_rebuild();
+ if (variable_get('features_rebuild_modules_page', FALSE)) {
+ features_rebuild();
+ }
}
/**
@@ -1223,12 +1228,14 @@ function features_feature_unlock($feature, $component = NULL) {
}
/**
- * Sets the current language to english to ensure a proper export.
+ * Sets/Returns the current language to english to ensure a proper export.
*/
-function _features_set_export_language() {
- // Ensure this is only done if the language isn't already en.
- // This can be called multiple times - ensure the handling is done just once.
- if ($GLOBALS['language']->language != 'en' && !drupal_static(__FUNCTION__)) {
+function _features_export_language($language = NULL) {
+ $current = $GLOBALS['language'];
+ if (isset($language)) {
+ $GLOBALS['language'] = $language;
+ }
+ elseif ($GLOBALS['language']->language != 'en') {
// Create the language object as language_default() does.
$GLOBALS['language'] = (object) array(
'language' => 'en',
@@ -1243,57 +1250,8 @@ function _features_set_export_language() {
'weight' => 0,
'javascript' => '',
);
- // Ensure that static caches are cleared, as they might contain language
- // specific information. But keep some important ones. The call below
- // accesses a non existing key and requests to reset it. In such cases the
- // whole caching data array is returned.
- $static = drupal_static(uniqid('', TRUE), NULL, TRUE);
- drupal_static_reset();
- // Restore some of the language independent, runtime state information to
- // keep everything working and avoid unnecessary double processing.
- $static_caches_to_keep = array(
- 'conf_path',
- 'system_list',
- 'ip_address',
- 'drupal_page_is_cacheable',
- 'list_themes',
- 'drupal_page_header',
- 'drupal_send_headers',
- 'drupal_http_headers',
- 'language_list',
- 'module_implements',
- 'drupal_alter',
- 'path_is_admin',
- 'path_get_admin_paths',
- 'drupal_match_path',
- 'menu_get_custom_theme',
- 'menu_get_item',
- 'arg',
- 'drupal_system_listing',
- 'drupal_parse_info_file',
- 'libraries_get_path',
- 'module_hook_info',
- 'drupal_add_js',
- 'drupal_add_js:jquery_added',
- 'drupal_add_library',
- 'drupal_get_library',
- 'drupal_add_css',
- 'menu_set_active_trail',
- 'menu_link_get_preferred',
- 'menu_set_active_menu_names',
- 'theme_get_registry',
- 'features_get_components',
- 'features_get_components_by_key',
- );
- foreach ($static_caches_to_keep as $cid) {
- if (isset($static[$cid])) {
- $data = &drupal_static($cid);
- $data = $static[$cid];
- }
- }
- $called = &drupal_static(__FUNCTION__);
- $called = TRUE;
}
+ return $current;
}
/**
@@ -1330,6 +1288,11 @@ function features_features_ignore($component) {
case 'field':
$ignores['locked'] = 1;
break;
+ case 'field_base':
+ $ignores['indexes'] = 0;
+ break;
+ case 'taxonomy':
+ $ignores['hierarchy'] = 0;
}
return $ignores;
}
diff --git a/profiles/commerce_kickstart/modules/contrib/features/includes/features.contact.inc b/profiles/commerce_kickstart/modules/contrib/features/includes/features.contact.inc
new file mode 100644
index 00000000..af9b9193
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/features/includes/features.contact.inc
@@ -0,0 +1,115 @@
+ array(
+ 'name' => t('Contact categories'),
+ 'feature_source' => TRUE,
+ 'default_hook' => 'contact_categories_defaults',
+ 'default_file' => FEATURES_DEFAULTS_INCLUDED,
+ ),
+ );
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function contact_categories_features_export_options() {
+ $options = array();
+ $categories = db_select('contact', 'c')->fields('c')->execute()->fetchAll();
+ foreach ($categories as $category) {
+ $options["$category->category"] = "$category->category";
+ }
+ return $options;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function contact_categories_features_export($data, &$export, $module_name = '') {
+ $export['dependencies']['features'] = 'features';
+ $export['dependencies']['contact'] = 'contact';
+
+ foreach ($data as $name) {
+ $export['features']['contact_categories'][$name] = $name;
+ }
+
+ return array();
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function contact_categories_features_export_render($module, $data, $export = NULL) {
+ $render = array();
+ foreach ($data as $name) {
+ $export_category = db_select('contact', 'c')
+ ->fields('c', array('cid', 'category'))
+ ->condition('category', $name, 'LIKE')
+ ->execute()
+ ->fetchAll();
+ if (isset($export_category[0]->cid) && ($category = contact_load($export_category[0]->cid))) {
+ unset($category['cid']);
+ $render[$name] = $category;
+ }
+ }
+ return array('contact_categories_defaults' => ' return ' . features_var_export($render, ' ') . ';');
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function contact_categories_features_revert($module) {
+ return contact_categories_features_rebuild($module);
+}
+
+/**
+ * Implements hook_features_rebuild().
+ */
+function contact_categories_features_rebuild($module) {
+ if ($defaults = features_get_default('contact_categories', $module)) {
+ foreach ($defaults as $default_category) {
+ $existing_categories = db_select('contact', 'c')
+ ->fields('c', array('cid', 'category'))
+ ->execute()
+ ->fetchAll();
+ if ($existing_categories) {
+ foreach ($existing_categories as $existing_category) {
+ if ($default_category['category'] == $existing_category->category) {
+ db_update('contact')
+ ->fields(
+ array(
+ 'recipients' => $default_category['recipients'],
+ 'reply' => $default_category['reply'],
+ 'weight' => $default_category['weight'],
+ 'selected' => $default_category['selected'],
+ )
+ )
+ ->condition('category', $existing_category->category, '=')
+ ->execute();
+ }
+ else {
+ db_merge('contact')
+ ->key(array('category' => $default_category['category']))
+ ->fields($default_category)
+ ->execute();
+ }
+ }
+ }
+ else {
+ db_merge('contact')
+ ->key(array('category' => $default_category['category']))
+ ->fields($default_category)
+ ->execute();
+ }
+ }
+ }
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/features/includes/features.field.inc b/profiles/commerce_kickstart/modules/contrib/features/includes/features.field.inc
index 01202b64..849081dd 100644
--- a/profiles/commerce_kickstart/modules/contrib/features/includes/features.field.inc
+++ b/profiles/commerce_kickstart/modules/contrib/features/includes/features.field.inc
@@ -158,7 +158,7 @@ function field_base_features_export_render($module, $data, $export = NULL) {
unset($field['storage']);
}
// If we still have a storage declaration here it means that a non-default
- // storage type was altered into to the field definition. And noone would
+ // storage type was altered into to the field definition. And no one would
// never need to change the 'details' key, so don't render it.
if (isset($field['storage']['details'])) {
unset($field['storage']['details']);
@@ -170,10 +170,10 @@ function field_base_features_export_render($module, $data, $export = NULL) {
$field_identifier = features_var_export($identifier);
if (features_field_export_needs_wrap($field_prefix, $field_identifier)) {
$code[] = rtrim($field_prefix);
- $code[] = " // {$field_identifier}";
+ $code[] = " // {$field_identifier}.";
}
else {
- $code[] = $field_prefix . $field_identifier;
+ $code[] = $field_prefix . $field_identifier . '.';
}
$code[] = " \$field_bases[{$field_identifier}] = {$field_export};";
$code[] = "";
@@ -201,10 +201,10 @@ function field_instance_features_export_render($module, $data, $export = NULL) {
$instance_identifier = features_var_export($identifier);
if (features_field_export_needs_wrap($instance_prefix, $instance_identifier)) {
$code[] = rtrim($instance_prefix);
- $code[] = " // {$instance_identifier}";
+ $code[] = " // {$instance_identifier}.";
}
else {
- $code[] = $instance_prefix . $instance_identifier;
+ $code[] = $instance_prefix . $instance_identifier . '.';
}
$code[] = " \$field_instances[{$instance_identifier}] = {$field_export};";
$code[] = "";
@@ -420,7 +420,7 @@ function field_features_export_render($module, $data, $export = NULL) {
unset($field['field_config']['storage']);
}
// If we still have a storage declaration here it means that a non-default
- // storage type was altered into to the field definition. And noone would
+ // storage type was altered into to the field definition. And no one would
// never need to change the 'details' key, so don't render it.
if (isset($field['field_config']['storage']['details'])) {
unset($field['field_config']['storage']['details']);
@@ -572,5 +572,6 @@ function features_field_load($identifier) {
* @see https://www.drupal.org/node/1354
*/
function features_field_export_needs_wrap($prefix, $identifier) {
- return (strlen($prefix) + strlen($identifier) > 80);
+ // Check for 79 characters, since the comment ends with a full stop.
+ return (strlen($prefix) + strlen($identifier) > 79);
}
diff --git a/profiles/commerce_kickstart/modules/contrib/features/includes/features.locale.inc b/profiles/commerce_kickstart/modules/contrib/features/includes/features.locale.inc
index 126d177d..258d5413 100644
--- a/profiles/commerce_kickstart/modules/contrib/features/includes/features.locale.inc
+++ b/profiles/commerce_kickstart/modules/contrib/features/includes/features.locale.inc
@@ -141,8 +141,8 @@ function _features_language_save($language) {
}
// Update Existing language.
else {
- // @TODO: get properties from schema.
- $properties = array('language', 'name', 'native', 'direction', 'enabled', 'plurals', 'formula', 'domain', 'prefix', 'weight', 'javascript');
+ // Get field list from table schema.
+ $properties = drupal_schema_fields_sql('languages');
// The javascript hash is not in the imported data but should be empty
if (!isset($language->javascript)) {
$language->javascript = '';
diff --git a/profiles/commerce_kickstart/modules/contrib/features/includes/features.menu.inc b/profiles/commerce_kickstart/modules/contrib/features/includes/features.menu.inc
index 6ba83e6e..edd47514 100644
--- a/profiles/commerce_kickstart/modules/contrib/features/includes/features.menu.inc
+++ b/profiles/commerce_kickstart/modules/contrib/features/includes/features.menu.inc
@@ -103,7 +103,6 @@ function menu_custom_features_export_render($module, $data) {
$code[] = features_translatables_export($translatables, ' ');
}
- $code[] = '';
$code[] = ' return $menus;';
$code = implode("\n", $code);
return array('menu_default_menu_custom' => $code);
@@ -248,7 +247,7 @@ function menu_links_features_export_render($module, $data, $export = NULL) {
unset($link['plid']);
unset($link['mlid']);
- $code[] = " // Exported menu link: {$new_identifier}";
+ $code[] = " // Exported menu link: {$new_identifier}.";
$code[] = " \$menu_links['{$new_identifier}'] = ". features_var_export($link, ' ') .";";
$translatables[] = $link['link_title'];
}
@@ -316,6 +315,7 @@ function menu_links_features_rebuild_ordered($menu_links, $reset = FALSE) {
foreach ($unordered as $link) {
$identifier = menu_links_features_identifier($link);
$ordered[$identifier] = 0;
+ $all_links[$identifier] = $link;
}
asort($ordered);
}
diff --git a/profiles/commerce_kickstart/modules/contrib/features/includes/features.node.inc b/profiles/commerce_kickstart/modules/contrib/features/includes/features.node.inc
index f40341af..25a2c1cd 100644
--- a/profiles/commerce_kickstart/modules/contrib/features/includes/features.node.inc
+++ b/profiles/commerce_kickstart/modules/contrib/features/includes/features.node.inc
@@ -145,11 +145,14 @@ function node_features_disable_feature($module) {
* When a features module is enabled, modify any node types it provides so
* they can no longer be deleted manually through the content types UI.
*
+ * Update the database cache of node types if needed.
+ *
* @param $module
* Name of module that has been enabled.
*/
function node_features_enable_feature($module) {
if ($default_types = features_get_default('node', $module)) {
+ $rebuild = FALSE;
foreach ($default_types as $type_name => $type_info) {
// Ensure the type exists.
if ($type_info = node_type_load($type_name)) {
@@ -160,6 +163,12 @@ function node_features_enable_feature($module) {
$type_info->disabled = 0;
node_type_save($type_info);
}
+ else {
+ $rebuild = TRUE;
+ }
+ }
+ if ($rebuild) {
+ node_types_rebuild();
}
}
}
diff --git a/profiles/commerce_kickstart/modules/contrib/features/tests/features.test b/profiles/commerce_kickstart/modules/contrib/features/tests/features.test
index bbdeb0b9..025ef23c 100644
--- a/profiles/commerce_kickstart/modules/contrib/features/tests/features.test
+++ b/profiles/commerce_kickstart/modules/contrib/features/tests/features.test
@@ -218,7 +218,7 @@ class FeaturesEnableTestCase extends DrupalWebTestCase {
/**
- * Tests intergration of ctools for features.
+ * Tests integration of ctools for features.
*/
class FeaturesCtoolsIntegrationTest extends DrupalWebTestCase {
protected $profile = 'testing';
diff --git a/profiles/commerce_kickstart/modules/contrib/features/tests/features_test/features_test.info b/profiles/commerce_kickstart/modules/contrib/features/tests/features_test/features_test.info
index 50085c55..04f01d33 100644
--- a/profiles/commerce_kickstart/modules/contrib/features/tests/features_test/features_test.info
+++ b/profiles/commerce_kickstart/modules/contrib/features/tests/features_test/features_test.info
@@ -21,9 +21,9 @@ features[user_permission][] = create features_test content
features[views_view][] = features_test
hidden = 1
-; Information added by Drupal.org packaging script on 2015-06-24
-version = "7.x-2.6"
+; Information added by Drupal.org packaging script on 2016-04-18
+version = "7.x-2.10"
core = "7.x"
project = "features"
-datestamp = "1435165997"
+datestamp = "1461011641"
diff --git a/profiles/commerce_kickstart/modules/contrib/features_override/features_override.export.inc b/profiles/commerce_kickstart/modules/contrib/features_override/features_override.export.inc
index 49182b62..745f9e06 100644
--- a/profiles/commerce_kickstart/modules/contrib/features_override/features_override.export.inc
+++ b/profiles/commerce_kickstart/modules/contrib/features_override/features_override.export.inc
@@ -51,19 +51,6 @@ function features_override_make_key($keys) {
}
}
-/**
- * Returns an array of keys to be ignored for various exportables
- * @param $component
- * The component to retrieve ignore_keys from.
- */
-function features_get_ignore_keys($component) {
- static $cache;
- if (!isset($cache[$component])) {
- $cache[$component] = module_invoke_all('features_override_ignore', $component);
- }
- return $cache[$component];
-}
-
/**
* Calculates what overrides exist for by component/element.
*
@@ -107,36 +94,6 @@ function features_override_get_overrides($component_key = FALSE, $element_key =
return $cache;
}
-/**
- * Helper function in determining equality of arrays. Credit to http://stackoverflow.com/a/4263181
- *
- * @see _features_override_remove_recursion()
- *
- * @param $a
- * object a
- * @param $b
- * object b
- * @return bool
- *
- */
-function _features_override_is_ref_to(&$a, &$b, $uniqid) {
- if (is_object($a) && is_object($b)) {
- return ($a === $b);
- }
-
- $temp_a = $a;
- $temp_b = $b;
-
- $b = $uniqid;
-
- if ($a === $uniqid) $return = true;
- else $return = false;
-
- $a = $temp_a;
- $b = $temp_b;
- return $return;
-}
-
/**
* Get overrides for specific module/component.
*
@@ -195,20 +152,17 @@ function features_override_module_component_overrides($module, $component, $rese
// Can't use _features_sanitize as that resets some keys.
_features_override_sanitize($normal);
_features_override_sanitize($default);
- // make a deep copy of data to prevent problems when removing recursion later
- $default_copy = unserialize(serialize($default));
- $normal_copy = unserialize(serialize($normal));
- $ignore_keys = features_get_ignore_keys($component);
+ $default_copy = features_remove_recursion($default);
+ $normal_copy = features_remove_recursion($normal);
+
+ $ignore_keys = _features_get_ignore_keys($component);
// remove keys to be ignored
// doing this now allows us to better control which recursive parts are removed
if (count($ignore_keys)) {
- _features_override_remove_ignores($default_copy, $ignore_keys);
- _features_override_remove_ignores($normal_copy, $ignore_keys);
+ _features_remove_ignores($default_copy, $ignore_keys);
+ _features_remove_ignores($normal_copy, $ignore_keys);
}
- // now remove any remaining recursion
- features_override_remove_recursion($default_copy);
- features_override_remove_recursion($normal_copy);
$component_overrides = array();
if ($normal && is_array($normal) || is_object($normal)) {
@@ -394,83 +348,6 @@ function features_override_export_keys($keys) {
return $line;
}
-/**
- * Removes recursion from an object or array.
- *
- * @param $item
- * An object or array passed by reference.
- */
-function features_override_remove_recursion(&$item) {
- $uniqid = __FUNCTION__ . mt_rand(); // use of uniqid() here impacts performance
- $stack = array();
- _features_override_remove_recursion($item, $stack, $uniqid);
-}
-
-/**
- * Helper to removes recursion from an object/array.
- *
- * @param $item
- * An object or array passed by reference.
- */
-function _features_override_remove_recursion(&$object, &$stack = array(), $uniqid) {
- if ((is_object($object) || is_array($object)) && $object) {
- $in_stack = FALSE;
- foreach($stack as &$item) {
- if(_features_override_is_ref_to($object, $item, $uniqid)) {
- $in_stack = TRUE;
- break;
- }
- }
- if(!$in_stack) {
- $stack[] = $object;
- foreach ($object as $key => &$subobject) {
- if (_features_override_remove_recursion($subobject, $stack, $uniqid)) {
- if (is_object($object)) {
- unset($object->$key);
- }
- else {
- unset($object[$key]);
- }
- }
- }
- } else {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-/**
- * Helper to removes a set of keys an object/array.
- *
- * @param $item
- * An object or array passed by reference.
- * @param $ignore_keys
- * Array of keys to be ignored. Values are the level of the key.
- * @param $level
- * Level of key to remove. Up to 2 levels deep because $item can still be
- * recursive
- */
-function _features_override_remove_ignores(&$item, $ignore_keys, $level = -1) {
- $is_object = is_object($item);
- if (!is_array($item) && !is_object($item)) {
- return;
- }
- foreach ($item as $key => $value) {
- if (isset($ignore_keys[$key]) && ($ignore_keys[$key] == $level)) {
- if ($is_object) {
- unset($item->$key);
- }
- else {
- unset($item[$key]);
- }
- }
- elseif (($level < 2) && (is_array($value) || is_object($value))) {
- _features_override_remove_ignores($value, $ignore_keys, $level+1);
- }
- }
-}
-
/**
* Drupal-friendly var_export().
*
diff --git a/profiles/commerce_kickstart/modules/contrib/features_override/features_override.hooks.inc b/profiles/commerce_kickstart/modules/contrib/features_override/features_override.hooks.inc
index 83d1ab92..5d848ed0 100644
--- a/profiles/commerce_kickstart/modules/contrib/features_override/features_override.hooks.inc
+++ b/profiles/commerce_kickstart/modules/contrib/features_override/features_override.hooks.inc
@@ -27,6 +27,7 @@ function image_features_override_export_render_addition($alter, $element) {
$value_export = features_override_var_export($alter['value'], ' ');
$code[] = "";
$code[] = " if (!isset(" . $component_start . "['storage']) || " . $component_start . "['storage'] == IMAGE_STORAGE_DEFAULT) {";
+ $code[] = " " . $component_start . "['effects'] = array_values(" . $component_start . "['effects']" . ');';
$code[] = " " . $component_start . $code_line . ' = ' . $value_export . ';';
$code[] = " }";
}
diff --git a/profiles/commerce_kickstart/modules/contrib/features_override/features_override.info b/profiles/commerce_kickstart/modules/contrib/features_override/features_override.info
index ed6ed981..48327e8a 100644
--- a/profiles/commerce_kickstart/modules/contrib/features_override/features_override.info
+++ b/profiles/commerce_kickstart/modules/contrib/features_override/features_override.info
@@ -5,9 +5,9 @@ dependencies[] = ctools
dependencies[] = features
package = "Features"
-; Information added by Drupal.org packaging script on 2014-08-01
-version = "7.x-2.0-rc2"
+; Information added by Drupal.org packaging script on 2015-10-14
+version = "7.x-2.0-rc3"
core = "7.x"
project = "features_override"
-datestamp = "1406903928"
+datestamp = "1444843045"
diff --git a/profiles/commerce_kickstart/modules/contrib/features_override/features_override.module b/profiles/commerce_kickstart/modules/contrib/features_override/features_override.module
index 1c83e920..22040263 100644
--- a/profiles/commerce_kickstart/modules/contrib/features_override/features_override.module
+++ b/profiles/commerce_kickstart/modules/contrib/features_override/features_override.module
@@ -63,7 +63,7 @@ function features_override_menu_alter(&$items) {
'description' => 'Compare default and current feature.',
'page callback' => 'features_override_feature_diff',
'page arguments' => array(3, 5),
- 'load arguments' => array(3, TRUE),
+ 'load arguments' => array(TRUE),
'access callback' => 'features_access_override_actions',
'access arguments' => array(3),
'type' => MENU_LOCAL_TASK,
@@ -72,44 +72,6 @@ function features_override_menu_alter(&$items) {
);
}
-/**
- * Implements hook_features_override_ignore().
- */
-function features_override_features_override_ignore($component) {
- // Determine which keys need to be ignored for override diff for various components.
- // value is shows how many levels deep the key is
- $ignores = array();
- switch ($component) {
- case 'views_view':
- $ignores['current_display'] = 0;
- $ignores['display_handler'] = 0;
- $ignores['handler'] = 2;
- $ignores['query'] = 0;
- $ignores['localization_plugin'] = 0;
- // Views automatically adds these two on export to set values.
- $ignores['api_version'] = 0;
- $ignores['disabled'] = 0;
- break;
- case 'image':
- $ignores['module'] = 0;
- $ignores['name'] = 0;
- $ignores['storage'] = 0;
- // Various properities are loaded into the effect in image_styles.
- $ignores['summary theme'] = 2;
- $ignores['module'] = 2;
- $ignores['label'] = 2;
- $ignores['help'] = 2;
- $ignores['form callback'] = 2;
- $ignores['effect callback'] = 2;
- $ignores['dimensions callback'] = 2;
- break;
- case 'field':
- $ignores['locked'] = 1;
- break;
- }
- return $ignores;
-}
-
/**
* Implements hook_modules_enabled().
*
diff --git a/profiles/commerce_kickstart/modules/contrib/features_override/features_override_form.js b/profiles/commerce_kickstart/modules/contrib/features_override/features_override_form.js
index 4103cab4..46db6b4a 100644
--- a/profiles/commerce_kickstart/modules/contrib/features_override/features_override_form.js
+++ b/profiles/commerce_kickstart/modules/contrib/features_override/features_override_form.js
@@ -14,7 +14,7 @@
$parent_label.append('' + Drupal.t('view') + '');
}
- var $child_checkboxes = $('input[type=checkbox][name^="sources[features_overrides]"][value^=' + this.value + ']').each(function (i) {
+ var $child_checkboxes = $('input[type=checkbox][name^="sources[features_overrides]"][value^="' + this.value + '"]').each(function (i) {
if (Drupal.settings.features_override_links['sub'][this.value]) {
$($(this).parent()).find('label').append('' + Drupal.t('view') + '');
}
diff --git a/profiles/commerce_kickstart/modules/contrib/fences/CHANGELOG.txt b/profiles/commerce_kickstart/modules/contrib/fences/CHANGELOG.txt
index 41aeb0e4..a3f516d1 100644
--- a/profiles/commerce_kickstart/modules/contrib/fences/CHANGELOG.txt
+++ b/profiles/commerce_kickstart/modules/contrib/fences/CHANGELOG.txt
@@ -1,3 +1,13 @@
+Fences 7.x-1.2, 2015-09-24
+--------------------------
+- #2573745 by JohnAlbin: Un-configured fields appear to be configured to "no wrapper"
+
+Fences 7.x-1.1, 2015-09-21
+--------------------------
+- #1857230 by Xen, JohnAlbin: Add option to use the "normal" Drupal field output
+- #1711490 by dalberts69: @theme_name not properly replaced in UI
+- #1561244 by RoySegall and JohnAlbin: Undefined Index (with installation profiles and features?)
+
Fences 7.x-1.0, 2012-04-26
--------------------------
- #1352202: Add option to limit field classes
diff --git a/profiles/commerce_kickstart/modules/contrib/fences/PATCHES.txt b/profiles/commerce_kickstart/modules/contrib/fences/PATCHES.txt
deleted file mode 100644
index a6e1e968..00000000
--- a/profiles/commerce_kickstart/modules/contrib/fences/PATCHES.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-The following patches have been applied to this project:
-- http://drupal.org/files/undefined-index-1561244-7.patch
-- http://drupal.org/files/fences-default_markup_option-1857230-2.patch
-
-This file was automatically generated by Drush Make (http://drupal.org/project/drush).
\ No newline at end of file
diff --git a/profiles/commerce_kickstart/modules/contrib/fences/fences.admin.inc b/profiles/commerce_kickstart/modules/contrib/fences/fences.admin.inc
index 64f68dae..bee22426 100644
--- a/profiles/commerce_kickstart/modules/contrib/fences/fences.admin.inc
+++ b/profiles/commerce_kickstart/modules/contrib/fences/fences.admin.inc
@@ -14,36 +14,34 @@ function _fences_theme($existing, $type, $theme, $path) {
$supported_hooks = array('field');
foreach ($supported_hooks as $hook) {
- // If there are no implementation then skip the iteration.
- if (empty($existing[$hook])) {
- continue;
- }
- foreach ($fences[$hook] as $suggestion => $data) {
- // Manually register the suggestions for a module, but let hook_theme
- // auto-discover theme-owned suggestions as it normally does.
- if ($fences[$hook][$suggestion]['type'] == 'module') {
- $hook_suggestion = $hook . '__fences_' . str_replace('-', '_', $suggestion);
- $hook_suggestions = array($hook_suggestion);
- // Register the "-multiple" suggestion if that template was found.
- if ($fences[$hook][$suggestion]['multiple']) {
- $hook_suggestions[] = $hook_suggestion . '_multiple';
- }
- foreach ($hook_suggestions as $name) {
- $hooks[$name] = array(
- 'base hook' => $hook,
- 'render element' => $existing[$hook]['render element'],
- 'type' => $fences[$hook][$suggestion]['type'],
- 'theme path' => $existing[$hook]['theme path'],
- 'template' => str_replace('_', '-', $name),
- 'path' => $fences[$hook][$suggestion]['path'],
- );
+ if (!empty($existing[$hook])) {
+ foreach ($fences[$hook] as $suggestion => $data) {
+ // Manually register the suggestions for a module, but let hook_theme
+ // auto-discover theme-owned suggestions as it normally does.
+ if ($fences[$hook][$suggestion]['type'] == 'module') {
+ $hook_suggestion = $hook . '__fences_' . str_replace('-', '_', $suggestion);
+ $hook_suggestions = array($hook_suggestion);
+ // Register the "-multiple" suggestion if that template was found.
+ if ($fences[$hook][$suggestion]['multiple']) {
+ $hook_suggestions[] = $hook_suggestion . '_multiple';
+ }
+ foreach ($hook_suggestions as $name) {
+ $hooks[$name] = array(
+ 'base hook' => $hook,
+ 'render element' => $existing[$hook]['render element'],
+ 'type' => $fences[$hook][$suggestion]['type'],
+ 'theme path' => $existing[$hook]['theme path'],
+ 'template' => str_replace('_', '-', $name),
+ 'path' => $fences[$hook][$suggestion]['path'],
+ );
+ }
}
}
}
}
// Register theme hook suggestions for field_collection's entity.
- if (module_exists('entity')) {
+ if (module_exists('entity') && !empty($existing['entity'])) {
$hooks['entity__fences_no_wrapper'] = array(
'base hook' => 'entity',
'render element' => $existing['entity']['render element'],
@@ -116,8 +114,7 @@ function _fences_get_fences_suggestion_info(&$fences) {
// Create a list of the default theme and its base themes.
$theme_default = $GLOBALS['conf']['theme_default'];
- // We can't use list_themes() here because of #761608.
- $theme_data = _system_rebuild_theme_data();
+ $theme_data = list_themes();
if (isset($theme_data[$theme_default]->base_themes)) {
foreach (array_keys($theme_data[$theme_default]->base_themes) as $base_theme) {
$themes[$base_theme] = 'base_theme_engine';
@@ -166,7 +163,7 @@ function _fences_get_fences_suggestion_info(&$fences) {
'label' => $suggestion,
'element' => $suggestion,
'description' => t('A <@tag> tag', array('@tag' => $suggestion)),
- 'groups' => array(t('Provided by @theme_name', array('@theme_name', $theme))),
+ 'groups' => array(t('Provided by @theme_name', array('@theme_name' => $theme))),
'type' => $type,
);
}
@@ -212,9 +209,6 @@ function _fences_get_fences_options($theme_hook) {
unset($options['no_wrapper']);
$options = array('no_wrapper' => $no_wrapper) + $options;
}
- if (!variable_get('fences_default_markup', 0)) {
- $options = array('' => t('Use Drupal standard markup')) + $options;
- }
return $options;
}
@@ -225,10 +219,13 @@ function _fences_get_fences_options($theme_hook) {
function _fences_form_field_ui_field_edit_form_alter(&$form, &$form_state) {
$suggestion = fences_get_suggestion($form['#instance']['entity_type'], $form['#instance']['bundle'], $form['#instance']['field_name']);
+ // Make the default markup selection match the Fences default markup setting.
+ $default_markup = variable_get('fences_default_markup', 0) ? 'div' : 'div_div_div';
+
$form['instance']['fences_wrapper'] = array(
'#type' => 'select',
'#title' => t('Wrapper markup'),
- '#default_value' => $suggestion ? $suggestion : '',
+ '#default_value' => $suggestion ? $suggestion : $default_markup,
'#options' => fences_get_fences_options('field'),
'#description' => t('Choose the HTML to use to wrap the field.'),
);
diff --git a/profiles/commerce_kickstart/modules/contrib/fences/fences.api.php b/profiles/commerce_kickstart/modules/contrib/fences/fences.api.php
index 967470c3..3338bc43 100644
--- a/profiles/commerce_kickstart/modules/contrib/fences/fences.api.php
+++ b/profiles/commerce_kickstart/modules/contrib/fences/fences.api.php
@@ -29,7 +29,7 @@ function hook_fences_suggestion_info() {
'label' => t('paragraph'),
// The HTML element(s) used by the suggestion. This will be added to the
// label in the UI to provide additional context. If multiple elements are
- // used they should be seperated by spaces, e.g. 'pre code'.
+ // used they should be separated by spaces, e.g. 'pre code'.
'element' => 'p',
// A short description used in the UI when selecting a suggestion.
'description' => t('A paragraph; multiple values are each wrapped in a
'),
diff --git a/profiles/commerce_kickstart/modules/contrib/fences/fences.fences.inc b/profiles/commerce_kickstart/modules/contrib/fences/fences.fences.inc
index 88fbd576..fbf7e0f0 100644
--- a/profiles/commerce_kickstart/modules/contrib/fences/fences.fences.inc
+++ b/profiles/commerce_kickstart/modules/contrib/fences/fences.fences.inc
@@ -99,6 +99,12 @@ function fences_fences_suggestion_info() {
'description' => t('Generic container; only use as a last resort'),
'groups' => array(t('Block-level')),
),
+ 'div_div_div' => array(
+ 'label' => t('division (nested)'),
+ 'element' => 'div div div',
+ 'description' => t("Drupal's default field markup"),
+ 'groups' => array(t('Block-level')),
+ ),
'em' => array(
'label' => t('emphasis'),
'element' => 'em',
diff --git a/profiles/commerce_kickstart/modules/contrib/fences/fences.info b/profiles/commerce_kickstart/modules/contrib/fences/fences.info
index b6262694..17dee886 100644
--- a/profiles/commerce_kickstart/modules/contrib/fences/fences.info
+++ b/profiles/commerce_kickstart/modules/contrib/fences/fences.info
@@ -8,9 +8,9 @@ dependencies[] = field
configure = admin/config/content/fences
-; Information added by drupal.org packaging script on 2012-04-25
-version = "7.x-1.0"
+; Information added by Drupal.org packaging script on 2015-09-24
+version = "7.x-1.2"
core = "7.x"
project = "fences"
-datestamp = "1335373578"
+datestamp = "1443071044"
diff --git a/profiles/commerce_kickstart/modules/contrib/fences/fences.module b/profiles/commerce_kickstart/modules/contrib/fences/fences.module
index 118d811d..6a080034 100644
--- a/profiles/commerce_kickstart/modules/contrib/fences/fences.module
+++ b/profiles/commerce_kickstart/modules/contrib/fences/fences.module
@@ -169,7 +169,10 @@ function fences_preprocess_field(&$variables) {
$suggestion = 'div';
}
- if ($suggestion) {
+ // Add a theme hook suggestion for the configured suggestion, unless the
+ // suggestion is "div_div_div", in which case we should use Drupal's default
+ // field markup instead of a theme hook suggestion.
+ if ($suggestion && $suggestion !== 'div_div_div') {
// Make fences' suggestions low priority by placing them at the front of the queue.
$suggestion = 'field__fences_' . $suggestion;
if (count($variables['items']) > 1) {
diff --git a/profiles/commerce_kickstart/modules/contrib/fences/templates/field--fences-div-div-div.tpl.php b/profiles/commerce_kickstart/modules/contrib/fences/templates/field--fences-div-div-div.tpl.php
new file mode 100644
index 00000000..09f8b7b5
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/fences/templates/field--fences-div-div-div.tpl.php
@@ -0,0 +1,20 @@
+ elements. Note: This template is never used; instead
+ * Drupal core's theme_field() is used.
+ *
+ * @see http://developers.whatwg.org/grouping-content.html#the-div-element
+ */
+?>
+
>
+
+
>:
+
+
>
+ $item): ?>
+
>
+
+
+
diff --git a/profiles/commerce_kickstart/modules/contrib/fences/templates/field--fences-figcaption.tpl.php b/profiles/commerce_kickstart/modules/contrib/fences/templates/field--fences-figcaption.tpl.php
index b2eeccfa..a50f0601 100644
--- a/profiles/commerce_kickstart/modules/contrib/fences/templates/field--fences-figcaption.tpl.php
+++ b/profiles/commerce_kickstart/modules/contrib/fences/templates/field--fences-figcaption.tpl.php
@@ -1,7 +1,7 @@
element.
+ * Wrap all field values in a single element.
*
* @see http://developers.whatwg.org/grouping-content.html#the-figcaption-element
*
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/README.txt b/profiles/commerce_kickstart/modules/contrib/i18n/README.txt
index 5a8a4f14..060563bb 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/README.txt
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/README.txt
@@ -20,7 +20,7 @@ For support, please create a support request for this module's project:
Support questions by email to the module maintainer will be simply ignored. Use the issue tracker.
-Now if you want professional (paid) support the module maintainer may be available occassionally.
+Now if you want professional (paid) support the module maintainer may be available occasionally.
Drop me a message to check availability and hourly rates, http://reyero.net/en/contact
====================================================================
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n.info b/profiles/commerce_kickstart/modules/contrib/i18n/i18n.info
index d4f5c430..971f5de8 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n.info
@@ -8,9 +8,9 @@ files[] = i18n_object.inc
files[] = i18n.test
configure = admin/config/regional/i18n
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n.test b/profiles/commerce_kickstart/modules/contrib/i18n/i18n.test
index 491d7ef7..2a82e17a 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n.test
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n.test
@@ -11,7 +11,7 @@ class Drupali18nTestCase extends DrupalWebTestCase {
function setUpLanguages($admin_permissions = array()) {
// Setup admin user.
- $this->admin_user = $this->drupalCreateUser(array_merge(array('bypass node access', 'administer nodes', 'administer languages', 'administer content types', 'administer blocks', 'access administration pages', 'translate interface'), $admin_permissions));
+ $this->admin_user = $this->drupalCreateUser(array_merge(array('bypass node access', 'administer nodes', 'administer languages', 'administer content types', 'administer fields', 'administer blocks', 'access administration pages', 'translate interface'), $admin_permissions));
$this->drupalLogin($this->admin_user);
@@ -362,6 +362,7 @@ class Drupali18nTestCase extends DrupalWebTestCase {
function resetCaches() {
drupal_static_reset('locale_url_outbound_alter');
drupal_static_reset('language_list');
+ drupal_language_initialize();
}
/**
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_block/README.txt b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_block/README.txt
new file mode 100644
index 00000000..5d0ddb87
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_block/README.txt
@@ -0,0 +1,74 @@
+CONTENTS OF THIS FILE
+---------------------
+
+* Introduction
+* Requirements
+* Recommended modules
+* Installation
+* Configuration
+* Troubleshooting
+* Maintainers
+
+
+INTRODUCTION
+------------
+
+The Block languages module, part of the Internationalization (https://www.drupal.org/project/i18n) package, allows the user to configure for which languages each block is visible.
+
+* For a full description of the module, visit https://www.drupal.org/node/1279698
+
+* To submit bug reports and feature suggestions, or to track changes visit https://www.drupal.org/project/issues/i18n
+
+
+REQUIREMENTS
+------------
+
+This module requires the following modules:
+
+Internationalization - https://www.drupal.org/project/i18n
+
+
+RECOMMENDED MODULES
+-------------------
+
+* Internationalization Views - https://www.drupal.org/project/i18nviews
+* Language Icons - https://www.drupal.org/project/languageicons
+* Translation Overview - https://www.drupal.org/project/translation_overview
+* Localization Client - https://www.drupal.org/project/l10n_client
+* Internationalization contributions - https://www.drupal.org/project/i18n_contrib
+
+
+INSTALLATION
+------------
+
+* This is a submodule of the Internationalization module. Install the Internationalization module as you would normally install a contributed Drupal module. Visit https://www.drupal.org/docs/7/extending-drupal-7/installing-contributed-modules-find-import-enable-configure-drupal-7 for further information.
+
+
+CONFIGURATION
+-------------
+
+The settings for visibility per language are provided under Visibility Settings via the Languages tab when configuring a block.
+
+The Languages tab also provides a setting for whether the block is translatable. For custom blocks, the block title and the block content will be translatable. For blocks defined by modules, only the block title will be translatable. If "Make this block translatable" is selected, a Translate tab will appear for that block. This tab provides a UI for adding translations of the block in each available language.
+
+
+TROUBLESHOOTING
+---------------
+
+Conflicts with Context
+
+The Block languages module conflicts with the Context module, which alters how blocks are rendered. This issue can be tracked in the Internationalization issue queue: http://drupal.org/node/1343044
+
+String Errors
+
+The user must allow your used string format to be translated on admin/config/regional/i18n/strings or you are going to have a error message like "The string blocks:block:1:body for textgroup blocks is not allowed for translation because of its text format."
+
+
+MAINTAINERS
+-----------
+
+* Jose Reyero - https://www.drupal.org/u/jose-reyero
+* Florian Weber (webflo) - https://www.drupal.org/u/webflo
+* Peter Philipp - https://www.drupal.org/u/das-peter
+* Joseph Olstad - https://www.drupal.org/u/joseph.olstad
+* Nathaniel Catchpole - https://www.drupal.org/u/catch
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_block/i18n_block.info b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_block/i18n_block.info
index 0e599035..53b4b889 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_block/i18n_block.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_block/i18n_block.info
@@ -8,9 +8,9 @@ files[] = i18n_block.inc
files[] = i18n_block.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_block/i18n_block.test b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_block/i18n_block.test
index b1e46809..e33d99ef 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_block/i18n_block.test
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_block/i18n_block.test
@@ -72,15 +72,16 @@ class i18nBlocksTestCase extends Drupali18nTestCase {
$this->clickLink(t('translate'));
+ // Title is a textarea, body is a text_format.
$this->assertFieldByName('strings[blocks:block:' . $box2['delta'] . ':title]', $translations['title']['es']);
- $this->assertFieldByName('strings[blocks:block:' . $box2['delta'] . ':body]', $translations['body']['es']);
+ $this->assertFieldByName('strings[blocks:block:' . $box2['delta'] . ':body][value]', $translations['body']['es']);
// Update the translation.
$translations['title']['es'] = $this->randomName(10);
$translations['body']['es'] = $this->randomName(20);
$edit = array(
'strings[blocks:block:' . $box2['delta'] . ':title]' => $translations['title']['es'],
- 'strings[blocks:block:' . $box2['delta'] . ':body]' => $translations['body']['es'],
+ 'strings[blocks:block:' . $box2['delta'] . ':body][value]' => $translations['body']['es'],
);
$this->drupalPost(NULL, $edit, t('Save translation'));
$this->i18nAssertTranslations($translations['title'], '', 'Updated block title translation displayed.');
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_contact/README.txt b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_contact/README.txt
new file mode 100644
index 00000000..cc62ab7f
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_contact/README.txt
@@ -0,0 +1,67 @@
+CONTENTS OF THIS FILE
+---------------------
+
+* Introduction
+* Requirements
+* Recommended modules
+* Installation
+* Configuration
+* Maintainers
+
+
+INTRODUCTION
+------------
+
+The Contact translation module, part of the Internationalization (https://www.drupal.org/project/i18n) package, helps with the multilingual configuration of the site contact forms. This module makes contact categories and replies available for translation.
+
+* For a full description of the module, visit https://www.drupal.org/node/1396984
+
+* To submit bug reports and feature suggestions, or to track changes, visit https://www.drupal.org/project/issues/i18n
+
+
+REQUIREMENTS
+------------
+
+This module requires the following modules:
+
+Internationalization (https://www.drupal.org/project/i18n)
+
+
+RECOMMENDED MODULES
+-------------------
+
+* Internationalization Views (https://www.drupal.org/project/i18nviews)
+* Language Icons (https://www.drupal.org/project/languageicons)
+* Translation Overview (https://www.drupal.org/project/translation_overview)
+* Localization Client (https://www.drupal.org/project/l10n_client)
+* Internationalization contributions (https://www.drupal.org/project/i18n_contrib)
+
+
+INSTALLATION
+------------
+
+* This is a submodule of the Internationalization module. Install the Internationalization module as you would normally install a contributed Drupal module. See https://drupal.org/documentation/install/modules-themes/modules-7 for further information.
+
+
+CONFIGURATION
+-------------
+
+1. Enable the Contact translation module included with the Internationalization module.
+2. Go to Administration > Structure > Contact form.
+3. Click edit for the form to configure.
+4. Click the Translate tab.
+5. Click the translate link for a language.
+6. Translate the Category and Auto-reply text.
+7. Click Save translation.
+8. Repeat steps 5 to 7 for each language.
+9. Repeat steps 2 to 8 for all forms.
+
+
+MAINTAINERS
+-----------
+
+* Jose Reyero - https://www.drupal.org/u/jose-reyero
+* Florian Weber (webflo) - https://www.drupal.org/u/webflo
+* Peter Philipp - https://www.drupal.org/u/das-peter
+* Joseph Olstad - https://www.drupal.org/u/joseph.olstad
+* Nathaniel Catchpole - https://www.drupal.org/u/catch
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_contact/i18n_contact.info b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_contact/i18n_contact.info
index 7bad71d2..13e576a6 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_contact/i18n_contact.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_contact/i18n_contact.info
@@ -5,9 +5,9 @@ dependencies[] = i18n_string
package = Multilingual - Internationalization
core = 7.x
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_field/README.txt b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_field/README.txt
new file mode 100644
index 00000000..cb7a5e5e
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_field/README.txt
@@ -0,0 +1,65 @@
+CONTENTS OF THIS FILE
+---------------------
+
+* Introduction
+* Requirements
+* Recommended modules
+* Installation
+* Configuration
+* Maintainers
+
+
+INTRODUCTION
+------------
+
+The Field translation module, part of the Internationalization (https://www.drupal.org/project/i18n) package, allows for translation of text associated with a field's settings including the label, help text, default value, and list options.
+
+* For a full description of the module, visit this page https://www.drupal.org/node/1279346
+
+* To submit bug reports and feature suggestions, or to track changes visit https://www.drupal.org/project/issues/i18n
+
+
+REQUIREMENTS
+------------
+
+This module requires the following modules:
+
+Internationalization (https://www.drupal.org/project/i18n)
+
+
+RECOMMENDED MODULES
+-------------------
+
+* Internationalization Views (https://www.drupal.org/project/i18nviews)
+* Language Icons (https://www.drupal.org/project/languageicons)
+* Translation Overview (https://www.drupal.org/project/translation_overview)
+* Localization Client (https://www.drupal.org/project/l10n_client)
+* Internationalization contributions (https://www.drupal.org/project/i18n_contrib)
+
+
+INSTALLATION
+------------
+
+* This is a submodule of the Internationalization module. Install the Internationalization module as you would normally install a contributed Drupal module. Visit https://drupal.org/documentation/install/modules-themes/modules-7 for further information.
+
+
+CONFIGURATION
+-------------
+
+1. Enable the Field translation module included with Internationalization.
+2. Go to Administration > Configuration > Regional and language > Translate interface.
+3. Click on Filter Translatable Strings field set and limit search to fields.
+4. Edit the desired field and Save.
+For the translation to be displayed, you need to use some of the Field Formatters provided by this module whose name usually ends up in 'translated'. For most core fields it is Default translated.
+
+Note: The Field Translation module does not provide content translation for fields. This functionality is provided by the Entity Translation (ET) module.
+
+
+MAINTAINERS
+-----------
+
+* Jose Reyero - https://www.drupal.org/u/jose-reyero
+* Florian Weber (webflo) - https://www.drupal.org/u/webflo
+* Peter Philipp - https://www.drupal.org/u/das-peter
+* Joseph Olstad - https://www.drupal.org/u/joseph.olstad
+* Nathaniel Catchpole - https://www.drupal.org/u/catch
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_field/i18n_field.info b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_field/i18n_field.info
index 552eb392..baf7ac72 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_field/i18n_field.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_field/i18n_field.info
@@ -6,9 +6,9 @@ package = Multilingual - Internationalization
core = 7.x
files[] = i18n_field.inc
files[] = i18n_field.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_field/i18n_field.module b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_field/i18n_field.module
index eadd2f5c..f78f9c0e 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_field/i18n_field.module
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_field/i18n_field.module
@@ -446,3 +446,69 @@ function i18n_field_type_info($type = NULL, $property = NULL) {
return $info;
}
}
+
+/**
+ * Implements hook_field_info_alter().
+ */
+function i18n_field_field_info_alter(&$field_info) {
+ foreach(array_keys($field_info) as $type) {
+ $field_info[$type]['property_callbacks'][] = 'i18n_field_entity_property_callback';
+ }
+}
+
+/**
+ * Callback to translate entity property info for a fields.
+ *
+ * @see entity_metadata_field_entity_property_info()
+ * @see entity_metadata_field_default_property_callback()
+ * @see i18n_field_i18n_object_info_alter()
+ * @see hook_module_implements_alter()
+ */
+function i18n_field_entity_property_callback(&$info, $entity_type, $field, $instance, $field_type) {
+ global $language;
+
+ // This could create a endless recursion if it's called during rebuilding the
+ // cache for i18n_object_info(). So if the cache of i18n_object_info isn't
+ // available yet we assume the worst case, leave the info alone but trigger a
+ // rebuild of the property when hook_i18n_object_info_alter is invoked. At
+ // that point the info is available and we can rely on it.
+ if (!$info = &drupal_static('i18n_object_info')) {
+ $i18n_field_entity_property_callback_fallback = &drupal_static(__FUNCTION__);
+ $i18n_field_entity_property_callback_fallback = TRUE;
+ return;
+ }
+
+ $name = $field['field_name'];
+ $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$name];
+ $property['label'] = i18n_field_translate_property($instance, 'label', $language->language);
+}
+
+/**
+ * Implements hook_i18n_object_info_alter().
+ */
+function i18n_field_i18n_object_info_alter(&$info) {
+ if (drupal_static('i18n_field_entity_property_callback')) {
+ if ($info = drupal_static('i18n_object_info')) {
+ // Clean static and permanent cache of the data and then re-run the property
+ // building.
+ drupal_static_reset('entity_get_property_info');
+ cache_clear_all('entity_property_info:' . $GLOBALS['language']->language, 'cache');
+ entity_get_property_info();
+ }
+ else {
+ watchdog('i18n_field', 'Unable to run fall-back handling for entity property translation due missing "i18n_object_info" cache', array(), WATCHDOG_WARNING);
+ }
+ }
+}
+
+/**
+ * Implements hook_module_implements_alter().
+ */
+function i18n_field_module_implements_alter(&$implementations, $hook) {
+ if ($hook == 'i18n_object_info_alter') {
+ // Move our hook implementation to the bottom.
+ $group = $implementations['i18n_field'];
+ unset($implementations['i18n_field']);
+ $implementations['i18n_field'] = $group;
+ }
+}
\ No newline at end of file
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_forum/README.txt b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_forum/README.txt
new file mode 100644
index 00000000..e8ab6bf4
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_forum/README.txt
@@ -0,0 +1,80 @@
+CONTENTS OF THIS FILE
+---------------------
+
+* Introduction
+* Requirements
+* Recommended modules
+* Installation
+* Configuration
+* Maintainers
+
+
+INTRODUCTION
+------------
+
+The Multilingual forum module, part of the Internationalization (https://www.drupal.org/project/i18n) package, helps with the multilingual configuration of the site’s forums.
+
+* For a full description of the module visit https://www.drupal.org/node/1396988
+
+* To submit bug reports and feature suggestions, or to track changes visit https://www.drupal.org/project/issues/i18n
+
+
+REQUIREMENTS
+------------
+
+This module requires the following modules:
+
+* Internationalization (https://www.drupal.org/project/i18n)
+
+
+RECOMMENDED MODULES
+-------------------
+
+* Internationalization Views (https://www.drupal.org/project/i18nviews)
+* Language Icons (https://www.drupal.org/project/languageicons)
+* Translation Overview (https://www.drupal.org/project/translation_overview)
+* Localization Client (https://www.drupal.org/project/l10n_client)
+* Internationalization contributions (https://www.drupal.org/project/i18n_contrib)
+
+INSTALLATION
+
+------------
+
+* This is a submodule of the Internationalization module. Install the Internationalization module as you would normally install a contributed Drupal module. See https://www.drupal.org/docs/7/extending-drupal-7/installing-contributed-modules-find-import-enable-configure-drupal-7 for further information.
+
+
+CONFIGURATION
+-------------
+
+To configure forum vocabulary
+
+1. Enable the Multilingual forum module included with Internationalization.
+2. Go to Administration > Structure > Taxonomy.
+3. Click "edit vocabulary" for the Forums vocabulary.
+4. Choose the translation mode (Localize or Translate).
+5. Click "Save and translate" button.
+6. Click "translate" link for a language.
+7. Translate the "Name" and "Description" for the forum.
+8. Click "Save translation" button.
+9. Repeat steps 6 to 8 for each language.
+
+To configure forum terms
+
+1. Go to Administration > Structure > Forums.
+2. Click "edit" link for a forum or container.
+3. Click "Translate" tab.
+4. Click "translate" link for a language.
+5. Translate the "Name" and "Description" for the term.
+6. Click "Save translation" button.
+7. Repeat steps 4 to 6 for each language.
+8. Repeat all steps for all terms.
+
+
+MAINTAINERS
+-----------
+
+* Jose Reyero - https://www.drupal.org/u/jose-reyero
+* Florian Weber (webflo) - https://www.drupal.org/u/webflo
+* Peter Philipp - https://www.drupal.org/u/das-peter
+* Joseph Olstad - https://www.drupal.org/u/joseph.olstad
+* Nathaniel Catchpole - https://www.drupal.org/u/catch
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_forum/i18n_forum.info b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_forum/i18n_forum.info
index afd96583..d857630c 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_forum/i18n_forum.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_forum/i18n_forum.info
@@ -7,9 +7,9 @@ package = Multilingual - Internationalization
core = 7.x
files[] = i18n_forum.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_menu/README.txt b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_menu/README.txt
new file mode 100644
index 00000000..76eef55e
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_menu/README.txt
@@ -0,0 +1,89 @@
+CONTENTS OF THIS FILE
+---------------------
+
+* Introduction
+* Requirements
+* Recommended modules
+* Installation
+* Configuration
+* Troubleshooting
+* Maintainers
+
+
+INTRODUCTION
+------------
+
+The Menu translation module, part of the Internationalization (https://www.drupal.org/project/i18n) package, allows users to select a translation mode for each menu.
+
+* For a full description of the module, visit this page:
+https://www.drupal.org/node/1113982
+
+* To submit bug reports and feature suggestions, or to track changes:
+https://www.drupal.org/project/issues/i18n
+
+
+REQUIREMENTS
+------------
+
+This module requires the following modules:
+
+* Internationalization (https://www.drupal.org/project/i18n)
+
+
+RECOMMENDED MODULES
+-------------------
+
+* Internationalization Views (https://www.drupal.org/project/i18nviews)
+* Language Icons (https://www.drupal.org/project/languageicons)
+* Translation Overview (https://www.drupal.org/project/translation_overview)
+* Localization Client (https://www.drupal.org/project/l10n_client)
+* Internationalization contributions (https://www.drupal.org/project/i18n_contrib)
+
+To link menu item menus to nodes, it is useful to have the following modules:
+
+* Entity translation i18n menu module, a sub module of Entity translation (https://www.drupal.org/project/entity_translation)
+* Menu translation node module (https://www.drupal.org/project/i18n_menu_node)
+
+
+INSTALLATION
+------------
+
+* This is a submodule of the Internationalization module. Install the Internationalization module as you would normally install a contributed Drupal module. Visit https://www.drupal.org/docs/7/extending-drupal-7/installing-contributed-modules-find-import-enable-configure-drupal-7 for further information
+
+
+CONFIGURATION
+-------------
+
+Language-specific menus
+1. To create or edit a menu, navigate to Structure > Menus > (menu to edit) > Edit.
+2. In the Translation mode section, choose Fixed Language and a Language field will appear.
+3. Select a language, select Save, and add or update the menu items as needed.
+The menu block will only appear when viewing content in the same language.
+
+There are three modes available:
+
+Translate and Localize:
+You can create one menu for all languages, and translate or localize each menu item. There are two ways that menu items will be translated.
+1. You can set a language when creating a custom menu item so that the menu item will only show up for that language. Menu items that link to nodes in a particular language will be treated this way.
+2. You can localize other custom menu items without a language (for example, menu items linking to Views pages). Use the Translate tab to translate the menu item title and description. Translators can also use the "Translate interface" pages to translate these menu items.
+
+Fixed Language:
+If you choose Fixed Language, you'll have to set up a separate menu in each language. This could become tedious if have a lot of languages enabled on your site, but is useful if the content or menu structure is different for each language.
+
+No Multilingual Options:
+Only the menu will be translatable.
+
+TROUBLESHOOTING
+---------------
+
+A menu item linked to a node will be displayed only when the node language matches the page language. This is due to how the menu system works and the "Language selection" feature in i18n. Therefore, to get translated menus items that link to nodes, you first need translated content. For more information visit https://www.drupal.org/docs/7/multilingual/translating-content.
+
+
+MAINTAINERS
+-----------
+
+* Jose Reyero - https://www.drupal.org/u/jose-reyero
+* Florian Weber (webflo) - https://www.drupal.org/u/webflo
+* Peter Philipp - https://www.drupal.org/u/das-peter
+* Joseph Olstad - https://www.drupal.org/u/joseph.olstad
+* Nathaniel Catchpole - https://www.drupal.org/u/catch
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_menu/i18n_menu.info b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_menu/i18n_menu.info
index 7a6821c7..f1f4bfc8 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_menu/i18n_menu.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_menu/i18n_menu.info
@@ -10,9 +10,9 @@ core = 7.x
files[] = i18n_menu.inc
files[] = i18n_menu.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_menu/i18n_menu.module b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_menu/i18n_menu.module
index 8bcf6796..5f8645f9 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_menu/i18n_menu.module
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_menu/i18n_menu.module
@@ -53,6 +53,24 @@ function i18n_menu_menu_alter(&$items) {
$items['admin/structure/menu/item/%menu_link'] = $items['admin/structure/menu/item/%menu_link/edit'];
$items['admin/structure/menu/item/%menu_link']['type'] = MENU_CALLBACK;
$items['admin/structure/menu/item/%menu_link/edit']['type'] = MENU_DEFAULT_LOCAL_TASK;
+ $items['admin/structure/menu/manage/%menu']['title callback'] = 'i18n_menu_menu_overview_title';
+}
+
+/**
+ * Preprocess theme_menu_admin_overview to translate menu name and description
+ *
+ * @param $variables
+ */
+function i18n_menu_preprocess_menu_admin_overview(&$variables) {
+ $variables['title'] = i18n_string(array('menu', 'menu', $variables['name'], 'title'), $variables['title']);
+ $variables['description'] = i18n_string(array('menu', 'menu', $variables['name'], 'description'), $variables['description']);
+}
+
+/**
+ * Title callback for the menu overview page and links.
+ */
+function i18n_menu_menu_overview_title($menu) {
+ return i18n_string(array('menu', 'menu', $menu['menu_name'], 'title'), $menu['title']);
}
/**
@@ -379,7 +397,7 @@ function i18n_menu_localize_tree($tree, $langcode = NULL) {
if (_i18n_menu_link_process($item['link'])) {
if (!_i18n_menu_link_is_visible($item['link'], $langcode)) {
// Remove links for other languages than current.
- // Links with language wont be localized.
+ // Links with language won't be localized.
unset($tree[$index]);
// @todo Research whether the above has any advantage over:
// $item['hidden'] = TRUE;
@@ -515,9 +533,11 @@ function _i18n_menu_link_description($link, $langcode = NULL) {
* Check whether this link is to be processed by i18n_menu and start processing.
*/
function _i18n_menu_link_process(&$link) {
- // Only visible links that have a language property and haven't been processed
- // before. We also check that they belong to a menu with language options.
- if (empty($link['i18n_menu']) && !empty($link['language']) && !empty($link['access']) && empty($link['hidden']) && i18n_menu_mode($link['menu_name'])) {
+ // Only links that have a language property and haven't been processed before.
+ // We also translate links marked as hidden because core breadcrumbs ignore
+ // that flag and excluding them would basically interfere with core behaviour.
+ // We also check that they belong to a menu with language options.
+ if (empty($link['i18n_menu']) && !empty($link['language']) && !empty($link['access']) && i18n_menu_mode($link['menu_name'])) {
// Mark so it won't be processed twice.
$link['i18n_menu'] = TRUE;
// Skip if administering this menu or this menu item.
@@ -579,7 +599,7 @@ function _i18n_menu_link_is_visible($link, $langcode = NULL) {
}
/**
- * Get localizable properties for menu link checking agains the router item.
+ * Get localizable properties for menu link checking against the router item.
*/
function _i18n_menu_link_localizable_properties($link) {
$props = array();
@@ -588,7 +608,7 @@ function _i18n_menu_link_localizable_properties($link) {
// If the title callback is 't' and the link title matches the router title
// it will be localized by core, not by i18n_menu.
if (!$router ||
- (empty($router['title_callback']) || $router['title_callback'] != 't') ||
+ (empty($router['title_callback']) || ($router['title_callback'] != 't' || !empty($link['customized']))) ||
(empty($router['title']) || $router['title'] != $link['link_title'])
) {
$props[] = 'title';
@@ -597,7 +617,7 @@ function _i18n_menu_link_localizable_properties($link) {
if (!empty($link['options']['attributes']['title'])) {
// If the description matches the router description, it will be localized
// by core.
- if (!$router || empty($router['description']) || $router['description'] != $link['options']['attributes']['title']) {
+ if (!$router || empty($router['description']) || ($router['description'] != $link['options']['attributes']['title']) || !empty($link['customized'])) {
$props[] = 'description';
}
}
@@ -723,15 +743,19 @@ function i18n_menu_form_menu_edit_item_alter(&$form, &$form_state) {
* Add a "translate" link in operations column for each menu item.
*/
function i18n_menu_form_menu_overview_form_alter(&$form, &$form_state) {
- foreach (element_children($form) as $element) {
- if (substr($element, 0, 5) == 'mlid:') {
- $mlid = $form[$element]['#item']['mlid'];
- if (i18n_get_object('menu', $mlid)->get_translate_access()) {
- $form[$element]['operations']['translate'] = array(
- '#type' => 'link',
- '#title' => t('translate'),
- '#href' => "admin/structure/menu/item/{$mlid}/translate",
- );
+ if (i18n_menu_mode($form['#menu']['menu_name'], I18N_MODE_MULTIPLE)) {
+ foreach (element_children($form) as $element) {
+ if (substr($element, 0, 5) == 'mlid:') {
+ $item = $form[$element]["#item"];
+ $mlid = $form[$element]['#item']['mlid'];
+ if (i18n_get_object('menu', $mlid)->get_translate_access()) {
+ $form[$element]['operations']['translate'] = array(
+ '#type' => 'link',
+ '#title' => t('translate'),
+ '#href' => "admin/structure/menu/item/{$mlid}/translate",
+ );
+ $form[$element]['title']['#markup'] = l(_i18n_menu_link_title($item), $item['href'], $item['localized_options']);
+ }
}
}
}
@@ -898,93 +922,25 @@ function i18n_menu_query_features_menu_link_alter($query) {
}
/**
- * Implements hook_init().
- */
-function i18n_menu_init() {
-
- // The only way to override the default preferred menu link for a path is to
- // inject it into the static cache of the function menu_link_get_preferred().
-
- // The problem with the default implementation is that it does not take the
- // language of a menu link into account. Whe having different menu trees for
- // different menus, this means that the active trail will not work for all but
- // one language.
-
- // The code below is identical to the mentioned function except the added
- // language condition on the query.
-
- // TODO: Adding an alter tag to the query would allow to do this with a simple
- // hook_query_alter() implementation.
-
- $preferred_links = &drupal_static('menu_link_get_preferred');
-
- $path = $_GET['q'];
-
- // Look for the correct menu link by building a list of candidate paths,
- // which are ordered by priority (translated hrefs are preferred over
- // untranslated paths). Afterwards, the most relevant path is picked from
- // the menus, ordered by menu preference.
- $item = menu_get_item($path);
- $path_candidates = array();
- // 1. The current item href.
- $path_candidates[$item['href']] = $item['href'];
- // 2. The tab root href of the current item (if any).
- if ($item['tab_parent'] && ($tab_root = menu_get_item($item['tab_root_href']))) {
- $path_candidates[$tab_root['href']] = $tab_root['href'];
- }
- // 3. The current item path (with wildcards).
- $path_candidates[$item['path']] = $item['path'];
- // 4. The tab root path of the current item (if any).
- if (!empty($tab_root)) {
- $path_candidates[$tab_root['path']] = $tab_root['path'];
- }
- // Retrieve a list of menu names, ordered by preference.
- $menu_names = menu_get_active_menu_names();
- // Use an illegal menu name as the key for the preferred menu link.
- $selected_menu = MENU_PREFERRED_LINK;
- // Put the selected menu at the front of the list.
- array_unshift($menu_names, $selected_menu);
-
- $query = db_select('menu_links', 'ml', array('fetch' => PDO::FETCH_ASSOC));
- $query->leftJoin('menu_router', 'm', 'm.path = ml.router_path');
- $query->fields('ml');
- // Weight must be taken from {menu_links}, not {menu_router}.
- $query->addField('ml', 'weight', 'link_weight');
- $query->fields('m');
- $query->condition('ml.link_path', $path_candidates, 'IN');
-
- // Only look menu links with none or the current language.
- $query->condition('ml.language', array(LANGUAGE_NONE, i18n_language_interface()->language), 'IN');
-
- // Sort candidates by link path and menu name.
- $candidates = array();
- foreach ($query->execute() as $candidate) {
- $candidate['weight'] = $candidate['link_weight'];
- $candidates[$candidate['link_path']][$candidate['menu_name']] = $candidate;
- // Add any menus not already in the menu name search list.
- if (!in_array($candidate['menu_name'], $menu_names)) {
- $menu_names[] = $candidate['menu_name'];
- }
- }
-
- // Store the most specific link for each menu. Also save the most specific
- // link of the most preferred menu in $preferred_link.
- foreach ($path_candidates as $link_path) {
- if (isset($candidates[$link_path])) {
- foreach ($menu_names as $menu_name) {
- if (empty($preferred_links[$path][$menu_name]) && isset($candidates[$link_path][$menu_name])) {
- $candidate_item = $candidates[$link_path][$menu_name];
- $map = explode('/', $path);
- _menu_translate($candidate_item, $map);
- if ($candidate_item['access']) {
- $preferred_links[$path][$menu_name] = $candidate_item;
- if (empty($preferred_links[$path][MENU_PREFERRED_LINK])) {
- // Store the most specific link.
- $preferred_links[$path][MENU_PREFERRED_LINK] = $candidate_item;
- }
- }
- }
+ * Implements hook_query_TAG_alter()
+ *
+ * Using tag 'preferred_menu_links' added in menu_link_get_preferred().
+ * See http://drupal.org/node/1854134
+ */
+function i18n_menu_query_preferred_menu_links_alter(QueryAlterableInterface $query) {
+ global $language;
+ // Get queried tables.
+ $tables = $query->getTables();
+
+ foreach ($tables as $alias => $table) {
+ if ($table['table'] == 'menu_links') {
+ // Add language filter, ensuring that we don't have any collision when
+ // determining the active menu trail when there are multiple menu items
+ // with same link path but different languages.
+ if ($language) {
+ $query->condition('language', array($language->language, LANGUAGE_NONE), 'IN');
}
+ break;
}
}
}
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_node/README.txt b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_node/README.txt
new file mode 100644
index 00000000..2c4bc402
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_node/README.txt
@@ -0,0 +1,71 @@
+CONTENTS OF THIS FILE
+---------------------
+
+* Introduction
+* Requirements
+* Recommended modules
+* Installation
+* Configuration
+* Maintainers
+
+
+INTRODUCTION
+------------
+
+The Multilingual content module, part of the Internationalization (https://www.drupal.org/project/i18n) package, provides extended multilingual options for nodes. These options help accommodate a variety of translation workflows by controlling how the language for nodes is set.
+
+Note that the Multilingual content module lives in the i18n_node directory in the Internationalization package. Don't confuse this module with the core Content translation module.
+
+* For a full description of the module visit https://www.drupal.org/node/1279644
+
+* To submit bug reports and feature suggestions, or to track changes visit https://www.drupal.org/project/issues/i18n
+
+
+REQUIREMENTS
+------------
+
+This module requires the following modules:
+
+* Internationalization (https://www.drupal.org/project/i18n)
+
+
+RECOMMENDED MODULES
+-------------------
+
+* Internationalization Views (https://www.drupal.org/project/i18nviews)
+* Language Icons (https://www.drupal.org/project/languageicons)
+* Translation Overview (https://www.drupal.org/project/translation_overview)
+* Localization Client (https://www.drupal.org/project/l10n_client)
+* Internationalization contributions (https://www.drupal.org/project/i18n_contrib)
+
+
+INSTALLATION
+
+------------
+
+* This is a submodule of the Internationalization module. Install the Internationalization module as you would normally install a contributed Drupal module. See https://www.drupal.org/docs/7/extending-drupal-7/installing-contributed-modules-find-import-enable-configure-drupal-7 for further information.
+
+
+CONFIGURATION
+-------------
+
+For each content type, the following Extended language options are available under the Multilingual Settings tab
+1. "Set current language as default for new content" can be useful for content that is community-generated.
+2. "Require language" prevents users from creating 'Language neutral' nodes.
+3. "Lock language" prevents users from changing the language of a node after it's created.
+
+Site-wide Settings for Node Translation
+1. There are also site-wide settings provided to help streamline how multilingual content is created. Navigate to Config > Regional and language > Multilingual settings > Node Options.
+2. "Switch interface for translating" switches the language of the user interface to the chosen language when a user translates a node. This is useful if users speak the language in which the translation is written. It means that after the node translation is saved, the language of the UI will match the language of the node.
+3. "Hide content translation links" will prevent the language switcher links from appearing in nodes and teasers. This is useful if a language switcher block is enabled on the site.
+4.You can also select the default language for new nodes if the corresponding content type doesn't have language support. By default, it is set to be in the default language of the site, but this can be changed to be language neutral. This is a useful option when thinking about forward compatibility for adding multilingual support to these content types in the future.
+
+
+MAINTAINERS
+-----------
+
+* Jose Reyero - https://www.drupal.org/u/jose-reyero
+* Florian Weber (webflo) - https://www.drupal.org/u/webflo
+* Peter Philipp - https://www.drupal.org/u/das-peter
+* Joseph Olstad - https://www.drupal.org/u/joseph.olstad
+* Nathaniel Catchpole - https://www.drupal.org/u/catch
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_node/i18n_node.info b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_node/i18n_node.info
index 4522510e..4dc29755 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_node/i18n_node.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_node/i18n_node.info
@@ -9,9 +9,9 @@ configure = admin/config/regional/i18n/node
files[]=i18n_node.test
files[]=i18n_node.variable.inc
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_node/i18n_node.module b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_node/i18n_node.module
index 8c2e38e3..bd51ad2d 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_node/i18n_node.module
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_node/i18n_node.module
@@ -222,8 +222,16 @@ function i18n_node_language_mode($type) {
function i18n_node_node_prepare($node) {
$options = variable_get('i18n_node_options_' . $node->type, array());
if (i18n_node_type_enabled($node) && empty($node->nid) && !i18n_object_langcode($node) && in_array('current', $options)) {
+ $default = variable_get('i18n_node_default_language_for_' . $node->type, '-- current --');
+
// Set current language for new nodes if option enabled
- $node->language = i18n_language_content()->language;
+ if ($default === '-- current --') {
+ $node->language = i18n_language_content()->language;
+ }
+ // If a custom language was specified, apply it.
+ else {
+ $node->language = $default;
+ }
}
}
@@ -417,7 +425,16 @@ function i18n_node_form_node_type_form_alter(&$form, &$form_state) {
// Some settings about node languages. Add variables for node type from variable definition
if ($form['#node_type']->type) {
variable_type_include('node_type');
- $form['i18n'] += node_variable_type_subform($form['#node_type']->type, array('i18n_node_options', 'i18n_node_extended'));
+ $form['i18n'] += node_variable_type_subform($form['#node_type']->type, array('i18n_node_options', 'i18n_node_default_language_for', 'i18n_node_extended'));
+ // Only show custom default language field if "current" is checked.
+ $form['i18n']['i18n_node_default_language_for']['#states'] = array(
+ 'visible' => array(
+ ':input[name="i18n_node_options[current]"]' => array('checked' => TRUE),
+ ),
+ 'required' => array(
+ ':input[name="i18n_node_options[current]"]' => array('checked' => TRUE),
+ ),
+ );
}
// Add disabled message
if ($disabled) {
@@ -506,8 +523,11 @@ function _i18n_node_form_node_form_alter($form, &$form_state) {
}
}
elseif (variable_get('i18n_node_default_language_none', 0) && !isset($form['#node']->nid)) {
- // Override locale module setting default language to nodes. It is already in form_state.
- $form['language']['#value'] = $form_state['values']['language'] = LANGUAGE_NONE;
+ // Only do this if the language is really disabled
+ if (variable_get('language_content_type_' . $node->type, 0) == 0) {
+ // Override locale module setting default language to nodes. It is already in form_state.
+ $form['language']['#value'] = $form_state['values']['language'] = LANGUAGE_NONE;
+ }
}
// Translate field names for title and body for the node edit form.
if (!empty($form['title']['#title'])) {
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_node/i18n_node.variable.inc b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_node/i18n_node.variable.inc
index 9362fc3f..b9b0495f 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_node/i18n_node.variable.inc
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_node/i18n_node.variable.inc
@@ -45,13 +45,30 @@ function i18n_node_variable_info($options = array()) {
'repeat' => array(
'type' => 'options',
'options' => array(
- 'current' => t('Set current language as default for new content.', array(), $options),
+ // Note: this was previously used only to mark new, translatable nodes
+ // with the current language of the user. Now, this setting is extended
+ // to allow a specific language to be chosen (defaulting to the current
+ // language). This was done for backwards compatibility reasons.
+ 'current' => t('Set custom language as default for new content.', array(), $options),
'required' => t('Require language (Do not allow Language Neutral).', array(), $options),
'lock' => t('Lock language (Cannot be changed).', array(), $options),
),
),
'group' => 'i18n',
);
+ // This field will only be displayed if "current" is checked above.
+ $variables['i18n_node_default_language_for_[node_type]'] = array(
+ 'type' => 'multiple',
+ 'title' => t('Custom default language', array(), $options),
+ 'repeat' => array(
+ 'type' => 'select',
+ 'options' => array_merge(array(
+ '-- current --' => t('Current language')
+ ), locale_language_list('name')),
+ 'default' => '-- current --',
+ ),
+ 'group' => 'i18n',
+ );
$variables['i18n_node_extended_[node_type]'] = array(
'type' => 'multiple',
'title' => t('Extended language support'),
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_path/i18n_path.info b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_path/i18n_path.info
index 10f62e7c..bb0adcd5 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_path/i18n_path.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_path/i18n_path.info
@@ -6,9 +6,9 @@ core = 7.x
files[] = i18n_path.inc
files[] = i18n_path.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_redirect/README.txt b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_redirect/README.txt
new file mode 100644
index 00000000..3d10403b
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_redirect/README.txt
@@ -0,0 +1,68 @@
+CONTENTS OF THIS FILE
+---------------------------
+
+* Introduction
+* Requirements
+* Recommended modules
+* Installation
+* Configuration
+* Maintainers
+
+
+INTRODUCTION
+------------
+
+The Redirect translation module, part of the Internationalization (https://www.drupal.org/project/i18n) package, improves search engine optimization (SEO) for multilingual websites.
+
+It redirects anonymous users (including web crawlers) to the translation of the page in the requested language, if it exists, using a 301 redirect code.
+
+* For a full description of the module, visit this page:
+https://www.drupal.org/node/1280468
+
+* To submit bug reports and feature suggestions, or to track changes:
+https://www.drupal.org/project/issues/i18n
+
+
+REQUIREMENTS
+------------
+
+This module requires the following modules:
+
+* Internationalization (https://www.drupal.org/project/i18n)
+
+The Translation redirect module requires the implementation of hook_i18n_translate_path by another module for the redirect page to be determined. Currently, the Multilingual content, Path translation, and Taxonomy translation modules implement this hook.
+
+
+RECOMMENDED MODULES
+-------------------
+
+* Internationalization Views (https://www.drupal.org/project/i18nviews)
+* Language Icons (https://www.drupal.org/project/languageicons)
+* Translation Overview (https://www.drupal.org/project/translation_overview)
+* Localization Client (https://www.drupal.org/project/l10n_client)
+* Internationalization contributions (https://www.drupal.org/project/i18n_contrib)
+
+
+INSTALLATION
+------------
+
+* This is a submodule of the Internationalization module. Install the Internationalization module as you would normally install a contributed Drupal module. Visit https://www.drupal.org/docs/7/extending-drupal-7/installing-contributed-modules-find-import-enable-configure-drupal-7 for further information.
+
+
+CONFIGURATION
+-------------
+
+No configuration is necessary.
+
+For node translation, enable the Multilingual content and the Translation redirect modules. For non-node pages, the redirection hook must be implemented by the relevant module.
+For example, for taxonomy pages, you should enable the Taxonomy translation module because the module provides the necessary hook code. If you are using the Path translation module to create translation sets for non-node pages, then it implements the hook code for determining the redirection page.
+
+
+MAINTAINERS
+-----------
+
+* Jose Reyero - https://www.drupal.org/u/jose-reyero
+* Florian Weber (webflo) - https://www.drupal.org/u/webflo
+* Peter Philipp - https://www.drupal.org/u/das-peter
+* Joseph Olstad - https://www.drupal.org/u/joseph.olstad
+* Nathaniel Catchpole - https://www.drupal.org/u/catch
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_redirect/i18n_redirect.info b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_redirect/i18n_redirect.info
index 6f6ee43d..97af54ff 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_redirect/i18n_redirect.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_redirect/i18n_redirect.info
@@ -4,9 +4,9 @@ dependencies[] = i18n
package = Multilingual - Internationalization
core = 7.x
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_select/README.txt b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_select/README.txt
new file mode 100644
index 00000000..8f13ddf0
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_select/README.txt
@@ -0,0 +1,67 @@
+CONTENTS OF THIS FILE
+---------------------
+
+* Introduction
+* Requirements
+* Recommended modules
+* Installation
+* Configuration
+* Maintainers
+
+
+INTRODUCTION
+------------
+
+The Multilingual select module, part of the Internationalization (https://www.drupal.org/project/i18n) package, allows the user to define whether content is filtered by language on pages provided by Drupal core.
+
+* For a full description of the module visit https://www.drupal.org/node/1279512
+
+* To submit bug reports and feature suggestions, or to track changes visit https://www.drupal.org/project/issues/i18n
+
+
+REQUIREMENTS
+------------
+
+This module requires the following modules:
+
+* Internationalization (https://www.drupal.org/project/i18n)
+* Variable (https://www.drupal.org/project/variable)
+
+
+RECOMMENDED MODULES
+-------------------
+
+* Internationalization Views (https://www.drupal.org/project/i18nviews)
+* Language Icons (https://www.drupal.org/project/languageicons)
+* Translation Overview (https://www.drupal.org/project/translation_overview)
+* Localization Client (https://www.drupal.org/project/l10n_client)
+* Internationalization contributions (https://www.drupal.org/project/i18n_contrib)
+
+
+INSTALLATION
+------------
+
+* This is a submodule of the Internationalization module. Install the Internationalization module as you would normally install a contributed Drupal module. See https://www.drupal.org/docs/7/extending-drupal-7/installing-contributed-modules-find-import-enable-configure-drupal-7 for further information.
+
+
+CONFIGURATION
+-------------
+
+The module allows you to configure whether or not to filter pages by the current language. If the Taxonomy translation submodule is also enabled, an option will be available for how taxonomy term pages are filtered. It also allows the exclusion of the module’s language selection handling for some elements and certain paths.
+
+1. Enable the Multilingual select module included with Internationalization.
+2. Go to Configuration > Regional and language > Multilingual settings > Selection.
+3. Select nodes and taxonomy can be filtered by language in the Content to Filter by Language field set.
+4. The "Content Selection Mode" allows content with specific tags to be skipped by entering a list of tags.
+5. The "Enable for Specific Pages" field set allows specific pages to be included by path.
+6. After making choices click Save configuration.
+
+
+MAINTAINERS
+-----------
+
+* Jose Reyero - https://www.drupal.org/u/jose-reyero
+* Florian Weber (webflo) - https://www.drupal.org/u/webflo
+* Peter Philipp - https://www.drupal.org/u/das-peter
+* Joseph Olstad - https://www.drupal.org/u/joseph.olstad
+* Nathaniel Catchpole - https://www.drupal.org/u/catch
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_select/i18n_select.info b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_select/i18n_select.info
index 7c47197f..f9c221d2 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_select/i18n_select.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_select/i18n_select.info
@@ -6,9 +6,9 @@ core = 7.x
configure = admin/config/regional/i18n/select
files[] = i18n_select.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_select/i18n_select.module b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_select/i18n_select.module
index bcba5782..9063fe9d 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_select/i18n_select.module
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_select/i18n_select.module
@@ -82,11 +82,11 @@ function i18n_select_mode($type = NULL) {
}
/**
- * Check current path to enable selection
+ * Check current path to enable selection.
*
- * This works pretty much like block visibility
+ * This works pretty much like block visibility.
*
- * @return boolean
+ * @return bool
* TRUE if content selection should be enabled for this page.
*/
function i18n_select_page() {
@@ -100,8 +100,11 @@ function i18n_select_page() {
// with different case. Ex: /Page, /page, /PAGE.
$pages = drupal_strtolower($pages);
if ($visibility < I18N_SELECT_PAGE_PHP) {
- // Convert the Drupal path to lowercase
- $path = drupal_strtolower(drupal_get_path_alias($_GET['q']));
+ // @see views_ajax()
+ // @see I18NSelectAdminViewsAjax::testViewsAjaxWithoutSkippingTags()
+ $path = isset($_REQUEST['view_path']) ? $_REQUEST['view_path'] : $_GET['q'];
+ // Convert the Drupal path to lowercase.
+ $path = drupal_strtolower(drupal_get_path_alias($path));
// Compare the lowercase internal and lowercase path alias (if any).
$page_match = drupal_match_path($path, $pages);
if ($path != $_GET['q']) {
@@ -109,8 +112,8 @@ function i18n_select_page() {
}
// When $visibility has a value of 0 (I18N_SELECT_PAGE_NOTLISTED),
// the block is displayed on all pages except those listed in $pages.
- // When set to 1 (I18N_SELECT_PAGE_LISTED), it is displayed only on those
- // pages listed in $pages.
+ // When set to 1 (I18N_SELECT_PAGE_LISTED), it is displayed only on
+ // those pages listed in $pages.
$mode = !($visibility xor $page_match);
}
elseif (module_exists('php')) {
@@ -121,7 +124,7 @@ function i18n_select_page() {
}
}
else {
- // No pages defined, still respect the setting (unlike blocks)
+ // No pages defined, still respect the setting (unlike blocks).
$mode = $visibility == I18N_SELECT_PAGE_NOTLISTED;
}
}
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_select/i18n_select.test b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_select/i18n_select.test
index b46fb986..5af85431 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_select/i18n_select.test
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_select/i18n_select.test
@@ -84,3 +84,87 @@ class i18nSelectTestCase extends Drupali18nTestCase {
}
}
}
+
+/**
+ * Test case for AJAX queries on "views/ajax" when view on admin page.
+ */
+class I18NSelectAdminViewsAjax extends Drupali18nTestCase {
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getInfo() {
+ return array(
+ 'name' => t('I18N select Admin Views (AJAX)'),
+ 'group' => 'Internationalization',
+ 'description' => t('Test AJAX requests to the "views/ajax" when view located on "admin/*" and list of skipping tags is empty.'),
+ // Skip this test when "admin_views" module does not exists.
+ 'dependencies' => array('admin_views'),
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp('translation', 'i18n_variable', 'i18n_select', 'admin_views');
+ parent::setUpLanguages(array('access content overview'));
+ parent::setUpContentTranslation();
+ }
+
+ /**
+ * Test AJAX of a view without skipping tags for selection.
+ *
+ * @see i18n_select_page()
+ */
+ public function testViewsAjaxWithoutSkippingTags() {
+ // If this variable will have the "views" value then this test will not
+ // have sense. For instance, we want apply language selection filter
+ // for views and remove "views" from "i18n_select_skip_tags" variable.
+ // In this case all AJAX for views, on administration part of the site,
+ // will be broken because the "i18n_select_page()" function will work
+ // with "views/ajax" path instead of, for example, "admin/content".
+ variable_set('i18n_select_skip_tags', '');
+
+ // Create one hundred of nodes.
+ for ($i = 1; $i <= 100; $i++) {
+ // Create every second node on Spanish language and
+ // every first - on English.
+ $node = $this->createNode('page', "Node $i", '', $i % 2 ? $this->default_language : $this->secondary_language);
+
+ // Update "changed" in order to sort the content by updating date. In
+ // other case all nodes will be with the same date and not arranged in
+ // order.
+ db_update('node')
+ ->fields(array('changed' => strtotime("+ $i minute")))
+ ->condition('nid', $node->nid)
+ ->execute();
+ }
+
+ $this->drupalGet('admin/content');
+
+ // Check that latest node exists at the top.
+ $this->assertText('Node 100');
+ // Check that our page contains fifty nodes (the latest must be 51).
+ $this->assertNoText('Node 50');
+
+ // Test $_REQUEST['view_path']. There's no form to submit to, so
+ // drupalPost() won't work here. This just tests a direct $_POST
+ // request instead.
+ $this->curlExec(array(
+ CURLOPT_URL => $this->getAbsoluteUrl('views/ajax'),
+ CURLOPT_POST => TRUE,
+ CURLOPT_POSTFIELDS => http_build_query(array(
+ 'page' => 1,
+ 'view_path' => 'admin/content',
+ 'view_name' => 'admin_views_node',
+ 'view_display_id' => 'system_1',
+ )),
+ ));
+
+ // Check that we are successfully switched to a new page of content.
+ $this->assertText('Node 50');
+ $this->assertNoText('Node 100');
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/README.txt b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/README.txt
new file mode 100644
index 00000000..0e6645ae
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/README.txt
@@ -0,0 +1,72 @@
+CONTENTS OF THIS FILE
+---------------------
+
+* Introduction
+* Requirements
+* Recommended modules
+* Installation
+* Configuration
+* Maintainers
+
+
+INTRODUCTION
+------------
+
+The String translation module, part of the Internationalization (https://www.drupal.org/project/i18n) package, provides support for other modules to translate user-defined strings. This is an API module that must be enabled only when required by other modules in the i18n package.
+
+
+* For a full description of the module, visit this page:
+https://www.drupal.org/node/1279668
+
+* To submit bug reports and feature suggestions, or to track changes:
+https://www.drupal.org/project/issues/i18n
+
+
+REQUIREMENTS
+------------
+
+This module requires the following modules:
+
+Internationalization (https://www.drupal.org/project/i18n)
+
+
+RECOMMENDED MODULES
+-------------------
+
+* Internationalization Views (https://www.drupal.org/project/i18nviews)
+* Language Icons (https://www.drupal.org/project/languageicons)
+* Translation Overview (https://www.drupal.org/project/translation_overview)
+* Localization Client (https://www.drupal.org/project/l10n_client)
+* Internationalization contributions (https://www.drupal.org/project/i18n_contrib)
+
+
+INSTALLATION
+------------
+
+* This is a submodule of the Internationalization module. Install the Internationalization module as you would normally install a contributed Drupal module. Visit https://www.drupal.org/docs/7/extending-drupal-7/installing-contributed-modules-find-import-enable-configure-drupal-7 for further information.
+
+
+CONFIGURATION
+-------------
+
+Strings will be translated from the source languages. By default the source language is the site's default language, so changing the default language could break these translations.
+
+1. You can set which language is used as the source language via Administration > Configuration > Regional and language > Multilingual settings > Strings. By default, only plain strings are enabled, so regular blocks are not fully translatable.
+2. To allow Filtered HTML, Full HTML or Plain text select the appropriate radio box(es) and Save configuration.
+3. To select the strings to be translated navigate to Administration > Configuration > Regional and language > Translate interface and select on Stings vertical tab. From here you can select which text groups to translate and select the Refresh strings tab.
+
+
+FAQ
+---
+
+The String translation module allows you to configure which text formats are translatable. Formats like PHP Filter and Full HTML are translated before they are processed, so allowing a translator to edit these can be a security risk. This is particularly problematic when importing translations in bulk from a CSV file, since the translator's access to the import formats isn't verified by Drupal. After updating this setting, be sure to refresh the strings via Administration > Configuration > Regional and language > Translate interface > Strings so that strings in forbidden formats are deleted.
+
+
+MAINTAINERS
+-----------
+
+* Jose Reyero - https://www.drupal.org/u/jose-reyero
+* Florian Weber (webflo) - https://www.drupal.org/u/webflo
+* Peter Philipp - https://www.drupal.org/u/das-peter
+* Joseph Olstad - https://www.drupal.org/u/joseph.olstad
+* Nathaniel Catchpole - https://www.drupal.org/u/catch
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.inc b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.inc
index 33fa444d..0b2d4fcf 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.inc
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.inc
@@ -1166,10 +1166,17 @@ class i18n_string_object_wrapper extends i18n_object_wrapper {
$info = is_array($info) ? $info : array('title' => $info);
$field_name = isset($info['field']) ? $info['field'] : $field;
$value = $this->get_field($field_name);
+ if (is_array($value) && isset($value['value'])) {
+ $format = isset($value['format']) ? $value['format'] : NULL;
+ $value = $value['value'];
+ }
+ else {
+ $format = isset($info['format']) ? $this->get_field($info['format']) : NULL;
+ }
$strings[$this->get_textgroup()][$string_type][$object_id][$field] = array(
'string' => is_array($value) || isset($info['empty']) && $value === $info['empty'] ? NULL : $value,
'title' => $info['title'],
- 'format' => isset($info['format']) ? $this->get_field($info['format']) : NULL,
+ 'format' => $format,
'name' => array_merge($object_keys, array($field)),
);
}
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.info b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.info
index 301a54ec..48a76da9 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.info
@@ -10,9 +10,9 @@ files[] = i18n_string.inc
files[] = i18n_string.test
configure = admin/config/regional/i18n/strings
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.install b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.install
index 100d7c04..30e8cd26 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.install
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.install
@@ -29,7 +29,9 @@ function i18n_string_install() {
i18n_string_update_7001();
}
// Create new index in {locales_source}, performance improvement in sites with i18n.
- db_add_index('locales_source', 'textgroup_context', array('textgroup', 'context'));
+ if (!db_index_exists('locales_source', 'textgroup_context')) {
+ db_add_index('locales_source', 'textgroup_context', array('textgroup', array('context', 50)));
+ }
}
/**
@@ -106,7 +108,7 @@ function i18n_string_schema() {
),
'primary key' => array('lid'),
'indexes' => array(
- 'group_context' => array('textgroup', 'context'),
+ 'group_context' => array('textgroup', array('context', 50)),
),
);
return $schema;
@@ -238,7 +240,9 @@ function i18n_string_update_7001() {
* Create new index in {locales_source}, performance improvement in sites with i18n.
*/
function i18n_string_update_7002() {
- db_add_index('locales_source', 'textgroup_context', array('textgroup', 'context'));
+ if (!db_index_exists('locales_source', 'textgroup_context')) {
+ db_add_index('locales_source', 'textgroup_context', array('textgroup', array('context', 50)));
+ }
}
@@ -269,4 +273,4 @@ function i18n_string_update_7002() {
* Node type
* nodetype:type:[type]:[property] -> node:type:[type]:[property]
* Property names: title -> title_label
- */
\ No newline at end of file
+ */
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.module b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.module
index 9c232c08..209b654c 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.module
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.module
@@ -258,6 +258,34 @@ function i18n_string_locale_translate_import_form_submit($form, &$form_state) {
}
}
+/**
+ * Implements hook_element_info_alter().
+ *
+ * We need to do this on the element info level as wysiwyg also does so and form
+ * API (incorrectly) does not merge in the defaults for values that are arrays.
+ */
+function i18n_string_element_info_alter(&$types) {
+ $types['text_format']['#pre_render'][] = 'i18n_string_pre_render_text_format';
+}
+
+/**
+ * The '#pre_render' function to alter the text format element in a translation.
+ * The text format for a translation is taken form the original, so the text
+ * format drop down should be disabled.
+ *
+ * @param array $element
+ * The text_format element which will be rendered.
+ *
+ * @return array
+ * The altered text_format element with a disabled "Text format" select.
+ */
+function i18n_string_pre_render_text_format($element) {
+ if (!empty($element['#i18n_string_is_translation'])) {
+ $element['format']['format']['#attributes']['disabled'] = TRUE;
+ }
+ return $element;
+}
+
/**
* Check if translation is required for this language code.
*
@@ -334,7 +362,10 @@ function i18n_string_update_context($oldname, $newname) {
}
/**
- * Get textgroup handler
+ * Get textgroup handler.
+ *
+ * @return i18n_string_textgroup_default
+ *
*/
function i18n_string_textgroup($textgroup) {
$groups = &drupal_static(__FUNCTION__);
@@ -519,11 +550,12 @@ function i18n_string_multiple($operation, $name, $strings, $options = array()) {
*
* This function is intended to return translations for plain strings that have NO text format
*
- * @param $name
+ * @param array|string name
* Array or string concatenated with ':' that contains textgroup and string context
- * @param $string
- * String in default language or array of strings to be translated
- * @param $options
+ * @param array|string $string
+ * A string in the default language, a string wth format (array with keys
+ * value and format),or an array of strings (without format) to be translated.
+ * @param array $options
* An associative array of additional options, with the following keys:
* - 'langcode' (defaults to the current language) The language code to translate to a language other than what is used to display the page.
* - 'filter' Filtering callback to apply to the translated string only
@@ -531,8 +563,13 @@ function i18n_string_multiple($operation, $name, $strings, $options = array()) {
* - 'callback' Callback to apply to the result (both to translated or untranslated string
* - 'sanitize' Whether to filter the translation applying the text format if any, default is TRUE
* - 'sanitize default' Whether to filter the default value if no translation found, default is FALSE
+ *
+ * @return string
*/
function i18n_string_translate($name, $string, $options = array()) {
+ if (is_array($string) && isset($string['value'])) {
+ $string = $string['value'];
+ }
if (is_array($string)) {
return i18n_string_translate_list($name, $string, $options);
}
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.pages.inc b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.pages.inc
index 4d0da59c..fd657b5a 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.pages.inc
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.pages.inc
@@ -170,14 +170,16 @@ function i18n_string_translate_page_form_base($form, $langcode, $redirect = NULL
/**
* Create field elements for strings
+ *
+ * @param i18n_string_object[] $strings
+ * @param string $langcode
+ *
+ * @return array
*/
function i18n_string_translate_page_form_strings($strings, $langcode) {
- $formats = filter_formats();
+ global $user;
+ $form = array();
foreach ($strings as $item) {
- // We may have a source or not. Load it, our string may get the format from it.
- $source = $item->get_source();
- $format_id = $source ? $source->format : $item->format;
- $description = '';
// Check permissions to translate this string, depends on format, etc..
if ($message = $item->check_translate_access()) {
// We'll display a disabled element with the reason it cannot be translated.
@@ -188,27 +190,31 @@ function i18n_string_translate_page_form_strings($strings, $langcode) {
$disabled = FALSE;
$description = '';
// If we don't have a source and it can be translated, we create it.
- if (!$source) {
+ if (!$item->get_source()) {
// Enable messages just as a reminder these strings are not being updated properly.
$status = $item->update(array('messages' => TRUE));
if ($status === FALSE || $status === SAVED_DELETED) {
// We don't have a source string so nothing to translate here
$disabled = TRUE;
}
- else {
- $source = $item->get_source();
- }
}
}
$default_value = $item->format_translation($langcode, array('langcode' => $langcode, 'sanitize' => FALSE, 'debug' => FALSE));
+ $available_formats = array_keys(filter_formats($user));
+ if (!in_array($item->format, $available_formats)) {
+ $item->format = NULL;
+ }
$form[$item->get_name()] = array(
'#title' => $item->get_title(),
- '#type' => 'textarea',
+ '#type' => $item->format ? 'text_format' : 'textarea',
'#default_value' => $default_value,
+ '#format' => $item->format,
+ // This will trigger i18n_string_pre_render_text_format() to actually
+ // alter the element.
+ '#i18n_string_is_translation' => TRUE,
'#disabled' => $disabled,
- '#description' => $description . _i18n_string_translate_format_help($format_id),
- //'#i18n_string_format' => $source ? $source->format : 0,
+ '#description' => $description,
// If disabled, provide smaller textarea (that can be expanded anyway).
'#rows' => $disabled ? 1 : min(ceil(str_word_count($default_value) / 12), 10),
// Change the parent for disabled strings so we don't get empty values later
@@ -226,6 +232,16 @@ function i18n_string_translate_page_form_submit($form, &$form_state) {
foreach ($form_state['values']['strings'] as $name => $value) {
$count++;
list($textgroup, $context) = i18n_string_context(explode(':', $name));
+ if (is_array($value)) {
+ if (isset($value['value'])) {
+ $value = $value['value'];
+ $form_state['values']['strings'][$name] = $value;
+ }
+ else {
+ form_set_error("strings][$name", t('Unable to get the translated string value.'));
+ watchdog('locale', 'Unable to get the translated string value, string array is: %string', array('%string' => var_dump($value)), WATCHDOG_WARNING);
+ }
+ }
$result = i18n_string_textgroup($textgroup)->update_translation($context, $form_state['values']['langcode'], $value);
$success += ($result ? 1 : 0);
}
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.test b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.test
index f11c7564..d4563405 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.test
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_string/i18n_string.test
@@ -53,6 +53,28 @@ class i18nStringTestCase extends Drupali18nTestCase {
$this->assertEqual($translation, $translations[$key][$language->language], "The right $language->name ($language->language) translation has been retrieved for $name, $translation");
}
}
+
+ // Test that regular strings can be translated. Use 'Built-in interface' as
+ // filter, and translate first one.
+ $search = array(
+ 'language' => 'all',
+ 'translation' => 'all',
+ 'group' => 'default',
+ 'string' => '',
+ );
+ $this->drupalPost('admin/config/regional/translate/translate', $search, t('Filter'));
+ $this->clickLink(t('edit'));
+ // Just add a random translation.
+ $translation = $this->randomString();
+ $edit = array();
+ foreach ($this->getOtherLanguages() as $language) {
+ $langcode = $language->language;
+ $edit["translations[$langcode]"] = $translation;
+ }
+ $this->drupalPost(NULL, $edit, t('Save translations'));
+ $this->assertText(t('The string has been saved.'), t('The string has been saved.'));
+ $this->assertEqual($this->getUrl(), url('admin/config/regional/translate/translate', array('absolute' => TRUE)), t('Correct page redirection.'));
+
}
/**
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_sync/README.txt b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_sync/README.txt
index ce7ea6aa..c106dcb6 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_sync/README.txt
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_sync/README.txt
@@ -3,7 +3,7 @@ README.txt
==========
Drupal module: i18n_sync (Synchronization)
-This module will handle content synchronization accross translations.
+This module will handle content synchronization across translations.
The available list of fields to synchronize will include standard node fields and cck fields.
To have aditional fields, add the list in a variable in the settings.php file, like this:
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_sync/i18n_sync.info b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_sync/i18n_sync.info
index 2f1cd55e..eec7f24f 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_sync/i18n_sync.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_sync/i18n_sync.info
@@ -1,5 +1,5 @@
name = Synchronize translations
-description = Synchronizes taxonomy and fields accross translations of the same content.
+description = Synchronizes taxonomy and fields across translations of the same content.
dependencies[] = i18n
dependencies[] = translation
package = Multilingual - Internationalization
@@ -10,9 +10,9 @@ files[] = i18n_sync.install
files[] = i18n_sync.module.inc
files[] = i18n_sync.node.inc
files[] = i18n_sync.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_sync/i18n_sync.module b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_sync/i18n_sync.module
index 8aaadbec..bf5f37d4 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_sync/i18n_sync.module
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_sync/i18n_sync.module
@@ -33,7 +33,7 @@ function i18n_sync($status = NULL) {
function i18n_sync_help($path, $arg) {
switch ($path) {
case 'admin/help#i18n_sync' :
- $output = '
' . t('This module synchronizes content taxonomy and fields across translations:') . '
';
$output .= '
' . t('First you need to select which fields should be synchronized. Then, after a node has been updated, all enabled vocabularies and fields will be synchronized as follows:') . '
';
$output .= '
';
$output .= '
' . t('All the node fields selected for synchronization will be set to the same value for all translations.') . '
';
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_sync/i18n_sync.node.inc b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_sync/i18n_sync.node.inc
index 8ccad676..8b09427a 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_sync/i18n_sync.node.inc
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_sync/i18n_sync.node.inc
@@ -98,7 +98,7 @@ function i18n_sync_node_translation_nodereference_field(&$node, &$translation, $
* Example:
* English A references English B and English C.
* English A and B are translated to German A and B, but English C is not.
- * The syncronization from English A to German A would it German B and English C.
+ * The synchronization from English A to German A would it German B and English C.
*/
function i18n_sync_node_translation_reference_field(&$reference_node, $default_value, $langcode) {
if (isset($reference_node->tnid) && translation_supported_type($reference_node->type)) {
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_taxonomy/README.txt b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_taxonomy/README.txt
new file mode 100644
index 00000000..0813883a
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_taxonomy/README.txt
@@ -0,0 +1,86 @@
+CONTENTS OF THIS FILE
+---------------------
+
+* Introduction
+* Requirements
+* Recommended modules
+* Installation
+* Configuration
+* Maintainers
+
+
+INTRODUCTION
+------------
+
+The Taxonomy translation module, part of the Internationalization (https://www.drupal.org/project/i18n) package, provides multiple options to translate taxonomy vocabularies and terms. For each vocabulary, there are four types of behaviors to choose from: Language-independent terms, Language-specific terms, Localized terms, and Mixed-language vocabulary.
+
+* For a full description of the module visit https://www.drupal.org/node/1114016
+
+* To submit bug reports and feature suggestions, or to track changes visit https://www.drupal.org/project/issues/i18n
+
+
+REQUIREMENTS
+------------
+
+This module requires the following modules:
+
+* Internationalization - https://www.drupal.org/project/i18n
+
+
+RECOMMENDED MODULES
+-------------------
+
+* Internationalization Views - https://www.drupal.org/project/i18nviews
+* Language Icons - https://www.drupal.org/project/languageicons
+* Translation Overview - https://www.drupal.org/project/translation_overview
+* Localization Client - https://www.drupal.org/project/l10n_client
+* Internationalization contributions - https://www.drupal.org/project/i18n_contrib
+
+
+INSTALLATION
+------------
+
+* This is a submodule of the Internationalization module. Install the Internationalization module as you would normally install a contributed Drupal module. Visit https://www.drupal.org/docs/7/extending-drupal-7/installing-contributed-modules-find-import-enable-configure-drupal-7 for further information.
+
+
+CONFIGURATION
+-------------
+
+Language-independent terms - only vocabulary will be translatable.
+1. Navigate to Structure > Taxonomy.
+2. Select the "edit vocabulary" link.
+3. Select the "No multilingual options for terms".
+
+Language-specific terms - vocabulary is only used for content in that language. The terms will only be available if the term language matches the UI language.
+1. Navigate to Structure > Taxonomy and select the "edit vocabulary link".
+2. Choose "Fixed Language" and a Language drop-down field will be displayed.
+3. Select the language.
+4. Select "Fixed Language" and Save.
+
+Localized terms - Terms are common for all languages, but their name and description may be localized.
+1. Navigate to Structure > Taxonomy > vocabulary-to-edit > Edit.
+2. Select "Localize" and select Save.
+3. Edit a term and there will be a Translate tab. Select this tab.
+4. Select Translate, translate the Name and Description, select "Save translation", and repeat for all languages.
+5. Repeat the process for all terms.
+6. Navigate to Structure > Content types > term-to-edit > Manage display.
+7. By default, the term reference is set to Link. Change this to "Link (localized)" and Save.
+The vocabulary will be appropriate for the language.
+
+Mixed-language vocabulary - Use for vocabularies with terms in multiple languages.
+1. Navigate to Structure > Taxonomy > vocabulary-to-edit > Edit.
+2. Select the Translate radio button and Save.
+3. Edit a vocabulary term and there will be a new Language field. Choose a language and then select Save and translate.
+4. There are two options, the user can either select "Add translation link" or the user can select an existing term in the Select translations form.
+5. Create translations for the terms and add terms for specific languages only.
+Now if the user edits a node associated with this vocabulary, only the relevant terms will appear.
+
+
+MAINTAINERS
+-----------
+
+* Jose Reyero - https://www.drupal.org/u/jose-reyero
+* Florian Weber (webflo) - https://www.drupal.org/u/webflo
+* Peter Philipp - https://www.drupal.org/u/das-peter
+* Joseph Olstad - https://www.drupal.org/u/joseph.olstad
+* Nathaniel Catchpole - https://www.drupal.org/u/catch
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_taxonomy/i18n_taxonomy.info b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_taxonomy/i18n_taxonomy.info
index 2412c40e..da9281e4 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_taxonomy/i18n_taxonomy.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_taxonomy/i18n_taxonomy.info
@@ -11,9 +11,9 @@ files[] = i18n_taxonomy.pages.inc
files[] = i18n_taxonomy.admin.inc
files[] = i18n_taxonomy.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_taxonomy/i18n_taxonomy.module b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_taxonomy/i18n_taxonomy.module
index 40533489..add24f56 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_taxonomy/i18n_taxonomy.module
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_taxonomy/i18n_taxonomy.module
@@ -213,7 +213,12 @@ function i18n_taxonomy_field_formatter_view($entity_type, $entity, $field, $inst
);
}
else {
- $term = $item['taxonomy_term'];
+ if (isset($item['taxonomy_term'])) {
+ $term = $item['taxonomy_term'];
+ }
+ else {
+ $term = taxonomy_term_load($item['tid']);
+ }
$uri = entity_uri('taxonomy_term', $term);
$element[$delta] = array(
'#type' => 'link',
@@ -372,10 +377,19 @@ function i18n_taxonomy_field_prepare_translation($entity_type, $entity, $field,
* The array of valid terms for this field, keyed by term id.
*/
function i18n_taxonomy_allowed_values($field) {
+ global $language;
$options = array();
foreach ($field['settings']['allowed_values'] as $tree) {
if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
- if ($terms = taxonomy_get_tree($vocabulary->vid, $tree['parent'])) {
+ if (i18n_taxonomy_vocabulary_mode($vocabulary->vid) == I18N_MODE_TRANSLATE) {
+ $parent = i18n_taxonomy_translation_term_tid($tree['parent'], NULL, $tree['parent']);
+ $language = i18n_language_context();
+ $terms = i18n_taxonomy_get_tree($vocabulary->vid, $language->language, $parent);
+ }
+ else {
+ $terms = taxonomy_get_tree($vocabulary->vid, $tree['parent']);
+ }
+ if ($terms) {
foreach ($terms as $term) {
$options[$term->tid] = str_repeat('-', $term->depth) . i18n_taxonomy_term_name($term);
}
@@ -1020,6 +1034,10 @@ function i18n_taxonomy_localize_terms($terms) {
if (!i18n_string_translate_langcode()) {
return $terms;
}
+ // $terms is not a valid array or term.
+ if (empty($terms)) {
+ return $terms;
+ }
$object_info = i18n_object_info('taxonomy_term');
$list = is_array($terms) ? $terms : array($terms);
foreach ($list as $index => $term) {
@@ -1087,7 +1105,7 @@ function i18n_taxonomy_get_tree($vid, $langcode, $parent = 0, $max_depth = NULL,
$query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
$result = $query
->addTag('translatable')
- ->addTag('term_access')
+ ->addTag('taxonomy_term_access')
->fields('t')
->fields('h', array('parent'))
->condition('t.vid', $vid)
@@ -1261,3 +1279,22 @@ function i18n_taxonomy_modules_enabled($modules) {
}
}
}
+
+/**
+ * Implements hook_views_pre_render().
+ */
+function i18n_taxonomy_views_pre_render(&$view) {
+ if(!module_exists('rules_scheduler')) {
+ global $language;
+
+ foreach ($view->result as $delta => $term){
+ if (isset($term->tid)) {
+ i18n_string_translate_langcode($language->language);
+ $localized_term = i18n_taxonomy_localize_terms(taxonomy_term_load($term->tid));
+ $term->tid = $localized_term->tid;
+ $term->taxonomy_term_data_name = $localized_term->name;
+ $term->taxonomy_term_data_description = $localized_term->description;
+ }
+ }
+ }
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_taxonomy/i18n_taxonomy.pages.inc b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_taxonomy/i18n_taxonomy.pages.inc
index ab77cbc1..8d8f8c6f 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_taxonomy/i18n_taxonomy.pages.inc
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_taxonomy/i18n_taxonomy.pages.inc
@@ -100,7 +100,7 @@ function _i18n_taxonomy_autocomplete($langcode, $vids, $tags_typed = '') {
$query = db_select('taxonomy_term_data', 't')
->fields('t', array('tid', 'name'));
$query->addTag('translatable');
- $query->addTag('term_access');
+ $query->addTag('taxonomy_term_access');
// Disable i18n_select for this query
$query->addTag('i18n_select');
// Add language condition
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_translation/i18n_translation.info b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_translation/i18n_translation.info
index 190173c5..47f12951 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_translation/i18n_translation.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_translation/i18n_translation.info
@@ -6,9 +6,9 @@ core = 7.x
files[] = i18n_translation.inc
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_translation/i18n_translation.module b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_translation/i18n_translation.module
index de4aad4e..3fa78c8d 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_translation/i18n_translation.module
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_translation/i18n_translation.module
@@ -20,7 +20,7 @@ class I18nTranslationSetController extends DrupalDefaultEntityController {
* @param $queried_entities
* Associative array of query results, keyed on the entity ID.
* @param $revision_id
- * ID of the revision that was loaded, or FALSE if teh most current revision
+ * ID of the revision that was loaded, or FALSE if the most current revision
* was loaded.
*/
protected function attachLoad(&$queried_entities, $revision_id = FALSE) {
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_user/README.txt b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_user/README.txt
new file mode 100644
index 00000000..67eedcc1
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_user/README.txt
@@ -0,0 +1,63 @@
+CONTENTS OF THIS FILE
+---------------------
+
+* Introduction
+* Requirements
+* Recommended modules
+* Installation
+* Configuration
+* Maintainers
+
+
+INTRODUCTION
+------------
+
+The User mail translation module, part of the Internationalization (https://www.drupal.org/project/i18n) package, translates emails sent from the User module.
+
+* For a full description of the module, visit this page:
+https://www.drupal.org/node/133977
+
+* To submit bug reports and feature suggestions, or to track changes:
+https://www.drupal.org/project/issues/i18n
+
+
+REQUIREMENTS
+------------
+
+This module requires the following modules:
+
+Internationalization (https://www.drupal.org/project/i18n)
+
+
+RECOMMENDED MODULES
+-------------------
+
+* Internationalization Views (https://www.drupal.org/project/i18nviews)
+* Language Icons (https://www.drupal.org/project/languageicons)
+* Translation Overview (https://www.drupal.org/project/translation_overview)
+* Localization Client (https://www.drupal.org/project/l10n_client)
+* Internationalization contributions (https://www.drupal.org/project/i18n_contrib)
+
+
+INSTALLATION
+------------
+
+* This is a submodule of the Internationalization module. Install the Internationalization module as you would normally install a contributed Drupal module. Visit https://www.drupal.org/docs/7/extending-drupal-7/installing-contributed-modules-find-import-enable-configure-drupal-7 for further information.
+
+
+CONFIGURATION
+-------------
+
+To configure email translations
+1. Navigate to Administration > Configuration > Regional and language > Multilingual settings and select the variables tab.
+2. Select the "User emails" tab. Select the variables you would like translated and Save configuration.
+
+
+MAINTAINERS
+-----------
+
+* Jose Reyero - https://www.drupal.org/u/jose-reyero
+* Florian Weber (webflo) - https://www.drupal.org/u/webflo
+* Peter Philipp - https://www.drupal.org/u/das-peter
+* Joseph Olstad - https://www.drupal.org/u/joseph.olstad
+* Nathaniel Catchpole - https://www.drupal.org/u/catch
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_user/i18n_user.info b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_user/i18n_user.info
index 7c6ee3ba..eb7a364d 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_user/i18n_user.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_user/i18n_user.info
@@ -4,9 +4,9 @@ core = 7.x
package = Multilingual - Internationalization
dependencies[] = i18n_variable
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_user/i18n_user.module b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_user/i18n_user.module
index 4d13b3ba..bd7d5dda 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_user/i18n_user.module
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_user/i18n_user.module
@@ -9,7 +9,7 @@
*/
function i18n_user_mail_alter(&$message) {
if ($message['module'] == 'user') {
- $language = $message['language'];
+ $language = (isset($message['language']) ? $message['language'] : language_default());
$variables = array('user' => $message['params']['account']);
$key = $message['key'];
@@ -54,7 +54,7 @@ function i18n_user_user_mail_tokens(&$replacements, $data, $options) {
*/
function i18n_user_user_pass_reset_url($account) {
$timestamp = REQUEST_TIME;
- return url("user/reset/$account->uid/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE, 'language' => i18n_language($account->language)));
+ return url("user/reset/$account->uid/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid), array('absolute' => TRUE, 'language' => i18n_language($account->language)));
}
/**
@@ -65,5 +65,5 @@ function i18n_user_user_pass_reset_url($account) {
*/
function i18n_user_user_cancel_url($account) {
$timestamp = REQUEST_TIME;
- return url("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login), array('absolute' => TRUE, 'language' => i18n_language($account->language)));
+ return url("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid), array('absolute' => TRUE, 'language' => i18n_language($account->language)));
}
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_variable/README.txt b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_variable/README.txt
new file mode 100644
index 00000000..39e0f2bb
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_variable/README.txt
@@ -0,0 +1,67 @@
+CONTENTS OF THIS FILE
+---------------------
+
+* Introduction
+* Requirements
+* Recommended modules
+* Installation
+* Configuration
+* Maintainers
+
+INTRODUCTION
+------------
+
+The Variable translation module, part of the Internationalization (https://www.drupal.org/project/i18n) package, allows the user to translate text and settings that are stored in Drupal as variables. These variables include text such as 'site name' and 'site slogan', as well as settings like 'Default front page' and 'Default 404 page'.
+
+* For a full description of the module, visit https://www.drupal.org/node/1113374
+
+* To submit bug reports and feature suggestions, or to track changes visit https://www.drupal.org/project/issues/i18n
+
+
+REQUIREMENTS
+------------
+
+This module requires the following modules:
+
+* Internationalization (https://www.drupal.org/project/i18n)
+* Variable (https://www.drupal.org/project/variable)
+
+
+RECOMMENDED MODULES
+-------------------
+
+* Internationalization Views (https://www.drupal.org/project/i18nviews)
+* Language Icons (https://www.drupal.org/project/languageicons)
+* Translation Overview (https://www.drupal.org/project/translation_overview)
+* Localization Client (https://www.drupal.org/project/l10n_client)
+* Internationalization contributions (https://www.drupal.org/project/i18n_contrib)
+
+
+INSTALLATION
+------------
+
+* This is a submodule of the Internationalization module. Install the Internationalization module as you would normally install a contributed Drupal module. See https://www.drupal.org/docs/7/extending-drupal-7/installing-contributed-modules-find-import-enable-configure-drupal-7 for further information.
+
+
+CONFIGURATION
+-------------
+
+To enable multilingual variables
+
+1. Enable the Variable translation module included with the Internationalization package.
+2. Go to Administration > Configuration > Regional and language > Multilingual settings.
+3. Click on the Variables tab.
+4. Select the variables that will be multilingual.
+5. Click Save configuration button.
+
+Once you have the correct settings, they'll be marked with "This is a multilingual variable" when you go to the corresponding administration pages. You must switch the site language while in the administration pages to set the variables for each language. A language switcher link will appear at the top of each administrative page that has multilingual variables.
+
+
+MAINTAINERS
+-----------
+
+* Jose Reyero - https://www.drupal.org/u/jose-reyero
+* Florian Weber (webflo) - https://www.drupal.org/u/webflo
+* Peter Philipp - https://www.drupal.org/u/das-peter
+* Joseph Olstad - https://www.drupal.org/u/joseph.olstad
+* Nathaniel Catchpole - https://www.drupal.org/u/catch
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_variable/i18n_variable.info b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_variable/i18n_variable.info
index 6956a25d..7a26ab61 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/i18n_variable/i18n_variable.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/i18n_variable/i18n_variable.info
@@ -10,9 +10,9 @@ configure = admin/config/regional/i18n/variable
files[] = i18n_variable.class.inc
files[] = i18n_variable.test
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/i18n/tests/i18n_test.info b/profiles/commerce_kickstart/modules/contrib/i18n/tests/i18n_test.info
index 9ccf441d..1ec747ae 100644
--- a/profiles/commerce_kickstart/modules/contrib/i18n/tests/i18n_test.info
+++ b/profiles/commerce_kickstart/modules/contrib/i18n/tests/i18n_test.info
@@ -7,9 +7,9 @@ package = Testing
core = 6.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2015-01-26
-version = "7.x-1.12"
+; Information added by Drupal.org packaging script on 2017-04-18
+version = "7.x-1.17"
core = "7.x"
project = "i18n"
-datestamp = "1422286982"
+datestamp = "1492537747"
diff --git a/profiles/commerce_kickstart/modules/contrib/inline_conditions/README b/profiles/commerce_kickstart/modules/contrib/inline_conditions/README
deleted file mode 100644
index 5b16f678..00000000
--- a/profiles/commerce_kickstart/modules/contrib/inline_conditions/README
+++ /dev/null
@@ -1,12 +0,0 @@
-It is common for a rule to be generated based on an entity (discounts, shipping rates, etc).
-
-This module allows conditions to be defined on the entity add / edit form, and
-those conditions are later mapped to rules conditions when the rule is generated.
-
-Inline Conditions are specially defined (hook_inline_condition_info()) and
-consist of a configure callback (provides a user-facing form) and a build
-callback (adds the actual condition to the rule).
-Integration consists of creating a field of the "inline_conditions" type on the
-entity, and later calling inline_conditions_build_rule() from the implementation
-of hook_default_rules_configuration().
-See inline_conditions.api.php for more information.
diff --git a/profiles/commerce_kickstart/modules/contrib/inline_conditions/README.md b/profiles/commerce_kickstart/modules/contrib/inline_conditions/README.md
new file mode 100644
index 00000000..01a4f6fd
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/inline_conditions/README.md
@@ -0,0 +1,21 @@
+## CONTENTS OF THIS FILE
+
+ * Description
+
+
+## DESCRIPTION
+
+It is common for a rule to be generated based on an entity (discounts, shipping
+rates, etc).
+
+This module allows conditions to be defined on the entity add / edit form, and
+those conditions are later mapped to rules conditions when the rule is
+generated.
+
+Inline Conditions are specially defined (hook_inline_condition_info()) and
+consist of a configure callback (provides a user-facing form) and a build
+callback (adds the actual condition to the rule). Integration consists of
+creating a field of the "inline_conditions" type on the entity, and later
+calling inline_conditions_build_rule() from the implementation of
+hook_default_rules_configuration(). See inline_conditions.api.php for more
+information.
diff --git a/profiles/commerce_kickstart/modules/contrib/inline_conditions/css/inline_conditions-rtl.css b/profiles/commerce_kickstart/modules/contrib/inline_conditions/css/inline_conditions-rtl.css
deleted file mode 100644
index 1d0cf82b..00000000
--- a/profiles/commerce_kickstart/modules/contrib/inline_conditions/css/inline_conditions-rtl.css
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
-* inline_conditions main css file.
-*/
-
-/**
-* Condition area.
-*/
-.inline-conditions-container .condition-wrapper {
- float: right;
-}
-.inline-conditions-container .condition-wrapper .form-item label {
- float: right; /* RTL */
-}
-/* Throbber */
-.inline-conditions-container .condition-wrapper .form-item .ajax-progress {
- display: inline;
- margin-top: 0; /* RTL */
- left: 0;
- right: 62px; /* RTL */
- width: auto; /* RTL */
-}
-.inline-conditions-container .remove-condition .form-submit {
- float: right;
-}
-.inline-conditions-container .remove-condition .ajax-progress .message {
- float: right;
- padding-right: 5px;
- padding-left: 0; /* RTL */
-}
-
-/* order conditions */
-.inline-conditions-container div.condition-instructions {
- margin-right: 85px;
- margin-left: 0; /* RTL */
-}
diff --git a/profiles/commerce_kickstart/modules/contrib/inline_conditions/css/inline_conditions.css b/profiles/commerce_kickstart/modules/contrib/inline_conditions/css/inline_conditions.css
index 0bbe796c..4b326736 100644
--- a/profiles/commerce_kickstart/modules/contrib/inline_conditions/css/inline_conditions.css
+++ b/profiles/commerce_kickstart/modules/contrib/inline_conditions/css/inline_conditions.css
@@ -1,91 +1,44 @@
/**
-* inline_conditions main css file.
-*/
-
-/**
-* Discount conditions block.
-*/
-.inline-conditions-container .form-wrapper {
- margin: 10px;
-}
-.inline-conditions-container .even,
-.inline-conditions-container .odd {
- margin-top: 2px;
- padding: 10px 5px;
-}
-.inline-conditions-container .odd {
- background-color: #eee;
-}
+ * @file
+ * Inline conditions main stylesheet.
+ *
+ * This file exposes the common style rules for the inline_conditions field
+ * widget and its child elements should be displayed.
+ */
-/**
-* Condition area.
+/*
+ Wrappers for select, checkbox, checkboxes and textfield elements are
+ displayed inline.
+ The #id selector is used to counter core's tr.odd .form-item styles.
*/
-.inline-conditions-container .condition-wrapper {
- display: block;
- float: left; /* LTR */
- position: relative;
-}
-.inline-conditions-container .condition-wrapper .form-item label {
+#inline-conditions-inline_conditions .inline-conditions-settings-wrapper .form-wrapper,
+#inline-conditions-inline_conditions .inline-conditions-settings-wrapper .form-type-select,
+#inline-conditions-inline_conditions .inline-conditions-settings-wrapper .form-type-checkbox,
+#inline-conditions-inline_conditions .inline-conditions-settings-wrapper .form-type-checkboxes,
+#inline-conditions-inline_conditions .inline-conditions-settings-wrapper .form-type-textfield {
display: inline-block;
- width: 80px;
-}
-/* Throbber */
-.inline-conditions-container .condition-wrapper .form-item .ajax-progress {
- position: absolute;
- left: 62px; /* LTR */
-}
-.inline-conditions-container .condition-wrapper .form-item .ajax-progress .message {
- display: none;
+ vertical-align: top;
}
-.inline-conditions-container .condition-logic {
- position: relative;
-}
-.inline-conditions-container .condition-logic select {
- float: left; /* LTR */
- margin-right: 10px;
+/* Labels inside wrappers are displayed inline. */
+.inline-conditions-settings-wrapper .form-item label:not(.option) {
+ display: inline;
+ vertical-align: top;
}
-.inline-conditions-container .remove-condition {
- position: relative;
-}
-.inline-conditions-container .remove-condition .form-submit {
- float: left; /* LTR */
- margin: 0 10px;
-}
-.inline-conditions-container .remove-condition .ajax-progress .message {
- float: left; /* LTR */
- padding-left: 5px; /* LTR */
+/* Make bigger the logical operators to make them even more clear. */
+.inline-conditions-logic-operator {
+ font-size: 1.2em;
}
-/* order conditions */
-.inline-conditions-container .form-item {
- margin: 0;
-}
-.inline-conditions-container .form-submit {
- margin: 0;
+/* Add vertical space to direct children of the settings wrapper. */
+.inline-conditions-settings-wrapper > .form-item {
+ margin-top: 0.25em;
+ margin-bottom: 0.25em;
}
-.inline-conditions-container .form-submit.add-new-condition {
- margin-top: 10px;
-}
-.inline-conditions-container div.condition-instructions {
- color: #6d6d6d;
- font-style: italic;
- display: block;
- font-size: smaller;
- /* Equal to ..inline-conditions-container .condition-wrapper .form-item label width+5px */
- margin-left: 85px; /* LTR */
-}
-.inline-conditions-container .product-taxonomy .form-type-radio {
- display: block;
- margin: 0;
- padding: 0;
-}
-.inline-conditions-container .product-taxonomy .form-type-radio > label {
- color: #6d6d6d;
- font-style: italic;
- font-size: smaller;
-}
-.commerce-discount-form .negate-condition input.form-checkbox + label::before {
- top: inherit;
+
+/* Ensure alignment of controls in the cells. */
+#inline-conditions-inline_conditions th,
+#inline-conditions-inline_conditions td {
+ vertical-align: top;
}
diff --git a/profiles/commerce_kickstart/modules/contrib/inline_conditions/inline_conditions.api.php b/profiles/commerce_kickstart/modules/contrib/inline_conditions/inline_conditions.api.php
index a486dbdd..262f850a 100644
--- a/profiles/commerce_kickstart/modules/contrib/inline_conditions/inline_conditions.api.php
+++ b/profiles/commerce_kickstart/modules/contrib/inline_conditions/inline_conditions.api.php
@@ -31,7 +31,15 @@
* operate on the same entity type -> commerce_order).
* - callbacks: An array of callbacks:
* - configure: (Optional) Returns a configuration form embedded into the
- * field widget, and used to configure the inline condition.
+ * field widget, and used to configure the inline condition. The following
+ * list of parameters will be passed to the configure callback function:
+ * - condition_settings (Array): an array containing all configured
+ * settings; typically this will match the values of the form elements
+ * defined in the 'configure' callback. It should be transformed into
+ * an array of parameter values as the rules condition needs them.
+ * - instance (Array): The field instance array (which includes the entity
+ * information that is related to the condition, such as the ID).
+ * - delta (Int): The current field delta defined as an integer.
* - build: [Do not use if rule condition name is set] Gets the rule and any
* settings added by the configure callback, then builds and adds an actual
* rules condition to the rule. Also, if the rule condition name key is set,
diff --git a/profiles/commerce_kickstart/modules/contrib/inline_conditions/inline_conditions.field.inc b/profiles/commerce_kickstart/modules/contrib/inline_conditions/inline_conditions.field.inc
new file mode 100644
index 00000000..83e092bd
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/inline_conditions/inline_conditions.field.inc
@@ -0,0 +1,381 @@
+ array(
+ 'label' => t('Inline conditions'),
+ 'description' => t('This field stores conditions that are later added to a matching rule.'),
+ // entity_type is the type of the entity operated on by the matching rule.
+ 'instance_settings' => array('entity_type' => NULL),
+ 'default_widget' => 'inline_conditions',
+ 'default_formatter' => 'hidden',
+ 'no_ui' => TRUE,
+ 'property_type' => 'inline_conditions',
+ 'property_callbacks' => array('inline_conditions_field_property_callback'),
+ ),
+ );
+}
+
+/**
+ * Implements hook_field_widget_info().
+ */
+function inline_conditions_field_widget_info() {
+ return array(
+ 'inline_conditions' => array(
+ 'label' => t('Inline conditions'),
+ 'field types' => array('inline_conditions'),
+ 'behaviors' => array(
+ 'multiple values' => FIELD_BEHAVIOR_CUSTOM,
+ 'default value' => FIELD_BEHAVIOR_NONE,
+ ),
+ 'settings' => array(),
+ ),
+ );
+}
+
+/**
+ * Implements hook_field_load().
+ *
+ * Prepare items array in order to be usable with inline_condition field widget.
+ */
+function inline_conditions_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) {
+ // Loop on every entities given.
+ foreach ($entities as $id => $entity) {
+ // Ensures that field is inline_conditions type.
+ if ($field['type'] == 'inline_conditions') {
+
+ foreach ($items[$id] as $delta => $item) {
+ // Ensure condition_settings is unserialised.
+ if (is_string($item['condition_settings'])) {
+ // Unserialize the field settings.
+ $item['condition_settings'] = unserialize($item['condition_settings']);
+
+ // Look up for the value of the logic operators.
+ if (isset($item['condition_settings']['condition_negate'])) {
+ $item['condition_negate'] = $item['condition_settings']['condition_negate'];
+ unset($item['condition_settings']['condition_negate']);
+ }
+ if (isset($item['condition_settings']['condition_logic_operator'])) {
+ $item['condition_logic_operator'] = $item['condition_settings']['condition_logic_operator'];
+ unset($item['condition_settings']['condition_logic_operator']);
+ }
+
+ // Replace item value.
+ $items[$id][$delta] = $item;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Implements hook_field_insert().
+ *
+ * Call inline_conditions_prepare_field_items() in order to rebuild items.
+ *
+ * @see inline_conditions_field_prepare_items()
+ */
+function inline_conditions_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
+ // Ensures that field is inline_conditions type.
+ if ($field['type'] == 'inline_conditions') {
+ inline_conditions_field_prepare_items($items);
+ }
+}
+
+/**
+ * Implements hook_field_update().
+ *
+ * Call inline_conditions_prepare_field_items() in order to rebuild items.
+ *
+ * @see inline_conditions_field_prepare_items()
+ */
+function inline_conditions_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
+ // Ensures that field is inline_conditions type.
+ if ($field['type'] == 'inline_conditions') {
+ inline_conditions_field_prepare_items($items);
+ }
+}
+
+/**
+ * Implements hook_field_is_empty().
+ */
+function inline_conditions_field_is_empty($item, $field) {
+ return empty($item['condition_name']);
+}
+
+/**
+ * Alter $items array and prepare it to be saved.
+ *
+ * Serialize the condition_settings column.
+ *
+ * @param array $items
+ * A referenced array of field items.
+ *
+ * @see inline_conditions_field_load()
+ * @see inline_conditions_field_insert()
+ */
+function inline_conditions_field_prepare_items(&$items) {
+ // A simple way to check if array is a multi-dimensional array.
+ if (is_array($items)) {
+ foreach ($items as $delta => $item) {
+ // Ensures that $item has a condition name.
+ if (!empty($item['condition_name'])) {
+ // Ensure that condition_settings is not serialized.
+ if (is_array($item['condition_settings'])) {
+ $condition_settings = array_merge($item['condition_settings'], array(
+ // Store the rule condition logic operators.
+ 'condition_negate' => isset($item['condition_negate']) ? $item['condition_negate'] : NULL,
+ 'condition_logic_operator' => isset($item['condition_logic_operator']) ? $item['condition_logic_operator'] : NULL,
+ ));
+ $item['condition_settings'] = serialize($condition_settings);
+ }
+ // Replace item value.
+ $items[$delta] = $item;
+ }
+ }
+ }
+}
+
+/**
+ * Implements hook_field_widget_form().
+ */
+function inline_conditions_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+ // Ensure this .inline_conditions files are loaded when the form is rebuilt
+ // from the cache.
+ foreach (inline_conditions_get_info_by_module() as $module => $condition) {
+ $form_state['build_info']['files']["form_ic_$module"] = drupal_get_path('module', $module) . "/$module.inline_conditions.inc";
+ }
+
+ // Prepare a list of all possible conditions.
+ $condition_info = inline_conditions_get_info_by_type(empty($instance['settings']['entity_type']) ? 'commerce_order' : $instance['settings']['entity_type'], $instance['entity_type']);
+
+ // Build main wrapper id.
+ $main_wrapper_id = sprintf('inline-conditions-%s', $field['field_name']);
+
+ $element = array(
+ '#type' => 'container',
+ '#id' => $main_wrapper_id,
+ '#caption' => $element['#title'],
+ '#theme' => 'inline_conditions_table',
+ '#element_validate' => array('inline_conditions_field_widget_form_validate'),
+ ) + $element;
+
+ // Attach module style sheet to widget form.
+ $form['#attached']['css'][] = drupal_get_path('module', 'inline_conditions') . '/css/inline_conditions.css';
+
+ // If "Add a new condition" button has been pressed.
+ if (isset($form_state['triggering_element']['#condition_action'])) {
+ switch ($form_state['triggering_element']['#condition_action']) {
+ case 'and':
+ $items[] = array(
+ 'condition_name' => '',
+ 'condition_settings' => array(),
+ 'condition_logic_operator' => INLINE_CONDITIONS_AND,
+ );
+ break;
+
+ case 'or':
+ $items[] = array(
+ 'condition_name' => '',
+ 'condition_settings' => array(),
+ 'condition_logic_operator' => INLINE_CONDITIONS_OR,
+ );
+ break;
+
+ case 'remove':
+ unset($items[$form_state['triggering_element']['#element_delta']]);
+ // Rebuild array keys.
+ $items = array_values($items);
+ break;
+ }
+ }
+
+ // If no items found, create an empty item for display purposes.
+ if (empty($items)) {
+ $items[] = array('condition_name' => '', 'condition_settings' => array());
+ }
+
+ foreach ($items as $delta => $item) {
+ $settings_wrapper_id = sprintf('inline-conditions-settings-wrapper-%s-%s', $instance['id'], $delta);
+
+ // Condition selector.
+ $element[$delta]['condition_name'] = array(
+ '#type' => 'select',
+ '#options' => inline_conditions_options_list($condition_info),
+ '#default_value' => $item['condition_name'],
+ '#ajax' => array(
+ 'callback' => 'inline_conditions_form_ajax_callback',
+ 'wrapper' => $settings_wrapper_id,
+ ),
+ '#condition_action' => 'select',
+ // Identifies the condition operated upon.
+ '#element_delta' => $delta,
+ '#limit_validation_errors' => array(),
+ );
+
+ // Condition settings.
+ $element[$delta]['condition_settings'] = array(
+ '#type' => 'value',
+ '#value' => array(),
+ );
+
+ // A condition has been selected, and a "configure" callback exists. Fills
+ // up the condition_settings key with form elements returned by condition
+ // configure callback.
+ if (!empty($item['condition_name']) && !empty($condition_info[$item['condition_name']]['callbacks']['configure'])) {
+ $callback = $condition_info[$item['condition_name']]['callbacks']['configure'];
+ $element[$delta]['condition_settings'] = $callback($item['condition_settings'], $instance, $delta);
+ $element[$delta]['#attributes'] = array('class' => array('container-inline'));
+ }
+
+ // Merge additional properties for the ajax wrapping.
+ $element[$delta]['condition_settings'] += array(
+ '#prefix' => sprintf('
',
- '#element_delta' => $delta,
- '#condition_action' => 'remove',
- '#executes_submit_callback' => FALSE,
- '#limit_validation_errors' => array(),
- );
-
- // Add an option list to select logical disjunctions for each inline
- // condition.
- if ($delta > 0) {
- // Remove the default condition selector label and also remove the prefix
- // used as HTML wrapper for the current condition.
- unset($element[$delta]['condition_name']['#title'], $element[$delta]['condition_name']['#prefix']);
- // Add an option list to select the logic operator for the current
- // condition.
- $element[$delta]['condition_logic_operator'] = array(
- '#type' => 'select',
- '#options' => array(
- INLINE_CONDITIONS_OR => t('Or:'),
- INLINE_CONDITIONS_AND => t('And:'),
- ),
- '#default_value' => isset($item['condition_logic_operator']) ? $item['condition_logic_operator'] : INLINE_CONDITIONS_AND,
- '#weight' => -50,
- '#prefix' => '
',
- );
- }
- }
-
- // Add the "Add another" button.
- $element['add_more'] = array(
- '#type' => 'button',
- '#name' => $field['field_name'] . '-' . $instance['id'] . '-add_condition',
- '#value' => t('Add a new condition'),
- '#ajax' => array(
- 'callback' => 'inline_conditions_form_ajax_callback',
- 'wrapper' => 'inline-conditions-' . $field['field_name'],
- 'effect' => 'fade',
- ),
- '#attributes' => array('class' => array('add-new-condition')),
- '#element_delta' => $element['#delta'],
- '#condition_action' => 'add',
- '#limit_validation_errors' => array(),
- );
-
- return $element;
-}
-
-/**
- * Callback : Validate inline_conditions_field_widget_form.
- *
- * @param array $element
- * A form element array containing basic properties for the widget:
- * - #entity_type: The name of the entity the field is attached to.
- * - #bundle: The name of the field bundle the field is contained in.
- * - #field_name: The name of the field.
- * - #language: The language the field is being edited in.
- * - #field_parents: The 'parents' space for the field in the form. Most
- * widgets can simply overlook this property. This identifies the
- * location where the field values are placed within
- * $form_state['values'], and is used to access processing information
- * for the field through the field_form_get_state() and
- * field_form_set_state() functions.
- * - #columns: A list of field storage columns of the field.
- * - #title: The sanitized element label for the field instance, ready for
- * output.
- * - #description: The sanitized element description for the field instance,
- * ready for output.
- * - #required: A Boolean indicating whether the element value is required;
- * for required multiple value fields, only the first widget's values are
- * required.
- * - #delta: The order of this item in the array of subelements; see $delta
- * above.
- * @param array $form_state
- * An associative array containing the current state of the form.
- * @param array $form
- * The form structure where widgets are being attached to. This might be a
- * full form structure, or a sub-element of a larger form.
- *
- * @return bool
- * Return a boolean to validate or not form elements.
- */
-function inline_conditions_field_widget_form_validate($element, &$form_state, $form) {
- // Support removing the conditions from the entity.
- if (isset($form_state['triggering_element']['#condition_action']) && $form_state['triggering_element']['#condition_action'] == 'remove') {
- $element['#parents'][] = $form_state['triggering_element']['#element_delta'];
- drupal_array_set_nested_value($form_state['values'], $element['#parents'], array(), TRUE);
- drupal_array_set_nested_value($form_state['input'], $element['#parents'], array(), TRUE);
- }
-}
-
-/**
- * Ajax callback for the Inline Conditions form elements.
- *
- * @param array $form
- * The form array.
- * @param array &$form_state
- * The reference of form_state array.
- *
- * @return array
- * Return form element to display.
- */
-function inline_conditions_form_ajax_callback($form, &$form_state) {
- $element_parents = array_slice($form_state['triggering_element']['#array_parents'], 0, -2);
- $element = drupal_array_get_nested_value($form, $element_parents);
-
- // Triggered when user selects a condition.
- if ($form_state['triggering_element']['#condition_action'] == 'select') {
- $delta = $form_state['triggering_element']['#element_delta'];
-
- return $element[$delta];
- }
- else {
- return $element;
- }
-}
-
/**
* Defines a callback to add condition(s) to the given rule.
*
@@ -633,7 +338,7 @@ function inline_conditions_form_ajax_callback($form, &$form_state) {
* @param array $field_values
* An array of values from an inline_conditions field.
*
- * @see hook_inline_conditions_prebuild_alter()
+ * @see hook_inline_conditions_build_alter()
*/
function inline_conditions_build(RulesReactionRule $rule, $field_values) {
if (!empty($field_values)) {
@@ -699,7 +404,6 @@ function inline_conditions_build(RulesReactionRule $rule, $field_values) {
}
// No logical operator found, so we put the condition in the temp array.
- // It will be added to next condition using a logical operator.
$temp = $condition;
}
@@ -711,7 +415,8 @@ function inline_conditions_build(RulesReactionRule $rule, $field_values) {
$rule->condition($or);
}
- // If a condition is still present in the temp var, attach it to the rule.
+ // If a condition is still present in the temp var, attach it to the rule
+ // using an AND operator.
if (isset($temp)) {
$rule->condition($temp);
}
@@ -729,7 +434,7 @@ function inline_conditions_build(RulesReactionRule $rule, $field_values) {
* An array of conditions.
*/
function inline_conditions_get_info($condition_name = NULL) {
- $conditions = & drupal_static(__FUNCTION__);
+ $conditions = &drupal_static(__FUNCTION__);
if (!isset($conditions)) {
$conditions = array();
@@ -738,7 +443,19 @@ function inline_conditions_get_info($condition_name = NULL) {
$condition_info += array(
// Remember the providing module.
'module' => $module,
+ 'callbacks' => array(),
+ );
+ // Provide default callbacks based on condition name when they are using
+ // the MODULE_CONDITION condition name's naming pattern.
+ $callback_prefix = $condition;
+ if (strpos($callback_prefix, $module . '_') !== 0) {
+ $callback_prefix = $module . '_' . $condition;
+ }
+ $condition_info['callbacks'] += array(
+ 'configure' => $callback_prefix . '_configure',
+ 'build' => $callback_prefix . '_build',
);
+
$conditions[$condition] = $condition_info;
}
}
@@ -792,13 +509,11 @@ function inline_conditions_get_info_by_type($entity_type, $parent_entity_type) {
/**
* Get inline conditions per module name.
*
- * Return an array of conditions keyed by module name.
- *
* @param string $module
* The module name.
*
* @return array
- * An array of conditions.
+ * An array of inline conditions keyed by module name.
*/
function inline_conditions_get_info_by_module($module = NULL) {
$filtered_conditions = array();
@@ -807,5 +522,29 @@ function inline_conditions_get_info_by_module($module = NULL) {
$filtered_conditions[$condition['module']][$name] = $condition;
}
+ // Apply module filter if it's set.
+ if (!empty($module)) {
+ $filtered_conditions = !empty($filtered_conditions[$module]) ? array($module => $filtered_conditions[$module]) : array();
+ }
+
return $filtered_conditions;
}
+
+/**
+ * Returns an options list of inline conditions per type.
+ *
+ * @param array $condition_info
+ * An array of inline conditions.
+ *
+ * @return array
+ * An array of inline conditions keyed by condition machine name.
+ */
+function inline_conditions_options_list($condition_info) {
+ // Complete an array ready to be used as value for a select form element.
+ $condition_list = array('' => t('- All -'));
+ foreach ($condition_info as $condition_name => $info) {
+ $condition_list[$condition_name] = $info['label'];
+ }
+
+ return $condition_list;
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/inline_entity_form/includes/commerce_product.inline_entity_form.inc b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/includes/commerce_product.inline_entity_form.inc
index 07b57247..5dcb6f21 100644
--- a/profiles/commerce_kickstart/modules/contrib/inline_entity_form/includes/commerce_product.inline_entity_form.inc
+++ b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/includes/commerce_product.inline_entity_form.inc
@@ -334,6 +334,16 @@ class CommerceProductInlineEntityFormController extends EntityInlineEntityFormCo
return $attributes;
}
+ /**
+ * Overrides EntityInlineEntityFormController::createClone().
+ */
+ public function createClone($entity) {
+ $cloned_entity = parent::createClone($entity);
+ $cloned_entity->sku = NULL;
+
+ return $cloned_entity;
+ }
+
/**
* Overrides EntityInlineEntityFormController::save().
*
diff --git a/profiles/commerce_kickstart/modules/contrib/inline_entity_form/includes/entity.inline_entity_form.inc b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/includes/entity.inline_entity_form.inc
index 353faac7..89a42461 100644
--- a/profiles/commerce_kickstart/modules/contrib/inline_entity_form/includes/entity.inline_entity_form.inc
+++ b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/includes/entity.inline_entity_form.inc
@@ -144,6 +144,7 @@ class EntityInlineEntityFormController {
$defaults['allow_new'] = TRUE;
$defaults['allow_existing'] = FALSE;
$defaults['match_operator'] = 'CONTAINS';
+ $defaults['allow_clone'] = FALSE;
$defaults['delete_references'] = FALSE;
$labels = $this->defaultLabels();
$defaults['override_labels'] = FALSE;
@@ -200,12 +201,16 @@ class EntityInlineEntityFormController {
$form['match_operator']['#access'] = FALSE;
}
+ $form['allow_clone'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Allow users to clone @label.', array('@label' => $labels['plural'])),
+ '#default_value' => isset($this->settings['allow_clone'])? $this->settings['allow_clone'] : FALSE,
+ );
$form['delete_references'] = array(
'#type' => 'checkbox',
'#title' => t('Delete referenced @label when the parent entity is deleted.', array('@label' => $labels['plural'])),
'#default_value' => $this->settings['delete_references'],
);
-
$form['override_labels'] = array(
'#type' => 'checkbox',
'#title' => t('Override labels'),
@@ -377,6 +382,44 @@ class EntityInlineEntityFormController {
return IEF_ENTITY_UNLINK_DELETE;
}
+ /**
+ * Creates a clone of the given entity.
+ *
+ * Copies the entity_ui_clone_entity() approach, extending it to unset
+ * additional unique properties.
+ *
+ * @param $entity
+ * The entity to clone.
+ *
+ * @return
+ * The unsaved cloned entity.
+ */
+ public function createClone($entity) {
+ $cloned_entity = clone $entity;
+ $cloned_entity->is_new = TRUE;
+
+ $entity_info = entity_get_info($this->entityType);
+ // Make sure the status of a cloned exportable is custom.
+ if (!empty($entity_info['exportable'])) {
+ $status_key = isset($entity_info['entity keys']['status']) ? $entity_info['entity keys']['status'] : 'status';
+ $cloned_entity->$status_key = ENTITY_CUSTOM;
+ }
+ // Unset properties specified as entity keys.
+ foreach (array('id', 'name', 'revision') as $key) {
+ if (!empty($entity_info['entity keys'][$key])) {
+ $cloned_entity->{$entity_info['entity keys'][$key]} = NULL;
+ }
+ }
+ // Unset other common properties.
+ foreach (array('created', 'changed', 'uid', 'revision_timestamp', 'revision_uid') as $property) {
+ if (isset($cloned_entity->{$property})) {
+ $cloned_entity->{$property} = NULL;
+ }
+ }
+
+ return $cloned_entity;
+ }
+
/**
* Permanently saves the given entity.
*
diff --git a/profiles/commerce_kickstart/modules/contrib/inline_entity_form/includes/node.inline_entity_form.inc b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/includes/node.inline_entity_form.inc
index ceccb3ac..4d481cbd 100644
--- a/profiles/commerce_kickstart/modules/contrib/inline_entity_form/includes/node.inline_entity_form.inc
+++ b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/includes/node.inline_entity_form.inc
@@ -85,4 +85,18 @@ class NodeInlineEntityFormController extends EntityInlineEntityFormController {
$function($entity_form['#entity'], $entity_form, $child_form_state);
}
}
+
+ /**
+ * Overrides EntityInlineEntityFormController::createClone().
+ */
+ public function createClone($entity) {
+ global $user;
+
+ $cloned_entity = parent::createClone($entity);
+ $cloned_entity->tnid = NULL;
+ $cloned_entity->name = isset($user->name) ? $user->name : NULL;
+ $cloned_entity->path = NULL;
+
+ return $cloned_entity;
+ }
}
diff --git a/profiles/commerce_kickstart/modules/contrib/inline_entity_form/includes/taxonomy_term.inline_entity_form.inc b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/includes/taxonomy_term.inline_entity_form.inc
index b6ef7ff3..bd2ec593 100644
--- a/profiles/commerce_kickstart/modules/contrib/inline_entity_form/includes/taxonomy_term.inline_entity_form.inc
+++ b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/includes/taxonomy_term.inline_entity_form.inc
@@ -82,7 +82,7 @@ class TaxonomyTermInlineEntityFormController extends EntityInlineEntityFormContr
'#title' => t('Description'),
'#default_value' => $term->description,
'#format' => $term->format,
- '#weight' => $extra_fields['description']['weight'],
+ '#weight' => !empty($extra_fields['description']) ? $extra_fields['description']['weight'] : -4,
);
$langcode = entity_language('taxonomy_term', $term);
diff --git a/profiles/commerce_kickstart/modules/contrib/inline_entity_form/inline_entity_form.info b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/inline_entity_form.info
index 9d14ed1c..7452543c 100644
--- a/profiles/commerce_kickstart/modules/contrib/inline_entity_form/inline_entity_form.info
+++ b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/inline_entity_form.info
@@ -3,6 +3,8 @@ description = "Provides a widget for inline management (creation, modification,
package = Fields
dependencies[] = entity
dependencies[] = system (>7.14)
+test_dependencies[] = ctools
+test_dependencies[] = entityreference
core = 7.x
files[] = includes/entity.inline_entity_form.inc
@@ -10,10 +12,12 @@ files[] = includes/node.inline_entity_form.inc
files[] = includes/taxonomy_term.inline_entity_form.inc
files[] = includes/commerce_product.inline_entity_form.inc
files[] = includes/commerce_line_item.inline_entity_form.inc
+files[] = tests/inline_entity_form_test_base.test
+files[] = tests/multiple_values_widget.test
-; Information added by Drupal.org packaging script on 2015-06-17
-version = "7.x-1.6"
+; Information added by Drupal.org packaging script on 2016-04-16
+version = "7.x-1.8"
core = "7.x"
project = "inline_entity_form"
-datestamp = "1434553381"
+datestamp = "1460849408"
diff --git a/profiles/commerce_kickstart/modules/contrib/inline_entity_form/inline_entity_form.module b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/inline_entity_form.module
index 2fa09b1d..c1a7d823 100644
--- a/profiles/commerce_kickstart/modules/contrib/inline_entity_form/inline_entity_form.module
+++ b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/inline_entity_form.module
@@ -397,7 +397,6 @@ function inline_entity_form_field_widget_form(&$form, &$form_state, $field, $ins
$widget = $instance['widget'];
$settings = inline_entity_form_settings($field, $instance);
$entity_info = entity_get_info($settings['entity_type']);
- $cardinality = $field['cardinality'];
$controller = inline_entity_form_get_controller($instance);
// The current entity type is not supported, execution can't continue.
if (!$controller) {
@@ -478,6 +477,11 @@ function inline_entity_form_field_widget_form(&$form, &$form_state, $field, $ins
}
}
+ // Prepare cardinality information.
+ $cardinality = $field['cardinality'];
+ $entity_count = count($form_state['inline_entity_form'][$ief_id]['entities']);
+ $cardinality_reached = ($cardinality > 0 && $entity_count == $cardinality);
+
// Build the appropriate widget.
// The "Single value" widget assumes it is operating on a required single
// value reference field with 1 allowed bundle.
@@ -532,6 +536,7 @@ function inline_entity_form_field_widget_form(&$form, &$form_state, $field, $ins
'#tree' => TRUE,
'#theme' => 'inline_entity_form_entity_table',
'#entity_type' => $settings['entity_type'],
+ '#cardinality' => (int) $cardinality,
);
// Get the fields that should be displayed in the table.
@@ -620,6 +625,25 @@ function inline_entity_form_field_widget_form(&$form, &$form_state, $field, $ins
'#ief_row_form' => 'edit',
);
}
+ // Add the clone button, if allowed.
+ // The clone form follows the same semantics as the create form, so
+ // it's opened below the table.
+ if ($controller->getSetting('allow_clone') && !$cardinality_reached
+ && entity_access('create', $controller->entityType(), $entity)) {
+ $row['actions']['ief_entity_clone'] = array(
+ '#type' => 'submit',
+ '#value' => t('Clone'),
+ '#name' => 'ief-' . $ief_id . '-entity-clone-' . $key,
+ '#limit_validation_errors' => array(array_merge($parents, array('actions'))),
+ '#ajax' => array(
+ 'callback' => 'inline_entity_form_get_element',
+ 'wrapper' => $wrapper,
+ ),
+ '#submit' => array('inline_entity_form_open_form'),
+ '#ief_row_delta' => $key,
+ '#ief_form' => 'clone',
+ );
+ }
// If 'allow_existing' is on, the default removal operation is unlink
// and the access check for deleting happens inside the controller
@@ -643,7 +667,6 @@ function inline_entity_form_field_widget_form(&$form, &$form_state, $field, $ins
}
}
- $entity_count = count($form_state['inline_entity_form'][$ief_id]['entities']);
if ($cardinality > 1) {
// Add a visual cue of cardinality count.
$message = t('You have added @entities_count out of @cardinality_count allowed @label.', array(
@@ -656,14 +679,18 @@ function inline_entity_form_field_widget_form(&$form, &$form_state, $field, $ins
);
}
// Do not return the rest of the form if cardinality count has been reached.
- if ($cardinality > 0 && $entity_count == $cardinality) {
+ if ($cardinality_reached) {
return $element;
}
- // Try to open the add form (if it's the only allowed action, the
- // field is required and empty, and there's only one allowed bundle).
- if (empty($form_state['inline_entity_form'][$ief_id]['entities'])) {
- if (count($settings['create_bundles']) == 1 && $instance['required'] && !$controller->getSetting('allow_existing')) {
+ $hide_cancel = FALSE;
+ // If the field is required and empty try to open one of the forms.
+ if (empty($form_state['inline_entity_form'][$ief_id]['entities']) && $instance['required']) {
+ if ($controller->getSetting('allow_existing') && !$controller->getSetting('allow_new')) {
+ $form_state['inline_entity_form'][$ief_id]['form'] = 'ief_add_existing';
+ $hide_cancel = TRUE;
+ }
+ elseif (count($settings['create_bundles']) == 1 && $controller->getSetting('allow_new') && !$controller->getSetting('allow_existing')) {
$bundle = reset($settings['create_bundles']);
// The parent entity type and bundle must not be the same as the inline
@@ -673,6 +700,7 @@ function inline_entity_form_field_widget_form(&$form, &$form_state, $field, $ins
$form_state['inline_entity_form'][$ief_id]['form settings'] = array(
'bundle' => $bundle,
);
+ $hide_cancel = TRUE;
}
}
}
@@ -695,6 +723,7 @@ function inline_entity_form_field_widget_form(&$form, &$form_state, $field, $ins
$bundles[$bundle_name] = $bundle_info['label'];
}
}
+ asort($bundles);
$element['actions']['bundle'] = array(
'#type' => 'select',
@@ -757,18 +786,25 @@ function inline_entity_form_field_widget_form(&$form, &$form_state, $field, $ins
if ($form_state['inline_entity_form'][$ief_id]['form'] == 'add') {
$element['form']['#op'] = 'add';
$element['form'] += inline_entity_form_entity_form($controller, $element['form'], $form_state);
-
- // Hide the cancel button if the reference field is required but
- // contains no values. That way the user is forced to create an entity.
- if (!$controller->getSetting('allow_existing') && $instance['required']
- && empty($form_state['inline_entity_form'][$ief_id]['entities'])
- && count($settings['create_bundles']) == 1) {
- $element['form']['actions']['ief_add_cancel']['#access'] = FALSE;
- }
}
elseif ($form_state['inline_entity_form'][$ief_id]['form'] == 'ief_add_existing') {
$element['form'] += inline_entity_form_reference_form($controller, $element['form'], $form_state);
}
+ elseif ($form_state['inline_entity_form'][$ief_id]['form'] == 'clone') {
+ $element['form']['#op'] = 'clone';
+ $element['form'] += inline_entity_form_entity_form($controller, $element['form'], $form_state);
+ }
+
+ // Pre-opened forms can't be closed in order to force the user to
+ // add / reference an entity.
+ if ($hide_cancel) {
+ if (isset($element['form']['actions']['ief_add_cancel'])) {
+ $element['form']['actions']['ief_add_cancel']['#access'] = FALSE;
+ }
+ elseif (isset($element['form']['actions']['ief_reference_cancel'])) {
+ $element['form']['actions']['ief_reference_cancel']['#access'] = FALSE;
+ }
+ }
// No entities have been added. Remove the outer fieldset to reduce
// visual noise caused by having two titles.
@@ -801,16 +837,19 @@ function inline_entity_form_form_alter(&$form, &$form_state, $form_id) {
}
if ($submit_element) {
- $submit = array_merge(array('inline_entity_form_trigger_submit'), $form['#submit']);
+ // Merge the IEF submit handler with the button level submit handlers if
+ // available. Otherwise use the form level submit handlers.
if (!empty($submit_element['#submit'])){
- $submit = array_merge($submit, $submit_element['#submit']);
- // $form['#submit'] and $submit_element['#submit'] might have matching
- // callbacks, resulting in duplicates and double processing.
- $submit_element['#submit'] = array_unique($submit);
+ $submit = array_merge(array('inline_entity_form_trigger_submit'), (array) $submit_element['#submit']);
}
- else{
- $submit_element['#submit'] = $submit;
+ else {
+ $submit = array_merge(array('inline_entity_form_trigger_submit'), (array) $form['#submit']);
}
+
+ // Reduce any duplicates on the off chance the IEF submit handler was
+ // already a part of the array used.
+ $submit_element['#submit'] = array_unique($submit);
+
$submit_element['#ief_submit_all'] = TRUE;
}
}
@@ -856,6 +895,14 @@ function inline_entity_form_entity_form($controller, $entity_form, &$form_state)
$entity_form['#title'] = t('Add new @type_singular', array('@type_singular' => $labels['singular']));
$save_label = t('Create @type_singular', array('@type_singular' => $labels['singular']));
}
+ elseif ($entity_form['#op'] == 'clone') {
+ // Clone the entity.
+ $form_settings = $form_state['inline_entity_form'][$entity_form['#ief_id']]['form settings'];
+ $entity = $form_state['inline_entity_form'][$entity_form['#ief_id']]['entities'][$form_settings['source']]['entity'];
+ $entity_form['#entity'] = $controller->createClone($entity);
+ $entity_form['#title'] = t('Clone @type_singular', array('@type_singular' => $labels['singular']));
+ $save_label = t('Clone @type_singular', array('@type_singular' => $labels['singular']));
+ }
// Retrieve the form provided by the controller.
$entity_form = $controller->entityForm($entity_form, $form_state);
@@ -888,13 +935,13 @@ function inline_entity_form_entity_form($controller, $entity_form, &$form_state)
);
// Add the appropriate submit handlers and their related data.
- if ($entity_form['#op'] == 'add') {
- $entity_form['actions']['ief_add_save']['#submit'] = array(
+ if (in_array($entity_form['#op'], array('add', 'clone'))) {
+ $entity_form['actions']['ief_' . $entity_form['#op'] . '_save']['#submit'] = array(
'inline_entity_form_trigger_submit',
'inline_entity_form_close_child_forms',
'inline_entity_form_close_form',
);
- $entity_form['actions']['ief_add_cancel']['#submit'] = array(
+ $entity_form['actions']['ief_' . $entity_form['#op'] . '_cancel']['#submit'] = array(
'inline_entity_form_close_child_forms',
'inline_entity_form_close_form',
'inline_entity_form_cleanup_form_state',
@@ -976,7 +1023,7 @@ function inline_entity_form_entity_form_submit($entity_form, &$form_state) {
$controller->entityFormSubmit($entity_form, $form_state);
inline_entity_form_cleanup_entity_form_state($entity_form, $form_state);
- if ($entity_form['#op'] == 'add') {
+ if (in_array($entity_form['#op'], array('add', 'clone'))) {
// Determine the correct weight of the new element.
$weight = 0;
if (!empty($form_state['inline_entity_form'][$ief_id]['entities'])) {
@@ -1106,7 +1153,7 @@ function inline_entity_form_reference_form_validate(&$reference_form, &$form_sta
foreach ($form_state['inline_entity_form'][$ief_id]['entities'] as $key => $value) {
if ($value['entity'] == $attach_entity) {
form_set_error($parents_path . '][existing_entity', t('The selected @label has already been added.', array('@label' => $labels['singular'])));
- unset($attach_entity);
+ break;
}
}
}
@@ -1301,10 +1348,14 @@ function inline_entity_form_open_form($form, &$form_state) {
$form_values = drupal_array_get_nested_value($form_state['values'], $parents);
$form_state['inline_entity_form'][$ief_id]['form'] = $form_state['triggering_element']['#ief_form'];
+ $form_state['inline_entity_form'][$ief_id]['form settings'] = array();
+ // Special code for the add form.
if (!empty($form_values['actions']['bundle'])) {
- $form_state['inline_entity_form'][$ief_id]['form settings'] = array(
- 'bundle' => $form_values['actions']['bundle'],
- );
+ $form_state['inline_entity_form'][$ief_id]['form settings']['bundle'] = $form_values['actions']['bundle'];
+ }
+ // Special code for the clone form.
+ if (isset($form_state['triggering_element']['#ief_row_delta'])) {
+ $form_state['inline_entity_form'][$ief_id]['form settings']['source'] = $form_state['triggering_element']['#ief_row_delta'];
}
}
@@ -1496,11 +1547,11 @@ function inline_entity_form_field_attach_submit($parent_entity_type, $parent_ent
uasort($values['entities'], 'drupal_sort_weight');
// Go through the IEF data and assemble a list of ids.
$entity_ids = array();
- $need_reset = false;
+ $need_reset = FALSE;
foreach ($values['entities'] as $item) {
if ($item['needs_save']) {
$controller->save($item['entity'], $context);
- $need_reset = true;
+ $need_reset = TRUE;
}
list($entity_id) = entity_extract_ids($entity_type, $item['entity']);
@@ -1609,15 +1660,9 @@ function theme_inline_entity_form_entity_table($variables) {
$form = $variables['form'];
$entity_type = $form['#entity_type'];
$fields = $form['#table_fields'];
+ $has_tabledrag = inline_entity_form_has_tabledrag($form);
// Sort the fields by weight.
uasort($fields, 'drupal_sort_weight');
- // If one of the rows is in form context, disable tabledrag.
- $has_tabledrag = TRUE;
- foreach (element_children($form) as $key) {
- if (!empty($form[$key]['form'])) {
- $has_tabledrag = FALSE;
- }
- }
$header = array();
if ($has_tabledrag) {
@@ -1696,7 +1741,7 @@ function theme_inline_entity_form_entity_table($variables) {
}
$data = drupal_render($renderable_data);
}
- elseif ($field['type'] == 'callback' && isset($field['render_callback']) && function_exists($field['render_callback'])) {
+ elseif ($field['type'] == 'callback' && isset($field['render_callback']) && is_callable($field['render_callback'])) {
$data = call_user_func($field['render_callback'], $entity_type, $entity);
}
@@ -1732,6 +1777,31 @@ function theme_inline_entity_form_entity_table($variables) {
}
}
+/**
+ * Returns whether tabledrag should be enabled for the given table.
+ *
+ * @param $element
+ * The form element representing the IEF table.
+ *
+ * @return
+ * TRUE if tabledrag should be enabled, FALSE otherwise.
+ */
+function inline_entity_form_has_tabledrag($element) {
+ $children = element_children($element);
+ // If there is only one row, disable tabletrag.
+ if (count($children) == 1) {
+ return FALSE;
+ }
+ // If one of the rows is in form context, disable tabledrag.
+ foreach ($children as $key) {
+ if (!empty($element[$key]['form'])) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
/**
* Implements hook_field_widget_error().
*/
diff --git a/profiles/commerce_kickstart/modules/contrib/inline_entity_form/tests/inline_entity_form_test_base.test b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/tests/inline_entity_form_test_base.test
new file mode 100644
index 00000000..2ea97911
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/tests/inline_entity_form_test_base.test
@@ -0,0 +1,70 @@
+xpath($xpath)) {
+ foreach ($elements[0]->attributes() as $name => $value) {
+ if ($name == 'name') {
+ $retval = $value;
+ break;
+ }
+ }
+ }
+ return $retval;
+ }
+
+ /**
+ * Passes if no node is found for the title.
+ *
+ * @param $title
+ * Node title to check.
+ * @param $message
+ * Message to display.
+ */
+ protected function assertNoNodeByTitle($title, $message = '') {
+ if (!$message) {
+ $message = "No node with title: $title";
+ }
+ $node = $this->getNodeByTitle($title);
+
+ $this->assertTrue(empty($node), $message);
+ }
+
+ /**
+ * Passes if node is found for the title.
+ *
+ * @param $title
+ * Node title to check.
+ * @param $message
+ * Message to display.
+ */
+ protected function assertNodeByTitle($title, $bundle = NULL, $message = '') {
+ if (!$message) {
+ $message = "Node with title found: $title";
+ }
+ $node = $this->getNodeByTitle($title);
+ if ($this->assertTrue(!empty($node), $message)) {
+ if ($bundle) {
+ $this->assertEqual($node->bundle(), $bundle, "Node is correct bundle: $bundle");
+ }
+ }
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/inline_entity_form/tests/modules/inline_entity_form_test/inline_entity_form_test.info b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/tests/modules/inline_entity_form_test/inline_entity_form_test.info
new file mode 100644
index 00000000..b8ec37c5
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/tests/modules/inline_entity_form_test/inline_entity_form_test.info
@@ -0,0 +1,18 @@
+name = Inline entity form test
+description = Contains all content types required for IEF testing
+core = 7.x
+package = Testing
+hidden = TRUE
+
+dependencies[] = entityreference
+dependencies[] = image
+dependencies[] = inline_entity_form
+dependencies[] = number
+dependencies[] = text
+
+; Information added by Drupal.org packaging script on 2016-04-16
+version = "7.x-1.8"
+core = "7.x"
+project = "inline_entity_form"
+datestamp = "1460849408"
+
diff --git a/profiles/commerce_kickstart/modules/contrib/inline_entity_form/tests/modules/inline_entity_form_test/inline_entity_form_test.module b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/tests/modules/inline_entity_form_test/inline_entity_form_test.module
new file mode 100644
index 00000000..8f463486
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/tests/modules/inline_entity_form_test/inline_entity_form_test.module
@@ -0,0 +1,364 @@
+ 'ief_reference_type',
+ 'name' => t('IEF reference type'),
+ 'base' => 'node_content',
+ 'description' => t('Entity reference content type.'),
+ 'custom' => 1,
+ 'modified' => 1,
+ 'locked' => 0,
+ ),
+ array(
+ 'type' => 'ief_simple_single',
+ 'name' => t('IEF simple single'),
+ 'base' => 'node_content',
+ 'description' => t('Content type for IEF simple widget testing.'),
+ 'custom' => 1,
+ 'modified' => 1,
+ 'locked' => 0,
+ ),
+ array(
+ 'type' => 'ief_test_multiple',
+ 'name' => t('IEF test multiple'),
+ 'base' => 'node_content',
+ 'description' => t('Content type for IEF multiple widget testing.'),
+ 'custom' => 1,
+ 'modified' => 1,
+ 'locked' => 0,
+ ),
+ array(
+ 'type' => 'ief_test_custom',
+ 'name' => t('IEF test custom'),
+ 'base' => 'node_content',
+ 'description' => t('Content type for IEF custom form testing.'),
+ 'custom' => 1,
+ 'modified' => 1,
+ 'locked' => 0,
+ ),
+ array(
+ 'type' => 'ief_test_nested1',
+ 'name' => t('IEF test nested1'),
+ 'base' => 'node_content',
+ 'description' => t('Content type for IEF custom form testing.'),
+ 'custom' => 1,
+ 'modified' => 1,
+ 'locked' => 0,
+ ),
+ array(
+ 'type' => 'ief_test_nested2',
+ 'name' => t('IEF test nested2'),
+ 'base' => 'node_content',
+ 'description' => t('Content type for IEF custom form testing.'),
+ 'custom' => 1,
+ 'modified' => 1,
+ 'locked' => 0,
+ ),
+ array(
+ 'type' => 'ief_test_nested3',
+ 'name' => t('IEF test nested3'),
+ 'base' => 'node_content',
+ 'description' => st("Use basic pages for your static content, such as an 'About us' page."),
+ 'custom' => 1,
+ 'modified' => 1,
+ 'locked' => 0,
+ ),
+ );
+
+ foreach ($types as $type) {
+ $type = node_type_set_defaults($type);
+ node_type_save($type);
+ }
+
+ // Create fields.
+ field_info_cache_clear();
+
+ $field = array(
+ 'field_name' => 'field_all_bundles',
+ 'type' => 'entityreference',
+ 'cardinality' => -1,
+ 'settings' => array(
+ 'target_type' => 'node',
+ 'handler' => 'base',
+ 'handler_settings' => array(
+ 'target_bundles' => array(),
+ ),
+ ),
+ );
+ field_create_field($field);
+
+ $field = array(
+ 'field_name' => 'field_first_name',
+ 'type' => 'text',
+ 'cardinality' => 1,
+ 'settings' => array(
+ 'max_length' => 255,
+ ),
+ );
+ field_create_field($field);
+
+ $field = array(
+ 'field_name' => 'field_unrelatedimage',
+ 'type' => 'image',
+ 'cardinality' => 1,
+ 'settings' => array(
+ 'default_image' => 0,
+ 'uri_scheme' => 'public',
+ ),
+ );
+ field_create_field($field);
+
+ $field = array(
+ 'field_name' => 'field_last_name',
+ 'type' => 'text',
+ 'cardinality' => 1,
+ 'settings' => array(
+ 'max_length' => 255,
+ ),
+ );
+ field_create_field($field);
+
+ $field = array(
+ 'field_name' => 'field_multiple_nodes',
+ 'type' => 'entityreference',
+ 'cardinality' => -1,
+ 'required' => TRUE,
+ 'settings' => array(
+ 'target_type' => 'node',
+ 'handler' => 'base',
+ 'handler_settings' => array(
+ 'target_bundles' => array(
+ 'ief_reference_type' => 'ief_reference_type',
+ ),
+ ),
+ ),
+ );
+ field_create_field($field);
+
+ $field_bases['field_positive_int'] = array(
+ 'active' => 1,
+ 'cardinality' => 1,
+ 'deleted' => 0,
+ 'entity_types' => array(),
+ 'field_name' => 'field_positive_int',
+ 'indexes' => array(),
+ 'locked' => 0,
+ 'module' => 'number',
+ 'settings' => array(),
+ 'translatable' => 0,
+ 'type' => 'number_integer',
+ );
+
+ $field = array(
+ 'field_name' => 'field_positive_int',
+ 'type' => 'number_integer',
+ 'cardinality' => 1,
+ 'settings' => array(),
+ );
+ field_create_field($field);
+
+ $field = array(
+ 'field_name' => 'field_single_node',
+ 'type' => 'entityreference',
+ 'cardinality' => 1,
+ 'settings' => array(
+ 'target_type' => 'node',
+ 'handler' => 'base',
+ 'handler_settings' => array(
+ 'target_bundles' => array(
+ 'ief_test_custom' => 'ief_test_custom',
+ ),
+ ),
+ ),
+ );
+ field_create_field($field);
+
+ $field = array(
+ 'field_name' => 'field_test_ref_nested1',
+ 'type' => 'entityreference',
+ 'cardinality' => -1,
+ 'settings' => array(
+ 'target_type' => 'node',
+ 'handler' => 'base',
+ 'handler_settings' => array(
+ 'target_bundles' => array(
+ 'ief_test_nested2' => 'ief_test_nested2',
+ ),
+ ),
+ ),
+ );
+ field_create_field($field);
+
+ $field = array(
+ 'field_name' => 'field_test_ref_nested2',
+ 'type' => 'entityreference',
+ 'cardinality' => -1,
+ 'settings' => array(
+ 'target_type' => 'node',
+ 'handler' => 'base',
+ 'handler_settings' => array(
+ 'target_bundles' => array(
+ 'ief_test_nested3' => 'ief_test_nested3',
+ ),
+ ),
+ ),
+ );
+ field_create_field($field);
+
+
+ // Create field instances.
+ $instance = array(
+ 'bundle' => 'ief_reference_type',
+ 'entity_type' => 'node',
+ 'field_name' => 'field_first_name',
+ 'label' => 'First name',
+ 'required' => TRUE,
+ 'widget' => array('type' => 'text_textfield'),
+ );
+ field_create_instance($instance);
+
+ $instance = array(
+ 'bundle' => 'ief_reference_type',
+ 'entity_type' => 'node',
+ 'field_name' => 'field_last_name',
+ 'label' => 'Last name',
+ 'required' => TRUE,
+ 'widget' => array('type' => 'text_textfield'),
+ );
+ field_create_instance($instance);
+
+ $instance = array(
+ 'bundle' => 'ief_simple_single',
+ 'entity_type' => 'node',
+ 'field_name' => 'field_single_node',
+ 'label' => 'Single node',
+ 'widget' => array('type' => 'inline_entity_form_single'),
+ );
+ field_create_instance($instance);
+
+ $instance = array(
+ 'bundle' => 'ief_test_multiple',
+ 'entity_type' => 'node',
+ 'field_name' => 'field_all_bundles',
+ 'label' => 'All bundles',
+ 'widget' => array(
+ 'type' => 'inline_entity_form',
+ 'settings' => array(
+ 'fields' => array(),
+ 'type_settings' => array(
+ 'allow_clone' => 0,
+ 'allow_existing' => 1,
+ 'allow_new' => 1,
+ 'delete_references' => 0,
+ 'label_plural' => 'nodes',
+ 'label_singular' => 'node',
+ 'match_operator' => 'CONTAINS',
+ 'override_labels' => 0,
+ ),
+ ),
+ ),
+ );
+ field_create_instance($instance);
+
+ $instance = array(
+ 'bundle' => 'ief_test_multiple',
+ 'entity_type' => 'node',
+ 'field_name' => 'field_unrelatedimage',
+ 'label' => 'Image',
+ 'widget' => array('type' => 'image_image'),
+ );
+ field_create_instance($instance);
+
+ $instance = array(
+ 'bundle' => 'ief_test_multiple',
+ 'entity_type' => 'node',
+ 'field_name' => 'field_multiple_nodes',
+ 'label' => 'Multiple nodes',
+ 'required' => TRUE,
+ 'widget' => array(
+ 'type' => 'inline_entity_form',
+ 'settings' => array(
+ 'fields' => array(),
+ 'type_settings' => array(
+ 'allow_clone' => 0,
+ 'allow_existing' => 0,
+ 'allow_new' => 1,
+ 'delete_references' => 0,
+ 'label_plural' => 'nodes',
+ 'label_singular' => 'node',
+ 'match_operator' => 'CONTAINS',
+ 'override_labels' => 0,
+ ),
+ ),
+ ),
+ );
+ field_create_instance($instance);
+
+ $instance = array(
+ 'bundle' => 'ief_test_custom',
+ 'entity_type' => 'node',
+ 'field_name' => 'field_positive_int',
+ 'label' => 'Positive int',
+ 'widget' => array('type' => 'number'),
+ );
+ field_create_instance($instance);
+
+ $instance = array(
+ 'bundle' => 'ief_test_nested1',
+ 'entity_type' => 'node',
+ 'field_name' => 'field_test_ref_nested1',
+ 'label' => 'Multiple nodes',
+ 'required' => TRUE,
+ 'widget' => array(
+ 'type' => 'inline_entity_form',
+ 'settings' => array(
+ 'fields' => array(),
+ 'type_settings' => array(
+ 'allow_existing' => 0,
+ 'allow_new' => 1,
+ 'delete_references' => 0,
+ 'label_plural' => 'nodes 2',
+ 'label_singular' => 'node 2',
+ 'match_operator' => 'CONTAINS',
+ 'override_labels' => 1,
+ ),
+ ),
+ ),
+ );
+ field_create_instance($instance);
+
+ $instance = array(
+ 'bundle' => 'ief_test_nested2',
+ 'entity_type' => 'node',
+ 'field_name' => 'field_test_ref_nested2',
+ 'label' => 'Multiple nodes',
+ 'required' => TRUE,
+ 'widget' => array(
+ 'type' => 'inline_entity_form',
+ 'settings' => array(
+ 'fields' => array(),
+ 'type_settings' => array(
+ 'allow_existing' => 0,
+ 'allow_new' => 1,
+ 'delete_references' => 0,
+ 'label_plural' => 'nodes 3',
+ 'label_singular' => 'node 3',
+ 'match_operator' => 'CONTAINS',
+ 'override_labels' => 1,
+ ),
+ ),
+ ),
+ );
+ field_create_instance($instance);
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/inline_entity_form/tests/multiple_values_widget.test b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/tests/multiple_values_widget.test
new file mode 100644
index 00000000..99d170ee
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/inline_entity_form/tests/multiple_values_widget.test
@@ -0,0 +1,695 @@
+ 'Multiple values widget',
+ 'description' => 'Tests the "Inline Entity Form" multiple values widget.',
+ 'group' => 'Inline entity form',
+ );
+ }
+
+ protected function setUp() {
+ $modules = $modules = array(
+ 'inline_entity_form_test',
+ 'field',
+ 'field_ui',
+ );
+ parent::setUp($modules);
+
+ $this->administrator_user = $this->drupalCreateUser(array(
+ 'create ief_reference_type content',
+ 'edit any ief_reference_type content',
+ 'delete any ief_reference_type content',
+ 'create ief_test_multiple content',
+ 'edit any ief_test_multiple content',
+ 'delete any ief_test_multiple content',
+ 'edit any ief_test_nested1 content',
+ 'edit any ief_test_nested2 content',
+ 'edit any ief_test_nested3 content',
+ 'view own unpublished content',
+ 'administer content types',
+ 'administer nodes',
+ ));
+ $this->drupalLogin($this->administrator_user);
+
+ $this->formContentAddUrl = 'node/add/ief-test-multiple';
+ }
+
+ /**
+ * Tests if form behaves correctly when field is empty.
+ */
+ public function testEmptyFieldIEF() {
+ // Don't allow addition of existing nodes.
+ $this->setAllowExisting(FALSE);
+ $this->drupalGet($this->formContentAddUrl);
+
+ $this->assertFieldByName('field_multiple_nodes[und][form][title]', NULL, 'Title field on inline form exists.');
+ $this->assertFieldByName('field_multiple_nodes[und][form][field_first_name][und][0][value]', NULL, 'First name field on inline form exists.');
+ $this->assertFieldByName('field_multiple_nodes[und][form][field_last_name][und][0][value]', NULL, 'Last name field on inline form exists.');
+ $this->assertFieldByXpath('//input[@type="submit" and @value="Create node"]', NULL, 'Found "Create node" submit button');
+
+ // Allow addition of existing nodes.
+ $this->setAllowExisting(TRUE);
+ $this->drupalGet($this->formContentAddUrl);
+
+ $this->assertNoFieldByName('field_multiple_nodes[und][form][title]]', NULL, 'Title field does not appear.');
+ $this->assertNoFieldByName('field_multiple_nodes[und][form][field_first_name][und][0][value]', NULL, 'First name field does not appear.');
+ $this->assertNoFieldByName('field_multiple_nodes[und][form][field_last_name][und][0][value]', NULL, 'Last name field does not appear.');
+ $this->assertFieldByXpath('//input[@type="submit" and @value="Add new node"]', NULL, 'Found "Add new node" submit button');
+ $this->assertFieldByXpath('//input[@type="submit" and @value="Add existing node"]', NULL, 'Found "Add existing node" submit button');
+
+ // Now submit 'Add new node' button.
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @value="Add new node" and @id="edit-field-multiple-nodes-und-actions-ief-add"]'));
+
+ $this->assertFieldByName('field_multiple_nodes[und][form][title]', NULL, 'Title field on inline form exists.');
+ $this->assertFieldByName('field_multiple_nodes[und][form][field_first_name][und][0][value]', NULL, 'First name field on inline form exists.');
+ $this->assertFieldByName('field_multiple_nodes[und][form][field_last_name][und][0][value]', NULL, 'Second name field on inline form exists.');
+ $this->assertFieldByXpath('//input[@type="submit" and @value="Create node"]', NULL, 'Found "Create node" submit button');
+ $this->assertFieldByXpath('//input[@type="submit" and @value="Cancel"]', NULL, 'Found "Cancel" submit button');
+
+ // Now submit 'Add Existing node' button.
+ $this->drupalGet($this->formContentAddUrl);
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @value="Add existing node" and @id="edit-field-multiple-nodes-und-actions-ief-add-existing"]'));
+
+ $this->assertFieldByName('field_multiple_nodes[und][form][entity_id]', NULL, 'Existing entity reference autocomplete field found.');
+ $this->assertFieldByXpath('//input[@type="submit" and @value="Add node"]', NULL, 'Found "Add node" submit button');
+ $this->assertFieldByXpath('//input[@type="submit" and @value="Cancel"]', NULL, 'Found "Cancel" submit button');
+ }
+
+ /**
+ * Tests creation of entities.
+ */
+ public function testEntityCreation() {
+ // Allow addition of existing nodes.
+ $this->setAllowExisting(TRUE);
+ $this->drupalGet($this->formContentAddUrl);
+
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @value="Add new node" and @id="edit-field-multiple-nodes-und-actions-ief-add"]'));
+ $this->assertResponse(200, 'Opening new inline form was successful.');
+
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @value="Create node" and @id="edit-field-multiple-nodes-und-form-actions-ief-add-save"]'));
+ $this->assertResponse(200, 'Submitting empty form was successful.');
+ $this->assertText('First name field is required.', 'Validation failed for empty "First name" field.');
+ $this->assertText('Last name field is required.', 'Validation failed for empty "Last name" field.');
+ $this->assertText('Title field is required.', 'Validation failed for empty "Title" field.');
+
+ // Create ief_reference_type node in IEF.
+ $this->drupalGet($this->formContentAddUrl);
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @value="Add new node" and @id="edit-field-multiple-nodes-und-actions-ief-add"]'));
+ $this->assertResponse(200, 'Opening new inline form was successful.');
+
+ $edit = array(
+ 'field_multiple_nodes[und][form][title]' => 'Some reference',
+ 'field_multiple_nodes[und][form][field_first_name][und][0][value]' => 'John',
+ 'field_multiple_nodes[und][form][field_last_name][und][0][value]' => 'Doe',
+ );
+ $this->drupalPostAjax(NULL, $edit, $this->getButtonName('//input[@type="submit" and @value="Create node" and @id="edit-field-multiple-nodes-und-form-actions-ief-add-save"]'));
+ $this->assertResponse(200, 'Creating node via inline form was successful.');
+
+ // Tests if correct fields appear in the table.
+ $this->assertTrue((bool) $this->xpath('//td[@class="inline-entity-form-node-title" and contains(.,"Some reference")]'), 'Node title field appears in the table');
+ $this->assertTrue((bool) $this->xpath('//td[@class="inline-entity-form-node-status" and contains(.,"Published")]'), 'Node status field appears in the table');
+
+ // Tests if edit and remove buttons appear.
+ $this->assertTrue((bool) $this->xpath('//input[@type="submit" and @value="Edit"]'), 'Edit button appears in the table.');
+ $this->assertTrue((bool) $this->xpath('//input[@type="submit" and @value="Remove"]'), 'Remove button appears in the table.');
+
+ // Test edit functionality.
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @value="Edit"]'));
+ $edit = array(
+ 'field_multiple_nodes[und][entities][0][form][title]' => 'Some changed reference',
+ );
+ $this->drupalPostAjax(NULL, $edit, $this->getButtonName('//input[@type="submit" and @value="Update node"]'));
+ $this->assertTrue((bool) $this->xpath('//td[@class="inline-entity-form-node-title" and contains(.,"Some changed reference")]'), 'Node title field appears in the table');
+ $this->assertTrue((bool) $this->xpath('//td[@class="inline-entity-form-node-status" and contains(.,"Published")]'), 'Node status field appears in the table');
+
+ // Make sure unrelated AJAX submit doesn't save the referenced entity.
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @value="Upload"]'));
+ $node = $this->drupalGetNodeByTitle('Some changed reference');
+ $this->assertFalse($node, 'Referenced node was not saved during unrelated AJAX submit.');
+
+ // Create ief_test_multiple node.
+ $edit = array('title' => 'Some title');
+ $this->drupalPost(NULL, $edit, t('Save'));
+ $this->assertResponse(200, 'Saving parent entity was successful.');
+
+ // Checks values of created entities.
+ $node = $this->drupalGetNodeByTitle('Some changed reference');
+ $this->assertTrue($node, 'Created ief_reference_type node ' . $node->title);
+ $this->assertTrue($node->field_first_name[LANGUAGE_NONE][0]['value'] == 'John', 'First name in reference node set to John');
+ $this->assertTrue($node->field_last_name[LANGUAGE_NONE][0]['value'] == 'Doe', 'Last name in reference node set to Doe');
+
+ $parent_node = $this->drupalGetNodeByTitle('Some title');
+ $this->assertTrue($parent_node, 'Created ief_test_multiple node ' . $parent_node->title);
+ $this->assertTrue($parent_node->field_multiple_nodes[LANGUAGE_NONE][0]['target_id'] == $node->nid, 'Refererence node id set to ' . $node->nid);
+ }
+
+ /**
+ * Tests the entity creation with different bundles nested in each other.
+ *
+ * ief_test_nested1 -> ief_test_nested2 -> ief_test_nested3
+ */
+ public function testNestedEntityCreationWithDifferentBundlesAjaxSubmit() {
+ $required_possibilities = array(
+ FALSE,
+ TRUE,
+ );
+ foreach ($required_possibilities as $required) {
+ $this->setupNestedMultipleForm($required);
+
+ $nested3_title = 'nested3 title steps ' . ($required ? 'required' : 'not required');
+ $nested2_title = 'nested2 title steps ' . ($required ? 'required' : 'not required');
+ $nested1_title = 'nested1 title steps ' . ($required ? 'required' : 'not required');
+ $edit = array(
+ 'field_test_ref_nested1[und][form][field_test_ref_nested2][und][form][title]' => $nested3_title,
+ );
+ $this->drupalPostAjax(NULL, $edit, $this->getButtonName('//input[@type="submit" and @value="Create node 3"]'));
+ $this->assertText($nested3_title, 'Title of second nested node found.');
+ $this->assertFalse($this->drupalGetNodeByTitle($nested3_title), 'Second nested entity is not saved yet.');
+
+ $edit = array(
+ 'field_test_ref_nested1[und][form][title]' => $nested2_title,
+ );
+ $this->drupalPostAjax(NULL, $edit, $this->getButtonName('//input[@type="submit" and @value="Create node 2"]'));
+ $this->assertText($nested2_title, 'Title of first nested node found.');
+ $this->assertFalse($this->drupalGetNodeByTitle($nested2_title), 'First nested entity is not saved yet.');
+
+ $edit = array(
+ 'title' => $nested1_title,
+ );
+ $this->drupalPost(NULL, $edit, t('Save'));
+ $nested1_node = $this->drupalGetNodeByTitle($nested1_title);
+ $this->assertEqual($nested1_title, $nested1_node->title, "First node's title looks correct.");
+ $this->assertEqual('ief_test_nested1', $nested1_node->type, "First node's type looks correct.");
+ if ($this->assertNotNull($nested1_node->field_test_ref_nested1[LANGUAGE_NONE][0]['target_id'], 'Second node was created.')) {
+ $creatednested2 = node_load($nested1_node->field_test_ref_nested1[LANGUAGE_NONE][0]['target_id']);
+ $this->assertEqual($nested2_title, $creatednested2->title, "Second node's title looks correct.");
+ $this->assertEqual('ief_test_nested2', $creatednested2->type, "Second node's type looks correct.");
+ if ($this->assertNotNull($creatednested2->field_test_ref_nested2[LANGUAGE_NONE][0]['target_id'], 'Third node was created')) {
+ $creatednested3 = node_load($creatednested2->field_test_ref_nested2[LANGUAGE_NONE][0]['target_id']);
+ $this->assertEqual($nested3_title, $creatednested3->title, "Third node's title looks correct.");
+ $this->assertEqual('ief_test_nested3', $creatednested3->type, "Third node's type looks correct.");
+
+ $this->checkNestedEntityEditing($nested1_node, TRUE);
+ }
+ }
+ }
+ }
+
+ /**
+ * Tests the entity creation with different bundles nested in each other.
+ *
+ * ief_test_nested1 -> ief_test_nested2 -> ief_test_nested3
+ */
+ public function testNestedEntityCreationWithDifferentBundlesNoAjaxSubmit() {
+ $required_possibilities = array(
+ FALSE,
+ TRUE,
+ );
+
+ foreach ($required_possibilities as $required) {
+ $this->setupNestedMultipleForm($required);
+
+ $nested3_title = 'nested3 title single ' . ($required ? 'required' : 'not required');
+ $nested2_title = 'nested2 title single ' . ($required ? 'required' : 'not required');
+ $nested1_title = 'nested1 title single ' . ($required ? 'required' : 'not required');
+
+ $edit = array(
+ 'title' => $nested1_title,
+ 'field_test_ref_nested1[und][form][title]' => $nested2_title,
+ 'field_test_ref_nested1[und][form][field_test_ref_nested2][und][form][title]' => $nested3_title,
+ );
+ $this->drupalPost(NULL, $edit, t('Save'));
+ $nested1_node = $this->drupalGetNodeByTitle($nested1_title);
+ $this->assertEqual($nested1_title, $nested1_node->title, "First node's title looks correct.");
+ $this->assertEqual('ief_test_nested1', $nested1_node->type, "First node's type looks correct.");
+ $creatednested2 = node_load($nested1_node->field_test_ref_nested1[LANGUAGE_NONE][0]['target_id']);
+ $this->assertEqual($nested2_title, $creatednested2->title, "Second node's title looks correct.");
+ $this->assertEqual('ief_test_nested2', $creatednested2->type, "Second node's type looks correct.");
+ $creatednested3 = node_load($creatednested2->field_test_ref_nested2[LANGUAGE_NONE][0]['target_id']);
+ $this->assertEqual($nested3_title, $creatednested3->title, "Third node's title looks correct.");
+ $this->assertEqual('ief_test_nested3', $creatednested3->type, "Third node's type looks correct.");
+ $this->checkNestedEntityEditing($nested1_node, FALSE);
+ }
+ }
+
+ /**
+ * Tests if editing and removing entities work.
+ */
+ public function testEntityEditingAndRemoving() {
+ // Allow addition of existing nodes.
+ $this->setAllowExisting(TRUE);
+
+ // Create three ief_reference_type entities.
+ $referenceNodes = $this->createReferenceContent(3);
+ $field_multiple_nodes = array();
+ foreach($referenceNodes as $nid){
+ $field_multiple_nodes[LANGUAGE_NONE][] = array('target_id' => $nid);
+ }
+ $this->drupalCreateNode(array(
+ 'type' => 'ief_test_multiple',
+ 'title' => 'Some title',
+ 'field_multiple_nodes' => $field_multiple_nodes,
+ ));
+ $parent_node = $this->drupalGetNodeByTitle('Some title');
+
+ // Edit the second entity.
+ $this->drupalGet('node/' . $parent_node->nid . '/edit');
+ $cell = $this->xpath('//table[@id="ief-entity-table-edit-field-multiple-nodes-und-entities"]/tbody/tr[@class="ief-row-entity draggable even"]/td[@class="inline-entity-form-node-title"]');
+ $title = (string) $cell[0];
+
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @id="edit-field-multiple-nodes-und-entities-1-actions-ief-entity-edit"]'));
+ $this->assertResponse(200, 'Opening inline edit form was successful.');
+
+ $edit = array(
+ 'field_multiple_nodes[und][entities][1][form][field_first_name][und][0][value]' => 'John',
+ 'field_multiple_nodes[und][entities][1][form][field_last_name][und][0][value]' => 'Doe',
+ );
+ $this->drupalPostAjax(NULL, $edit, $this->getButtonName('//input[@type="submit" and @id="edit-field-multiple-nodes-und-entities-1-form-actions-ief-edit-save"]'));
+ $this->assertResponse(200, 'Saving inline edit form was successful.');
+
+ // Save the ief_test_multiple node.
+ $this->drupalPost(NULL, array(), t('Save'));
+ $this->assertResponse(200, 'Saving parent entity was successful.');
+
+ // Checks values of changed entities.
+ $node = $this->drupalGetNodeByTitle($title, TRUE);
+ $this->assertTrue($node->field_first_name[LANGUAGE_NONE][0]['value'] == 'John', 'First name in reference node changed to John');
+ $this->assertTrue($node->field_last_name[LANGUAGE_NONE][0]['value'] == 'Doe', 'Last name in reference node changed to Doe');
+
+ // Delete the last entity.
+ $this->drupalGet('node/' . $parent_node->nid . '/edit');
+ $cell = $this->xpath('//table[@id="ief-entity-table-edit-field-multiple-nodes-und-entities"]/tbody//tr[3]//td[@class="inline-entity-form-node-title"]');
+ $title = (string) $cell[0];
+
+ $this->drupalPost(NULL, array(), 'Remove');
+ $this->assertResponse(200, 'Opening inline remove confirm form was successful.');
+ $this->assertText('Are you sure you want to remove', 'Remove warning message is displayed.');
+
+ $edit = array('field_multiple_nodes[und][entities][2][form][delete]' => '1');
+ $this->drupalPost(NULL, $edit, 'Remove');
+
+ $this->assertResponse(200, 'Removing inline entity was successful.');
+ $this->assertNoText($title, 'Deleted inline entity is not present on the page.');
+
+ // Save the ief_test_multiple node.
+ $this->drupalPost(NULL, array(), t('Save'));
+ $this->assertResponse(200, 'Saving parent node was successful.');
+
+ $deleted_node = $this->drupalGetNodeByTitle($title);
+ $this->assertTrue(empty($deleted_node), 'The inline entity was deleted from the site.');
+
+ // Checks that entity does nor appear in IEF.
+ $this->drupalGet('node/' . $parent_node->nid . '/edit');
+ $this->assertNoText($title, 'Deleted inline entity is not present on the page after saving parent.');
+
+ // Delete the last entity reference only, don't delete the node. The last
+ // entity now is second referenced entity because we already deleted one
+ // in previous step.
+ $this->drupalGet('node/' . $parent_node->nid . '/edit');
+ $cell = $this->xpath('//table[@id="ief-entity-table-edit-field-multiple-nodes-und-entities"]/tbody//tr[2]//td[@class="inline-entity-form-node-title"]');
+ $title = (string) $cell[0];
+
+ $this->drupalPost(NULL, array(), 'Remove');
+ $this->assertResponse(200, 'Opening inline remove confirm form was successful.');
+
+ $this->drupalPost(NULL, array(), 'Remove');
+ $this->assertResponse(200, 'Removing inline entity was successful.');
+
+ // Save the ief_test_multiple node.
+ $this->drupalPost(NULL, array(), t('Save'));
+ $this->assertResponse(200, 'Saving parent node was successful.');
+
+ // Checks that entity does nor appear in IEF.
+ $this->drupalGet('node/' . $parent_node->nid . '/edit');
+ $this->assertNoText($title, 'Deleted inline entity is not present on the page after saving parent.');
+
+ // Checks that entity is not deleted.
+ $node = $this->drupalGetNodeByTitle($title, TRUE);
+ $this->assertTrue($node, 'Reference node not deleted');
+ }
+
+ /**
+ * Tests if referencing existing entities work.
+ */
+ public function testReferencingExistingEntities() {
+ // Allow addition of existing nodes.
+ $this->setAllowExisting(TRUE);
+
+ // Create three ief_reference_type entities.
+ $referenceNodes = $this->createReferenceContent(3);
+
+ // Create a node for every bundle available.
+ $bundle_nodes = $this->createNodeForEveryBundle();
+
+ // Create ief_test_multiple node with first ief_reference_type node and first
+ // node from bundle nodes.
+ $this->drupalCreateNode(array(
+ 'type' => 'ief_test_multiple',
+ 'title' => 'Some title',
+ 'multi' => array(1),
+ 'all_bundles' => key($bundle_nodes),
+ ));
+ // Remove first node since we already added it.
+ unset($bundle_nodes[key($bundle_nodes)]);
+
+ $parent_node = $this->drupalGetNodeByTitle('Some title', TRUE);
+
+ // Add remaining existing reference nodes.
+ $this->drupalGet('node/' . $parent_node->nid . '/edit');
+ for ($i = 2; $i <= 3; $i++) {
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @value="Add existing node" and @id="edit-field-multiple-nodes-und-actions-ief-add-existing"]'));
+ $this->assertResponse(200, 'Opening reference form was successful.');
+ $title = 'Some reference ' . $i;
+ $edit = array(
+ 'field_multiple_nodes[und][form][entity_id]' => $title . ' (' . $referenceNodes[$title] . ')',
+ );
+ $this->drupalPostAjax(NULL, $edit, $this->getButtonName('//input[@type="submit" and @id="edit-field-multiple-nodes-und-form-actions-ief-reference-save"]'));
+ $this->assertResponse(200, 'Adding new referenced entity was successful.');
+ }
+ // Add all remaining nodes from all bundles.
+ foreach ($bundle_nodes as $id => $title) {
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @value="Add existing node" and @id="edit-field-all-bundles-und-actions-ief-add-existing"]'));
+ $this->assertResponse(200, 'Opening reference form was successful.');
+ $edit = array(
+ 'field_all_bundles[und][form][entity_id]' => $title . ' (' . $id . ')',
+ );
+ $this->drupalPostAjax(NULL, $edit, $this->getButtonName('//input[@type="submit" and @id="edit-field-all-bundles-und-form-actions-ief-reference-save"]'));
+ $this->assertResponse(200, 'Adding new referenced entity was successful.');
+ }
+ // Save the node.
+ $this->drupalPost(NULL, array(), t('Save'));
+ $this->assertResponse(200, 'Saving parent for was successful.');
+
+ // Check if entities are referenced.
+ $this->drupalGet('node/' . $parent_node->nid . '/edit');
+ for ($i = 2; $i <= 3; $i++) {
+ $cell = $this->xpath('//table[@id="ief-entity-table-edit-field-multiple-nodes-und-entities"]/tbody/tr[' . ($i - 1) . ']/td[@class="inline-entity-form-node-title"]');
+ $this->assertTrue($cell[0] == 'Some reference ' . $i, 'Found reference node title "Some reference ' . $i . '" in the IEF table.');
+ }
+ // Check if all remaining nodes from all bundles are referenced.
+ $count = 1;
+ foreach ($bundle_nodes as $id => $title) {
+ $cell = $this->xpath('//table[@id="ief-entity-table-edit-field-all-bundles-und-entities"]/tbody/tr[' . $count . ']/td[@class="inline-entity-form-node-title"]');
+ $this->assertTrue($cell[0] == $title, 'Found reference node title "' . $title . '" in the IEF table.');
+ $count++;
+ }
+ }
+
+ /**
+ * Tests if a referenced content can be edited while the referenced content is
+ * newer than the referencing parent node.
+ */
+ public function testEditedInlineEntityValidation() {
+ $this->setAllowExisting(TRUE);
+
+ // Create referenced content.
+ $referenced_nodes = $this->createReferenceContent(1);
+ $field_multiple_nodes = array();
+ foreach($referenced_nodes as $nid){
+ $field_multiple_nodes[LANGUAGE_NONE][] = array('target_id' => $nid);
+ }
+
+ // Create first referencing node.
+ $this->drupalCreateNode(array(
+ 'type' => 'ief_test_multiple',
+ 'title' => 'First referencing node',
+ 'field_multiple_nodes' => $field_multiple_nodes,
+ ));
+ $first_node = $this->drupalGetNodeByTitle('First referencing node');
+
+ // Create second referencing node.
+ $this->drupalCreateNode(array(
+ 'type' => 'ief_test_multiple',
+ 'title' => 'Second referencing node',
+ 'field_multiple_nodes' => $field_multiple_nodes,
+ ));
+ $second_node = $this->drupalGetNodeByTitle('Second referencing node');
+
+ // Edit referenced content in first node.
+ $this->drupalGet('node/' . $first_node->nid . '/edit');
+
+ // Edit referenced node.
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @value="Edit" and @id="edit-field-multiple-nodes-und-entities-0-actions-ief-entity-edit"]'));
+ $edit = array(
+ 'field_multiple_nodes[und][entities][0][form][title]' => 'Some reference updated',
+ );
+ $this->drupalPostAjax(NULL, $edit, $this->getButtonName('//input[@type="submit" and @value="Update node" and @id="edit-field-multiple-nodes-und-entities-0-form-actions-ief-edit-save"]'));
+
+ // Save the first node after editing the reference.
+ $edit = array('title' => 'First node updated');
+ $this->drupalPost(NULL, $edit, t('Save'));
+
+ // The changed value of the referenced content is now newer than the
+ // changed value of the second node.
+
+ // Edit referenced content in second node.
+ $this->drupalGet('node/' . $second_node->nid . '/edit');
+
+ // Edit referenced node.
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @value="Edit" and @id="edit-field-multiple-nodes-und-entities-0-actions-ief-entity-edit"]'));
+ $edit = array(
+ 'field_multiple_nodes[und][entities][0][form][title]' => 'Some reference updated the second time',
+ );
+ $this->drupalPostAjax(NULL, $edit, $this->getButtonName('//input[@type="submit" and @value="Update node" and @id="edit-field-multiple-nodes-und-entities-0-form-actions-ief-edit-save"]'));
+
+ // Save the second node after editing the reference.
+ $edit = array('title' => 'Second node updated');
+ $this->drupalPost(NULL, $edit, t('Save'));
+
+ // Check if the referenced content could be edited.
+ $this->assertNoText('The content has either been modified by another user, or you have already submitted modifications. As a result, your changes cannot be saved.', 'The referenced content could be edited.');
+ }
+
+ /**
+ * Tests create access on IEF Multiple content type.
+ */
+ public function testMultipleEntityCreate() {
+ $user = $this->drupalCreateUser(array(
+ 'create ief_test_multiple content',
+ ));
+ $this->drupalLogin($user);
+
+ $this->drupalGet('node/add/ief-test-multiple');
+ $this->assertNoFieldByName('field_all_bundles[und][actions][bundle]', NULL, 'Bundle select is not shown when only one bundle is available.');
+ $this->assertNoFieldByName('field_multiple_nodes[und][form][title]', NULL);
+
+ $user = $this->drupalCreateUser(array(
+ 'create ief_test_multiple content',
+ 'create ief_reference_type content'
+ ));
+ $this->drupalLogin($user);
+
+ $this->drupalGet('node/add/ief-test-multiple');
+ $this->assertFieldByName('field_all_bundles[und][actions][bundle]', NULL, 'Bundle select is shown when more than one bundle is available.');
+ $this->assertTrue((bool) $this->xpath('//select[@id="edit-field-all-bundles-und-actions-bundle"]//option[@value="ief_reference_type"]'), 'IEF Reference type is available');
+ $this->assertTrue((bool) $this->xpath('//select[@id="edit-field-all-bundles-und-actions-bundle"]//option[@value="ief_test_multiple"]'), 'IEF test multiple is available');
+ $this->assertFieldByName('field_multiple_nodes[und][form][title]');
+ }
+
+ /**
+ * Tests entity create access is correct on nested IEF forms.
+ */
+ public function testNestedEntityCreateAccess() {
+ $permissions = array(
+ 'create ief_test_nested1 content',
+ 'create ief_test_nested2 content',
+ );
+ $this->setupNestedMultipleForm(TRUE, $permissions);
+ $this->assertFieldByName('title');
+ $this->assertFieldByName('field_test_ref_nested1[und][form][title]');
+ $this->assertNoFieldByName('field_test_ref_nested1[und][form][field_test_ref_nested2][und][form][title]', NULL);
+
+ $this->setupNestedMultipleForm(FALSE, $permissions);
+ $this->assertNoFieldByXPath('//input[@type="submit" and @value="Create node 3"]');
+ }
+
+ /**
+ * Creates ief_reference_type nodes which shall serve as reference nodes.
+ *
+ * @param int $numNodes
+ * The number of nodes to create
+ * @return array
+ * Array of created node ids keyed by labels.
+ */
+ protected function createReferenceContent($numNodes = 3) {
+ $retval = array();
+ for ($i = 1; $i <= $numNodes; $i++) {
+ $this->drupalCreateNode(array(
+ 'type' => 'ief_reference_type',
+ 'title' => 'Some reference ' . $i,
+ 'field_first_name' => 'First Name ' . $i,
+ 'field_last_name' => 'Last Name ' . $i,
+ ));
+ $node = $this->drupalGetNodeByTitle('Some reference ' . $i);
+ $this->assertTrue($node, 'Created ief_reference_type node "' . $node->title . '"');
+ $retval[$node->title] = $node->nid;
+ }
+ return $retval;
+ }
+
+ /**
+ * Sets allow_existing IEF setting.
+ *
+ * @param bool $flag
+ * "allow_existing" flag to be set.
+ */
+ protected function setAllowExisting($flag) {
+ $edit = array(
+ 'instance[widget][settings][type_settings][allow_existing]' => $flag,
+ );
+ $this->drupalPost('admin/structure/types/manage/ief-test-multiple/fields/field_multiple_nodes', $edit, t('Save settings'));
+ $this->drupalGet('admin/structure/types/manage/ief-test-multiple/fields/field_multiple_nodes');
+ }
+
+ /**
+ * Creates a node for every node bundle.
+ *
+ * @return array
+ * Array of node titles keyed by ids.
+ */
+ protected function createNodeForEveryBundle() {
+ $retval = array();
+ $bundles = node_type_get_types();
+ foreach ($bundles as $id => $value) {
+ $this->drupalCreateNode(array('type' => $id, 'title' => $value->name));
+ $node = $this->drupalGetNodeByTitle($value->name);
+ $this->assertTrue($node, 'Created node "' . $node->title . '"');
+ $retval[$node->nid] = $value->name;
+ }
+ return $retval;
+ }
+
+ /**
+ * Set up the ief_test_nested1 node add form.
+ *
+ * Sets the nested fields' required settings.
+ * Gets the form.
+ * Opens the inline entity forms if they are not required.
+ *
+ * @param boolean $required
+ * Whether the fields are required.
+ * @param array $permissions
+ * (optional) Permissions to sign testing user in with. You may pass in an
+ * empty array (default) to use the all the permissions necessary create and
+ * edit nodes on the form.
+ */
+ protected function setupNestedMultipleForm($required, $permissions = array()) {
+ $this->drupalLogin($this->administrator_user);
+ $edit = array(
+ 'instance[required]' => $required,
+ );
+ $this->drupalPost('admin/structure/types/manage/ief-test-nested1/fields/field_test_ref_nested1', $edit, t('Save settings'));
+ $this->drupalPost('admin/structure/types/manage/ief-test-nested2/fields/field_test_ref_nested2', $edit, t('Save settings'));
+
+ if (!$permissions) {
+ $permissions = array(
+ 'create ief_test_nested1 content',
+ 'create ief_test_nested2 content',
+ 'create ief_test_nested3 content',
+ 'edit any ief_test_nested1 content',
+ 'edit any ief_test_nested2 content',
+ 'edit any ief_test_nested3 content',
+ );
+ }
+ $this->user = $this->drupalCreateUser($permissions);
+ $this->drupalLogin($this->user);
+
+ $this->drupalGet('node/add/ief-test-nested1');
+
+ if (!$required) {
+ // Open inline forms if not required.
+ if (in_array('create ief_test_nested2 content', $permissions)) {
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @value="Add new node 2"]'));
+ }
+ if (in_array('create ief_test_nested3 content', $permissions)) {
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @value="Add new node 3"]'));
+ }
+ }
+ }
+
+ /**
+ * Closes the existing node form on the "multi" field.
+ */
+ protected function cancelExistingMultiForm($edit) {
+ $this->drupalPostAjax(NULL, $edit, $this->getButtonName('//div[@id="edit-field-multiple-nodes"]//input[@type="submit" and @value="Cancel"]'));
+ $this->assertNoFieldByName('field_multiple_nodes[und][form][entity_id]', NULL, 'Existing entity reference autocomplete field removed.');
+ }
+
+ /**
+ * Opens the existing node form on the "multi" field.
+ */
+ protected function openMultiExistingForm() {
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @value="Add existing node" and @id="edit-field-multiple-nodes-und-actions-ief-add-existing"]'));
+ $this->assertResponse(200, 'Opening reference form was successful.');
+ $this->assertFieldByName('field_multiple_nodes[und][form][entity_id]', NULL, 'Existing entity reference autocomplete field found.');
+ }
+
+ /**
+ * Checks that nested IEF entity references can be edit and saved.
+ *
+ * @param $node
+ * Top level node of type ief_test_nested1 to check.
+ * @param bool $ajax_submit
+ * Whether IEF form widgets should be submitted via AJax or left open.
+ *
+ */
+ protected function checkNestedEntityEditing($node, $ajax_submit = TRUE) {
+ $this->drupalGet("node/{$node->nid}/edit");
+ $level_1_node = node_load($node->field_test_ref_nested1[LANGUAGE_NONE][0]['target_id']);
+ $level_2_node = node_load($level_1_node->field_test_ref_nested2[LANGUAGE_NONE][0]['target_id']);
+ $level_2_node_update_title = $level_2_node->title . ' - updated';
+ //edit-test-ref-nested1-entities-0-actions-ief-entity-edit
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @id="edit-field-test-ref-nested1-und-entities-0-actions-ief-entity-edit"]'));
+ //edit-test-ref-nested1-form-inline-entity-form-entities-0-form-test-ref-nested2-entities-0-actions-ief-entity-edit
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @id="edit-field-test-ref-nested1-und-entities-0-form-field-test-ref-nested2-und-entities-0-actions-ief-entity-edit"]'));
+ $edit['field_test_ref_nested1[und][entities][0][form][field_test_ref_nested2][und][entities][0][form][title]'] = $level_2_node_update_title;
+ if ($ajax_submit) {
+ // Close IEF Forms with AJAX posts
+ //edit-test-ref-nested1-form-inline-entity-form-entities-0-form-test-ref-nested2-form-inline-entity-form-entities-0-form-actions-ief-edit-save
+ $this->drupalPostAjax(NULL, $edit, $this->getButtonName('//input[@type="submit" and @id="edit-field-test-ref-nested1-und-entities-0-form-field-test-ref-nested2-und-entities-0-form-actions-ief-edit-save"]'));
+ $this->drupalPostAjax(NULL, array(), $this->getButtonName('//input[@type="submit" and @id="edit-field-test-ref-nested1-und-entities-0-form-actions-ief-edit-save"]'));
+ $this->drupalPost(NULL, array(), t('Save'));
+ }
+ else {
+ $this->drupalPost(NULL, $edit, t('Save'));
+ }
+ $level_2_node = node_load($level_2_node->nid, NULL, TRUE);
+ $this->assertEqual($level_2_node_update_title, $level_2_node->title);
+ }
+
+ /**
+ * Checks that an invalid value for an existing node will be display the expected error.
+ *
+ * @param $existing_node_text
+ * The text to enter into the existing node text field.
+ * @param $expected_error
+ * The error message that is expected to be shown.
+ */
+ protected function checkExistingValidationExpectation($existing_node_text, $expected_error) {
+ $edit = array(
+ 'field_multiple_nodes[und][form][entity_id]' => $existing_node_text,
+ );
+ $this->openMultiExistingForm();
+
+ $this->drupalPostAjax(NULL, $edit, $this->getButtonName('//input[@type="submit" and @id="edit-field-multiple-nodes-und-form-actions-ief-reference-save"]'));
+ $this->assertText($expected_error);
+ $this->cancelExistingMultiForm($edit);
+ }
+
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/CHANGELOG.txt b/profiles/commerce_kickstart/modules/contrib/libraries/CHANGELOG.txt
index e3c94119..33fa5e8a 100644
--- a/profiles/commerce_kickstart/modules/contrib/libraries/CHANGELOG.txt
+++ b/profiles/commerce_kickstart/modules/contrib/libraries/CHANGELOG.txt
@@ -1,4 +1,20 @@
+Libraries 7.x-2.3, 2016-05-12
+-----------------------------
+#1884246 by BR0kEN, tstoeckler et al: Allow downloading libraries via Drush.
+by tstoeckler: Allow detecting all libraries by calling libraries_detect().
+by tstoeckler: Prevent LibrariesWebTestBase from being displayed in the UI.
+#819610 by tstoeckler: Add tests for the Libraries UI.
+#1884246 by BR0kEN, tstoeckler: Show the provider in drush libraries-list
+#819610 by Pol, tstoeckler: Show the provider in the UI.
+#2634732 by Rob Holmes, tstoeckler: Sort libraries by title in the UI.
+#2585395 by robinsonsarah01: Allow object methods as version callbacks.
+#819610 by tstoeckler, Pol: Provide a status report for library information.
+#2352251 by netw3rker: Fix incorrect hook name in libraries.api.php.
+#2352237 by netw3rker, tstoeckler: Allow clearing the libraries cache from Drush.
+#2193969 by tstoeckler: Avoid warnings for stale library caches.
+#2287529 by drupalshrek, tstoeckler: Update installation link in README.txt.
+
Libraries 7.x-2.2, 2014-02-09
-----------------------------
#2046919 by tstoeckler: Clarify 'version' docs.
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/LICENSE.txt b/profiles/commerce_kickstart/modules/contrib/libraries/LICENSE.txt
old mode 100755
new mode 100644
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/README.txt b/profiles/commerce_kickstart/modules/contrib/libraries/README.txt
index 70a77256..200bc537 100644
--- a/profiles/commerce_kickstart/modules/contrib/libraries/README.txt
+++ b/profiles/commerce_kickstart/modules/contrib/libraries/README.txt
@@ -16,10 +16,11 @@ Bug reports, feature suggestions and latest developments:
-- INSTALLATION --
-* Install as usual, see http://drupal.org/node/70151 for further information.
- Note that installing external libraries is separate from installing this
- module and should happen in the sites/all/libraries directory. See
- http://drupal.org/node/1440066 for more information.
+* Install as usual, see
+ https://www.drupal.org/documentation/install/modules-themes/modules-7 for
+ further information. Note that installing external libraries is separate from
+ installing this module and should happen in the sites/all/libraries directory.
+ See http://drupal.org/node/1440066 for more information.
-- CONTACT --
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/libraries.admin.inc b/profiles/commerce_kickstart/modules/contrib/libraries/libraries.admin.inc
new file mode 100644
index 00000000..8d9e0fbd
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/libraries/libraries.admin.inc
@@ -0,0 +1,547 @@
+ $library) {
+ $actions = array();
+
+ if ($library['vendor url']) {
+ $actions[] = l('Homepage', $library['vendor url']);
+ }
+ if ($library['download url']) {
+ $actions[] = l('Download', $library['download url']);
+ }
+
+ $rows[] = array(
+ 'data' => array(
+ l($library['name'], 'admin/reports/libraries/' . $machine_name),
+ ($library['installed'] ? t('OK') : drupal_ucfirst($library['error'])),
+ (isset($library['version']) ? $library['version'] : ''),
+ libraries_admin_get_provider_with_type($library),
+ implode(' | ', $actions),
+ ),
+ 'class' => ($library['installed'] ? array('ok') : array('error')),
+ );
+ }
+
+ $form['libraries']['list'] = array(
+ '#theme' => 'table',
+ '#header' => $header,
+ '#rows' => $rows,
+ '#empty' => t('There are currently no libraries installed'),
+ );
+
+ return $form;
+}
+
+/**
+ * Form generation callback for the status overview for a single library.
+ *
+ * This is a form instead of a page to allow easier extending in contributed
+ * modules.
+ *
+ * @param array $form
+ * An associative array containing the structure of the form.
+ * @param array $form_state
+ * A keyed array containing the current state of the form.
+ * @param array $library
+ * A library information array.
+ *
+ * @return array|null
+ * The form array for the status form or NULL if the library was not found.
+ *
+ * @todo Add some var_export($library)-style output
+ */
+function libraries_admin_library_status_form(array $form, array &$form_state, $library) {
+ drupal_set_title(t('Status report for library %library', array('%library' => $library['name'])), PASS_THROUGH);
+
+ if ($library['installed']) {
+ drupal_set_message(t('The %name library is installed correctly.', array('%name' => $library['name'])));
+ $form['status'] = libraries_admin_status_table($library);
+ }
+ else {
+ drupal_set_message($library['error message'], 'error');
+ switch ($library['error']) {
+ case 'not found':
+ $form['instructions'] = libraries_admin_instructions_missing($library);
+ break;
+
+ case 'not detected':
+ $form['instructions'] = libraries_admin_instructions_undetected($library);;
+ break;
+
+ case 'not supported':
+ $form['instructions'] = libraries_admin_instructions_unsupported($library);
+ break;
+
+ case 'missing dependency':
+ $form['instructions']['instruction']['#markup'] = t('There a missing dependency in your configuration that prevent this library to work properly.') . ' ';
+ break;
+
+ case 'incompatible dependency':
+ $form['instructions']['instruction']['#markup'] = t('There an incompatible dependency in your configuration that prevent this library to work properly.') . ' ';
+ break;
+ }
+ }
+
+ return $form;
+}
+
+
+/**
+ * Displays a table of status information about a library.
+ *
+ * @param array $library
+ * A library information array.
+ *
+ * @return array
+ * A renderable array containing a table with status information.
+ */
+function libraries_admin_status_table(array $library) {
+ $header = array(array(
+ // @todo The title implies that other type of information is displayed, as
+ // well, but this is currently not the case.
+ // @todo Use CSS instead of a element.
+ 'data' => '' . t('General information') . '',
+ 'colspan' => 2,
+ 'class' => 'table-heading',
+ 'no_striping' => TRUE,
+ ));
+
+ $rows = array();
+ // @todo Use CSS instead of elements.
+ $rows['name'] = array('' . t('Name') . '', check_plain($library['name']));
+ $rows['machine_name'] = array('' . t('Machine name') . '', check_plain($library['machine name']));
+ if ($library['vendor url']) {
+ $rows['vendor_url'] = array('' . t('Vendor URL') . '', l($library['vendor url'], $library['vendor url']));
+ }
+ if ($library['download url']) {
+ $rows['download_url'] = array('' . t('Download URL') . '', l($library['download url'], $library['download url']));
+ }
+ $rows['provider'] = array('' . t('Provider') . '', libraries_admin_get_provider_with_type($library));
+ $rows['library_path'] = array('' . t('Library path') . '', $library['library path']);
+ $rows['version'] = array('' . t('Version') . '', $library['version']);
+ if (!empty($library['variants'])) {
+ $rows['variants'] = array('' . t('Variants') . '', implode(', ', array_keys($library['variants'])));
+ }
+
+ return array(
+ '#theme' => 'table',
+ '#header' => $header,
+ '#rows' => $rows,
+ );
+}
+
+/**
+ * Returns instructions for dealing with a missing library.
+ *
+ * @param array $library
+ * A library information array.
+ *
+ * @return array
+ * A renderable array containing the instructions.
+ */
+function libraries_admin_instructions_missing(array $library) {
+ $build = array();
+
+ $build['instruction']['#markup'] = t('Follow these steps to install the library:');
+
+ $items = array();
+ // 1. Download the library.
+ // If no supported versions are specified, the latest version is
+ // recommended.
+ if (empty($library['versions'])) {
+ $items[] = t('Download the latest version of the library here.', array(
+ '@download-url' => $library['download url'],
+ ));
+ }
+ // Otherwise, the latest supported version is recommended.
+ else {
+ $versions = array_keys($library['versions']);
+ usort($versions, 'version_compare');
+ $versions = array_reverse($versions);
+ $version = $versions[0];
+ $items[] = t('Download version %version of the library here.', array(
+ '%version' => $version,
+ '@download-url' => $library['download url'],
+ ));
+ }
+ // 2. Unpack it.
+ $items[] = t('If the library is an archive, i.e. if the file ending is for example .tar.gz or .zip, unpack it.');
+ // 3. Create the libraries folder.
+ $items[] = t('In the %library-directory directory of your Drupal installation create a %library directory.', array(
+ '%library-directory' => 'sites/all/libraries',
+ '%library' => $library['machine name'],
+ ));
+ // 4. Upload it.
+ // If the library has variant-independent files, give the user the
+ // location of an example file to check his filesystem against.
+ if ($directory_layout = libraries_admin_directory_layout($library)) {
+ $items[] = t('Upload the whole library (which can consist of multiple directories) into the newly created %library-path directory. The following files and directories should be contained in that directory: !directory-layout', array(
+ '%library-path' => 'sites/all/libraries/' . $library['machine name'],
+ '!directory-layout' => drupal_render($directory_layout),
+ ));
+ }
+ else {
+ $items[] = t('Upload the whole library (which can consist of multiple directories) into the newly created %library-path directory.', array(
+ '%library-path' => 'sites/all/libraries/' . $library['machine name'],
+ ));
+ }
+ // 5. Reload.
+ $items[] = t('Reload the page. If successful, you should see status information about this library.');
+
+ $build['steps'] = array(
+ '#theme' => 'item_list',
+ '#items' => $items,
+ '#type' => 'ol'
+ );
+
+ return $build;
+}
+
+
+/**
+ * Returns instructions for dealing with an undetected library.
+ *
+ * @param array $library
+ * A library information array.
+ *
+ * @return array
+ * A renderable array containing the instructions.
+ */
+function libraries_admin_instructions_undetected($library) {
+ $build = array();
+ // Re-check location.
+ // @todo Avoid usage of elements.
+ $build['instruction']['#markup'] = t('Check that the whole library is located at %library-path.', array(
+ '%library-path' => $library['library path'],
+ )) . ' ';
+ // If the library has variant-independent files, give the user the
+ // exact location of the files to check against.
+ // @todo It should be possible to display even variant-specific files
+ // in case the variant is installed, but libraries_detect() does not
+ // detect variants if the library version cannot be detected.
+ if ($directory_layout = libraries_admin_directory_layout($library)) {
+ $build['directory_layout'] = $directory_layout;
+ $build['directory_layout']['#prefix'] = t('The following files and directories should be contained in that directory:');
+ }
+
+ // If the library is placed correctly the library information is
+ // incorrect.
+ // This switch could be avoided by using $library['info type'], but that would
+ // hinder properly translating these strings.
+ $build['reload']['#markup'] = t('If you have moved any files, reload the page. If successful, you should see status information about this library.') . ' ';
+ $build['notice']['#markup'] = t('If the files are placed correctly and the version can still not be detected, the library information is incorrect.') . ' ';
+
+ $provider = libraries_admin_get_provider($library);
+ switch ($library['info type']) {
+ case 'module':
+ $build['contact']['#markup'] = t('Contact the maintainer of the %module module to correct this.', array(
+ '%module' => $provider,
+ )) . ' ';
+ break;
+
+ case 'theme':
+ $build['contact']['#markup'] = t('Contact the maintainer of the %theme theme to correct this.', array(
+ '%theme' => $provider,
+ )) . ' ';
+ break;
+
+ case 'info file':
+ $build['contact']['#markup'] = t('Contact the maintainer of the %info-file info file to correct this.', array(
+ '%info-file' => $provider,
+ )) . ' ';
+ break;
+ }
+ return $build;
+}
+
+
+/**
+ * Returns instructions for dealing with an unsupported library.
+ *
+ * @param array $library
+ * A library information array.
+ *
+ * @return array
+ * A renderable array containing the instructions.
+ */
+function libraries_admin_instructions_unsupported($library) {
+ $build = array();
+ $items = array();
+
+ // Either download a different version of the library...
+ $versions = array_keys($library['versions']);
+ usort($versions, 'version_compare');
+ $versions = array_reverse($versions);
+ $version = $versions[0];
+ $build['instruction']['#markup'] = t('Please install version %version of the library by following the following steps:',
+ array(
+ '%version' => $version,
+ ));
+ // 1. Delete the old library.
+ $items[] = t('Delete the entire contents of the %library-path directory.',
+ array(
+ '%library-path' => $library['library path'],
+ ));
+ // 2. Download the new library.
+ $items[] = t('Download version %version of the library here.',
+ array(
+ '%version' => $version,
+ '@download-url' => $library['download url'],
+ ));
+ // 3. Unpack it.
+ $items[] = t('If the library is an archive, i.e. if the file ending is for example .tar.gz or .zip, unpack it.');
+ // 4. Upload the new library.
+ // If the library has variant-independent files, give the user the
+ // location of an example file to check his filesystem against.
+ if ($directory_layout = libraries_admin_directory_layout($library)) {
+ $items[] = t('Upload the new files into the %library-path directory. The following files and directories should be contained in that directory: !directory-layout',
+ array(
+ '%library-path' => $library['library path'],
+ '!directory-layout' => drupal_render($directory_layout),
+ ));
+ }
+ else {
+ $items[] = t('Upload the new files into the %library-path directory.',
+ array(
+ '%library-path' => $library['library path'],
+ ));
+ }
+ // 5. Reload.
+ $items[] = t('Reload the page. If successful, you should see status information about this library.');
+ $build['steps'] = array(
+ '#theme' => 'item_list',
+ '#items' => $items,
+ '#type' => 'ol',
+ );
+ // ...or contact the maintainer of the library information.
+ $provider = libraries_admin_get_provider($library);
+ switch ($library['info type']) {
+ case 'module':
+ $build['contact']['#markup'] = t('If you are bound to version @version of the library, ask the maintainer of the %module module to provide support for it.', array(
+ '@version' => $library['version'],
+ '%module' => $provider,
+ )) . ' ';
+ break;
+
+ case 'theme':
+ $build['contact']['#markup'] = t('If you are bound to version @version of the library, ask the maintainer of the %theme theme to provide support for it.', array(
+ '@version' => $library['version'],
+ '%theme' => $provider,
+ )) . ' ';
+ break;
+
+ case 'info file':
+ $build['contact']['#markup'] = t('If you are bound to version @version of the library, ask the maintainer of the %info-file info file to provide support for it.', array(
+ '@version' => $library['version'],
+ '%info-file' => $provider,
+ )) . ' ';
+ break;
+ }
+ return $build;
+}
+
+/**
+ * Returns the directory layout of the library, if possible.
+ *
+ * The result of this function can help users to verify that they have uploaded
+ * the library to the correct location.
+ *
+ * @param array $library
+ * A library information array.
+ *
+ * @return array|false
+ * A renderable array containing the directory layout of the library or FALSE
+ * if a directory layout could not be generated.
+ */
+function libraries_admin_directory_layout(array $library) {
+ $build = array(
+ '#theme' => 'item_list',
+ '#type' => 'ul',
+ '#items' => array(),
+ );
+
+ $items = &$build['#items'];
+ if ($library['path']) {
+ $items = &libraries_admin_path_to_tree($items, $library['path']);
+ }
+ foreach (array('js', 'css', 'php') as $type) {
+ if (!empty($library['files'][$type])) {
+ $files = array_keys($library['files'][$type]);
+ foreach ($files as $file) {
+ // Skip JavaScript settings.
+ if (is_int($file)) {
+ continue;
+ }
+
+ $children = &$items;
+ libraries_admin_path_to_tree($children, $file);
+ }
+ }
+ }
+ return $build['#items'] ? $build : FALSE;
+}
+
+/**
+ * Converts a file path into a tree structure for use in an item list.
+ *
+ * For example, the path 'foo/bar/baz' will be converted into the tree structure
+ * represented by the following list:
+ * - foo
+ * - bar
+ * - baz
+ *
+ * The $items array that is modified by reference or returned (see below) can
+ * be used as the 'items' variable for theme_item_list().
+ *
+ * This function modifies passed-in $items array, so that multiple paths can
+ * be placed into the same tree structure easily.
+ *
+ * @code
+ * $items = array();
+ * foreach ($paths as $path) {
+ * libraries_admin_path_to_tree($items, $path);
+ * }
+ * @endcode
+ *
+ * It also returns the last item by reference, so that it can also be used to
+ * traverse into a sub-structure and add further children there.
+ *
+ * @code
+ * $items = array();
+ * $children = &libraries_admin_path_to_tree($items, $path);
+ * foreach ($sub_paths as $sub_path) {
+ * libraries_admin_path_to_tree($children, $sub_path);
+ * }
+ * @endcode
+ *
+ * @param array $items
+ * @param string $path
+ *
+ * @return array
+ */
+function &libraries_admin_path_to_tree(array &$items, $path) {
+ $part = strtok($path, '/');
+ while ($part) {
+ if (!isset($items[$part])) {
+ $items[$part] = array(
+ 'data' => $part,
+ 'children' => array(),
+ );
+ }
+ $items = &$items[$part]['children'];
+ $part = strtok('/');
+ }
+
+ return $items;
+}
+
+/**
+ * Sorts libraries by name.
+ *
+ * This function can be used as a callback for usort() or uasort().
+ *
+ * @param array $a
+ * The first library information array.
+ * @param array $b
+ * The second library information array.
+ *
+ * @return int
+ * Returns -1 if $a is considered smaller than $b, 1 if $a considered greater
+ * than $b and 0 if $a and $b are considered equal.
+ *
+ * @see strnatcasecmp()
+ * @see usort()
+ * @see uasort()
+ */
+function libraries_admin_sort_title(array $a, array $b) {
+ return strnatcasecmp($a['name'], $b['name']);
+}
+
+/**
+ * Returns the library's provider.
+ *
+ * The provider can be a module, a theme, or an info file.
+ *
+ * @param array $library
+ * A library information array.
+ *
+ * @return string
+ * The provider.
+ */
+function libraries_admin_get_provider($library) {
+ $provider = '';
+
+ switch ($library['info type']) {
+ case 'module':
+ case 'theme':
+ $info = system_get_info($library['info type'], $library[$library['info type']]);
+ $provider = $info['name'];
+ break;
+
+ case 'info file':
+ $provider = basename($library['info file']);
+ break;
+ }
+
+ return $provider;
+}
+
+/**
+ * Returns the library's provider and provider type.
+ *
+ * The provider type is either 'module', 'theme', or 'info file'.
+ *
+ * @param array $library
+ * A library information array.
+ *
+ * @return string
+ * The provider and provider type.
+ */
+function libraries_admin_get_provider_with_type($library) {
+ $provider = libraries_admin_get_provider($library);
+ $provider_with_type = '';
+
+ // This switch could be avoided by using $library['info type'], but that would
+ // hinder properly translating these strings.
+ switch ($library['info type']) {
+ case 'module':
+ $provider_with_type = t('%module module', array('%module' => $provider));
+ break;
+
+ case 'theme':
+ $provider_with_type = t('%theme theme', array('%theme' => $provider));
+ break;
+
+ case 'info file':
+ $provider_with_type = t('%info-file info file', array('%info-file' => $provider));
+ break;
+ }
+
+ return $provider_with_type;
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/libraries.api.php b/profiles/commerce_kickstart/modules/contrib/libraries/libraries.api.php
index 8ac31115..71e90e0c 100644
--- a/profiles/commerce_kickstart/modules/contrib/libraries/libraries.api.php
+++ b/profiles/commerce_kickstart/modules/contrib/libraries/libraries.api.php
@@ -16,6 +16,10 @@
* - name: The official, human-readable name of the library.
* - vendor url: The URL of the homepage of the library.
* - download url: The URL of a web page on which the library can be obtained.
+ * - download file url: (optional) The URL where the latest version of the
+ * library can be downloaded. In case such a static URL exists the library
+ * can be downloaded automatically via Drush. Run
+ * 'drush help libraries-download' in the command-line for more information.
* - path: (optional) A relative path from the directory of the library to the
* actual library. Only required if the extracted download package contains
* the actual library files in a sub-directory.
@@ -211,6 +215,9 @@ function hook_libraries_info() {
'name' => 'Example library',
'vendor url' => 'http://example.com',
'download url' => 'http://example.com/download',
+ // It is important that this URL does not include the actual version to
+ // download. Not all libraries provide such a static URL.
+ 'download file url' => 'http://example.com/latest.tar.gz',
// Optional: If, after extraction, the actual library files are contained in
// 'sites/all/libraries/example/lib', specify the relative path here.
'path' => 'lib',
@@ -343,6 +350,9 @@ function hook_libraries_info() {
'name' => 'Simple library',
'vendor url' => 'http://example.com/simple',
'download url' => 'http://example.com/simple',
+ // The download file URL can also point to a single file (instead of an
+ // archive).
+ 'download file url' => 'http://example.com/latest/simple.js',
'version arguments' => array(
'file' => 'readme.txt',
// Best practice: Document the actual version strings for later reference.
@@ -467,7 +477,7 @@ function hook_libraries_info_alter(&$libraries) {
* @return
* An array of paths.
*/
-function hook_libraries_paths() {
+function hook_libraries_info_file_paths() {
// Taken from the Libraries test module, which needs to specify the path to
// the test library.
return array(drupal_get_path('module', 'libraries_test') . '/example');
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/libraries.drush.inc b/profiles/commerce_kickstart/modules/contrib/libraries/libraries.drush.inc
index 26b35eb8..32587135 100644
--- a/profiles/commerce_kickstart/modules/contrib/libraries/libraries.drush.inc
+++ b/profiles/commerce_kickstart/modules/contrib/libraries/libraries.drush.inc
@@ -1,5 +1,4 @@
'libraries_drush_list',
- 'description' => dt('Lists registered library information.'),
+ 'description' => dt('Show a list of registered libraries.'),
'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
+ 'aliases' => array('lls', 'lib-list'),
);
- /**$items['libraries-download'] = array(
- 'callback' => 'libraries_drush_download',
- 'description' => dt('Downloads a registered library into the libraries directory for the active site.'),
+
+ $items['libraries-download'] = array(
+ 'description' => dt('Download library files of registered libraries.'),
+ 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
+ 'aliases' => array('ldl', 'lib-download'),
'arguments' => array(
- 'name' => dt('The internal name of the registered library.'),
+ 'libraries' => 'A comma delimited list of library machine names.',
),
- );*/
+ 'required-arguments' => TRUE,
+ );
+
return $items;
}
/**
- * Implements hook_drush_help().
+ * Implements hook_drush_cache_clear().
+ *
+ * @see drush_cache_clear_types()
*/
-function libraries_drush_help($section) {
- switch ($section) {
- case 'drush:libraries-list':
- return dt('Lists registered library information.');
-
- case 'drush:libraries-download':
- return dt('Downloads a registered library into the libraries directory for the active site.
+function libraries_drush_cache_clear(array &$types) {
+ $types['libraries'] = 'libraries_drush_invalidate_cache';
+}
-See libraries-list for a list of registered libraries.');
+/**
+ * Clears the library cache.
+ */
+function libraries_drush_invalidate_cache() {
+ // @see drupal_flush_all_caches()
+ foreach (libraries_flush_caches() as $table) {
+ cache_clear_all('*', $table, TRUE);
}
}
/**
- * Lists registered library information.
+ * Command callback. Show a list of registered libraries.
*/
-function libraries_drush_list() {
- $libraries = array();
- foreach (libraries_info() as $name => $info) {
- $libraries[$name] = libraries_detect($name);
- }
+function drush_libraries_list() {
+ $libraries = libraries_detect();
ksort($libraries);
if (empty($libraries)) {
drush_print('There are no registered libraries.');
}
-
else {
+ module_load_include('inc', 'libraries', 'libraries.admin');
+
$rows = array();
// drush_print_table() automatically treats the first row as the header, if
// $header is TRUE.
- $rows[] = array(dt('Name'), dt('Status'), dt('Version'), dt('Variants'), dt('Dependencies'));
+ $rows[] = array(
+ dt('Name'),
+ dt('Status'),
+ dt('Version'),
+ dt('Variants'),
+ dt('Dependencies'),
+ dt('Provider'),
+ );
foreach ($libraries as $name => $library) {
- $status = ($library['installed'] ? dt('OK') : drupal_ucfirst($library['error']));
- $version = (($library['installed'] && !empty($library['version'])) ? $library['version'] : '-');
-
// Only list installed variants.
$variants = array();
foreach ($library['variants'] as $variant_name => $variant) {
@@ -69,83 +80,150 @@ function libraries_drush_list() {
$variants[] = $variant_name;
}
}
- $variants = (empty($variants) ? '-' : implode(', ', $variants));
- $dependencies = (!empty($library['dependencies']) ? implode(', ', $library['dependencies']) : '-');
-
- $rows[] = array($name, $status, $version, $variants, $dependencies);
+ $rows[] = array(
+ $name,
+ $library['installed'] ? dt('OK') : drupal_ucfirst($library['error']),
+ ($library['installed'] && $library['version']) ? '-' : $library['version'],
+ $variants ? implode(', ', $variants) : '-',
+ $library['dependencies'] ? implode(', ', $library['dependencies']) : '-',
+ libraries_admin_get_provider($library),
+ );
}
+
// Make the possible values for the 'Status' column and the 'Version' header
// wrap nicely.
- $widths = array(0, 12, 7, 0, 0);
+ $widths = array(0, 12, 7, 0, 0, 0);
drush_print_table($rows, TRUE, $widths);
}
}
/**
- * Downloads a library.
+ * Command callback. Downloads a library.
+ *
+ * Only libraries that provide a download file URL can be downloaded.
*
- * @param $name
- * The internal name of the library to download.
+ * @see hook_libraries_info()
+ * @see drush_pm_download()
*/
-function libraries_drush_download($name) {
- return;
+function drush_libraries_download() {
+ drush_command_include('pm-download');
+
+ $libraries = libraries_info();
+
+ // @todo Consider supporting downloading all downloadable libraries.
+ // @todo Consider offering a selection if no library is specified.
+ foreach (pm_parse_arguments(func_get_args(), FALSE) as $machine_name) {
+ if (!isset($libraries[$machine_name])) {
+ $message = dt("The !library library is not registered with Libraries API.\n", array('!library' => $machine_name));
+ $message .= dt("Provide an info file for it or implement hook_libraries_info().\n");
+ $message .= dt("See hook_libraries_info() for more information.\n");
+ drush_set_error('DRUSH_LIBRARY_UKNOWN', $message);
+ continue;
+ }
+ $library = $libraries[$machine_name];
+
+ if (empty($library['download file url'])) {
+ $message = dt("The !library library cannot be downloaded.\n", array('!library' => $machine_name));
+ $message .= dt("Libraries need to specify a download file URL to support being downloaded via Drush.\n");
+ $message .= dt("See hook_libraries_info() for more information.\n");
+ drush_set_error('DRUSH_LIBRARY_NOT_DOWNLOADABLE', $message);
+ continue;
+ }
+ $download_url = $library['download file url'];
+
+ drush_log(dt('Downloading library !name ...', array('!name' => $machine_name)));
+
+ // @see package_handler_download_project() in wget.inc
+ // It cannot be used directly because it will always try to extract the
+ // archive which fails when downloading a single file.
+ // @todo Modify upstream to be able to use
+ // package_handler_download_project() directly.
+ // Prepare download path. On Windows file name cannot contain '?'.
+ // See http://drupal.org/node/1782444
+ $filename = str_replace('?', '_', basename($download_url));
+ $download_path = drush_tempdir() . '/' . $filename;
+
+ // Download the tarball.
+ // Never cache the downloaded file. The downloading relies on the fact that
+ // different versions of the library are available under the same URL as new
+ // versions are released.
+ $download_path = drush_download_file($download_url, $download_path, 0);
+ if ($download_path || drush_get_context('DRUSH_SIMULATE')) {
+ drush_log(dt('Downloading !filename was successful.', array('!filename' => $filename)));
+ }
+ else {
+ drush_set_error('DRUSH_PM_DOWNLOAD_FAILED', dt('Unable to download !project to !path from !url.', array('!project' => $machine_name, '!path' => $download_path, '!url' => $download_url)));
+ drush_log(dt('Error downloading !name', array('!name' => $machine_name)), 'error');
+ continue;
+ }
- // @todo Looks wonky?
- if (!drush_shell_exec('type unzip')) {
- return drush_set_error(dt('Missing dependency: unzip. Install it before using this command.'));
- }
+ // @todo Suport MD5 file hashing.
- // @todo Simply use current drush site.
- $args = func_get_args();
- if ($args[0]) {
- $path = $args[0];
- }
- else {
- $path = 'sites/all/libraries';
- }
+ // Extract the tarball in place and return the full path to the untarred directory.
+ $download_base = dirname($download_path);
+ if (drush_file_is_tarball($download_path)) {
+ if (!$tar_file_list = drush_tarball_extract($download_path, $download_base, TRUE)) {
+ // An error has been logged.
+ return FALSE;
+ }
+ $tar_directory = drush_trim_path($tar_file_list[0]);
+ $download_path = $download_base . '/' . $tar_directory;
+ }
+ else {
+ $download_path = $download_base;
+ }
- // Create the path if it does not exist.
- if (!is_dir($path)) {
- drush_op('mkdir', $path);
- drush_log(dt('Directory @path was created', array('@path' => $path)), 'notice');
- }
+ // Determine the install location for the project. User provided
+ // --destination has preference.
+ $destination = drush_get_option('destination');
+ if (!empty($destination)) {
+ if (!file_exists($destination)) {
+ drush_mkdir($destination);
+ }
+ $install_location = realpath($destination);
+ }
+ else {
+ /** @see _pm_download_destination_lookup() */
+ // _pm_download_destination_lookup() pluralizes the passed type by
+ // appending an s.
+ // This relies on the fact that there is no library named 'contrib'.
+ // @todo Request that this be turned into a proper API upstream.
+ $install_location = _pm_download_destination('librarie');
+ }
- // Set the directory to the download location.
- $olddir = getcwd();
- chdir($path);
+ // @todo Consider invoking a hook similar to
+ // hook_drush_pm_download_destination_alter().
- $filename = basename(COLORBOX_DOWNLOAD_URI);
- $dirname = basename(COLORBOX_DOWNLOAD_URI, '.zip');
+ // @todo Consider adding version-control support similar to pm-download.
- // Remove any existing Colorbox plugin directory
- if (is_dir($dirname)) {
- drush_log(dt('A existing Colorbox plugin was overwritten at @path', array('@path' => $path)), 'notice');
- }
- // Remove any existing Colorbox plugin zip archive
- if (is_file($filename)) {
- drush_op('unlink', $filename);
- }
+ $install_location .= '/' . $machine_name;
- // Download the zip archive
- if (!drush_shell_exec('wget '. COLORBOX_DOWNLOAD_URI)) {
- drush_shell_exec('curl -O '. COLORBOX_DOWNLOAD_URI);
- }
+ // Check if install location already exists.
+ if (is_dir($install_location)) {
+ if (drush_confirm(dt('Install location !location already exists. Do you want to overwrite it?', array('!location' => $install_location)))) {
+ drush_delete_dir($install_location, TRUE);
+ }
+ else {
+ drush_log(dt("Skip installation of !project to !dest.", array('!project' => $library['machine name'], '!dest' => $install_location)), 'warning');
+ continue;
+ }
+ }
- if (is_file($filename)) {
- // Decompress the zip archive
- drush_shell_exec('unzip -qq -o '. $filename);
- // Remove the zip archive
- drush_op('unlink', $filename);
- }
+ // Copy the project to the install location.
+ if (drush_op('_drush_recursive_copy', $download_path, $install_location)) {
+ drush_log(dt("Library !project downloaded to !dest.", array('!project' => $machine_name, '!dest' => $install_location)), 'success');
- // Set working directory back to the previous working directory.
- chdir($olddir);
+ // @todo Consider invoking a hook similar to
+ // hook_drush_pm_post_download().
- if (is_dir($path .'/'. $dirname)) {
- drush_log(dt('Colorbox plugin has been downloaded to @path', array('@path' => $path)), 'success');
- }
- else {
- drush_log(dt('Drush was unable to download the Colorbox plugin to @path', array('@path' => $path)), 'error');
+ // @todo Support printing release notes.
+ }
+ else {
+ // We don't `return` here in order to proceed with downloading additional projects.
+ drush_set_error('DRUSH_PM_DOWNLOAD_FAILED', dt("Project !project could not be downloaded to !dest.", array('!project' => $machine_name, '!dest' => $install_location)));
+ }
+
+ // @todo Consider adding notify support.
}
}
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/libraries.info b/profiles/commerce_kickstart/modules/contrib/libraries/libraries.info
index 136d323b..dcd2d486 100644
--- a/profiles/commerce_kickstart/modules/contrib/libraries/libraries.info
+++ b/profiles/commerce_kickstart/modules/contrib/libraries/libraries.info
@@ -3,11 +3,14 @@ description = Allows version-dependent and shared usage of external libraries.
core = 7.x
; We use hook_system_theme_info() which was added in Drupal 7.11
dependencies[] = system (>=7.11)
-files[] = tests/libraries.test
+files[] = tests/LibrariesAdminWebTest.test
+files[] = tests/LibrariesLoadWebTest.test
+files[] = tests/LibrariesUnitTest.test
+files[] = tests/LibrariesWebTestBase.test
-; Information added by Drupal.org packaging script on 2014-02-09
-version = "7.x-2.2"
+; Information added by Drupal.org packaging script on 2016-05-12
+version = "7.x-2.3"
core = "7.x"
project = "libraries"
-datestamp = "1391965716"
+datestamp = "1463077450"
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/libraries.install b/profiles/commerce_kickstart/modules/contrib/libraries/libraries.install
index b210b98c..ebc4087b 100644
--- a/profiles/commerce_kickstart/modules/contrib/libraries/libraries.install
+++ b/profiles/commerce_kickstart/modules/contrib/libraries/libraries.install
@@ -25,3 +25,12 @@ function libraries_update_7200() {
db_create_table('cache_libraries', $specs['cache_libraries']);
}
}
+
+/**
+ * Rebuild the class registry.
+ */
+function libraries_update_7201() {
+ // The tests were split from a single libraries.test file into multiple files
+ // during the 7.x-2.x cycle.
+ registry_rebuild();
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/libraries.module b/profiles/commerce_kickstart/modules/contrib/libraries/libraries.module
index 0448476d..48275250 100644
--- a/profiles/commerce_kickstart/modules/contrib/libraries/libraries.module
+++ b/profiles/commerce_kickstart/modules/contrib/libraries/libraries.module
@@ -33,7 +33,7 @@ function libraries_flush_caches() {
* @param $base_path
* Whether to prefix the resulting path with base_path().
*
- * @return
+ * @return string
* The path to the specified library or FALSE if the library wasn't found.
*
* @ingroup libraries
@@ -67,7 +67,7 @@ function libraries_get_path($name, $base_path = FALSE) {
* in both the site-wide directory and site-specific directory, only the
* site-specific version will be listed.
*
- * @return
+ * @return array
* A list of library directories.
*
* @ingroup libraries
@@ -122,7 +122,7 @@ function libraries_get_libraries() {
* - sites/$sitename/libraries
* - any directories specified via hook_libraries_info_file_paths()
*
- * @return
+ * @return array
* An array of info files, keyed by library name. The values are the paths of
* the files.
*/
@@ -429,17 +429,21 @@ function &libraries_info($name = NULL) {
/**
* Applies default properties to a library definition.
*
- * @library
+ * @param array $library
* An array of library information, passed by reference.
- * @name
+ * @param string $name
* The machine name of the passed-in library.
+ *
+ * @return array
+ * The library information array with defaults populated.
*/
-function libraries_info_defaults(&$library, $name) {
+function libraries_info_defaults(array &$library, $name) {
$library += array(
'machine name' => $name,
'name' => $name,
'vendor url' => '',
'download url' => '',
+ 'download file url' => '',
'path' => '',
'library path' => NULL,
'version callback' => 'libraries_get_version',
@@ -472,12 +476,15 @@ function libraries_info_defaults(&$library, $name) {
/**
* Tries to detect a library and its installed version.
*
- * @param $name
- * The machine name of a library to return registered information for.
+ * @param string $name
+ * (optional) The machine name of a library to detect and return registered
+ * information for. If omitted, information about all registered libraries is
+ * returned.
*
* @return array|false
- * An associative array containing registered information for the library
- * specified by $name, or FALSE if the library $name is not registered.
+ * An associative array containing registered information for all libraries,
+ * the registered information for the library specified by $name, or FALSE if
+ * the library $name is not registered.
* In addition to the keys returned by libraries_info(), the following keys
* are contained:
* - installed: A boolean indicating whether the library is installed. Note
@@ -491,7 +498,15 @@ function libraries_info_defaults(&$library, $name) {
*
* @see libraries_info()
*/
-function libraries_detect($name) {
+function libraries_detect($name = NULL) {
+ if (!isset($name)) {
+ $libraries = &libraries_info();
+ foreach ($libraries as $name => $library) {
+ libraries_detect($name);
+ }
+ return $libraries;
+ }
+
// Re-use the statically cached value of libraries_info() to save memory.
$library = &libraries_info($name);
@@ -531,7 +546,7 @@ function libraries_detect($name) {
$library['version'] = call_user_func_array($library['version callback'], array_merge(array($library), $library['version arguments']));
}
else {
- $library['version'] = $library['version callback']($library, $library['version arguments']);
+ $library['version'] = call_user_func($library['version callback'], $library, $library['version arguments']);
}
if (empty($library['version'])) {
$library['error'] = 'not detected';
@@ -693,6 +708,10 @@ function libraries_load($name, $variant = NULL) {
* The number of loaded files.
*/
function libraries_load_files($library) {
+ // As this key was added after 7.x-2.1 cached library structures might not
+ // have it.
+ $library += array('post-load integration files' => FALSE);
+
// Load integration files.
if (!$library['post-load integration files'] && !empty($library['integration files'])) {
$enabled_themes = array();
@@ -867,3 +886,61 @@ function libraries_get_version($library, $options) {
}
fclose($file);
}
+
+/**
+ * Implements hook_help().
+ */
+function libraries_help($path, $arg) {
+ switch ($path) {
+ case 'admin/reports/libraries':
+ return t('Click on a library for a status report or detailed installation instructions in case the library is not installed correctly.');
+ }
+}
+
+/**
+ * Implements hook_menu().
+ */
+function libraries_menu() {
+ $items = array();
+ $items['admin/reports/libraries'] = array(
+ 'title' => 'Libraries',
+ 'description' => 'An overview of libraries installed on this site.',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('libraries_admin_overview'),
+ 'access arguments' => array('access site reports'),
+ 'file' => 'libraries.admin.inc'
+ );
+ $items['admin/reports/libraries/%libraries_ui'] = array(
+ 'title' => 'Library status report',
+ 'description' => 'Status overview for a single library',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('libraries_admin_library_status_form', 3),
+ 'access arguments' => array('access site reports'),
+ 'file' => 'libraries.admin.inc'
+ );
+ return $items;
+}
+
+/**
+ * Loads library information for display in the user interface.
+ *
+ * This can be used as a menu loader function by specifying a '%libraries_ui'
+ * parameter in a path.
+ *
+ * We do not use libraries_load() (and, thus, a '%libraries' parameter) directly
+ * for displaying library information in the user interface as we do not want
+ * the library files to be loaded.
+ *
+ * @param string $name
+ * The machine name of a library to return registered information for.
+ *
+ * @return array|false
+ * An associative array containing registered information for the library
+ * specified by $name, or FALSE if the library $name is not registered.
+ *
+ * @see libraries_detect()
+ * @see libraries_menu()
+ */
+function libraries_ui_load($name) {
+ return libraries_detect($name);
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/tests/LibrariesAdminWebTest.test b/profiles/commerce_kickstart/modules/contrib/libraries/tests/LibrariesAdminWebTest.test
new file mode 100644
index 00000000..a4d2188b
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/libraries/tests/LibrariesAdminWebTest.test
@@ -0,0 +1,119 @@
+ 'Libraries administration',
+ 'description' => 'Tests the administrative interface for libraries.',
+ 'group' => 'Libraries API',
+ );
+ }
+
+ /**
+ * Tests the libraries report at /admin/reports/libraries.
+ */
+ public function testLibrariesReportOverview() {
+ $this->getWithPermissions(array('access site reports'), 'admin/reports/libraries');
+ $this->assertRaw('Libraries');
+
+ // Make sure that all the libraries are listed.
+ $libraries = libraries_info();
+ $this->assertTrue($libraries);
+ foreach ($libraries as $library) {
+ $this->assertText($library['name']);
+ $this->assertLinkByHref('admin/reports/libraries/' . $library['machine name']);
+ }
+
+ // Make sure that all possible statuses are displayed.
+ $this->assertText('OK');
+ $this->assertText('Not found');
+ $this->assertText('Not detected');
+ $this->assertText('Not supported');
+ $this->assertText('Missing dependency');
+ $this->assertText('Incompatible dependency');
+
+ // Make sure that the providers are displayed.
+ $this->assertRaw('Libraries test module module');
+ $this->assertRaw('Libraries test theme theme');
+ $this->assertRaw('example_info_file.libraries.info info file');
+
+ // Make sure that homepage and download links are displayed.
+ $this->assertLinkByHref('http://example.com');
+ $this->assertLinkByHref('http://example.com/download');
+ }
+
+ /**
+ * Tests the libraries report for an installed library.
+ */
+ public function testLibrariesReportInstalled() {
+ $this->getWithPermissions(array('access site reports'), 'admin/reports/libraries/example_files');
+ $this->assertRaw('Status report for library Example files');
+ $this->assertRaw('The Example files library is installed correctly.');
+ // Check that the information in the status report is displayed.
+ $this->assertText('Example files');
+ $this->assertText('example_files');
+ $this->assertRaw('Libraries test module module');
+ $this->assertText(drupal_get_path('module', 'libraries') . '/tests/libraries/example');
+ $this->assertText('1');
+ }
+
+ /**
+ * Tests the libraries report for a missing library.
+ */
+ public function testLibrariesReportMissing() {
+ $this->getWithPermissions(array('access site reports'), 'admin/reports/libraries/example_missing');
+ $this->assertRaw('Status report for library Example missing');
+ $this->assertRaw('The Example missing library could not be found.');
+ // Check that the download link is being displayed.
+ $this->assertLinkByHref('http://example.com/download');
+ }
+
+
+ /**
+ * Tests the libraries report for a missing library.
+ */
+ public function testLibrariesReportNotDetected() {
+ $this->getWithPermissions(array('access site reports'), 'admin/reports/libraries/example_undetected_version');
+ $this->assertRaw('Status report for library Example undetected version');
+ $this->assertRaw('The version of the Example undetected version library could not be detected.');
+ }
+
+ /**
+ * Tests the libraries report for a missing library.
+ */
+ public function testLibrariesReportNotSupported() {
+ $this->getWithPermissions(array('access site reports'), 'admin/reports/libraries/example_unsupported_version');
+ $this->assertRaw('Status report for library Example unsupported version');
+ $this->assertRaw('The installed version 1 of the Example unsupported version library is not supported.');
+ // Check that the download link is being displayed.
+ $this->assertLinkByHref('http://example.com/download');
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/tests/libraries.test b/profiles/commerce_kickstart/modules/contrib/libraries/tests/LibrariesLoadWebTest.test
similarity index 92%
rename from profiles/commerce_kickstart/modules/contrib/libraries/tests/libraries.test
rename to profiles/commerce_kickstart/modules/contrib/libraries/tests/LibrariesLoadWebTest.test
index 41926318..7c4fe51d 100644
--- a/profiles/commerce_kickstart/modules/contrib/libraries/tests/libraries.test
+++ b/profiles/commerce_kickstart/modules/contrib/libraries/tests/LibrariesLoadWebTest.test
@@ -2,67 +2,29 @@
/**
* @file
- * Tests for Libraries API.
+ * Contains LibrariesLoadWebTest.
+ *
+ * Simpletest automatically discovers test files using PSR-4. We cannot,
+ * however, declare a namespace for this class, as that would require PHP 5.3.
+ * To prepare the PHP 5.3 requirement and the usage of PSR-4 in 7.x-3.x, we
+ * place the test files in the correct directory already, but for now register
+ * them explicitly in libraries.info
*/
/**
- * Tests basic Libraries API functions.
+ * Tests basic detection and loading of libraries.
*/
-class LibrariesUnitTestCase extends DrupalUnitTestCase {
- public static function getInfo() {
- return array(
- 'name' => 'Libraries API unit tests',
- 'description' => 'Tests basic functions provided by Libraries API.',
- 'group' => 'Libraries API',
- );
- }
-
- function setUp() {
- drupal_load('module', 'libraries');
- parent::setUp();
- }
-
- /**
- * Tests libraries_get_path().
- */
- function testLibrariesGetPath() {
- // Note that, even though libraries_get_path() doesn't find the 'example'
- // library, we are able to make it 'installed' by specifying the 'library
- // path' up-front. This is only used for testing purposed and is strongly
- // discouraged as it defeats the purpose of Libraries API in the first
- // place.
- $this->assertEqual(libraries_get_path('example'), FALSE, 'libraries_get_path() returns FALSE for a missing library.');
- }
+class LibrariesLoadWebTest extends LibrariesWebTestBase {
/**
- * Tests libraries_prepare_files().
+ * Provides metadata about this test.
+ *
+ * @return array
+ * An array of test metadata with the following keys:
+ * - name: The name of the test.
+ * - description: The description of the test.
+ * - group: The group of the test.
*/
- function testLibrariesPrepareFiles() {
- $expected = array(
- 'files' => array(
- 'js' => array('example.js' => array()),
- 'css' => array('example.css' => array()),
- 'php' => array('example.php' => array()),
- ),
- );
- $library = array(
- 'files' => array(
- 'js' => array('example.js'),
- 'css' => array('example.css'),
- 'php' => array('example.php'),
- ),
- );
- libraries_prepare_files($library, NULL, NULL);
- $this->assertEqual($expected, $library, 'libraries_prepare_files() works correctly.');
- }
-}
-
-/**
- * Tests basic detection and loading of libraries.
- */
-class LibrariesTestCase extends DrupalWebTestCase {
- protected $profile = 'testing';
-
public static function getInfo() {
return array(
'name' => 'Libraries detection and loading',
@@ -71,15 +33,10 @@ class LibrariesTestCase extends DrupalWebTestCase {
);
}
- function setUp() {
- parent::setUp('libraries', 'libraries_test_module');
- theme_enable(array('libraries_test_theme'));
- }
-
/**
* Tests libraries_detect_dependencies().
*/
- function testLibrariesDetectDependencies() {
+ public function testLibrariesDetectDependencies() {
$library = array(
'name' => 'Example',
'dependencies' => array('example_missing'),
@@ -158,7 +115,7 @@ class LibrariesTestCase extends DrupalWebTestCase {
/**
* Tests libraries_scan_info_files().
*/
- function testLibrariesScanInfoFiles() {
+ public function testLibrariesScanInfoFiles() {
$expected = array('example_info_file' => (object) array(
'uri' => drupal_get_path('module', 'libraries') . '/tests/libraries/example_info_file.libraries.info',
'filename' => 'example_info_file.libraries.info',
@@ -171,7 +128,7 @@ class LibrariesTestCase extends DrupalWebTestCase {
/**
* Tests libraries_info().
*/
- function testLibrariesInfo() {
+ public function testLibrariesInfo() {
// Test that modules can provide and alter library information.
$info = libraries_info();
$this->assertTrue(isset($info['example_module']));
@@ -226,7 +183,7 @@ class LibrariesTestCase extends DrupalWebTestCase {
/**
* Tests libraries_detect().
*/
- function testLibrariesDetect() {
+ public function testLibrariesDetect() {
// Test missing library.
$library = libraries_detect('example_missing');
$this->verbose('
' . var_export($library, TRUE) . '
');
@@ -306,10 +263,24 @@ class LibrariesTestCase extends DrupalWebTestCase {
$this->assertEqual($library['variants']['example_variant']['installed'], TRUE, 'Existing variant found.');
}
+ /**
+ * Tests libraries_detect() without a $name parameter.
+ */
+ public function testLibrariesDetectAll() {
+ // Test that an array with all library information is returned and that the
+ // libraries are properly detected.
+ $libraries = libraries_detect();
+ $this->verbose('
' . var_export($libraries, TRUE) . '
');
+ $this->assertEqual($libraries['example_missing']['error'], 'not found');
+ $this->assertEqual($libraries['example_undetected_version']['error'], 'not detected');
+ $this->assertEqual($libraries['example_unsupported_version']['error'], 'not supported');
+ $this->assertEqual($libraries['example_supported_version']['installed'], TRUE);
+ }
+
/**
* Tests libraries_load().
*/
- function testLibrariesLoad() {
+ public function testLibrariesLoad() {
// Test dependencies.
$library = libraries_load('example_dependency_missing');
$this->verbose('
' . var_export($library, TRUE) . '
');
@@ -334,7 +305,7 @@ class LibrariesTestCase extends DrupalWebTestCase {
/**
* Tests the applying of callbacks.
*/
- function testCallbacks() {
+ public function testCallbacks() {
$expected = array(
'name' => 'Example callback',
'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
@@ -453,7 +424,7 @@ class LibrariesTestCase extends DrupalWebTestCase {
*
* @see _libraries_test_module_load()
*/
- function testLibrariesOutput() {
+ public function testLibrariesOutput() {
// Test loading of a simple library with a top-level files property.
$this->drupalGet('libraries-test-module/files');
$this->assertLibraryFiles('example_1', 'File loading');
@@ -527,7 +498,7 @@ class LibrariesTestCase extends DrupalWebTestCase {
* (optional) The expected file extensions of $name. Defaults to
* array('js', 'css', 'php').
*/
- function assertLibraryFiles($name, $label = '', $extensions = array('js', 'css', 'php')) {
+ public function assertLibraryFiles($name, $label = '', $extensions = array('js', 'css', 'php')) {
$label = ($label !== '' ? "$label: " : '');
// Test that the wrong files are not loaded...
@@ -570,4 +541,3 @@ class LibrariesTestCase extends DrupalWebTestCase {
}
}
-
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/tests/LibrariesUnitTest.test b/profiles/commerce_kickstart/modules/contrib/libraries/tests/LibrariesUnitTest.test
new file mode 100644
index 00000000..cd5d30a2
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/libraries/tests/LibrariesUnitTest.test
@@ -0,0 +1,78 @@
+ 'Libraries API unit tests',
+ 'description' => 'Tests basic functions provided by Libraries API.',
+ 'group' => 'Libraries API',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ drupal_load('module', 'libraries');
+ parent::setUp();
+ }
+
+ /**
+ * Tests libraries_get_path().
+ */
+ public function testLibrariesGetPath() {
+ // Note that, even though libraries_get_path() doesn't find the 'example'
+ // library, we are able to make it 'installed' by specifying the 'library
+ // path' up-front. This is only used for testing purposed and is strongly
+ // discouraged as it defeats the purpose of Libraries API in the first
+ // place.
+ $this->assertEqual(libraries_get_path('example'), FALSE, 'libraries_get_path() returns FALSE for a missing library.');
+ }
+
+ /**
+ * Tests libraries_prepare_files().
+ */
+ public function testLibrariesPrepareFiles() {
+ $expected = array(
+ 'files' => array(
+ 'js' => array('example.js' => array()),
+ 'css' => array('example.css' => array()),
+ 'php' => array('example.php' => array()),
+ ),
+ );
+ $library = array(
+ 'files' => array(
+ 'js' => array('example.js'),
+ 'css' => array('example.css'),
+ 'php' => array('example.php'),
+ ),
+ );
+ libraries_prepare_files($library, NULL, NULL);
+ $this->assertEqual($expected, $library, 'libraries_prepare_files() works correctly.');
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/tests/LibrariesWebTestBase.test b/profiles/commerce_kickstart/modules/contrib/libraries/tests/LibrariesWebTestBase.test
new file mode 100644
index 00000000..094534ce
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/libraries/tests/LibrariesWebTestBase.test
@@ -0,0 +1,64 @@
+drupalGetContent().
+ *
+ * @see \DrupalWebTestCase::drupalGet()
+ * @see \DrupalWebTestCase::drupalCreateUser()
+ */
+ protected function getWithPermissions(array $permissions, $path, array $options = array(), array $headers = array()) {
+ $this->drupalGet($path, $options, $headers);
+ $this->assertResponse(403);
+
+ $this->drupalLogin($this->drupalCreateUser($permissions));
+ $this->drupalGet($path, $options, $headers);
+ $this->assertResponse(200);
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/tests/libraries/example_info_file.libraries.info b/profiles/commerce_kickstart/modules/contrib/libraries/tests/libraries/example_info_file.libraries.info
index 59475b4e..11152731 100644
--- a/profiles/commerce_kickstart/modules/contrib/libraries/tests/libraries/example_info_file.libraries.info
+++ b/profiles/commerce_kickstart/modules/contrib/libraries/tests/libraries/example_info_file.libraries.info
@@ -2,9 +2,9 @@
name = Example info file
-; Information added by Drupal.org packaging script on 2014-02-09
-version = "7.x-2.2"
+; Information added by Drupal.org packaging script on 2016-05-12
+version = "7.x-2.3"
core = "7.x"
project = "libraries"
-datestamp = "1391965716"
+datestamp = "1463077450"
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/tests/modules/libraries_test_module/libraries_test_module.info b/profiles/commerce_kickstart/modules/contrib/libraries/tests/modules/libraries_test_module/libraries_test_module.info
index 450a0a20..7ad319a2 100644
--- a/profiles/commerce_kickstart/modules/contrib/libraries/tests/modules/libraries_test_module/libraries_test_module.info
+++ b/profiles/commerce_kickstart/modules/contrib/libraries/tests/modules/libraries_test_module/libraries_test_module.info
@@ -5,9 +5,9 @@ package = Testing
dependencies[] = libraries
hidden = TRUE
-; Information added by Drupal.org packaging script on 2014-02-09
-version = "7.x-2.2"
+; Information added by Drupal.org packaging script on 2016-05-12
+version = "7.x-2.3"
core = "7.x"
project = "libraries"
-datestamp = "1391965716"
+datestamp = "1463077450"
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/tests/modules/libraries_test_module/libraries_test_module.module b/profiles/commerce_kickstart/modules/contrib/libraries/tests/modules/libraries_test_module/libraries_test_module.module
index 65f412ec..51d07c98 100644
--- a/profiles/commerce_kickstart/modules/contrib/libraries/tests/modules/libraries_test_module/libraries_test_module.module
+++ b/profiles/commerce_kickstart/modules/contrib/libraries/tests/modules/libraries_test_module/libraries_test_module.module
@@ -18,6 +18,9 @@ function libraries_test_module_libraries_info() {
// Test library detection.
$libraries['example_missing'] = array(
'name' => 'Example missing',
+ // Provide a vendor and download URL to test that the UI links to it.
+ 'vendor url' => 'http://example.com',
+ 'download url' => 'http://example.com/download',
'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/missing',
);
$libraries['example_undetected_version'] = array(
@@ -28,6 +31,8 @@ function libraries_test_module_libraries_info() {
);
$libraries['example_unsupported_version'] = array(
'name' => 'Example unsupported version',
+ // Provide a download URL to test that the UI links to it.
+ 'download url' => 'http://example.com/download',
'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
'version callback' => '_libraries_test_module_return_version',
'version arguments' => array('1'),
diff --git a/profiles/commerce_kickstart/modules/contrib/libraries/tests/themes/libraries_test_theme/libraries_test_theme.info b/profiles/commerce_kickstart/modules/contrib/libraries/tests/themes/libraries_test_theme/libraries_test_theme.info
index 7528416b..255d1040 100644
--- a/profiles/commerce_kickstart/modules/contrib/libraries/tests/themes/libraries_test_theme/libraries_test_theme.info
+++ b/profiles/commerce_kickstart/modules/contrib/libraries/tests/themes/libraries_test_theme/libraries_test_theme.info
@@ -3,9 +3,9 @@ description = Tests that themes can provide and alter library information.
core = 7.x
hidden = TRUE
-; Information added by Drupal.org packaging script on 2014-02-09
-version = "7.x-2.2"
+; Information added by Drupal.org packaging script on 2016-05-12
+version = "7.x-2.3"
core = "7.x"
project = "libraries"
-datestamp = "1391965716"
+datestamp = "1463077450"
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/README.txt b/profiles/commerce_kickstart/modules/contrib/lingotek/README.txt
index 451d834c..9abcf6c9 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/README.txt
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/README.txt
@@ -41,4 +41,4 @@ http://www.drupaltranslation.com/drupal_translation_module_installation.
CONFIGURATION
--------------
-There is setup wizard that helps you to get started, go to admin/config/lingotek/setup.
\ No newline at end of file
+There is setup wizard that helps you to get started, go to admin/config/regional/lingotek/setup.
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/fprm/okf_html@drupal_subfilter.fprm b/profiles/commerce_kickstart/modules/contrib/lingotek/fprm/okf_html@drupal_subfilter.fprm
index 29e765f0..4683d4a5 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/fprm/okf_html@drupal_subfilter.fprm
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/fprm/okf_html@drupal_subfilter.fprm
@@ -48,7 +48,7 @@ elements:
ruleTypes: [TEXTUNIT]
idAttributes: [id]
drupalvar:
- ruleTypes: [INLINE, EXCLUDE]
+ ruleTypes: [INLINE]
dt:
ruleTypes: [TEXTUNIT]
idAttributes: [id]
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/includes/lingotek.ajax.inc b/profiles/commerce_kickstart/modules/contrib/lingotek/includes/lingotek.ajax.inc
index 906cb9eb..9fbbe167 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/includes/lingotek.ajax.inc
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/includes/lingotek.ajax.inc
@@ -26,6 +26,7 @@ function lingotek_page_mark_phases_complete($node) {
$targets = LingotekDocument::load($lingotek_document_id)->translationTargets();
$api = LingotekApi::instance();
foreach ($_POST['targets'] as $target) {
+ $target = filter_xss($target);
if ($remote_target = $api->getTranslationTarget($targets[$target]->id)) {
$current_phase_id = lingotek_current_phase($remote_target->phases);
if ($api->markPhaseComplete($current_phase_id)) {
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/js/lingotek.admin.js b/profiles/commerce_kickstart/modules/contrib/lingotek/js/lingotek.admin.js
index aa8f5826..bc8d3bed 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/js/lingotek.admin.js
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/js/lingotek.admin.js
@@ -24,31 +24,6 @@ Drupal.behaviors.lingotekAdminForm = {
}
});
- //when a content type checkbox is clicked
- $('.form-select', context).change( function() {
- isEnabled = $(this).val() != 'DISABLED';
- var totalChecked = $(this).parents('tr').find('.form-checkbox:checked').length;
-
- $(this).parents('tr').find('.form-checkbox').each( function() {
- if(isEnabled && totalChecked === 0) {
- $(this).attr('checked', isEnabled);
- } else if (!isEnabled) {
- $(this).removeAttr('checked');
- }
- })
- });
-
- // default all fields to be checked when profile is not disabled (and no fields are currently checked)
- $('.lingotek-content-settings-table').find('tr').each(function() {
- var val = $(this).find('.form-select').val();
- var count = 0;
- if (val != 'DISABLED') {
- count = $(this).find('.form-checkbox:checked').size();
- if (count == 0) {
- $(this).find('.form-checkbox').attr('checked', true);
- }
- }
- });
//when a field checkbox is clicked
var exemptions = [
"lingotek_prepare_config_blocks",
@@ -65,12 +40,12 @@ Drupal.behaviors.lingotekAdminForm = {
if($(this).attr('checked')) {
row.find('td:first-child .form-checkbox').each( function() {
$(this).attr('checked', true);
- })
+ });
} else {
count = 0;
row.find('.field.form-checkbox').each( function() {
count += $(this).attr('checked') ? 1 : 0;
- })
+ });
if(count == 0) {
row.find('td:first-child .form-checkbox').attr('checked',false);
row.find('.form-select').val('DISABLED');
@@ -84,6 +59,12 @@ Drupal.behaviors.lingotekAdminForm = {
if ($(this).children().first().is(':checked')) {
$('.field.form-checkbox').removeAttr('disabled').attr('checked',true);
}
+ else {
+ $('.field.form-checkbox').attr('checked',false);
+ $('#lingotek_prepare_config_blocks').attr('disabled',true);
+ $('#lingotek_prepare_config_menus').attr('disabled',true);
+ $('#lingotek_prepare_config_taxonomies').attr('disabled',true);
+ }
});
//uncheck dependent-function boxes when primary is not checked
@@ -101,6 +82,13 @@ Drupal.behaviors.lingotekAdminForm = {
$('#lingotek_prepare_config_menus').removeAttr('checked').attr('disabled',true);
}
});
+ $('#edit-config-lingotek-translate-config-taxonomies').change( function () {
+ if ($('#edit-config-lingotek-translate-config-taxonomies').is(':checked')) {
+ $('#lingotek_prepare_config_taxonomies').removeAttr('disabled').attr('checked',true);
+ } else {
+ $('#lingotek_prepare_config_taxonomies').removeAttr('checked').attr('disabled',true);
+ }
+ });
// set prep functions to disabled/enabled on initial page load
$( function () {
@@ -121,10 +109,12 @@ Drupal.behaviors.lingotekAdminForm = {
} else {
$('#lingotek_prepare_config_menus').attr('disabled',true);
}
-
if ($('.form-item-config-lingotek-translate-config-views').parent().siblings().last().children().last().val() != 1) {
$('#edit-config-lingotek-translate-config-views').attr('disabled',true);
}
+ if ($('.form-item-config-lingotek-translate-config-fields').parent().siblings().last().children().last().val() != 1) {
+ $('#edit-config-lingotek-translate-config-fields').attr('disabled',true);
+ }
});
//ensure that there is a vertical tab set
@@ -143,7 +133,7 @@ Drupal.behaviors.lingotekAdminForm = {
$(context).find('select').each(function( index ) {
var $this = $(this);
var name = $this.attr('name');
- if(name && name.substring(0, 7) == 'profile') {
+ if(name && name.substring(0, 7) == 'profile' && name.indexOf('__') < 0) {
if($this.val() != 'DISABLED') {
$list.push($this.val());
}
@@ -161,7 +151,7 @@ Drupal.behaviors.lingotekAdminForm = {
$('.ltk-entity').each(function(index) {
var $entity_utility_options = $(this).find('.js-utility-options');
- var $entity_profile_selects = $(this).find('select');
+ var $entity_profile_selects = $(this).find('select').filter(function() { return !this.id.match(/__/); });
function turn_on() {
$entity_utility_options.find('input[type="checkbox"]').attr('checked', true);
@@ -193,7 +183,7 @@ Drupal.behaviors.lingotekAdminForm = {
// config summary
$('fieldset#ltk-config', context).drupalSetSummary(function (context) {
$list = [];
- max = 7;
+ max = 8;
extra_text = "";
$(context).find('input').each(function( index ) {
@@ -230,13 +220,22 @@ Drupal.behaviors.lingotekAdminForm = {
}
};
+$(document).ready(function(){
+ $('.description').css('width','auto');
+ $('.description').css('border','0px');
+ $('.description').css('background','transparent');
+ $('.description').css('position','static');
+ $('.description').css('display','block');
+ $('.description').css('padding-left','0');
+ $('.form-type-checkbox').find('.description').css('margin-left','1.5em');
+});
+
})(jQuery);
-function lingotek_set_all(sel, val) {
+function lingotek_set_all(sel, target) {
fieldset = jQuery(sel);
- console.log(jQuery(sel));
jQuery(sel).find('.form-select').each( function() {
- jQuery(this).val(val);
+ jQuery(this).val(target.value);
jQuery(this).trigger('change');
});
}
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/js/lingotek.bulk_grid.js b/profiles/commerce_kickstart/modules/contrib/lingotek/js/lingotek.bulk_grid.js
index 670c7c02..fd830de0 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/js/lingotek.bulk_grid.js
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/js/lingotek.bulk_grid.js
@@ -5,8 +5,8 @@
function lingotek_perform_action(nid, action) {
jQuery('#edit-grid-container .form-checkbox').removeAttr('checked');
jQuery('#edit-the-grid-' + nid).attr('checked', 'checked');
- jQuery('#edit-actions-select').val(action);
- jQuery('#edit-actions-select').trigger('change');
+ jQuery('#edit-select-actions').val(action);
+ jQuery('#edit-select-actions').trigger('change');
}
(function ($) {
@@ -14,22 +14,21 @@ function lingotek_perform_action(nid, action) {
var $self = $(self);
url = $self.attr('href');
var entity_ids = [];
- $('#edit-grid-container .form-checkbox').each(function() {
- if($(this).attr('checked')) {
+ $('#edit-grid-container .form-checkbox').each(function () {
+ if ($(this).attr('checked')) {
val = $(this).val();
- if(val != 'on') {
+ if (val != 'on') {
entity_ids.push(val);
}
}
});
- console.log(entity_ids);
- if(entity_ids.length > 0) {
- $('#edit-actions-select').val('select');
+ if (entity_ids.length > 0) {
+ $('#edit-select-actions').val('select');
ob = Drupal.ajax[url];
ob.element_settings.url = ob.options.url = ob.url = url + '/' + entity_ids.join(',');
$self.trigger('click');
$self.attr('href', url);
- $('.modal-header .close').click( function() {
+ $('.modal-header .close').click(function () {
location.reload();
});
} else {
@@ -39,10 +38,10 @@ function lingotek_perform_action(nid, action) {
}
var message_already_shown = false;
-
+//causes all config content in a matching set to be selected together
Drupal.behaviors.lingotekBulkGrid = {
attach: function (context) {
- $('.form-checkbox').change(function() {
+ $('.form-checkbox').change(function () {
var cells_of_selected_row = $(this).parents("tr").children();
var selected_set_name = cells_of_selected_row.children('.set_name').text();
@@ -69,25 +68,456 @@ function lingotek_perform_action(nid, action) {
}
});
- $('input#edit-actions-submit.form-submit').hide();
- $('#edit-actions-select').change(function() {
- val = $(this).val();
+ $('input#edit-submit-actions.form-submit').hide();
+ $('#edit-select-actions').once('lingotek_once_id', function () {
+ $('#edit-select-actions').change(function () {
+ val = $(this).val();
- if(val == 'reset' || val == 'delete') {
- lingotek_trigger_modal($('#'+val+'-link'));
- } else if(val == 'edit') {
- lingotek_trigger_modal($('#edit-settings-link'));
- } else if(val == 'workflow') {
- lingotek_trigger_modal($('#change-workflow-link'));
- } else {
- $('input#edit-actions-submit.form-submit').trigger('click');
- }
+ if (val == 'reset' || val == 'delete') {
+ lingotek_trigger_modal($('#' + val + '-link'));
+ } else if (val == 'edit') {
+ lingotek_trigger_modal($('#edit-settings-link'));
+ } else if (val == 'workflow') {
+ lingotek_trigger_modal($('#change-workflow-link'));
+ } else if (val == 'delete_translations') {
+ lingotek_trigger_modal($('#delete-translations-link'));
+ } else {
+ $('input#edit-submit-actions.form-submit').trigger('click');
+ }
+ });
});
- $('#edit-limit-select').change(function() {
+ $('#edit-limit-select').change(function () {
$('#edit-search-submit.form-submit').trigger('click');
});
+ }
+ };
+
+ function addClickToDownloadReady() {
+ original_download_ready_URL = $('#download-ready').attr('href');
+ $('#download-ready').click(function () {
+ modifyActionButtonURL('#download-ready', original_download_ready_URL);
+ });
+ }
+
+ function addClickToUploadButton() {
+ original_upload_edited_URL = $('#upload-edited').attr('href');
+ $('#upload-edited').click(function () {
+ modifyActionButtonURL('#upload-edited', original_upload_edited_URL);
+ });
+ }
+
+ this.check_box_count = 0;
+ function addClickToCheckboxes() {
+ $('#edit-grid-container .form-checkbox').each(function () {
+ $(this).change(function (event) {
+ clarifyButtonsForCheckboxes(event);
+ });
+ });
+ }
+
+ //changes the href associated with the download/upload buttons after they are clicked
+ //but before the links are actually followed. Also checks to see if the results are
+ //filtered.
+ function modifyActionButtonURL(element_id, original_URL) {
+ var new_URL = original_URL.valueOf();//clones the original
+ var entity_ids = getIDArray();
+ var id_string = entity_ids.join(",");
+ new_URL += entity_ids.length !== 0 ? "/" + entity_ids.join(",") : "";
+ new_URL = entity_ids.length === 0 ? original_URL : new_URL;
+ $(element_id).attr('href', new_URL);
+ }
+
+ //looks at every currently displayed row and pushes the entity_id of each
+ //row with a checked checkbox into the return variable
+ function getIDArray(visible_check) {
+ var entity_ids = [];
+ var visible = visible_check === true;
+ $('#edit-grid-container .form-checkbox').each(function () {
+ var val = $(this).val();
+ if ($(this).attr('checked') || visible) {
+ if (val !== 'on') {//'on' represents the 'select all' checkbox
+ entity_ids.push(val);
+ }
+ }
+ });
+ return entity_ids;
+ }
+
+ function clarifyButtonsForFilter() {
+ $('.notify-checked-action').hide();
+ $('#upload-edited').attr('title', 'Re-upload all edited source content');
+ $('#download-ready').attr('title', 'Download Ready translations');
+ var text = $('#clear-filters').text();
+
+ if (text === undefined || text === "") {
+ $('.notify-filtered-action').hide();
+ }
+ else {
+ $('.notify-filtered-action').show();
+ $('#upload-edited').attr('title', 'Upload filtered results');
+ $('#download-ready').attr('title', 'Download filtered results');
+ }
+ }
+
+ function clarifyButtonsForCheckboxes(event) {
+ var box_checked = $(event.target).attr('checked');
+ //accounts for the select all box
+ if ($(event.target).val() === 'on' && box_checked) {
+ this.check_box_count = $('#edit-grid-container .form-checkbox').length - 2;
+ }
+ else if ($(event.target).val() === 'on' && !box_checked) {
+ this.check_box_count = 0;
+ }
+ else if (box_checked === true) {
+ this.check_box_count++;
+ }
+ else {
+ this.check_box_count--;
+ }
+ if (this.check_box_count > 0) {
+ $('.notify-filtered-action').hide();
+ $('.notify-checked-action').show();
+ $('#upload-edited').attr('title', 'Upload selected results');
+ $('#download-ready').attr('title', 'Download selected results');
+ return false;
+ }
+ else {
+ clarifyButtonsForFilter();
+ }
+ }
+
+ //guarantees that search and actions fields will match in width. Looks nicer,
+ //can't do this simply with css, because the actions dropdown's width may change
+ //based on its content
+ function alignFields() {
+ var common_width = $('#edit-select-actions').width();
+ var padding_top = $('#edit-select-actions').css('padding-top');
+ var padding_bottom = $('#edit-select-actions').css('padding-bottom');
+ var height = $('#edit-select-actions').height();
+ $('#edit-search').width(common_width);
+ $('#edit-search').css('paddingBottom', padding_bottom);
+ $('#edit-search').css('paddingTop', padding_top);
+ $('#edit-search').css('min-height', height);
+ }
+
+ function setupToggleMarked() {
+ $('.ltk-marked-checkbox').bind('click',function(){
+ var $self = $(this);
+ var url = $self.attr('href');
+ var marked = url.substring(url.length - 1, url.length);
+ var elements = $self.attr('id').split("-");
+ var entityType = elements[1];
+ var entityId = elements[2];
+ var newMarkedValue = marked == 1 ? 0 : 1;
+ var title = newMarkedValue == 1 ? 'Unmark content' : 'Mark content';
+ var markedClass0 = 'fa-square-o';
+ var markedClass1 = 'fa-check-square';
+ var newMarkedClass = newMarkedValue ? markedClass1 : markedClass0;
+ var newUrl = url.substring(0, url.length - 1) + newMarkedValue;
+ $.ajax({
+ url: url,
+ method: 'GET',
+ success: function (data) {
+ $self.attr('href',newUrl);
+ $self.attr('title',title);
+ $self.removeClass(markedClass0 + ' ' + markedClass1);
+ $self.addClass(newMarkedClass);
+ }
+ });
+ });
+ }
+
+ //update_empty_cells allows cells with no translations statuses to display them
+ //when they are available
+ function update_empty_cells(data, parent, entity_id) {
+ if(data[entity_id].length !== undefined) {
+ return;
+ }
+ var used_keys = {};
+ var entity_type = document.getElementById('entity-type').getAttribute('value');
+ if (entity_type === 'config') {
+ return;
+ }
+ for(var key in data[entity_id]){
+ if(entity_type !== 'config' && !data[entity_id][key].hasOwnProperty('status')){
+ continue;
+ }
+ var lang_code = key.valueOf();
+ //this keeps the displayed language code consistent with what is retrieved
+ //on page load
+ lang_code = lang_code.toLowerCase();
+ lang_code = lang_code.replace('_','-');
+ var url = window.location.href;
+ url = url.substr(0,url.indexOf('admin'));
+ var href = url + 'lingotek/workbench/' + data.entity_type + '/' + entity_id + '/' + key;
+ var link_text = key.substring(0,2);
+ //accounts for multiple dialects, current format is to shorten the first language
+ //and give the full language for all subsequent dialects of that language
+ if(used_keys.hasOwnProperty(link_text)){
+ link_text = lang_code;
+ }
+ else {
+ used_keys[link_text] = link_text;
+ }
+ //Create the appropriate title
+ var title;
+ var status = entity_type !== 'config' ? data[entity_id][key].status : data[entity_id][key].toUpperCase();
+ switch(status) {
+ case "READY":
+ title = 'Ready to download';
+ break;
+ case "CURRENT":
+ title = 'Current';
+ break;
+ case "READY_INTERIM":
+ title = 'Ready to Download Interim Translations';
+ break;
+ case "INTERIM":
+ title = 'Interim translation downloaded';
+ case "EDITED":
+ title = 'Needs to be Uploaded';
+ break;
+ case "PENDING":
+ title = 'In progress';
+ break;
+ case "ERROR":
+ title = 'Error';
+ break;
+ case "DELETED":
+ continue;
+ }
+ //create the link
+ var status_link = $('');
+ status_link.attr('href', href);
+ status_link.attr('target','_blank');
+ status_link.attr('title',title);
+ status_link.addClass('language-icon target-' + status.toLowerCase());
+ status_link.text(link_text);
+
+ $('.emptyTD', parent).each(function(){
+ var index = $('td',parent).index($(this));
+ var translation_header = $('th').eq(index);
+ if($('a',translation_header).text().toLowerCase() === 'translations'){
+ $(this).append(status_link);
+ }
+ });
+ }
+ //remove the identifying class
+ $('.emptyTD',parent).removeClass();
}
-};
+ function updateRowStatus(data, row, entity_id) {
+ //if the row does not yet have status indicators
+ if($('.emptyTD',row).length > 0){
+ update_empty_cells(data, row, entity_id);
+ return;
+ }
+ //content is disabled and should not be updated
+ if($(row).find('.fa-minus-square').length > 0){
+ return;
+ }
+ if(data[entity_id].hasOwnProperty('last_modified')){
+ var main_table = document.getElementsByClassName('table-select-processed');
+ var table_headers = main_table[0].getElementsByTagName('th');
+ var last_modified_index = null;
+ for(var i = 0; i < table_headers.length; i++){
+ if(table_headers[i].textContent.toLowerCase().indexOf('modified') !== -1) {
+ last_modified_index = i;
+ break;
+ }
+ }
+ if(last_modified_index !== null) {
+ var tds = row[0].getElementsByTagName('td');
+ tds[last_modified_index].textContent = data[entity_id]['last_modified'];
+ }
+ }
+ var entity_type = document.getElementById('entity-type').getAttribute('value');
+ if(data[entity_id].length !== undefined && entity_type === 'config') {
+ $('.language-icon', row).parent().empty().addClass('emptyTD');
+ $('.fa-check-square', row).removeClass().addClass('fa fa-square-o').attr('title', 'Needs to be Uploaded');
+ return;
+ }
+
+ // Find and update the source icon
+ var source_status = data[entity_id]['source_status'];
+ var source_icon = $(row).find('.ltk-source-icon');
+ var entity_profile = data[entity_id]['profile'];
+ switch (source_status) {
+ case "NONE" :
+ source_icon.removeClass().addClass('ltk-source-icon source-none');
+ source_icon.removeAttr('title').attr('title', 'Upload');
+ break;
+ case "EDITED":
+ source_icon.removeClass().addClass('ltk-source-icon source-edited');
+ source_icon.removeAttr('target');
+ source_icon.removeAttr('title').attr('title', 'Re-upload (content has changed since last upload');
+ source_icon.removeAttr('href').attr('href', '#');
+ source_icon.click(function(){
+ lingotek_perform_action(entity_id,'upload');
+ });
+ break;
+ case "CURRENT":
+ source_icon.removeClass().addClass('ltk-source-icon source-current');
+ source_icon.removeAttr('title').attr('title', 'Source Uploaded');
+ break;
+ case "ERROR":
+ source_icon.removeClass().addClass('ltk-source-icon source-error');
+ error_title = data[entity_id]['last_upload_error'];
+ source_icon.removeAttr('title').attr('title', error_title);
+ break;
+ }
+ if (entity_profile === 'DISABLED') {
+ source_icon.removeClass().addClass('ltk-source-icon source-disabled');
+ source_icon.attr('title', 'Disabled, cannot request translation');
+ }
+
+ //iterate through each target icon and update them
+ $(row).find('a.language-icon').each(function () {
+ var icon_href = $(this).attr('href');
+ //retrieve the language code from the href
+ icon_href = icon_href.split("#")[0];
+
+ var language_code = icon_href.substring(icon_href.length - 'xx_XX'.length);//normal locale code
+ if(data[entity_id][language_code] === undefined){
+ var language_code = icon_href.substring(icon_href.length - 'xx'.length);//language code case
+ }
+ var title = $(this).attr('title');
+ var cutoff = title.indexOf('-');
+ title = title.substring(0, cutoff + 1);
+ var target_status = entity_type !== 'config' ? data[entity_id][language_code]
+ : data[entity_id][language_code].toUpperCase();
+ switch (target_status) {
+ case "NONE":
+ var attrs = {
+ class:'ltk-target-none',
+ title:'No Translation',
+ };
+ $(this).replaceWith(function () {
+ var new_element = $("", attrs).append($(this).contents());
+ return new_element;
+ });
+ case "READY":
+ $(this).removeClass().addClass('language-icon target-ready');
+ $(this).attr('title', 'Ready for Download');
+ break;
+ case "CURRENT":
+ $(this).removeClass().addClass('language-icon target-current');
+ $(this).attr('title', 'Current');
+ break;
+ case "READY_INTERIM":
+ $(this).removeClass().addClass('language-icon target-ready_interim');
+ $(this).attr('title', 'Ready for Interim Download');
+ break;
+ case "INTERIM":
+ $(this).removeClass().addClass('language-icon target-interim');
+ $(this).attr('title', 'In-progress (interim translation downloaded)');
+ break;
+ case "EDITED":
+ $(this).removeClass().addClass('language-icon target-edited');
+ $(this).attr('title', 'Source Edited');
+ break;
+ case "PENDING":
+ $(this).removeClass().addClass('language-icon target-pending');
+ $(this).attr('title', 'In-Progress');
+ break;
+ case "UNTRACKED":
+ $(this).removeClass().addClass('language-icon target-untracked')
+ $(this).attr('title', 'Translation exists, but it is not being tracked by Lingotek');
+ break;
+ case "ERROR":
+ $(this).removeClass().addClass('language-icon target-error');
+ $(this).attr('title', 'Error');
+ break;
+ }
+ if (entity_profile === 'DISABLED') {
+ var attrs = {
+ class:'ltk-target-disabled',
+ title:'Disabled, cannot request translation',
+ };
+ $(this).replaceWith(function () {
+ var new_element = $("", attrs).append($(this).contents());
+ return new_element;
+ });
+ }
+ });
+ }
+
+ function updateStatusIndicators(data) {
+ //the checkboxes always have the row's entity id
+ $('#edit-grid-container .form-checkbox').each(function () {
+ var entity_id = $(this).val();
+ if (data.hasOwnProperty(entity_id)) {
+ var parent = $(this).closest('tr');
+ //this creates the random fill in effect, not sure if its a keeper
+ var i = Math.floor((Math.random() * 7) + 1);
+ setTimeout(updateRowStatus,300 * i,data,parent,entity_id);
+ }
+ });
+ }
+
+ function pollTranslationStatus(){
+ // Prevent jumping to top of page when source icons are clicked.
+ $('.ltk-source-icon.source-none').click(function(e) {
+ e.preventDefault();
+ });
+ $('.ltk-source-icon.source-edited').click(function(e){
+ e.preventDefault();
+ });
+ //makes it easy to find empty cells, the only empty ones will be in the status
+ //column if the row hasn't been uploaded yet.
+ $('td:empty').addClass('emptyTD');
+ var ids_to_poll = '';
+ //get all the entity_ids currently displayed
+ $('#edit-grid-container .form-checkbox').each(function () {
+ var entity_id = $(this).val();
+ if(entity_id !== 'on') {
+ ids_to_poll += $(this).val() + ',';
+ }
+ });
+ //start the poller on 30 sec interval (30000)
+ setInterval(function () {
+ $.ajax({
+ url: $('#async-update').attr('href') + '/' + ids_to_poll.substr(0,ids_to_poll.length-1),
+ dataType: 'json',
+ success: function (data) {
+ if (data !== null) {
+ updateStatusIndicators(data);
+ }
+ }
+ });
+ }, 10000);
+ }
+ function pollAutomaticDownloads(){
+ //config section does not have profiles, so automatic downloads should not
+ //happen
+ if($('#entity-type').val() === 'config'){
+ return;
+ }
+ setInterval(function () {
+ $.ajax({
+ url: $('#auto-download').attr('href'),
+ dataType: 'json'
+ });
+ }, 30000);
+ }
+ function configShowMoreOptions(){
+ $('#more-options').toggleClass('more-options-flip');
+ $('#force-down').toggle();
+ }
+ function setupConfigMoreOptions() {
+ $('#force-down').hide();
+ $('#more-options').click(configShowMoreOptions);
+ }
+ $(document).ready(function () {
+ setupConfigMoreOptions();
+ alignFields();
+ setupToggleMarked();
+ pollTranslationStatus();
+// pollAutomaticDownloads();
+ addClickToDownloadReady();
+ addClickToUploadButton();
+ addClickToCheckboxes();
+ clarifyButtonsForFilter();
+ });
})(jQuery);
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/js/lingotek.form.js b/profiles/commerce_kickstart/modules/contrib/lingotek/js/lingotek.form.js
index 0e266584..ecec6c87 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/js/lingotek.form.js
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/js/lingotek.form.js
@@ -9,6 +9,7 @@ lingotek.forms = lingotek.forms || {};
// Page setup for node add/edit forms.
lingotek.forms.init = function() {
+ $("#edit-language").change(updateProfileSelectorDefault);
$("#edit-language").change(updateVerticalTabSummary);
$("#edit-language").change(toggleMenuSelector);
$('#ltk-enable-from-et').bind('click',lingotek.forms.enableLtkFunc);
@@ -17,6 +18,7 @@ lingotek.forms = lingotek.forms || {};
$('#edit-lingotek-profile').change(updateVerticalTabSummary);
$('#edit-lingotek-profile').change(checkForEnablement);
$('#edit-lingotek-allow-source-overwriting').change(updateVerticalTabSummary);
+ updateProfileSelectorDefault();
updateVerticalTabSummary();
checkForEnablement();
toggleMenuSelector();
@@ -49,6 +51,29 @@ lingotek.forms = lingotek.forms || {};
}
}
+ var updateProfileSelectorDefault = function() {
+ // if the node already exists, then it must have a profile already: don't change it!
+ if ($('#lingotek-preserve-profile').val() == "1") {
+ return;
+ }
+ if ($('#lingotek-bundle-profiles').length > 0) {
+ // get the language map for the current bundle
+ var profiles_by_langcode = JSON.parse($('#lingotek-bundle-profiles').val());
+ // set the #edit-lingotek-profile select box
+ var langcode = $("#edit-language").val();
+ if ($('#lingotek-language-specific-profiles').val() == '0') {
+ $('#edit-lingotek-profile').val(profiles_by_langcode['DEFAULT']);
+ }
+ else if (langcode in profiles_by_langcode) {
+ $('#edit-lingotek-profile').val(profiles_by_langcode[langcode]);
+ }
+ else {
+ // The language must not be enabled for Lingotek at all.
+ $('#edit-lingotek-profile').val('DISABLED');
+ }
+ }
+ }
+
var checkForEnablement = function() {
if ($('#edit-lingotek-profile').val() != 'DISABLED') {
$('#edit-lingotek-overwrite-warning').show();
@@ -61,8 +86,6 @@ lingotek.forms = lingotek.forms || {};
var updateVerticalTabSummary = function() {
var isPushedToLingotek = !isNaN(parseInt($('#edit-lingotek-document-id').val()));
var isEntityTranslationNode = $('#ltk-entity-translation-node').val();
- //console.log('pushedToLingotek: '+isPushedToLingotek);
- //console.log('entityTranslationNode: '+isEntityTranslationNode);
var summaryMessages = [];
if(!lingotek.forms.enableLtkFromET && isEntityTranslationNode && !isPushedToLingotek) {
@@ -87,7 +110,6 @@ lingotek.forms = lingotek.forms || {};
var sourceLanguageSet = language != 'und';
var autoUpload = $('#edit-lingotek-create-lingotek-document').is(":checked");
var autoDownload = $('#edit-lingotek-sync-method').is(":checked");
- var custom = $('#edit-lingotek-profile').val() == 'CUSTOM';
// Source language set or not
if (sourceLanguageSet) {
@@ -107,17 +129,7 @@ lingotek.forms = lingotek.forms || {};
$('.form-item-lingotek-profile').hide();
}
- if($('#edit-lingotek-profile').val() != 'CUSTOM') {
- $('#edit-lingotek-content').hide();
- $('#edit-lingotek-advanced').hide();
- }
-
- if(custom) {
- summaryMessages.push( autoUpload ? Drupal.t("auto-upload") : Drupal.t("manual upload"));
- summaryMessages.push( autoDownload ? Drupal.t("auto-download") : Drupal.t("manual download"));
- } else {
- summaryMessages.push($('#edit-lingotek-profile option:selected').text());
- }
+ summaryMessages.push($('#edit-lingotek-profile option:selected').text());
if($('#edit-lingotek-allow-source-overwriting').is(":visible")) {
if($('#edit-lingotek-allow-source-overwriting').is(":checked")) {
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/Lingotek.php b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/Lingotek.php
index a03ad1f3..f979a740 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/Lingotek.php
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/Lingotek.php
@@ -208,7 +208,7 @@ class Lingotek {
);
public static $language_mapping_l2d_exceptions = array(
'ar' => 'ar',
- 'zh_CN' => 'zh',
+ 'zh_CN' => 'zh-hans',
'zh_TW' => 'zh-hant'
);
public static $language_mapping_d2l_exceptions = array(
@@ -229,13 +229,12 @@ class Lingotek {
* FALSE otherwise.
*/
public static function convertDrupal2Lingotek($drupal_language_code, $enabled_check = TRUE) {
-
$lingotek_locale = FALSE;
// standard conversion
if (!$enabled_check) {
- // If the code contains a dash then, keep it specific
- $exceptions = self::$language_mapping_d2l_exceptions;
+ // If the code contains a dash then, keep it specific
+ $exceptions = variable_get('lingotek_mapping_d2l_exceptions', self::$language_mapping_d2l_exceptions);
if (array_key_exists($drupal_language_code, $exceptions)) {
$lingotek_locale = $exceptions[$drupal_language_code];
}
@@ -277,21 +276,25 @@ public static function convertDrupal2Lingotek($drupal_language_code, $enabled_ch
* FALSE otherwise.
*/
public static function convertLingotek2Drupal($lingotek_locale, $enabled_check = TRUE) {
-
$drupal_language_code = strtolower(str_replace("_", "-", $lingotek_locale)); // standard conversion
$drupal_general_code = substr($drupal_language_code, 0, strpos($drupal_language_code, '-'));
+ $languages = language_list();
if (!$enabled_check) {
- $exceptions = self::$language_mapping_l2d_exceptions;
+ $exceptions = variable_get('lingotek_mapping_l2d_exceptions', self::$language_mapping_l2d_exceptions);
if (array_key_exists($lingotek_locale, $exceptions)) {
return $exceptions[$lingotek_locale];
}
+ foreach ($languages as $target) {
+ if ($target->language == $drupal_language_code) {
+ return $target->language;
+ }
+ }
return $drupal_general_code;
}
$ret = FALSE;
// check to see if the lingotek_locale is set in the drupal languages table
- $languages = language_list();
foreach ($languages as $target) {
if (isset($target->lingotek_locale) && strcmp($target->lingotek_locale, $lingotek_locale) == 0) {
return $target->language;
@@ -310,7 +313,6 @@ public static function convertLingotek2Drupal($lingotek_locale, $enabled_check =
$ret = $drupal_language_code;
}
}
- //echo "\n\n convertLingotek2Drupal: ".$lingotek_locale." => ".$ret." \n\n";
return $ret;
}
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekAccount.php b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekAccount.php
index 290bf1e5..5860890f 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekAccount.php
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekAccount.php
@@ -85,7 +85,10 @@ public function getPlan() {
}
public function setPlanType($type = 'unknown') {
- variable_set('lingotek_account_plan_type', $type);
+ // Set plan type variable only if it's needed.
+ if ($type != variable_get('lingotek_account_plan_type', 'standard')) {
+ variable_set('lingotek_account_plan_type', $type);
+ }
$standard_types = array('cosmopolitan_monthly', 'cosmopolitan_yearly'); // if in this list, then set to 'standard'
$type = in_array($type, $standard_types) ? 'standard' : $type;
$this->planType = $type;
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekApi.php b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekApi.php
index 8a691a7e..afa500c3 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekApi.php
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekApi.php
@@ -64,6 +64,8 @@ public static function instance() {
*
* @param object $translatable_object
* A Drupal node object or lingotek ConfigChunk object
+ * @param mixed $with_targets
+ * An optional array of locales to include for translation, or TRUE for all enabled languages.
*/
public function addContentDocument(LingotekTranslatableEntity $translatable_object, $with_targets = FALSE) {
$success = FALSE;
@@ -86,17 +88,48 @@ public function addContentDocument(LingotekTranslatableEntity $translatable_obje
);
$parameters['documentName'] = $translatable_object->getDocumentName();
$parameters['documentDesc'] = $translatable_object->getDescription();
- $parameters['content'] = $translatable_object->documentLingotekXML();
+ $parameters['content'] = $this->check_url_alias_translation($translatable_object, $translatable_object->documentLingotekXML());
$parameters['url'] = $translatable_object->getUrl();
$parameters['workflowId'] = $translatable_object->getWorkflowId();
$this->addAdvancedParameters($parameters, $translatable_object);
+ $has_language_specific_targets = FALSE;
- if ($with_targets) {
- $parameters['targetAsJSON'] = Lingotek::getLanguagesWithoutSourceAsJSON($source_language);
+ // If the document has invalid characters, return without uploading
+ $invalid_xml = lingotek_keystore($translatable_object->getEntityType(), $translatable_object->getId(), 'invalid_xml');
+ if ($invalid_xml == LingotekSync::INVALID_XML_PRESENT) {
+ drupal_set_message(t('Unable to upload to Lingotek because entity contains invalid XML characters.'), 'warning');
+ return FALSE;
+ }
- $parameters['applyWorkflow'] = 'true'; // API expects a 'true' string
- $result = $this->request('addContentDocumentWithTargetsAsync', $parameters);
+ if ($with_targets) {
+ if (is_array($with_targets)) {
+ // Assumes language-specific profiles are enabled, so handle adding
+ // target locales with *custom workflows* separately, and include
+ // all the other target locales here.
+ $default_targets = array();
+ foreach ($with_targets as $l => $v) {
+ if (empty($v['workflow_id'])) {
+ $default_targets[] = $l;
+ }
+ else {
+ $has_language_specific_targets = TRUE;
+ }
+ }
+ if (!empty($default_targets)) {
+ $parameters['targetAsJSON'] = json_encode($default_targets);
+ $parameters['applyWorkflow'] = 'true'; // API expects a 'true' string
+ $result = $this->request('addContentDocumentWithTargetsAsync', $parameters);
+ }
+ else {
+ $result = $this->request('addContentDocumentAsync', $parameters);
+ }
+ }
+ else {
+ $parameters['targetAsJSON'] = Lingotek::getLanguagesWithoutSourceAsJSON($source_language);
+ $parameters['applyWorkflow'] = 'true'; // API expects a 'true' string
+ $result = $this->request('addContentDocumentWithTargetsAsync', $parameters);
+ }
}
else {
$result = $this->request('addContentDocumentAsync', $parameters);
@@ -105,7 +138,7 @@ public function addContentDocument(LingotekTranslatableEntity $translatable_obje
if ($result) {
if (isset($result->errors) && $result->errors) {
LingotekLog::error(t('Request to send document to Lingotek failed: ') . print_r($result->errors, TRUE), array());
- $translatable_object->setStatus(LingotekSync::STATUS_FAILED);
+ $translatable_object->setStatus(LingotekSync::STATUS_ERROR);
$translatable_object->setLastError(is_array($result->errors) ? array_shift($result->errors) : $result->errors);
return FALSE;
}
@@ -113,7 +146,7 @@ public function addContentDocument(LingotekTranslatableEntity $translatable_obje
$translatable_object->setDocumentId($result->id);
$translatable_object->setProjectId($project_id);
$translatable_object->setStatus(LingotekSync::STATUS_CURRENT);
- $translatable_object->setTargetsStatus(LingotekSync::STATUS_PENDING);
+ $translatable_object->setTargetsStatus(LingotekSync::STATUS_PENDING, $with_targets);
// WTD: there is a race condition here where a user could modify a locales-
// source entry between the time the dirty segments are pulled and the time
@@ -122,18 +155,81 @@ public function addContentDocument(LingotekTranslatableEntity $translatable_obje
LingotekConfigSet::setSegmentStatusToCurrentById($translatable_object->getId());
}
else {
- // node assumed (based on two functions below...
+ // Add targets with custom workflows after the fact, if language-specific profiles are detected
+ if ($has_language_specific_targets) {
+ $this->upload_language_specific_targets($result->id, $with_targets);
+ }
$entity_type = $translatable_object->getEntityType();
lingotek_keystore($entity_type, $translatable_object->getId(), 'document_id', $result->id);
lingotek_keystore($entity_type, $translatable_object->getId(), 'last_uploaded', time());
}
-
$success = TRUE;
}
}
return $success;
}
-
+
+ /**
+ * Waits until document import status is complete, then adds targets, or logs an error
+ * @param string $doc_id
+ * @param string $target_locale
+ * @param string $workflow_id
+ */
+ private function upload_language_specific_targets($doc_id, $targets) {
+ $i = 0;
+ $sleep_intervals = array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
+ $done_processing = FALSE;
+ $params = array(
+ 'id' => $doc_id
+ );
+
+ while(!$done_processing) {
+ $response = $this->request('getDocumentImportStatus', $params);
+ if ($response->status === 'COMPLETE') {
+ $done_processing = TRUE;
+ }
+ elseif($i > count($sleep_intervals) - 1) {
+ drupal_set_message(t('Uploading some language-specific targets failed because of network timeout. Please retry.'), 'warning', FALSE);
+ LingotekLog::error(t('Adding language-specific targets failed: ') . print_r('Document id: ' . $doc_id, TRUE), array());
+ return;
+ }
+ else {
+ sleep($sleep_intervals[$i]);
+ $i++;
+ }
+ }
+
+ // The document has been imported successfully, now add the targets
+ if (is_array($targets)) {
+ foreach ($targets as $target_locale => $target_attribs) {
+ if (!empty($doc_id) && !empty($target_attribs['workflow_id'])) {
+ $tl_result = $this->addTranslationTarget($doc_id, NULL, $target_locale, $target_attribs['workflow_id']);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks if this content needs to have it's url translated, strips it out if it doesn't.
+ * Best place for this function as the function that puts the url alias into the content
+ * is used in other places.
+ * @param type $translatable_object
+ * @param string $content
+ * @return string
+ */
+ private function check_url_alias_translation($translatable_object, $content) {
+ if($translatable_object->lingotek['url_alias_translation'] != 1){
+ $openTagPosition = strpos($content, '');
+ if($openTagPosition !== FALSE){
+ $closeTagPosition = strpos($content, '') + strlen('');
+ $firstChunk = substr($content, 0, $openTagPosition);
+ $lastChunk = substr($content, $closeTagPosition);
+ $content = $firstChunk . $lastChunk;
+ }
+ }
+ return $content;
+ }
+
/**
* Updates the content of an existing Lingotek document with the current object contents.
*
@@ -148,24 +244,37 @@ public function updateContentDocument($translatable_object) {
$parameters['documentId'] = $translatable_object->getMetadataValue('document_id');
$parameters['documentName'] = $translatable_object->getDocumentName();
$parameters['documentDesc'] = $translatable_object->getDescription();
- $parameters['content'] = $translatable_object->documentLingotekXML();
+ $parameters['content'] = $this->check_url_alias_translation($translatable_object, $translatable_object->documentLingotekXML());
$parameters['url'] = $translatable_object->getUrl();
$parameters['format'] = $this->xmlFormat();
- $this->addAdvancedParameters($parameters, $translatable_object);
+ // If the document has invalid characters, return without uploading
+ $invalid_xml = lingotek_keystore($translatable_object->getEntityType(), $translatable_object->getId(), 'invalid_xml');
+ if ($invalid_xml == LingotekSync::INVALID_XML_PRESENT) {
+ drupal_set_message(t('Unable to upload to Lingotek because entity contains invalid XML characters.'), 'warning');
+ return FALSE;
+ }
+ $this->addAdvancedParameters($parameters, $translatable_object);
$result = $this->request('updateContentDocumentAsync', $parameters);
if ($result) {
if (get_class($translatable_object) == 'LingotekConfigSet') {
- $translatable_object->setStatus(LingotekSync::STATUS_CURRENT);
- $translatable_object->setTargetsStatus(LingotekSync::STATUS_PENDING);
-
- // WTD: there is a race condition here where a user could modify a locales-
- // source entry between the time the dirty segments are pulled and the time
- // they are set to current at this point. This same race condition exists
- // for nodes as well; however, the odds may be lower due to number of entries.
- LingotekConfigSet::setSegmentStatusToCurrentById($translatable_object->getId());
+ if ($result->results === 'success') {
+ $translatable_object->setStatus(LingotekSync::STATUS_CURRENT);
+ $translatable_object->setTargetsStatus(LingotekSync::STATUS_PENDING);
+ $translatable_object->deleteUploadError();
+ // WTD: there is a race condition here where a user could modify a locales-
+ // source entry between the time the dirty segments are pulled and the time
+ // they are set to current at this point. This same race condition exists
+ // for nodes as well; however, the odds may be lower due to number of entries.
+ LingotekConfigSet::setSegmentStatusToCurrentById($translatable_object->getId());
+ }
+ else {
+ $translatable_object->setStatus(LingotekSync::STATUS_ERROR);
+ $translatable_object->setTargetsStatus(LingotekSync::STATUS_EDITED);
+ $translatable_object->setUploadError('Failed to update config item.');
+ }
}
}
@@ -203,7 +312,6 @@ public function addTranslationTarget($lingotek_document_id, $lingotek_project_id
global $_lingotek_client, $_lingotek_locale;
$parameters = array(
- 'applyWorkflow' => 'true', // Ensure that as translation targets are added, the associated project's Workflow template is applied.
'targetLanguage' => $lingotek_locale
);
@@ -217,6 +325,10 @@ public function addTranslationTarget($lingotek_document_id, $lingotek_project_id
if ($workflow_id) {
$parameters['workflowId'] = $workflow_id;
}
+ else {
+ // The associated project's Workflow template should be applied.
+ $parameters['applyWorkflow'] = 'true';
+ }
if ($new_translation_target = $this->request('addTranslationTarget', $parameters)) {
// If the request went through, there was no OAuth error and we should enable.
@@ -229,9 +341,9 @@ public function addTranslationTarget($lingotek_document_id, $lingotek_project_id
* Removes a target language to an existing Lingotek Document or Project.
*
* @param int $lingotek_document_id
- * The document to which the new translation target should be added. Or null if the target will be added to the project.
+ * The document from which the translation target should be removed. Or null if the target will be removed from the project.
* @param int $lingotek_project_id
- * The project to which the new translation target should be added. Or null if the target will be added to a document instead.
+ * The project from which the translation target should be removed. Or null if the target will be removed from a document instead.
* @param string $lingotek_locale
* The two letter code representing the language which should be added as a translation target.
* @param string $workflow_id
@@ -241,10 +353,9 @@ public function addTranslationTarget($lingotek_document_id, $lingotek_project_id
* @return bool
* TRUE on success, or FALSE on error.
*/
- public function removeTranslationTarget($lingotek_document_id, $lingotek_project_id, $lingotek_locale, $workflow_id = '') {
+ public function removeTranslationTarget($lingotek_document_id, $lingotek_project_id, $lingotek_locale) {
$parameters = array(
- 'applyWorkflow' => 'true', // Ensure that as translation targets are added, the associated project's Workflow template is applied.
'targetLanguage' => $lingotek_locale
);
@@ -255,10 +366,6 @@ public function removeTranslationTarget($lingotek_document_id, $lingotek_project
$parameters['projectId'] = $lingotek_project_id;
}
- if ($workflow_id) {
- $parameters['workflowId'] = $workflow_id;
- }
-
if ($old_translation_target = $this->request('removeTranslationTarget', $parameters)) {
return ( $old_translation_target->results == 'success' ) ? TRUE : FALSE;
}
@@ -309,7 +416,7 @@ public function currentPhase($translation_target_id) {
* A Lingotek language/locale code.
*
* @return mixed
- * On success, a SimpleXMLElement object representing the translated document. FALSE on failure.
+ * On success, a LingotekXMLElement object representing the translated document. FALSE on failure.
*
*/
public function downloadDocument($document_id, $lingotek_locale) {
@@ -350,7 +457,7 @@ public function downloadDocument($document_id, $lingotek_locale) {
unlink($tmpFile);
- $document = new SimpleXMLElement($text);
+ $document = new LingotekXMLElement($text);
} catch (Exception $e) {
LingotekLog::error('Unable to parse downloaded document. Error: @error. Text: !xml.', array('!xml' => $text, '@error' => $e->getMessage()));
}
@@ -411,7 +518,7 @@ public function getDocumentProgress($document_id) {
return $document;
}
- /**
+ /**
* Gets the workflow progress of the specified documents.
*
* @param int $document_id
@@ -429,11 +536,26 @@ public function listDocumentProgress($document_ids) {
return $documents;
}
+ /**
+ * Gets the Target Tranlsations of the specified document.
+ *
+ * @param int $document_id
+ * The ID of the Lingotek Document to retrieve.
+ *
+ * @return mixed
+ * The API response object with Lingotek Document data, or FALSE on error.
+ */
+ public function listTranslationTargets($document_id) {
+ $params['documentId'] = $document_id;
+ $targetTranslations = $this->request('listTranslationTargets', $params);
+ return $targetTranslations;
+ }
+
/**
* Gets the workflow progress of the specified project (or list of document ids).
*
* @param int $project_id
- *
+ *
* @param array $document_ids
* An array of document IDs of the Lingotek Document to retrieve.
*
@@ -637,7 +759,7 @@ public function getWorkbenchLink($document_id, $phase_id) {
$links = &drupal_static(__FUNCTION__);
global $user;
- $externalId = isset($user->name) ? $user->name : ''; // send a blank string for anonymous users (community translation)
+ $externalId = isset($user->mail) ? $user->mail : ''; // send a blank string for anonymous users (community translation)
self::checkUserWorkbenchLinkPermissions($externalId);
$static_id = $document_id . '-' . $phase_id;
@@ -664,10 +786,10 @@ public function getWorkbenchLink($document_id, $phase_id) {
/**
* Gets available Lingotek projects.
- *
+ *
* @param $reset
* A boolean value to determin whether we need to query the API
- *
+ *
* @return array
* An array of available projects with project IDs as keys, project labels as values.
*/
@@ -677,7 +799,7 @@ public function listProjects($reset = FALSE) {
if (!empty($projects) && $reset == FALSE) {
return $projects;
}
-
+
if ($projects_raw = $this->request('listProjects')) {
$projects = array();
foreach ($projects_raw->projects as $project) {
@@ -691,12 +813,12 @@ public function listProjects($reset = FALSE) {
/**
* Gets available Lingotek Workflows.
- *
+ *
* @param $reset
* A boolean value to determine whether we need to query the API
* @param $include_public
* A boolean value to determine whether to show public workflows
- *
+ *
* @return array
* An array of available Workflows with workflow IDs as keys, workflow labels as values.
*/
@@ -709,7 +831,7 @@ public function listWorkflows($reset = FALSE, $include_public = FALSE) {
if ($workflows_raw = $this->request('listWorkflows')) {
$workflows = array();
foreach ($workflows_raw->workflows as $workflow) {
- if ($include_public || (!$workflow->is_public
+ if ($include_public || (!$workflow->is_public
&& $workflow->owner != LINGOTEK_DEFAULT_WORKFLOW_TEMPLATE))
$workflows[$workflow->id] = $workflow->name;
}
@@ -721,12 +843,12 @@ public function listWorkflows($reset = FALSE, $include_public = FALSE) {
/**
* Gets Lingotek Workflow by ID
- *
+ *
* @param $id
* a string containing the workflow ID
* @param $reset
* A boolean value to determine whether we need to query the API
- *
+ *
* @return array
* An array of workflow details
*/
@@ -745,10 +867,10 @@ public function getWorkflow($id, $reset = FALSE) {
/**
* Gets available Lingotek Translation Memory Vaults.
- *
+ *
* @param $reset
* A boolean value to determin whether we need to query the API
- *
+ *
* @return array
* An array of available vaults.
*/
@@ -786,14 +908,14 @@ public function listVaults($reset = FALSE, $show_public_vaults = FALSE) {
/**
* Updates one or more nids to belong to a given workflow
- *
+ *
* @param array $document_ids
* An array of document IDs
* @param string $workflow_id
* A string containing the desired workflow_id
* @param string $prefillPhase
* An optional parameter specifying the prefill phase
- *
+ *
* @return bool
* TRUE on success, FALSE on failure.
*/
@@ -901,7 +1023,7 @@ public function request($method, $parameters = array(), $request_method = 'POST'
$result = $request->doRequest(0, array(CURLOPT_SSL_VERIFYPEER => FALSE));
$response = json_decode($result['body']);
} catch (OAuthException2 $e) {
- LingotekLog::error('Failed OAuth request. Method: @method Message: @message
+ LingotekLog::error('Failed OAuth request. Method: @method Message: @message
API URL: @url
Parameters: !params.
Response: !response', array(
@@ -913,7 +1035,7 @@ public function request($method, $parameters = array(), $request_method = 'POST'
}
$timer_results = timer_stop($timer_name);
-
+
// cleanup parameters so that the logs aren't too long
if(isset($parameters['fprmFileContents'])) {
$parameters['fprmFileContents'] = 'removed for brevity';
@@ -963,7 +1085,7 @@ public function request($method, $parameters = array(), $request_method = 'POST'
public function createCommunity($parameters = array(), $callback_url = NULL) {
$credentials = array('consumer_key' => LINGOTEK_AP_OAUTH_KEY, 'consumer_secret' => LINGOTEK_AP_OAUTH_SECRET);
if (isset($callback_url)) {
- $parameters['projectName'] = lingotek_get_site_name();
+ $parameters['projectName'] = lingotek_get_site_name();
$parameters['callbackUrl'] = $callback_url;
}
$response = $this->request('autoProvisionCommunity', $parameters, 'POST', $credentials);
@@ -1022,7 +1144,7 @@ private function __construct() {
* Private clone implementation.
*/
private function __clone() {
-
+
}
}
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekConfigSet.php b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekConfigSet.php
index 4fa7b68f..acece03f 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekConfigSet.php
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekConfigSet.php
@@ -47,7 +47,7 @@ class LingotekConfigSet implements LingotekTranslatableEntity {
* A static flag for content updates.
*/
protected static $content_update_in_progress = FALSE;
-
+ protected $workflow_id = null;
/**
* Constructor.
*
@@ -62,9 +62,10 @@ private function __construct($set_id = NULL) {
$this->source_data = self::getAllSegments($this->sid);
$this->source_meta = self::getSetMeta($this->sid);
$this->language = language_default();
- if (!isset($this->language->lingotek_locale)) { // if Drupal variable 'language_default' does not exist
- $this->language->lingotek_locale = Lingotek::convertDrupal2Lingotek($this->language->language);
- }
+ // INT-791 Respecting the i18n_string_source_language setting
+ $i18n_language = variable_get('i18n_string_source_language', language_default()->language);
+ $this->language->language = $i18n_language;
+ $this->language->lingotek_locale = Lingotek::convertDrupal2Lingotek($this->language->language);
$this->language_targets = Lingotek::getLanguagesWithoutSource($this->language->lingotek_locale);
}
@@ -193,6 +194,43 @@ public static function getSetId($lid, $assign = TRUE) {
return $existing_sid;
}
+ public static function bulkGetSetId($lid_map){
+ $set_ids = array();
+ foreach($lid_map as $textgroup => $lids){
+ $open_set_id = self::getOpenSet($textgroup);
+ if ($open_set_id === FALSE) {
+ $open_set_id = self::createSet($textgroup);
+ }
+
+ $query = db_select('lingotek_config_map', 'lcm');
+ $query->addField('lcm', 'set_id');
+ $query->addField('lcm', 'lid');
+ $query->condition('lid', $lids, "IN");
+ $result = $query->execute()->fetchAllAssoc('lid');
+
+ $insert = db_insert('lingotek_config_map');
+ $insert->fields(array('lid','set_id'));
+
+ $count = 0;
+ foreach($lids as $lid){
+ if($count === LINGOTEK_CONFIG_SET_SIZE){
+ $open_set_id = self::createSet($textgroup);
+ $count = 0;
+ }
+ if(!isset($result[$lid])){
+ $insert->values(array('lid'=>$lid,'set_id'=>$open_set_id));
+ $set_ids[$open_set_id] = $open_set_id;
+ }
+ else {
+ $set_ids[$result[$lid]->set_id] = $result[$lid]->set_id;
+ }
+ $count++;
+ }
+ $insert->execute();
+ }
+ return $set_ids;
+ }
+
protected static function assignSetId($lid) {
// get the $lid's textgroup
$textgroup = db_select('locales_source', 'l')
@@ -279,9 +317,9 @@ protected static function createSet($textgroup) {
}
protected static function getNextSetId() {
- $query = db_select('lingotek_config_metadata', 'lcm');
- $query->addExpression('MAX(id)');
- $max_set_id = $query->execute()->fetchField();
+ $query = db_query('SELECT max(id) FROM lingotek_config_metadata WHERE id < :max_size', array(':max_size' => LingotekSync::MARKED_OFFSET));
+ $max_set_id = $query->fetchField();
+
if ($max_set_id) {
return (int) $max_set_id + 1;
}
@@ -307,6 +345,25 @@ public static function getAllConfigDocIds() {
return $doc_ids;
}
+ public static function getAllUnsetWorkflowConfigDocIds() {
+ $setWorkflowSetIds = db_select('lingotek_config_metadata', 'lcm')
+ ->fields('lcm', array('id'))
+ ->condition('config_key', 'workflow_id');
+ $doc_ids = db_select('lingotek_config_metadata', 'l')
+ ->fields('l', array('value'))
+ ->condition('config_key', 'document_id')
+ ->condition('id', $setWorkflowSetIds, 'NOT IN')
+ ->execute()
+ ->fetchCol();
+ return $doc_ids;
+ }
+
+ public static function deleteConfigSetWorkflowIds(){
+ db_delete('lingotek_config_metadata')
+ ->condition('config_key', 'workflow_id', '=')
+ ->execute();
+ }
+
public function getSourceLocale() {
return $this->language->lingotek_locale;
}
@@ -437,7 +494,7 @@ protected static function getAllSegments($set_id) {
$response[$r['lid']] = $r['source'];
}
else {
- LingotekLog::warning("Config item @id was not sent to Lingotek for translation because it exceeds the max length of 4096 characters.", array('@id' => $r['lid']));
+ LingotekLog::warning("Config item @id was not sent to Lingotek for translation because it exceeds the max length of @max_length characters.", array('@id' => $r['lid'], '@max_length' => $max_length));
// Remove it from the set in the config_map table so it doesn't get marked as uploaded or translated.
self::disassociateSegments($r['lid']);
}
@@ -481,6 +538,21 @@ public static function getLidsByStatus($status) {
$lids = self::getLidsFromSets($set_ids);
return $lids;
}
+
+ public static function getSetIdsByStatus($status, $lids = null) {
+ $query = db_select('lingotek_config_metadata', 'l');
+ if($lids !== null) {
+ $query->join('lingotek_config_map', 'lc', 'l.id = lc.set_id');
+ $query->condition('lc.lid', $lids, 'IN');
+ }
+ $query->fields('l', array('id'));
+ $query->condition('l.config_key', 'target_sync_status_%', 'LIKE');
+ $query->condition('l.value', $status);
+ $query->distinct();
+ $result = $query->execute();
+ $set_ids = $result->fetchCol();
+ return $set_ids;
+ }
/**
* Return any metadata for the given set ID, if it exists
@@ -530,65 +602,8 @@ public static function loadByLingotekDocumentId($lingotek_document_id) {
if (isset($set_id)) {
$set = self::loadById($set_id);
}
-
- return $set;
- }
-
- /**
- * Event handler for updates to the config set's data.
- */
- public function contentUpdated() {
-
- $metadata = $this->metadata();
- if (empty($metadata['document_id'])) {
- $this->createLingotekDocument();
- }
- else {
- $update_result = $this->updateLingotekDocument();
- }
-
- // Synchronize the local content with the translations from Lingotek.
- // We instruct the users to configure config set translation with a
- // single-phase machine translation-only Workflow, so the updated content
- // should be available right after our create/update document calls from above.
- // If it isn't, Lingotek will call us back via LINGOTEK_NOTIFICATIONS_URL
- // when machine translation for the item has finished.
- if (!self::$content_update_in_progress) {
- // Only update the local content if the Document is 100% complete
- // according to Lingotek.
-
- $document_id = $this->getMetadataValue('document_id');
- if ($document_id) {
- $document = $this->api->getDocument($document_id);
- if (!empty($document->percentComplete) && $document->percentComplete == 100) {
- $this->updateLocalContent();
- }
- }
- else {
- LingotekLog::error('Unable to retrieve Lingotek Document ID for config set @id', array('@id' => $this->sid));
- }
- }
- }
- /**
- * Creates a Lingotek Document for this config set.
- *
- * @return bool
- * TRUE if the document create operation was successful, FALSE on error.
- */
- protected function createLingotekDocument() {
- return ($this->api->addContentDocumentWithTargets($this)) ? TRUE : FALSE;
- }
-
- /**
- * Updates the existing Lingotek Documemnt for this config set.
- *
- * @return bool
- * TRUE if the document create operation was successful, FALSE on error.
- */
- protected function updateLingotekDocument() {
- $result = $this->api->updateContentDocument($this);
- return ($result) ? TRUE : FALSE;
+ return $set;
}
/**
@@ -620,7 +635,7 @@ protected function metadata() {
public function hasLingotekDocId() {
$has_id = array_key_exists('document_id', $this->source_meta);
if ($has_id && (strlen($this->source_meta['document_id']) > 0)) {
- return TRUE;
+ return $this->source_meta['document_id'];
}
return FALSE;
}
@@ -662,18 +677,47 @@ public function setStatus($status) {
}
/**
- * Assign the set's last error in the config metadata table
+ * Assign the set's last sync error in the config metadata table
*/
public function setLastError($errors) {
$this->setMetadataValue('last_sync_error', substr($errors, 0, 255));
return $this;
}
+ /**
+ * Assign the set's last upload_error in the config metadata table
+ */
+ public function setUploadError($errors) {
+ $this->setMetadataValue('upload_error', substr($errors, 0, 255));
+ return $this;
+ }
+
+ /**
+ * Delete the set's last error in the config metadata table
+ */
+ public function deleteLastError() {
+ $this->deleteMetadataValue('last_sync_error');
+ return $this;
+ }
+
+ /**
+ * Delete the set's last upload_error in the config metadata table
+ */
+ public function deleteUploadError() {
+ $this->deleteMetadataValue('upload_error');
+ return $this;
+ }
+
/**
* Assign the set's target status(es) in the config metadata table
*/
- public function setTargetsStatus($status, $lingotek_locale = 'all') {
- if ($lingotek_locale != 'all') {
+ public function setTargetsStatus($status, $lingotek_locale = NULL) {
+ if (is_array($lingotek_locale)) {
+ foreach ($lingotek_locale as $ll) {
+ $this->setMetadataValue('target_sync_status_' . $ll, $status);
+ }
+ }
+ elseif (is_string($lingotek_locale) && !empty($lingotek_locale)) {
$this->setMetadataValue('target_sync_status_' . $lingotek_locale, $status);
}
else { // set status for all available targets
@@ -768,10 +812,10 @@ public function setMetadataValue($key, $value) {
->execute();
}
}
-
+
/**
* Deletes a Lingotek metadata value for this item
- *
+ *
* @param string $key
* The key for a name/value pair
*/
@@ -962,6 +1006,7 @@ public static function getLidsToUpdate($current = 0, $lids = 'all') {
$query->condition('lcm.lid', $lids, 'IN');
}
$query->join('locales_source', 'ls', "lcm.lid = ls.lid");
+ $query->addField('ls', 'textgroup');
$query->condition('ls.textgroup', $textgroups, 'IN');
$query->join('locales_target', 'lt', "lcm.lid = lt.lid");
@@ -969,11 +1014,37 @@ public static function getLidsToUpdate($current = 0, $lids = 'all') {
$or->condition('lcm.current', $current);
$or->condition('lt.i18n_status', 1);
$query->condition($or);
-
- $lids = $query->execute()->fetchCol();
- return array_unique($lids);
+
+ $results = $query->execute();
+ $lids = array();
+ foreach($results as $result){
+ $lids[$result->textgroup][$result->lid] = $result->lid;
+ }
+ return $lids;
+ }
+ /**
+ * Check a given list for lids that have never been uploaded
+ * @param type $control_list
+ * The list of lids to search through
+ * @return type
+ */
+ public static function findNeverUploadedLids($control_list = NULL){
+ if($control_list !== NULL && !empty($control_list)){
+ $query = db_select('locales_source','ls');
+ $query->leftJoin('locales_target','lt','ls.lid = lt.lid');
+ $query->isNull("lt.lid");
+ $query->addField('ls', 'lid');
+ $query->addField('ls',"textgroup");
+ $query->condition('ls.lid',$control_list, 'IN');
+ $never_uploaded_lids = $query->execute();
+ $textgroup_lid = array();
+ foreach($never_uploaded_lids as $lid){
+ $textgroup_lid[$lid->textgroup][$lid->lid] = $lid->lid;
+ }
+ return $textgroup_lid;
+ }
+ return array();
}
-
/**
* Delete all target segments for a given set
*
@@ -1009,6 +1080,34 @@ public static function disassociateSegments($lids) {
->execute();
}
+ public static function deleteConfigSetMetadataBySetId($set_ids) {
+ db_delete('lingotek_config_metadata')
+ ->condition('id', $set_ids)
+ ->execute();
+ }
+
+ public static function deleteConfigSetMapDataBySetId($set_ids) {
+ db_delete('lingotek_config_map')
+ ->condition('set_id', $set_ids)
+ ->execute();
+ }
+
+ public static function removeEmptyConfigSets($set_ids) {
+ foreach($set_ids as $set_id) {
+ $set_members = db_select('lingotek_config_map', 'lcm')
+ ->fields('lcm', array('lid'))
+ ->condition('set_id', $set_ids, 'IN')
+ ->execute()
+ ->fetchAll();
+
+ if (empty($set_members)) { // The set is empty, so delete it.
+ db_delete('lingotek_config_metadata')
+ ->condition('id', $set_id)
+ ->execute();
+ }
+ }
+ }
+
/**
* Get lingotek translation agent ID
*/
@@ -1041,7 +1140,7 @@ protected static function getNonLingotekLocalesTargets($document_xml, $target_la
* Save segment target translations for the given language
*
* @param obj
- * the SimpleXMLElement object containing the translations to be saved
+ * the LingotekXMLElement object containing the translations to be saved
* @param string
* the language code under which to save the translations
*/
@@ -1097,7 +1196,7 @@ public function lingotekDocumentId() {
public function getEntityType() {
return self::DRUPAL_ENTITY_TYPE;
}
-
+
/**
* Magic get for access to set and set properties.
*/
@@ -1123,12 +1222,19 @@ protected static function getLidFromTag($tag) {
}
public function getWorkflowId() {
- $profiles = variable_get('lingotek_profiles');
- $config_profile = $profiles[LingotekSync::PROFILE_CONFIG];
- $workflow_id = array_key_exists('workflow_id', $config_profile) ? $config_profile['workflow_id'] : variable_get('lingotek_translate_config_workflow_id', '');
+ if($this->workflow_id !== null){
+ $workflow_id = $this->workflow_id;
+ }
+ else {
+ $profiles = variable_get('lingotek_profiles');
+ $config_profile = $profiles[LingotekSync::PROFILE_CONFIG];
+ $workflow_id = array_key_exists('workflow_id', $config_profile) ? $config_profile['workflow_id'] : variable_get('lingotek_translate_config_workflow_id', '');
+ }
return $workflow_id;
}
-
+ public function setWorkflowId($workflow_id) {
+ $this->workflow_id = $workflow_id;
+ }
public function getProjectId() {
$profiles = variable_get('lingotek_profiles');
$config_profile = $profiles[LingotekSync::PROFILE_CONFIG];
@@ -1166,12 +1272,15 @@ public static function getTextgroupsForTranslation() {
if (variable_get('lingotek_translate_config_fields', 0)) {
$textgroups[] = 'field';
}
+ if (variable_get('lingotek_translate_config_webform', 0)) {
+ $textgroups[] = 'webform';
+ }
if (variable_get('lingotek_translate_config_misc', 0)) {
$textgroups[] = 'misc';
}
return $textgroups;
}
-
+
public static function getLidBySource($source_string) {
return db_select('locales_source', 's')
->fields('s', array('lid'))
@@ -1200,7 +1309,7 @@ public function getDocumentName() {
public function getUrl() {
return '';
}
-
+
public function getNote() {
return '';
}
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekDocument.php b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekDocument.php
index d11f798f..3a6d7178 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekDocument.php
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekDocument.php
@@ -145,7 +145,7 @@ public function getImportStatus($include_details = TRUE) {
$response = $this->api->request('getDocumentImportStatus', array('id' => $this->document_id));
$status = self::IMPORT_STATUS__UNKNOWN;
$status_message = $status;
- if ($response->results == 'success') {
+ if ($response && $response->results == 'success') {
$status = $response->status;
if ($status === self::IMPORT_STATUS__PROCESSING) {
$status_message = $status . " (" . $response->process->percentComplete . "% complete)";
@@ -157,7 +157,7 @@ public function getImportStatus($include_details = TRUE) {
$status_message = $status;
}
}
- elseif ($response->results == 'fail') {
+ elseif ($response && $response->results == 'fail') {
$status = self::IMPORT_STATUS__ERROR;
$status_message = $status . " (" . $response->error . ")";
}
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekEntity.php b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekEntity.php
index fedb6b1f..b5fe4888 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekEntity.php
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekEntity.php
@@ -21,6 +21,11 @@ class LingotekEntity implements LingotekTranslatableEntity {
*/
protected $entity_type;
+ /**
+ * The Drupal entity id
+ */
+ protected $entity_id;
+
/**
* The title of the document
*/
@@ -46,6 +51,7 @@ class LingotekEntity implements LingotekTranslatableEntity {
private function __construct($entity, $entity_type) {
$this->entity = $entity;
$this->entity_type = $entity_type;
+ $this->entity_id = $this->getId();
$this->info = entity_get_info($this->entity_type);
if (!empty($entity->language_override)) {
$this->setLanguage($entity->language_override);
@@ -203,27 +209,29 @@ public function getMetadataValue($key) {
*/
public function setMetadataValue($key, $value) {
$metadata = $this->metadata();
+ $entity_type = $this->getEntityType();
+ $entity_id = $this->getId();
if (!isset($metadata[$key])) {
db_insert('lingotek_entity_metadata')
->fields(array(
- 'entity_id' => $this->getId(),
- 'entity_type' => $this->getEntityType(),
+ 'entity_id' => $entity_id,
+ 'entity_type' => $entity_type,
'entity_key' => $key,
'value' => $value,
))
->execute();
-
}
else {
db_update('lingotek_entity_metadata')
->fields(array(
'value' => $value
))
- ->condition('entity_id', $this->getId())
- ->condition('entity_type', $this->getEntityType())
+ ->condition('entity_id', $entity_id)
+ ->condition('entity_type', $entity_type)
->condition('entity_key', $key)
->execute();
}
+ lingotek_cache_clear($entity_type, $entity_id);
}
/**
@@ -235,11 +243,14 @@ public function setMetadataValue($key, $value) {
public function deleteMetadataValue($key) {
$metadata = $this->metadata();
if (isset($metadata[$key])) {
+ $entity_type = $this->getEntityType();
+ $entity_id = $this->getId();
db_delete('lingotek_entity_metadata')
- ->condition('entity_id', $this->getId())
- ->condition('entity_type', $this->getEntityType())
- ->condition('entity_key', $key, 'LIKE')
- ->execute();
+ ->condition('entity_id', $entity_id)
+ ->condition('entity_type', $entity_type)
+ ->condition('entity_key', $key, 'LIKE')
+ ->execute();
+ lingotek_cache_clear($entity_type, $entity_id);
}
}
@@ -295,6 +306,7 @@ public function getTitle() {
array('@entity_type' => $this->entity_type, '@entity_id' => $this->entity_id));
$this->title = $this->entity_type . " #" . $this->entity_id;
}
+
return $this->title;
}
@@ -339,6 +351,22 @@ public function getSourceLocale() {
return 'en_US';
}
}
+ if ($this->entity_type == 'bean') {
+ // Assume all block entities are created in the site's default language.
+ return Lingotek::convertDrupal2Lingotek(language_default()->language);
+ }
+ if ($this->entity_type == 'group') {
+ $group_language = lingotek_get_group_source($this->entity->gid);
+ return Lingotek::convertDrupal2Lingotek($group_language);
+ }
+ if ($this->entity_type == 'paragraphs_item') {
+ $paragraphs_language = lingotek_get_paragraphs_item_source($this->entity->item_id);
+ return Lingotek::convertDrupal2Lingotek($paragraphs_language);
+ }
+ if ($this->entity_type == 'file') {
+ $file_language = lingotek_get_file_source($this->entity->fid);
+ return Lingotek::convertDrupal2Lingotek($file_language);
+ }
return Lingotek::convertDrupal2Lingotek($this->language);
}
@@ -353,17 +381,25 @@ public function getNote() {
public function getUrl() {
global $base_url;
- if ($this->entity_type == 'node' || $this->entity_type == 'comment') {
+ $path = entity_uri($this->entity_type, $this->entity);
+ $url = '';
+
+ if ($path) {
$hack = (object) array('language' => ''); // this causes the url function to not prefix the url with the current language the user is viewing the site in
- return $base_url . "/lingotek/view/" . $this->getEntityType() . '/' . $this->getId() . '/{locale}';
+ $url = $base_url . "/lingotek/view/" . $this->getEntityType() . '/' . $this->getId() . '/{locale}';
}
- return '';
+
+ drupal_alter('lingotek_source_URL', $url);
+ return $url;
}
public function preDownload($lingotek_locale, $completed) {
if ($completed) {
lingotek_keystore($this->getEntityType(), $this->getId(), 'target_sync_status_' . $lingotek_locale, LingotekSync::STATUS_READY);
}
+ else{
+ lingotek_keystore($this->getEntityType(), $this->getId(), 'target_sync_status_' . $lingotek_locale, LingotekSync::STATUS_READY_INTERIM);
+ }
}
public function postDownload($lingotek_locale, $completed) {
@@ -392,8 +428,16 @@ public function setLastError($errors) {
return $this;
}
- public function setTargetsStatus($status, $lingotek_locale = 'all') {
- if ($lingotek_locale != 'all') {
+ /**
+ * Assign the entity's target status(es) in the config metadata table
+ */
+ public function setTargetsStatus($status, $lingotek_locale = NULL) {
+ if (is_array($lingotek_locale)) {
+ foreach ($lingotek_locale as $ll) {
+ $this->setMetadataValue('target_sync_status_' . $ll, $status);
+ }
+ }
+ elseif (is_string($lingotek_locale) && !empty($lingotek_locale)) {
$this->setMetadataValue('target_sync_status_' . $lingotek_locale, $status);
}
else { // set status for all available targets
@@ -410,12 +454,26 @@ public function setTargetsStatus($status, $lingotek_locale = 'all') {
*/
public function setLanguage($language = NULL) {
if (empty($language)) {
- $drupal_locale = Lingotek::convertDrupal2Lingotek($this->entity->language);
- if (!empty($this->entity->lingotek['allow_source_overwriting']) && !empty($this->entity->lingotek['source_language_' . $drupal_locale])) {
- $language = $this->entity->lingotek['source_language_' . $drupal_locale];
+ if ($this->entity_type == 'bean') {
+ $language = language_default()->language;
+ }
+ elseif ($this->entity_type == 'group') {
+ $language = lingotek_get_group_source($this->entity->gid);
+ }
+ elseif ($this->entity_type == 'paragraphs_item') {
+ $language = lingotek_get_paragraphs_item_source($this->entity->item_id);
+ }
+ elseif ($this->entity_type == 'file') {
+ $language = lingotek_get_file_source($this->entity->fid);
}
else {
- $language = $this->entity->language;
+ $drupal_locale = Lingotek::convertDrupal2Lingotek($this->entity->language);
+ if (!empty($this->entity->lingotek['allow_source_overwriting']) && !empty($this->entity->lingotek['source_language_' . $drupal_locale])) {
+ $language = $this->entity->lingotek['source_language_' . $drupal_locale];
+ }
+ else {
+ $language = $this->entity->language;
+ }
}
}
$this->language = $language;
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekException.php b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekException.php
new file mode 100644
index 00000000..0e362199
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekException.php
@@ -0,0 +1,8 @@
+setId($profile_id);
+ $this->setInherit(TRUE);
+ $this->refresh();
+
+ if (empty(self::$global_profile)) {
+ self::$global_profile = lingotek_get_global_profile();
+ }
+
+ if ($profile_id === LingotekSync::PROFILE_DISABLED || $profile_id === LingotekSync::PROFILE_ENABLED) {
+ $this->setName($profile_id);
+ return $this;
+ }
+ if ($profile_id === LingotekSync::PROFILE_INHERIT) {
+ $this->setName($profile_id);
+ return LingotekSync::PROFILE_INHERIT;
+ }
+ if (empty(self::$profiles[$profile_id]) && !empty($profile_attributes)) {
+ // create one on the fly
+ $unique_attributes = array();
+ foreach ($profile_attributes as $key => $value) {
+ if (empty(self::$global_profile[$key]) || self::$global_profile[$key] !== $value) {
+ $unique_attributes[$key] = $value;
+ }
+ }
+ self::$profiles[$profile_id] = $unique_attributes;
+ $this->save();
+ }
+ // A convenience reference to the current profile.
+ $this->profile = &self::$profiles[$profile_id];
+ }
+
+ public static function create($profile_id, array $profile_attributes) {
+ if (isset(self::$profiles[$profile_id])) {
+ throw new LingotekException('Unable to create profile "' . $profile_id . '": profile already exists.');
+ }
+ return new LingotekProfile($profile_id, $profile_attributes);
+ }
+
+ public static function update($profile_id, array $profile_attributes) {
+ if (!isset(self::$profiles[$profile_id])) {
+ throw new LingotekException('Unable to update profile "' . $profile_id . '": profile does not exist.');
+ }
+ $profile = self::loadById($profile_id);
+ foreach ($profile_attributes as $key => $value) {
+ if (!empty(self::$global_profile[$key]) && self::$global_profile[$key] === $value) {
+ // remove any attributes that are the same as the global ones
+ $profile->deleteAttribute($key);
+ }
+ else {
+ // keep any custom attributes
+ $profile->setAttribute($key, $value);
+ }
+ }
+ }
+
+ public static function loadById($profile_id) {
+ return new LingotekProfile($profile_id);
+ }
+
+ public static function loadByName($profile_name) {
+ $this->refresh();
+ foreach (self::$profiles as $profile_id => $profile) {
+ if ($profile['name'] == $profile_name) {
+ return new LingotekProfile($profile_id);
+ }
+ }
+ throw new LingotekException('Unknown profile name: ' . $profile_name);
+ }
+
+ public static function loadByBundle($entity_type, $bundle, $source_locale = NULL) {
+ $entity_profiles = variable_get('lingotek_entity_profiles', array());
+ if (!empty($source_locale) && isset($entity_profiles[$entity_type][$bundle . '__' . $source_locale])) {
+ try {
+ $profile = new LingotekProfile($entity_profiles[$entity_type][$bundle . '__' . $source_locale]);
+ if ($profile->getName() == LingotekSync::PROFILE_INHERIT) {
+ $profile = new LingotekProfile($entity_profiles[$entity_type][$bundle]);
+ }
+ return $profile;
+ }
+ catch (Exception $e) {
+ // TODO: a debug statement perhaps saying there are no customizations for the given source locale?
+ }
+ }
+ if (isset($entity_profiles[$entity_type][$bundle])) {
+ return new LingotekProfile($entity_profiles[$entity_type][$bundle]);
+ }
+ return self::loadById(LingotekSync::PROFILE_DISABLED);
+ }
+
+ public static function loadByEntity($entity_type, $entity) {
+ list($id, $vid, $bundle) = lingotek_entity_extract_ids($entity_type, $entity);
+ $result = db_select('lingotek_entity_metadata', 'l')
+ ->fields('l', array('value'))
+ ->condition('l.entity_id', $id)
+ ->condition('l.entity_type', $entity_type)
+ ->condition('l.entity_key', 'profile')
+ ->execute();
+ if ($result) {
+ $profile_id = $result->fetchfield();
+ if ($profile_id !== FALSE) {
+ return self::loadById($profile_id);
+ }
+ }
+ $source_locale = lingotek_entity_locale($entity_type, $entity);
+ return self::loadByBundle($entity_type, $bundle, $source_locale);
+ }
+
+ // Return the profile ID for a given entity.
+ public static function getIdByEntity($entity_type, $entity) {
+ $profile = self::loadByEntity($entity_type, $entity);
+ return $profile->getId();
+ }
+
+ // @params TRUE or FALSE, depending on whether the profile should look for inherited attributes
+ // from the global profile
+ public function setInherit($inherit) {
+ $this->inherit = (bool) $inherit;
+ }
+
+ public function lookForInherited() {
+ return $this->inherit;
+ }
+
+ public function getId() {
+ return $this->profile_id;
+ }
+
+ // IDs should either be auto-generated or special-case IDs, not configurable by the user
+ protected function setId($profile_id) {
+ $this->profile_id = $profile_id;
+ }
+
+ // replaces lingotek_admin_profile_usage() in lingotek.admin.inc
+ // replaces lingotek_admin_profile_usage_by_types() in lingotek.admin.inc
+ public function getUsage($by_bundle = FALSE) {
+ if ($by_bundle) {
+ $bundles_using_profile = lingotek_get_bundles_by_profile_id($this->getId());
+ $count_types = 0;
+ foreach ($bundles_using_profile as $bup) {
+ $count_types += count($bup);
+ }
+ return $count_types;
+ }
+ else {
+ /**
+ *This is a representation of the query and subquery we are building to get
+ *the usage for each profile.
+ *@author t.murphy, smithworx, jbhovik, clarticus
+ *
+ *
+ *SELECT count(*) as COUNT, entity_type as ENTITY_TYPE
+ *FROM lingotek_entity_metadata
+ *WHERE entity_key = 'profile'
+ *AND value = ''
+ *AND entity_id NOT IN
+ * (SELECT entity_id
+ * FROM lingotek_entity_metadata
+ * WHERE entity_key = 'upload_status'
+ * AND value = 'TARGET')
+ *GROUP BY entity_type;
+ *
+ */
+
+
+ $subquery = db_select('lingotek_entity_metadata', 'lem')
+ ->fields('lem', array('entity_id'))
+ ->condition('lem.entity_key', 'upload_status')
+ ->condition('lem.value', 'TARGET');
+ $entity_ids = $subquery->execute()->fetchCol();
+
+ $query = db_select('lingotek_entity_metadata', 'lem')
+ ->fields('lem', array('entity_type'))
+ ->condition('lem.entity_key', 'profile')
+ ->condition('lem.value', $this->getId());
+
+ if (!empty($entity_ids)) {
+ $query->condition('lem.entity_id', $entity_ids, 'NOT IN');
+ }
+
+
+ $query->groupBy('lem.entity_type');
+ $query->addExpression('count(lem.entity_id)', 'COUNT');
+ $entities = $query->execute()->fetchAll();
+
+ $entity_counts = array();
+ foreach ($entities as $e) {
+ $entity_counts[$e->entity_type] = $e->COUNT;
+ }
+ return $entity_counts;
+ }
+ }
+
+ public function getDocumentIds() {
+ $metadata_table = $this->getId() === LingotekSync::PROFILE_CONFIG ? 'lingotek_config_metadata' : 'lingotek_entity_metadata';
+ $metadata_key_col = $this->getId() === LingotekSync::PROFILE_CONFIG ? 'config_key' : 'entity_key';
+ $query = db_select($metadata_table, 't')
+ ->fields('t', array('value'))
+ ->condition('t.' . $metadata_key_col, 'document_id');
+ return $query->execute()->fetchcol();
+ }
+
+ public function getBundles() {
+ $entities = entity_get_info();
+ $lentities = variable_get('lingotek_entity_profiles');
+ $bundles = array();
+ foreach ($entities as $entity_name => $entity) {
+ if (!isset($lentities[$entity_name])) {
+ unset($entities[$entity_name]);
+ }
+ foreach ($entity['bundles'] as $bundle_name => $bundle) {
+ if (isset($lentities[$entity_name][$bundle_name]) && $lentities[$entity_name][$bundle_name] === (string)$this->getId()) {
+ if (!isset($bundles[$entity_name])) {
+ $bundles[$entity_name] = array();
+ }
+ $bundles[$entity_name][$bundle_name] = TRUE;
+ }
+ }
+ }
+ return $bundles;
+ }
+
+ public function getEntities($entity_type = NULL) {
+ if (!empty($entity_type)) {
+ // get all bundles that belong to the given profile
+ $all_bundles = $this->getBundles();
+ $bundles = array();
+ $entities = array();
+
+ if (isset($all_bundles[$entity_type])) {
+ $bundles = array($entity_type => $all_bundles[$entity_type]);
+ }
+
+ // get all entities that belond to those bundles
+ foreach ($bundles as $entity_type => $entity_bundles) {
+ if ($entity_type == 'comment') {
+ $ref_tables = array();
+ foreach (array_keys($entity_bundles) as $key) {
+ $tmp_array = explode('_', $key);
+ $key = implode('_', array_slice($tmp_array, 2));
+ $ref_tables[] = $key;
+ }
+ $query = db_select('' . $entity_type . '', 'e')
+ ->fields('e', array('cid'));
+ $query->join('node', 'n', "n.nid = e.nid AND n.type IN ('" . implode("','", $ref_tables) . "')");
+ $results = $query->execute()->fetchCol();
+ foreach ($results as $id) {
+ $entities[] = array('id' => $id, 'type' => $entity_type);
+ }
+ }
+ else {
+ $query = new EntityFieldQuery();
+ $query->entityCondition('entity_type', $entity_type)
+ ->entityCondition('bundle', array_keys($entity_bundles), 'IN');
+ $result = $query->execute();
+ unset($query);
+ if (isset($result[$entity_type])) {
+ foreach ($result[$entity_type] as $id => $entity_data) {
+ $entities[] = array('id' => $id, 'type' => $entity_type);
+ }
+ }
+ }
+ // END OPTIMIZED WAY
+ }
+
+ // subtract all entities specifically *not* set to the given profile
+ $query = db_select('lingotek_entity_metadata', 'lem')
+ ->fields('lem', array('entity_id', 'entity_type'))
+ ->condition('lem.entity_key', 'profile')
+ ->condition('lem.value', $this->getId(), '!=')
+ ->condition('lem.entity_type', $entity_type);
+ $result = $query->execute();
+ $subtract_entity_ids = $result->fetchAll();
+
+ $doc_ids = lingotek_get_document_id_tree();
+ $subtractions = array();
+ foreach ($subtract_entity_ids as $sei) {
+ if (!isset($subtractions[$sei->entity_type])) {
+ $subtractions[$sei->entity_type] = array();
+ }
+ $subtractions[$sei->entity_type][$sei->entity_id] = TRUE;
+ }
+ $filtered_entities = array();
+ foreach ($entities as $e) {
+ if (!isset($subtractions[$e['type']][$e['id']])) {
+ if (isset($doc_ids[$e['type']][$e['id']])) {
+ $e['document_id'] = $doc_ids[$e['type']][$e['id']];
+ }
+ $filtered_entities[$e['id']] = $e;
+ }
+ }
+
+ // add all entities specifically set to the given profile
+ $query = db_select('lingotek_entity_metadata', 'lem')
+ ->fields('lem', array('entity_id', 'entity_type'))
+ ->condition('lem.entity_key', 'profile')
+ ->condition('lem.value', $this->getId());
+ if ($entity_type != 'all') {
+ $query->condition('lem.entity_type', $entity_type);
+ }
+ $result = $query->execute();
+ $add_entity_ids = $result->fetchAll();
+ foreach ($add_entity_ids as $aei) {
+ $addition = array('id' => $aei->entity_id, 'type' => $aei->entity_type);
+ if (isset($doc_ids[$aei->entity_type][$aei->entity_id])) {
+ $addition['document_id'] = $doc_ids[$aei->entity_type][$aei->entity_id];
+ }
+ $filtered_entities[$aei->entity_id] = $addition;
+ }
+ return $filtered_entities;
+ }
+ else { // GATHER LIST OF ENTITIES AND RECURSE
+
+ // gather all bundles for searching, as some entities may be one-offs
+ // even though Lingotek is not enabled for the entire bundle.
+ self::$profiles[LingotekSync::PROFILE_DISABLED] = TRUE;
+ // TODO: CREATE SOME KIND OF FOREACH LOOP
+ $all_bundles = lingotek_get_bundles_by_profile_id(array_keys(self::$profiles));
+ $all_entities = array();
+ // aggregate all entity-type-specific results into a single numbered array
+ foreach (array_keys($all_bundles) as $entity_type) {
+ $entities = $this->getEntities($entity_type);
+ foreach ($entities as $e) {
+ $all_entities[] = $e;
+ }
+ }
+ return $all_entities;
+ }
+ }
+
+ public function save() {
+ if ($this->getId() !== LingotekSync::PROFILE_DISABLED && $this->getId() !== LingotekSync::PROFILE_ENABLED) {
+ variable_set('lingotek_profiles', self::$profiles);
+ }
+ }
+
+ public function refresh() {
+ self::$profiles = variable_get('lingotek_profiles', array());
+ }
+
+ public function delete() {
+ if (!$this->isProtected()) {
+ if ($this->getEntities()) {
+ throw new LingotekException('Unable to delete profile "@name": profile not empty.', array('@name' => $this->getName()));
+ }
+ unset(self::$profiles[$this->getId()]);
+ variable_set('lingotek_profiles', self::$profiles);
+ }
+ }
+
+ public function getName() {
+ return $this->getAttribute('name');
+ }
+
+ public function setName($profile_name) {
+ $this->setAttribute('name', $profile_name);
+ }
+
+ public function isAutoDownload($target_locale = NULL) {
+ return $this->getAttribute('auto_download', $target_locale);
+ }
+
+ public function setAutoDownload($active, $target_locale = NULL) {
+ // Make sure only TRUE or FALSE is saved.
+ $active = (bool) $active;
+ $this->setAttribute('auto_download', $active, $target_locale);
+ }
+
+ public function isNodeBased() {
+ $node_based = $this->getAttribute('lingotek_nodes_translation_method');
+ if ($node_based == 'node') {
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ public function setNodeBased($active) {
+ if ($active) {
+ $this->setAttribute('lingotek_nodes_translation_method', 'node');
+ }
+ else {
+ $this->deleteAttribute('lingotek_nodes_translation_method');
+ }
+ }
+
+ public function getWorkflow($target_locale = NULL) {
+ return $this->getAttribute('workflow_id', $target_locale);
+ }
+
+ public function setWorkflow($workflow_id, $target_locale = NULL) {
+ return $this->setAttribute('workflow_id', $workflow_id, $target_locale);
+ }
+
+ public function getProjectId() {
+ return $this->getAttribute('project_id');
+ }
+
+ public function setProjectId($project_id) {
+ $this->setAttribute('project_id', $project_id);
+ }
+
+ public function disableTargetLocale($target_locale) {
+ $this->deleteTargetLocaleOverrides($target_locale);
+ $this->setAttribute('disabled', TRUE, $target_locale);
+ }
+
+ public function isTargetLocaleDisabled($target_locale) {
+ // don't check for disabled attributes in the parent profiles
+ $this->setInherit(FALSE);
+ $disabled = FALSE;
+ if ($this->getAttribute('disabled', $target_locale)) {
+ $disabled = TRUE;
+ }
+ $this->setInherit(TRUE);
+ return $disabled;
+ }
+
+ public function isTargetLocaleCustom($target_locale) {
+ return !$this->isTargetLocaleDisabled($target_locale) && $this->getTargetLocaleOverrides($target_locale);
+ }
+
+ public function toArray() {
+ return array_merge(self::$global_profile, $this->profile);
+ }
+
+ protected function initTargetLocaleOverride($target_locale) {
+ if (!isset($this->profile['target_language_overrides'][$target_locale])) {
+ $this->profile['target_language_overrides'][$target_locale] = array();
+ }
+ }
+
+ public function getAttribute($attrib_name, $target_locale = NULL) {
+ if (!empty($target_locale) && isset($this->profile['target_language_overrides'][$target_locale][$attrib_name])) {
+ return $this->profile['target_language_overrides'][$target_locale][$attrib_name];
+ }
+ elseif ($this->lookForInherited()) {
+ if (!empty($this->profile[$attrib_name])) {
+ return $this->profile[$attrib_name];
+ }
+ elseif (!empty(self::$global_profile[$attrib_name])) {
+ return self::$global_profile[$attrib_name];
+ }
+ }
+ return NULL;
+ }
+
+ public function setAttribute($attrib_name, $value, $target_locale = NULL) {
+
+ if ($this->isProtectedAttribute($attrib_name)) {
+ return;
+ }
+
+ $original_value = $this->getAttribute($attrib_name, $value);
+
+ if ($target_locale) {
+ // Set the language-specific attribute if different from the base attribute
+ if ($value !== $original_value) {
+ $this->initTargetLocaleOverride($target_locale);
+ $this->profile['target_language_overrides'][$target_locale][$attrib_name] = $value;
+ }
+ else {
+ $this->deleteAttribute($attrib_name, $target_locale);
+ // Clean up any empty language overrides
+ if (empty($this->profile['target_language_overrides'][$target_locale])) {
+ unset($this->profile['target_language_overrides'][$target_locale]);
+ }
+ }
+ }
+ else {
+ // Set the base attribute if different from the global attribute
+ if (isset(self::$global_profile[$attrib_name])) {
+ $original_value = self::$global_profile[$attrib_name];
+ }
+ if ($value !== $original_value) {
+ $this->profile[$attrib_name] = $value;
+ }
+ else {
+ $this->deleteAttribute($attrib_name);
+ }
+ }
+ // Clean up target language attribute if empty
+ if (empty($this->profile['target_language_overrides'])) {
+ unset($this->profile['target_language_overrides']);
+ }
+ $this->save();
+ }
+
+ public function deleteAttribute($attrib_name, $target_locale = NULL) {
+ if ($target_locale) {
+ if (isset($this->profile['target_language_overrides'][$target_locale][$attrib_name])) {
+ unset($this->profile['target_language_overrides'][$target_locale][$attrib_name]);
+ $this->save();
+ }
+ }
+ else {
+ if (isset($this->profile[$attrib_name])) {
+ unset($this->profile[$attrib_name]);
+ $this->save();
+ }
+ }
+ }
+
+ public function deleteTargetLocaleOverrides($target_locale) {
+ unset($this->profile['target_language_overrides'][$target_locale]);
+ $this->save();
+ }
+
+ public function getTargetLocaleOverrides($target_locale) {
+ if (!empty($this->profile['target_language_overrides'][$target_locale])) {
+ return $this->profile['target_language_overrides'][$target_locale];
+ }
+ return array();
+ }
+
+ public function getAttributes($target_locale = NULL) {
+ if ($this->getId() == LingotekSync::PROFILE_DISABLED) {
+ return array(
+ 'name' => LingotekSync::PROFILE_DISABLED,
+ 'profile' => LingotekSync::PROFILE_DISABLED,
+ );
+ }
+ if ($this->getId() == LingotekSync::PROFILE_ENABLED) {
+ return array(
+ 'name' => LingotekSync::PROFILE_ENABLED,
+ 'profile' => LingotekSync::PROFILE_ENABLED,
+ );
+ }
+ if (empty(self::$profiles[$this->getId()])) {
+ drupal_set_message(t('Lingotek profile ID @profile_id not found.', array('@profile_id' => $this->getId())), 'error', FALSE);
+
+ //throw new LingotekException('Profile ID "' . $this->getId() . '" not found.');
+ }
+ if ($target_locale) {
+ $attributes = $this->getTargetLocaleOverrides($target_locale);
+ if ($this->lookForInherited()) {
+ $attributes = array_merge(self::$profiles[$this->getId()], $attributes);
+ }
+ }
+ elseif (!empty(self::$profiles[$this->getId()])) {
+ $attributes = self::$profiles[$this->getId()];
+ }
+ else {
+ $attributes = array();
+ }
+ return array_merge(self::$global_profile, $attributes);
+ }
+
+ public function filterTargetLocales($available_locales) {
+ $filtered_locales = array();
+ $default_workflow = $this->getWorkflow();
+ // foreach locale, get the overrides
+ foreach ($available_locales as $locale) {
+ if ($this->isTargetLocaleDisabled($locale)) {
+ // filter this out.
+ }
+ elseif ($this->isTargetLocaleCustom($locale)) {
+ $filtered_locales[$locale] = $this->getTargetLocaleOverrides($locale);
+ }
+ else {
+ $filtered_locales[$locale] = TRUE;
+ }
+ }
+ return $filtered_locales;
+ }
+
+ protected function isProtected() {
+ $locked_profiles = array(
+ LingotekSync::PROFILE_DISABLED,
+ LingotekSync::PROFILE_AUTOMATIC,
+ LingotekSync::PROFILE_MANUAL
+ );
+ if (in_array($this->getId(), $locked_profiles)) {
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ protected function isProtectedAttribute($attrib_name) {
+ $locked_attribs = array(
+ 0 => array('auto_upload', 'auto_download'),
+ 1 => array('auto_upload', 'auto_download'),
+ );
+ if (array_key_exists($this->getId(), $locked_attribs) && in_array($attrib_name, $locked_attribs[$this->getId()])) {
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekProfileManager.php b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekProfileManager.php
new file mode 100644
index 00000000..8fbc8360
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekProfileManager.php
@@ -0,0 +1,37 @@
+ 'Automatic',
+ 'auto_upload' => 1,
+ 'auto_download' => 1,
+ );
+ self::$profiles[] = array(
+ 'name' => 'Manual',
+ 'auto_upload' => 0,
+ 'auto_download' => 0,
+ );
+ variable_set('lingotek_profiles', self::$profiles);
+ }
+ return self::$profiles;
+ }
+
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekSync.php b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekSync.php
index 962c88a2..0d8d618d 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekSync.php
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekSync.php
@@ -10,22 +10,35 @@
*/
class LingotekSync {
- const STATUS_CURRENT = 'CURRENT'; // The node or target translation is current
+ const STATUS_NONE = 'NONE';
const STATUS_EDITED = 'EDITED'; // The node has been edited, but has not been uploaded to Lingotek
- const STATUS_FAILED = 'FAILED'; // The node or target translation has failed during processing
+ const STATUS_CURRENT = 'CURRENT'; // The node or target translation is current
+ const STATUS_ERROR = 'ERROR';
const STATUS_PENDING = 'PENDING'; // The target translation is awaiting to receive updated content from Lingotek
const STATUS_READY = 'READY'; // The target translation is complete and ready for download
+ const STATUS_INTERIM = 'INTERIM'; // Part of the target translation is done and ready for download what has been done
+ const STATUS_READY_INTERIM = 'READY_INTERIM';
const STATUS_TARGET = 'TARGET'; // A target node is being used to store a translation (ignored for upload by Lingotek)
const STATUS_UNTRACKED = 'UNTRACKED'; // A translation was discovered that is not currently managed by Lingotek
const STATUS_TARGET_LOCALIZE = 'TARGET_LOCALIZE'; // A localization must be made of the source before uploading to Lingotek
const STATUS_TARGET_EDITED = 'TARGET_EDITED'; // A localized version is ready for uploading to Lingotek
const STATUS_NON_LINGOTEK = 'NON_LINGOTEK'; // Translations exist but the translation_agent_id != 3 (Not owned by Lingotek)
+ const STATUS_DELETED = 'DELETED'; // Entity was translated but was afterward deleted
const PROFILE_CUSTOM = 'CUSTOM';
const PROFILE_DISABLED = 'DISABLED';
+ const PROFILE_ENABLED = 'ENABLED';
const PROFILE_CONFIG = 'CONFIG';
const PROFILE_AUTOMATIC = 0;
const PROFILE_MANUAL = 1;
+ const PROFILE_INHERIT = 'INHERIT';
+ const MARKED = 1;
+ const NOT_MARKED = 0;
+ const INVALID_XML_PRESENT = 1;
+ const TRANSLATION_AGENT_ID_UNKNOWN = 1;
+ const TRANSLATION_AGENT_ID_DRUPAL = 2;
+ const TRANSLATION_AGENT_ID_LINGOTEK = 3;
+ const MARKED_OFFSET = 1000000000;
public static function getTargetStatus($doc_id, $lingotek_locale) {
$key = 'target_sync_status_' . $lingotek_locale;
@@ -39,14 +52,39 @@ public static function getTargetStatus($doc_id, $lingotek_locale) {
LingotekLog::error('Did not find any local info for Lingotek Doc ID "@id"', array('@id' => $doc_id));
return FALSE;
}
+ public static function getAllTargetStatusForEntity($entity_type, $entity_id, $lingotek_locale = NULL) {
+ $dbkey = 'target_sync_status_';
+ $query = db_select('lingotek_entity_metadata', 'l')
+ ->fields('l', array('entity_key', 'value'))
+ ->condition('entity_type', $entity_type)
+ ->condition('entity_id', $entity_id);
+ if ($lingotek_locale !== NULL) {
+ $query->condition('entity_key', $dbkey . $lingotek_locale);
+ }
+ else {
+ $query->condition('entity_key', $dbkey . '%', 'LIKE');
+ }
+ $result = $query->execute()->fetchAll();
+ $targets = array();
+ foreach ($result as $r_obj) {
+ // get the locale of each result
+ $locale = substr($r_obj->entity_key, strlen($dbkey));
+ // assign the status for that locale
+ $targets[$locale] = $r_obj->value;
+ }
+ return $targets;
+ }
public static function getTargetStatusOptions() {
return array(
+ 'STATUS_NONE' => self::STATUS_NONE,
'STATUS_CURRENT' => self::STATUS_CURRENT,
'STATUS_EDITED' => self::STATUS_EDITED,
- 'STATUS_FAILED' => self::STATUS_FAILED,
+ 'STATUS_ERROR' => self::STATUS_ERROR,
'STATUS_PENDING' => self::STATUS_PENDING,
'STATUS_READY' => self::STATUS_READY,
+ 'STATUS_READY_INTERIM' => self::STATUS_READY_INTERIM,
+ 'STATUS_INTERIM' => self::STATUS_INTERIM,
'STATUS_TARGET' => self::STATUS_TARGET,
'STATUS_UNTRACKED' => self::STATUS_UNTRACKED,
'STATUS_TARGET_LOCALIZE' => self::STATUS_TARGET_LOCALIZE,
@@ -69,18 +107,75 @@ public static function setTargetStatus($entity_type, $entity_id, $lingotek_local
$key = 'target_sync_status_' . $lingotek_locale;
return lingotek_keystore($entity_type, $entity_id, $key, $status, $update_on_dup);
}
-
+
public static function setAllTargetStatus($entity_type, $entity_id, $status) {
+ if($entity_type === 'config'){
+ $query = db_update('lingotek_config_metadata')
+ ->condition('id', $entity_id, "=")
+ ->condition('config_key', 'target_sync_status%', 'LIKE')
+ ->fields(array('value' => $status, 'modified' => time()))
+ ->execute();
+ return;
+ }
+ $query = db_update('lingotek_entity_metadata')
+ ->condition('entity_type', $entity_type)
+ ->condition('entity_id', $entity_id)
+ ->condition('entity_key', 'target_sync_status%', 'LIKE')
+ ->fields(array('value' => $status, 'modified' => time()))
+ ->execute();
+ lingotek_cache_clear($entity_type, $entity_id);
+ }
+
+ public static function bulkSetAllTargetStatus($entity_type, $entity_ids, $status){
+ if($entity_type === 'config'){
+ $query = db_update('lingotek_config_metadata')
+ ->condition('id', $entity_ids, "IN")
+ ->condition('config_key', 'target_sync_status%', 'LIKE')
+ ->fields(array('value' => $status, 'modified' => time()))
+ ->execute();
+ return;
+ }
$query = db_update('lingotek_entity_metadata')
->condition('entity_type', $entity_type)
- ->condition('entity_id', $entity_id)
- ->condition('entity_key', 'target_sync_status%', 'LIKE')
- ->fields(array('value' => $status, 'modified' => time()))
+ ->condition('entity_id', $entity_ids, "IN")
+ ->condition('entity_key', 'target_sync_status%', 'LIKE')
+ ->fields(array('value' => $status, 'modified' => time()))
->execute();
+ foreach ($entity_ids as $eid) {
+ lingotek_cache_clear($entity_type, $eid);
+ }
+ }
+
+ public static function setUploadStatus($entity_type, $entity_id, $status) {
+ return lingotek_keystore($entity_type, $entity_id, 'upload_status', $status);
}
- public static function setNodeStatus($node_id, $status) {
- return lingotek_keystore('node', $node_id, 'upload_status', $status);
+ public static function setAllUploadStatuses($entity_type, $entity_ids, $status) {
+ foreach ($entity_ids as $entity_id) {
+ $query = db_update('lingotek_entity_metadata')
+ ->condition('entity_id', $entity_id)
+ ->condition('entity_type', $entity_type)
+ ->condition('entity_key', 'upload_status')
+ ->fields(array('value' => $status, 'modified' => time()))
+ ->execute();
+ }
+ }
+
+ public static function setUploadStatuses($entity_type, $entity_ids, $status) {
+ foreach($entity_ids as $entity_id) {
+ return lingotek_keystore($entity_type, $entity_id, 'upload_status', $status);
+ }
+ }
+
+ public static function getUploadStatus($entity_type, $entity_id) {
+ $query = db_select('lingotek_entity_metadata', 'lem')
+ ->fields('lem', array('value'))
+ ->condition('lem.entity_id', $entity_id)
+ ->condition('lem.entity_type', $entity_type)
+ ->condition('lem.entity_key', 'upload_status');
+ $upload_status = $query->execute()->fetchField();
+
+ return $upload_status;
}
public static function getSyncProjects() {
@@ -114,10 +209,53 @@ public static function insertTargetEntriesForAllSets($lingotek_locale) {
}
public static function insertTargetEntriesForAllEntities($lingotek_locale) {
+ //this prevents a target from being added to the same source
+ $locale = strtolower(str_replace("_", "-", $lingotek_locale));
+ $node_source_check = db_select('node', 'n');
+ $node_source_check->addField('n', 'nid');
+ $or = db_or()->condition('n.tnid','0')->where('n.tnid = n.nid');
+ $node_source_check->condition($or);
+ $node_source_check->condition('n.language', $locale);
+
+ $taxonomy_source_check = db_select('taxonomy_term_data', 't');
+ $taxonomy_source_check->addField('t', 'tid');
+ $taxonomy_source_check->condition('t.language', $locale);
+
// insert/update a target language for all entities
$query = db_select('lingotek_entity_metadata', 'meta')
->fields('meta', array('entity_id', 'entity_type'))
- ->condition('meta.entity_key', 'document_id');
+ ->condition('meta.entity_key', 'document_id')
+ ->condition('entity_id', $node_source_check, "NOT IN")
+ ->condition('entity_id', $taxonomy_source_check, "NOT IN");
+
+ if (module_exists('comment')) {
+ $comment_source_check = db_select('comment', 'c');
+ $comment_source_check->addField('c', 'cid');
+ $comment_source_check->condition('c.language', $locale);
+ $query->condition('entity_id', $comment_source_check, "NOT IN");
+ }
+
+ if (module_exists('bean') && variable_get('lingotek_translate_beans')) {
+ $bean_source_check = db_select('bean', 'b');
+ $bean_source_check->addField('b', 'bid');
+ $bean_source_check->condition('b.language', $locale);
+ $query->condition('entity_id', $bean_source_check, "NOT IN");
+ }
+
+ if (module_exists('group') && variable_get('lingotek_translate_groups')) {
+ $group_source_check = db_select('groups', 'g');
+ $group_source_check->addField('g', 'gid');
+ $group_source_check->condition('g.language', $locale);
+ $query->condition('entity_id', $group_source_check, "NOT IN");
+ }
+
+ if (module_exists('file_entity') && variable_get('lingotek_translate_files')) {
+ $file_source_check = db_select('file_managed', 'fm');
+ $file_source_check->addField('fm', 'fid');
+ $file_source_check->condition('fm.language', $locale);
+ $query->condition('entity_id', $file_source_check, "NOT IN");
+ }
+
$entities = $query->execute()->fetchAll();
foreach ($entities as $e) {
@@ -125,6 +263,19 @@ public static function insertTargetEntriesForAllEntities($lingotek_locale) {
}
}
+ public static function delete_entity_from_metadata($entity_type, $entity_id) {
+ db_delete('lingotek_entity_metadata')
+ ->condition('entity_type', $entity_type)
+ ->condition('entity_id', $entity_id)
+ ->execute();
+ lingotek_cache_clear($entity_type, $entity_id);
+ }
+
+ public static function deleteTargetStatus($entity_type, $entity_id, $lingotek_locale) {
+ $key = 'target_sync_status_' . $lingotek_locale;
+ return lingotek_keystore_delete($entity_type, $entity_id, $key);
+ }
+
// Remove the node sync target language entries from the lingotek table lingotek_delete_target_sync_status_for_all_nodes
public static function deleteTargetEntriesForAllEntities($lingotek_locale) {
$keys = array(
@@ -141,23 +292,28 @@ public static function deleteTargetEntriesForAllChunks($lingotek_locale) {
public static function deleteTargetEntriesForAllDocs($lingotek_locale) {
self::deleteTargetEntriesForAllEntities($lingotek_locale);
self::deleteTargetEntriesForAllChunks($lingotek_locale);
+ lingotek_cache_clear();
}
-
-
+
+
/**
* getDocIdTargetsByStatus
- *
+ *
* @param status (e.g., LingotekSync::READY)
- *
+ *
* @return an array of associate arrays. Each associate array will have a 'nid' (e.g., 5), 'locale' (e.g., 'de_DE'), and optionally 'doc_id' (e.g., 46677222-b5ec-47d5-880e-24632feffaf5)
*/
- public static function getTargetsByStatus($entity_type, $status, $include_doc_ids = FALSE) {
+ public static function getTargetsByStatuses($entity_type, $statuses=array(), $include_doc_ids = FALSE) {
$target_language_search = '%';
$query = db_select('lingotek_entity_metadata', 'l');
$query->fields('l', array('entity_id', 'entity_key', 'value'));
$query->condition('entity_type', $entity_type);
$query->condition('entity_key', 'target_sync_status_' . $target_language_search, 'LIKE');
- $query->condition('value', $status);
+ $or = db_or();
+ foreach($statuses as $status){
+ $or->condition('value', $status);
+ }
+ $query->condition($or);
$result = $query->execute();
$records = $result->fetchAll(); //$result->fetchAllAssoc('nid');
@@ -294,8 +450,24 @@ public static function getEntitySourceCount($lingotek_locale, $entity_type = NUL
$query->condition($tnid_query);
}
+ // Exclude translation sets for menu_links
+ if ($entity_base_table == 'menu_links') {
+ $min_query = db_select('menu_links', 'ml')
+ ->condition('ml.i18n_tsid', 0, '!=')
+ ->groupBy('i18n_tsid');
+ $min_query->addExpression('MIN(mlid)', 'minimum');
+
+ $ml_or = db_or();
+ $ml_or->condition('t.i18n_tsid', 0);
+ $ml_or->condition('t.mlid', $min_query, 'IN');
+
+ $query->condition('t.language', LANGUAGE_NONE, '!=');
+ $query->condition($ml_or);
+ }
+
// exclude disabled entities (including those that have disabled bundles)
- $disabled_entities = lingotek_get_entities_by_profile_and_entity_type(LingotekSync::PROFILE_DISABLED, $entity_type);
+ $disabled_profile = LingotekProfile::loadById(LingotekSync::PROFILE_DISABLED);
+ $disabled_entities = $disabled_profile->getEntities($entity_type);
if (count($disabled_entities)) {
$disabled_entity_ids = array();
array_walk($disabled_entities, function($a) use (&$disabled_entity_ids) {
@@ -371,7 +543,8 @@ public static function getEntityTargetCountByStatus($status, $lingotek_locale, $
}
// exclude disabled nodes (including those that have disabled bundles)
- $disabled_entities = lingotek_get_entities_by_profile_and_entity_type(LingotekSync::PROFILE_DISABLED, $entity_base_table);
+ $disabled_profile = LingotekProfile::loadById(LingotekSync::PROFILE_DISABLED);
+ $disabled_entities = $disabled_profile->getEntities($entity_base_table);
if (!empty($disabled_entities)) {
$disabled_entity_ids = array();
array_walk($disabled_entities, function($a) use (&$disabled_entity_ids) {
@@ -381,6 +554,12 @@ public static function getEntityTargetCountByStatus($status, $lingotek_locale, $
}
$query->condition('l.value', $status, 'IN');
+
+ // exclude orphaned targets (targets whose source language has been deleted)
+ if (db_field_exists($entity_base_table, 'language')) {
+ $query->condition('t.language', '', '!=');
+ }
+
$count = $query->countQuery()->execute()->fetchField();
$total_count += $count;
}
@@ -476,7 +655,7 @@ public static function getTargetCountByDocumentIds($document_ids) {
}
public static function getETNodeIds() { // get nids for entity_translation nodes that are not lingotek pushed
- $types = lingotek_translatable_node_types(); // get all translatable node types
+ $types = lingotek_translatable_node_types(); // get all translatable node types
$et_content_types = array();
foreach ($types as $type) {
if (lingotek_managed_by_entity_translation($type)) { // test if lingotek_managed_by_entity_translation
@@ -641,13 +820,22 @@ public static function getNodeIdsByStatus($status, $source) {
return $nids;
}
- public static function getEntityIdsToUpload($entity_type) {
+ public static function getEntityIdsToUpload($entity_type, $entity_ids = null) {
$info = entity_get_info($entity_type);
$id_key = $info['entity keys']['id'];
$query = db_select($info['base table'], 'base');
$query->addField('base', $id_key);
$query->leftJoin('lingotek_entity_metadata', 'upload', 'upload.entity_id = base.' . $id_key . ' and upload.entity_type =\'' . $entity_type . '\' and upload.entity_key = \'upload_status\'');
+ $query2 = db_select('lingotek_entity_metadata', 'lem');
+ $query2->distinct();
+ $query2->addField('lem', 'entity_id');
+ $query2->condition('entity_key', 'profile');
+ $query2->condition('entity_type', $entity_type);
+ $query2->condition('value', 'DISABLED');
+
+ $query->condition('upload.entity_id', $query2, 'NOT IN');
+
if ($entity_type == 'node') {
// Exclude any target nodes created using node-based translation.
$tnid_query = db_or();
@@ -660,7 +848,9 @@ public static function getEntityIdsToUpload($entity_type) {
$or->condition('upload.value', LingotekSync::STATUS_EDITED);
$or->isNull('upload.value');
$query->condition($or);
-
+ if($entity_ids !== null){
+ $query->condition('upload.entity_id', $entity_ids, 'IN');
+ }
$result = $query->execute()->fetchCol();
return $result;
}
@@ -682,7 +872,7 @@ public static function getConfigSetIdsToUpload() {
* a string containing the desired status
* @param $locales
* (optional) an array containing the locales to check
- *
+ *
* @return an array of IDs
*/
public static function getEntityIdsByTargetStatus($entity_type, $status, $locales = NULL) {
@@ -707,6 +897,33 @@ public static function getEntityIdsByTargetStatus($entity_type, $status, $locale
return $result;
}
+ public static function getEntityIdsByStatuses($entity_type, $statuses = array(), $locales = NULL) {
+ if ($locales === NULL) {
+ $verb = 'LIKE';
+ $target_locales = 'target_sync_status_%';
+ }
+ else {
+ $verb = 'IN';
+ $target_locales = array();
+ foreach ($locales as $l) {
+ $target_locales[] = 'target_sync_status_' . $l;
+ }
+ }
+ $or = db_or();
+ foreach($statuses as $status){
+ $or->condition('value', $status);
+ }
+ $query = db_select('lingotek_entity_metadata', 'l')
+ ->distinct()
+ ->condition('entity_type', $entity_type)
+ ->condition('entity_key', $target_locales, $verb)
+ ->condition($or)
+ ->condition('value', LingotekSync::PROFILE_DISABLED, '<>');
+ $query->addField('l', 'entity_id', 'nid');
+ $result = $query->execute()->fetchCol();
+ return $result;
+ }
+
public static function getEntityIdsByProfileStatus($entity_type, $status) {
$query = db_select('lingotek_entity_metadata', 'l')
->distinct()
@@ -718,6 +935,17 @@ public static function getEntityIdsByProfileStatus($entity_type, $status) {
return $result;
}
+ public static function getProfileByEntityId($entity_type, $entity_id) {
+ $query = db_select('lingotek_entity_metadata', 'lem')
+ ->fields('lem', array('value'))
+ ->condition('lem.entity_id', $entity_id)
+ ->condition('lem.entity_type', $entity_type)
+ ->condition('lem.entity_key', 'profile');
+ $profile = $query->execute()->fetchField();
+
+ return $profile;
+ }
+
public static function getConfigDocIdsByStatus($status) {
$doc_ids = array();
@@ -750,6 +978,9 @@ public static function getSetIdsFromLids($lids) {
}
public static function getConfigDocIdsFromSetIds($sids) {
+ if (empty($sids)) {
+ return $sids;
+ }
$query = db_select('lingotek_config_metadata', 'l');
$query->addField('l', 'value');
$query->condition('id', $sids, 'IN');
@@ -759,6 +990,44 @@ public static function getConfigDocIdsFromSetIds($sids) {
return $doc_ids;
}
+ public static function updateConfigSetWorkflow($set_id, $workflow_id){
+ $insertRecord = array(
+ "value" => $workflow_id,
+ "created" => time(),
+ "modified" => time(),
+ "id" => $set_id,
+ "config_key" => 'workflow_id'
+ );
+ $updateRecord = array(
+ "value" => $workflow_id,
+ "modified" => time()
+ );
+ db_merge('lingotek_config_metadata')
+ ->key(array('id' => $set_id, 'config_key' => 'workflow_id'))
+ ->insertFields($insertRecord)
+ ->updateFields($updateRecord)
+ ->execute();
+// drupal_write_record('lingotek_config_metadata', $record);
+ }
+
+ public static function getWorkflowIdFromConfigSet($sid){
+ $query = db_select('lingotek_config_metadata', 'lcm');
+ $query->addField('lcm', 'value');
+ $query->condition('id', $sid, '=');
+ return $query->execute()->fetchCol();
+ }
+
+ public static function getWorkflowIdFromEntityId($id) {
+ $query = db_select('lingotek_entity_metadata', 'lem');
+ $query->addField('lem', 'value');
+ $query->condition('entity_key', 'workflow_id', '=');
+ $query->condition('entity_id', $id, '=');
+
+ $result = $query->execute()->fetchCol();
+
+ return $result[0];
+ }
+
public static function getChunkIdsByStatus($status) {
$query = db_select('lingotek_config_metadata', 'meta');
$query->fields('meta', array('id'));
@@ -772,6 +1041,7 @@ public static function getChunkIdsByStatus($status) {
public static function disassociateAllEntities() {
db_truncate('lingotek_entity_metadata')->execute();
+ lingotek_cache_clear();
}
public static function disassociateAllSets() {
@@ -782,8 +1052,9 @@ public static function disassociateEntities($document_ids = array()) {
$eids = self::getNodeIdsFromDocIds($document_ids);
db_delete('lingotek_entity_metadata')
->condition('entity_type', 'node')
- ->condition('entity_id', $eids, 'IN')
- ->execute();
+ ->condition('entity_id', $eids, 'IN')
+ ->execute();
+ lingotek_cache_clear('node');
}
public static function getAllLocalDocIds() {
@@ -827,10 +1098,10 @@ public static function getEntityIdFromDocId($lingotek_document_id, $entity_type
$query->condition('entity_key', $key);
$query->condition('value', $lingotek_document_id);
$result = $query->execute();
-
+
$found = FALSE;
$type = FALSE;
-
+
if ($record = $result->fetchAssoc()) {
$found = $record['entity_id'];
$type = $record['entity_type'];
@@ -838,7 +1109,7 @@ public static function getEntityIdFromDocId($lingotek_document_id, $entity_type
return array($found, $type);
}
-
+
public static function getNodeIdFromDocId($lingotek_document_id) {
list($id, $type) = LingotekSync::getEntityIdFromDocId($lingotek_document_id);
return array($id, $type);
@@ -858,7 +1129,7 @@ public static function getNodeIdsFromDocIds($lingotek_document_ids) {
public static function getDocIdFromNodeId($drupal_node_id) {
return getDocIdFromEntityId('node', $drupal_node_id);
}
-
+
public static function getDocIdFromEntityId($entity_type, $entity_id) {
$found = FALSE;
@@ -942,10 +1213,108 @@ public static function updateNotifyUrl() {
if ($success) {
variable_set('lingotek_notify_url', $new_url);
variable_set('lingotek_notify_security_token', $security_token);
+ if (strpos($new_url,'localhost') !== false) {
+ $success = 'localhost_url';
+ }
}
return $success;
}
-}
+ public static function getMenuLinkTargetStatus($mlid, $lingotek_locale) {
+ $key = 'target_sync_status_' . $lingotek_locale;
+ $status = lingotek_keystore('menu_link', $mlid, $key);
+
+ if ($status) {
+ return $status;
+ }
+ else {
+ LingotekLog::error('Did not find any targets for menu link "@id"', array('@id' => $mlid));
+ return FALSE;
+ }
+ }
-?>
+ public static function getDocumentId($entity_type, $entity_id) {
+ $doc_id = db_select('lingotek_entity_metadata', 'lem')
+ ->fields('lem', array('value'))
+ ->condition('lem.entity_type', $entity_type)
+ ->condition('lem.entity_id', $entity_id)
+ ->condition('lem.entity_key', 'document_id')
+ ->execute()
+ ->fetch(PDO::FETCH_ASSOC);
+
+ if ($doc_id) {
+ return $doc_id;
+ }
+ else {
+ return FALSE;
+ }
+ }
+
+ public static function setLastSyncError($entity_type, $entity_id, $error) {
+ lingotek_keystore($entity_type, $entity_id, 'last_sync_error', $error);
+ }
+
+ public static function getLastSyncError($entity_type, $entity_id) {
+ $error = '';
+ $query = db_select('lingotek_entity_metadata', 'lem')
+ ->fields('lem', array('value'))
+ ->condition('lem.entity_id', $entity_id)
+ ->condition('lem.entity_type', $entity_type)
+ ->condition('lem.entity_key', 'last_sync_error');
+ $last_sync_error = $query->execute()->fetchField();
+
+ return $last_sync_error;
+ }
+
+ public static function deleteLastSyncError($entity_type, $entity_id) {
+ lingotek_keystore_delete($entity_type, $entity_id, 'last_sync_error');
+ }
+
+ public static function updateLingotekTranslationAgentId($lids, $agent_id) {
+ $query = db_update('locales_target')
+ ->condition('lid', $lids, "IN")
+ ->fields(array('translation_agent_id' => $agent_id))
+ ->execute();
+ }
+
+ /**
+ * Sets a Lingotek metadata value for this item.
+ * @param int $lid
+ * The lid for the config item.
+ * @param int $marked_offset
+ * Integer space reserved for marked value
+ */
+ public static function setConfigMarkedValue($lid, $marked_offset) {
+ $insertRecord = array(
+ "value" => $lid,
+ "created" => time(),
+ "modified" => time(),
+ "id" => $marked_offset,
+ "config_key" => 'marked'
+ );
+ $updateRecord = array(
+ "value" => $lid,
+ "modified" => time()
+ );
+ db_merge('lingotek_config_metadata')
+ ->key(array('id' => $marked_offset, 'config_key' => 'marked'))
+ ->insertFields($insertRecord)
+ ->updateFields($updateRecord)
+ ->execute();
+ }
+
+ /**
+ * Deletes a Lingotek metadata value for this item.
+ * @param int $lid
+ * The lid for the config item.
+ * @param string $marked_offset
+ * Integer space reserved for marked value.
+ */
+ public static function deleteConfigMarkedValue($lid, $marked_offset) {
+ db_delete('lingotek_config_metadata')
+ ->condition('id', $marked_offset)
+ ->condition('config_key', 'marked')
+ ->condition('value', $lid)
+ ->execute();
+ }
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekTranslatableEntity.php b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekTranslatableEntity.php
index 34bd8baa..af3aa4a6 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekTranslatableEntity.php
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekTranslatableEntity.php
@@ -98,7 +98,7 @@ public function setTitle($title);
public function setStatus($status);
- public function setTargetsStatus($status);
+ public function setTargetsStatus($status, $lingotek_locale = NULL);
/*
* Returns the source locale for the translatable entity
*/
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekXMLElement.php b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekXMLElement.php
new file mode 100644
index 00000000..32159535
--- /dev/null
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/Drupal/lingotek/LingotekXMLElement.php
@@ -0,0 +1,46 @@
+ownerDocument;
+ $xml->appendChild($doc->createCDATASection($text));
+ }
+
+ /**
+ * Add a SimpleXMLElement object as a child
+ * @param SimpleXMLElement $child
+ * @param type $element_name
+ */
+ public function addChildXML(SimpleXMLElement $child, $element_name = NULL) {
+ if (!$element_name) {
+ $element_name = $child->getName();
+ }
+ $this_child = $this->addChild($element_name);
+ $to_dom = dom_import_simplexml($this_child);
+ $from_dom = dom_import_simplexml($child);
+ foreach ($from_dom->childNodes as $child_element) {
+ $to_dom->appendChild($to_dom->ownerDocument->importNode($child_element, TRUE));
+ }
+ }
+
+ /**
+ * Add a SimpleXMLElement object to this object
+ * @param SimpleXMLElement $xml
+ */
+ public function addXML(SimpleXMLElement $xml) {
+ $to_dom = dom_import_simplexml($this);
+ $from_dom = dom_import_simplexml($xml);
+ foreach ($from_dom->childNodes as $child_element) {
+ $to_dom->appendChild($to_dom->ownerDocument->importNode($child_element, TRUE));
+ }
+ }
+}
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/example/client/googledocs.php b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/example/client/googledocs.php
index 8abac8f0..41c48ca6 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/example/client/googledocs.php
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/example/client/googledocs.php
@@ -73,13 +73,17 @@
}
else {
// STEP 2: Get an access token
- $oauthToken = $_GET["oauth_token"];
+ $oauthToken = check_plain($_GET["oauth_token"]);
// echo "oauth_verifier = '" . $oauthVerifier . "' ";
- $tokenResultParams = $_GET;
+ $params = array();
+ foreach($_GET as $key => $value){
+ $params[$key] = filter_xss($value);
+ }
+ $tokenResultParams = $params;
try {
- LingotekOAuthRequester::requestAccessToken(GOOGLE_CONSUMER_KEY, $oauthToken, 0, 'POST', $_GET);
+ LingotekOAuthRequester::requestAccessToken(GOOGLE_CONSUMER_KEY, $oauthToken, 0, 'POST', $params);
}
catch (OAuthException2 $e)
{
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/example/server/core/init.php b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/example/server/core/init.php
index 602058d8..4841cc81 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/example/server/core/init.php
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/example/server/core/init.php
@@ -112,10 +112,11 @@ function assert_request_vars()
function assert_request_vars_all()
{
foreach($_REQUEST as $row)
- {
+ {
foreach(func_get_args() as $a)
{
- if (!isset($row[$a]))
+ $filtered_row = filter_xss($row[$a]);
+ if ($filtered_row == NULL)
{
header('HTTP/1.1 400 Bad Request');
echo 'Bad request.';
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/example/server/www/logon.php b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/example/server/www/logon.php
index 5c937b71..e22d22b9 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/example/server/www/logon.php
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/example/server/www/logon.php
@@ -40,7 +40,7 @@
$_SESSION['authorized'] = true;
if (!empty($_REQUEST['goto']))
{
- header('Location: ' . $_REQUEST['goto']);
+ header('Location: ' . filter_xss($_REQUEST['goto']));
die;
}
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/example/server/www/register.php b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/example/server/www/register.php
index 0a74297b..7d5602ff 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/example/server/www/register.php
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/example/server/www/register.php
@@ -10,8 +10,12 @@
{
$store = OAuthStore::instance();
$user_id = 1; // this should not be hardcoded, of course
- $key = $store->updateConsumer($_POST, $user_id, true);
-
+ $params = array();
+ foreach ($_POST as $key => $value){
+ $params[$key] = filter_xss($value);
+ }
+ $key = $store->updateConsumer($params, $user_id, true);
+
$c = $store->getConsumer($key, $user_id);
echo 'Your consumer key is: ' . $c['consumer_key'] . ' ';
echo 'Your consumer secret is: ' . $c['consumer_secret'] . ' ';
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/library/LingotekOAuthRequest.php b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/library/LingotekOAuthRequest.php
index ae222e04..0ba25ca7 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/library/LingotekOAuthRequest.php
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lib/oauth-php/library/LingotekOAuthRequest.php
@@ -105,45 +105,14 @@ function __construct ( $uri = null, $method = null, $parameters = '', $headers =
}
$headers = LingotekOAuthRequestLogger::getAllHeaders();
$this->method = strtoupper($method);
-
- // If this is a post then also check the posted variables
- if (strcasecmp($method, 'POST') == 0)
- {
- // TODO: what to do with 'multipart/form-data'?
- if ($this->getRequestContentType() == 'multipart/form-data')
- {
- // Get the posted body (when available)
- if (!isset($headers['X-OAuth-Test']))
- {
- $parameters .= $this->getRequestBodyOfMultipart();
- }
- }
- if ($this->getRequestContentType() == 'application/x-www-form-urlencoded')
- {
- // Get the posted body (when available)
- if (!isset($headers['X-OAuth-Test']))
- {
- $parameters .= $this->getRequestBody();
- }
- }
- else
- {
- $body = $this->getRequestBody();
- }
- }
- else if (strcasecmp($method, 'PUT') == 0)
- {
- $body = $this->getRequestBody();
- }
-
+ $body = $this->getRequestBody();
$this->method = strtoupper($method);
$this->headers = $headers;
// Store the values, prepare for oauth
$this->uri = $uri;
$this->body = $body;
- $this->parseUri($parameters);
+ $this->parseUri();
$this->parseHeaders();
- $this->transcodeParams();
}
@@ -454,31 +423,6 @@ function setParam ( $name, $value, $encoded = false )
}
}
-
- /**
- * Re-encode all parameters so that they are encoded using RFC3986.
- * Updates the $this->param attribute.
- */
- protected function transcodeParams ()
- {
- $params = $this->param;
- $this->param = array();
-
- foreach ($params as $name=>$value)
- {
- if (is_array($value))
- {
- $this->param[$this->urltranscode($name)] = array_map(array($this,'urltranscode'), $value);
- }
- else
- {
- $this->param[$this->urltranscode($name)] = $this->urltranscode($value);
- }
- }
- }
-
-
-
/**
* Return the body of the OAuth request.
*
@@ -506,7 +450,7 @@ function setBody ( $body )
*
* @param string $parameters optional extra parameters (from eg the http post)
*/
- protected function parseUri ( $parameters )
+ protected function parseUri ()
{
$ps = @parse_url($this->uri);
@@ -551,34 +495,6 @@ protected function parseUri ( $parameters )
$ps['fragment'] = '';
}
- // Now all is complete - parse all parameters
- foreach (array($ps['query'], $parameters) as $params)
- {
- if (strlen($params) > 0)
- {
- $params = explode('&', $params);
- foreach ($params as $p)
- {
- @list($name, $value) = explode('=', $p, 2);
- if (!strlen($name))
- {
- continue;
- }
-
- if (array_key_exists($name, $this->param))
- {
- if (is_array($this->param[$name]))
- $this->param[$name][] = $value;
- else
- $this->param[$name] = array($this->param[$name], $value);
- }
- else
- {
- $this->param[$name] = $value;
- }
- }
- }
- }
$this->uri_parts = $ps;
}
@@ -780,7 +696,7 @@ private function getRequestBodyOfMultipart()
if (is_array($_POST) && count($_POST) > 1)
{
foreach ($_POST AS $k => $v) {
- $body .= $k . '=' . $this->urlencode($v) . '&';
+ $body .= $k . '=' . url_check($this->urlencode($v)) . '&';
} #end foreach
if(substr($body,-1) == '&')
{
diff --git a/profiles/commerce_kickstart/modules/contrib/lingotek/lingotek.admin.inc b/profiles/commerce_kickstart/modules/contrib/lingotek/lingotek.admin.inc
index c655463f..748bf4de 100644
--- a/profiles/commerce_kickstart/modules/contrib/lingotek/lingotek.admin.inc
+++ b/profiles/commerce_kickstart/modules/contrib/lingotek/lingotek.admin.inc
@@ -80,6 +80,8 @@ function lingotek_label_compare($a, $b) {
*/
function lingotek_admin_entity_bundle_profiles_form($form, &$form_state, $entity_type, $show_fieldset = FALSE) {
+ drupal_add_js('misc/collapse.js');
+
$setup_complete = (!lingotek_is_config_missing());
$entity_type_info = entity_get_info($entity_type);
$bundles = $entity_type_info['bundles'];
@@ -108,6 +110,8 @@ function lingotek_admin_entity_bundle_profiles_form($form, &$form_state, $entity
$entity_type_info['label'] = 'Field Collection';
}
+ drupal_alter('lingotek_entity_profiles_options', $entity_type, $profiles_options);
+
$entity_profiles = variable_get('lingotek_entity_profiles');
$form['entity_type'] = array(
@@ -116,12 +120,7 @@ function lingotek_admin_entity_bundle_profiles_form($form, &$form_state, $entity
);
$selector = '.lingotek-content-settings-table.' . $entity_type;
- $enable_all = l(t('(set all to automatic)'), '#', array('attributes' => array('onclick' => "lingotek_set_all('" . $selector . "', '0'); return false;")));
- $enable_all_manual = l(t('(set all to manual)'), '#', array('attributes' => array('onclick' => "lingotek_set_all('" . $selector . "', '1'); return false;")));
- $disable_all = l(t('(disable all)'), '#', array('attributes' => array('onclick' => "lingotek_set_all('" . $selector . "', 'DISABLED'); return false;")));
-
$title_str = ($setup_complete ? t('Translate @types', array('@type' => $entity_type_info['label'])) : t('Which content types do you want translated?'));
- $links_str = t('') . ' ' . $enable_all . ' ' . $enable_all_manual . ' ' . $disable_all;
$form['translation_' . $entity_type] = array(
'#type' => $show_fieldset ? 'fieldset' : 'item',
@@ -134,10 +133,16 @@ function lingotek_admin_entity_bundle_profiles_form($form, &$form_state, $entity
),
'#submit' => array('lingotek_admin_entity_bundle_profiles_form_submit'),
);
-
+ $changeAllSelect = 'Set all to: ';
+ $changeAllSelect .= '';
+ foreach($profiles_options as $key => $profile_option){
+ $changeAllSelect .= '';
+ }
+ $changeAllSelect .= '';
$form['translation_' . $entity_type][] = array(
'#type' => 'item',
- '#description' => $links_str,
+ '#markup' => $changeAllSelect
);
$translatable_field_types = lingotek_get_translatable_field_types();
@@ -148,12 +153,12 @@ function lingotek_admin_entity_bundle_profiles_form($form, &$form_state, $entity
foreach ($bundles as $bundle_name => $bundle) {
$original_fields = field_info_instances($entity_type, $bundle_name);
$fields = lingotek_node_settings_row_fields($entity_type, $bundle_name, $setup_complete, $translatable_field_types, $translate);
- $oneoffs = ($entity_type == 'node') ? lingotek_node_settings_row_oneoffs($bundle_name) : NULL;
$translation_mode = ($entity_type == 'taxonomy_term') ? lingotek_get_translation_mode($bundle_name) : NULL;
+
$config_handled = $entity_type == 'taxonomy_term' && empty($original_fields) && $translation_mode['#markup'] !== 'Translate';
$translation_handling = $config_handled ? array('#markup' => 'Config') : array('#markup' => 'Bundle');
$profiles = lingotek_node_settings_row_profiles($bundle_name, $entity_profiles, $entity_type, $profiles_options, $setup_complete, $config_handled);
- $entity_specifics = array('oneoffs' => $oneoffs, 'translation_mode' => $translation_mode, 'translation_handling' => $translation_handling);
+ $entity_specifics = array('translation_mode' => $translation_mode, 'translation_handling' => $translation_handling);
if ($config_handled) {
$fields = array(
@@ -163,22 +168,25 @@ function lingotek_admin_entity_bundle_profiles_form($form, &$form_state, $entity
);
}
+ $languages = lingotek_get_target_locales(FALSE);
+ $bundle['collapsible_label'] = lingotek_get_language_specific_labels($entity_type, $bundle, $languages);
+
if ($translation_mode['#markup'] == 'Fixed' || $translation_mode['#markup'] == 'No') {
continue;
}
$rows[$bundle_name] = lingotek_node_settings_row($entity_type, $bundle, $profiles, $fields, $entity_specifics);
}
- $header = array(t('Content Type'), t('Translation Profile *'), t('Fields'));
+ $header = array(t('Content Type'), t('Translation Profile *'), t('Fields'));
if ($entity_type == 'node') {
- $header = array(t('Content Type'), t('Translation Profile *'), t('Exceptions'), t('Fields'));
+ $header = array(t('Content Type'), t('Translation Profile *'), t('Fields'));
}
elseif ($entity_type == 'taxonomy_term') {
- $header = array(t('Content Type'), t('Translation Profile *'), t('Translation Mode'), t('Translation Handling'), t('Fields'));
+ $header = array(t('Content Type'), t('Translation Profile *'), t('Translation Mode'), t('Translation Handling'), t('Fields'));
}
elseif ($entity_type == 'field_collection_item') {
- $header = array(t('Collection Name'), t('Status *'), t('Fields'));
+ $header = array(t('Collection Name'), t('Status *'), t('Fields'));
}
$variables = array(
@@ -193,7 +201,11 @@ function lingotek_admin_entity_bundle_profiles_form($form, &$form_state, $entity
);
if ($setup_complete) {
- $form['translation_' . $entity_type]['types']['#suffix'] = t('Note: changing the profile will update all settings for existing @entity_types except for the project, workflow, vault, and storage method (e.g. node/field)', array('@entity_type' => strtolower($entity_type_info['label'])));
+ $node_message = '';
+ if (variable_get('lingotek_translate_original_node_titles', FALSE) && $entity_type === 'node') {
+ $node_message = " Note: If \"Node Title\" and \"Title\" are both translated, \"Title\" will display within nodes.";
+ }
+ $form['translation_' . $entity_type]['types']['#suffix'] = t('Note: Changing the default profile will affect only future content. Existing content will keep current profile settings. (To switch the profile for existing content, use the \'Edit translation settings\' action on the Manage tab.)' . $node_message, array('@entity_type' => strtolower($entity_type_info['label'])));
$form['#action'] = url('admin/settings/lingotek/settings', array('fragment' => lingotek_get_tab_id($entity_type)));
}
@@ -203,16 +215,17 @@ function lingotek_admin_entity_bundle_profiles_form($form, &$form_state, $entity
'#type' => 'submit',
'#value' => t('Save'),
);
-
return $form;
}
function lingotek_node_settings_row_profiles($bundle_name, $entity_profiles, $entity_type, $profiles_options, $setup_complete, $config_handled) {
$default_profile = $setup_complete ? LingotekSync::PROFILE_DISABLED : 0;
+ $inherit_profile = LingotekSync::PROFILE_INHERIT;
// Disable automatic profile as the default for comments during setup
if ($entity_type == 'comment') {
$default_profile = LingotekSync::PROFILE_DISABLED;
}
+ $languages = lingotek_get_target_locales(FALSE);
$profiles = array();
if ($config_handled) {
$profiles['profile_' . $bundle_name] = array(
@@ -228,6 +241,7 @@ function lingotek_node_settings_row_profiles($bundle_name, $entity_profiles, $en
);
}
else {
+
$profiles['profile_' . $bundle_name] = array(
'#type' => 'select',
'#options' => $profiles_options,
@@ -238,18 +252,67 @@ function lingotek_node_settings_row_profiles($bundle_name, $entity_profiles, $en
'class' => array('field'),
),
);
+
+ if (variable_get('lingotek_enable_language_specific_profiles', FALSE)) {
+
+ // add a title to the main profile for the bundle
+ $profiles['profile_' . $bundle_name]['#title'] = 'Default Profile';
+
+ // fieldset wrapper to indent the language overrides
+ $profiles['profile_overrides'] = array(
+ '#type' => 'fieldset',
+ '#id' => 'profile_override__' . $bundle_name,
+ '#states' => array(
+ 'invisible' => array(':input[name="' . $entity_type . '_language"]' => array('visible' => FALSE)),
+ ),
+ '#attributes' => array(
+ 'style' => 'border: none; padding: 0 0 0 0; background-color: inherit;',
+ )
+ );
+
+ // add the 'inherit' option after writing the main profile box
+ $profiles_options[LingotekSync::PROFILE_INHERIT] = '(use default profile for ' . $bundle_name . ')';
+
+ foreach ($languages as $language) {
+ $profiles['profile_overrides'][$bundle_name . '_' . $language->lingotek_locale] = array(
+ '#title' => 'Content created in ' . $language->name,
+ '#type' => 'select',
+ '#options' => $profiles_options,
+ '#value' => isset($entity_profiles[$entity_type][$bundle_name . '__' . $language->lingotek_locale]) ? $entity_profiles[$entity_type][$bundle_name . '__' . $language->lingotek_locale] : LingotekSync::PROFILE_INHERIT,
+ '#attributes' => array(
+ 'id' => array('edit-form-item-profile-' . $bundle_name . '__' . $language->lingotek_locale),
+ 'name' => 'profile_' . $bundle_name . '__' . $language->lingotek_locale,
+ 'class' => array('field'),
+ ),
+ );
+ }
+ }
}
return $profiles;
}
function lingotek_node_settings_row_fields($entity_type, $bundle_name, $setup_complete, $translatable_field_types, $translate) {
+ $field_types = field_info_fields();
+ $field_info_instances = field_info_instances($entity_type, $bundle_name);
+
+ if ($entity_type == 'menu_link') {
+ $field_info_instances = lingotek_get_menu_link_fields();
+ }
+
$fields = array();
- foreach (field_info_instances($entity_type, $bundle_name) as $field) {
+ foreach ($field_info_instances as $field) {
$field_label = $field['label'];
$field_machine_name = $field['field_name'];
- $field_type = $field['widget']['type'];
- if (array_search($field_type, $translatable_field_types)) {
+
+ if ($entity_type == 'menu_link') {
+ $field_type = 'text';
+ }
+ else {
+ $field_type = $field_types[$field['field_name']]['type'];
+ }
+
+ if (in_array($field_type, $translatable_field_types)) {
$fields[$field_machine_name] = array(
'#type' => 'checkbox',
'#title' => check_plain($field_label),
@@ -274,6 +337,8 @@ function lingotek_node_settings_row_fields($entity_type, $bundle_name, $setup_co
}
$missing_fields = array();
+ $title_id = "edit-form-item-$bundle_name-separator-title";
+
if (!isset($fields['title_field']) && $entity_type == 'node') {
$missing_fields[] = 'title';
}
@@ -288,17 +353,19 @@ function lingotek_node_settings_row_fields($entity_type, $bundle_name, $setup_co
}
if (!empty($missing_fields)) {
- foreach ($missing_fields as $missing_field) {
- $message = t(ucfirst($missing_field) . ' (Note: field will be created.)');
+ foreach ($missing_fields as $key => $missing_field) {
+ $message = t('@field (Note: field will be created)', array(
+ '@field' => ucfirst($missing_field),
+ ));
$fields[$missing_field . '_field'] = array(
'#type' => 'checkbox',
'#title' => check_plain($message),
'#attributes' => array(
- 'id' => array('edit-form-item-' . $bundle_name . '-seperator-title'),
+ 'id' => array("$title_id-$key"),
'name' => 'title_swap_' . $bundle_name . '_' . $missing_field,
'class' => array('field'),
),
- '#id' => 'edit-form-item-' . $bundle_name . '-seperator-title',
+ '#id' => "$title_id-$key",
'#states' => array(
'invisible' => array(
':input[name="profile_' . $bundle_name . '"]' => array('value' => 'DISABLED'),
@@ -310,7 +377,31 @@ function lingotek_node_settings_row_fields($entity_type, $bundle_name, $setup_co
}
}
}
+
+ // Enable translation of original title if preference is checked
+ if (variable_get('lingotek_translate_original_node_titles', FALSE) && $entity_type == 'node') {
+ $fields['title'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Node Title*'),
+ '#id' => $title_id,
+ '#attributes' => array(
+ 'id' => array($title_id),
+ 'name' => $bundle_name . '_SEPERATOR_title',
+ 'class' => array('field'),
+ ),
+ '#states' => array(
+ 'invisible' => array(
+ ':input[name="profile_' . $bundle_name . '"]' => array('value' => 'DISABLED'),
+ ),
+ ),
+ );
+ if (!$setup_complete || !empty($translate[$bundle_name]) && array_search('title', $translate[$bundle_name]) !== FALSE) {
+ $fields['title']['#attributes']['checked'] = 'checked';
+ }
+ }
+
uasort($fields, 'lingotek_title_compare');
+
return $fields;
}
@@ -321,60 +412,6 @@ function lingotek_title_compare($a, $b) {
return strcasecmp($a['#title'], $b['#title']);
}
-function lingotek_node_settings_row_oneoffs($bundle_name) {
- $exception_num = lingotek_oneoff_count($bundle_name);
-
- $options = array(
- 'attributes' => array('class' => array('ctools-use-modal ctools-modal-lingotek-small lingotek-center'), 'title' => 'Remove all profile exceptions for this content type'),
- );
-
- drupal_add_js(array(
- 'lingotek-small' => array(
- 'modalSize' => array(
- 'type' => 'fixed',
- 'width' => 450,
- 'height' => 400,
- ),
- 'closeImage' => theme('image', array('path' => drupal_get_path('module', 'lingotek') . '/images/close.png', 'alt' => t('Close window'), 'title' => t('Close window'))),
- 'closeText' => '',
- 'animation' => 'fadeIn',
- ),
- ), 'setting');
-
- $title = $exception_num > 0 ? l($exception_num, LINGOTEK_MENU_MAIN_BASE_URL . '/clearexceptions/' . $bundle_name, $options) : $exception_num;
-
- $oneoffs = array(
- '#type' => 'item',
- '#markup' => $title,
- );
-
- return $oneoffs;
-}
-
-function lingotek_oneoff_count($bundle_name) {
- $target_ids = db_select('lingotek_entity_metadata', 'lem')
- ->fields('lem', array('entity_id'))
- ->condition('entity_key', 'upload_status')
- ->condition('entity_type', 'node')
- ->condition('value', 'TARGET')
- ->execute()
- ->fetchCol();
- $query = db_select('lingotek_entity_metadata', 'lem')
- ->fields('lem')
- ->condition('lem.entity_key', 'profile')
- ->condition('lem.entity_type', 'node');
- if (!empty($target_ids)) {
- $query->condition('lem.entity_id', $target_ids, 'NOT IN');
- }
-
- $query->join('node', 'n', 'lem.entity_id = n.nid AND n.type = \'' . $bundle_name . '\'');
-
- $exception_num = $query->execute()
- ->rowCount();
-
- return $exception_num;
-}
-
function lingotek_get_translation_mode($bundle) {
$query = db_select('taxonomy_vocabulary', 't')
->fields('t', array('i18n_mode'))
@@ -397,17 +434,14 @@ function lingotek_get_translation_mode($bundle) {
}
function lingotek_node_settings_row($entity_type, $bundle, $profiles, $fields, $entity_specifics) {
- if ($entity_type == 'node') {
- $row = array(
- array('data' => $bundle['label'], 'width' => '20%'),
- array('data' => drupal_render($profiles)),
- array('data' => drupal_render($entity_specifics['oneoffs']), 'style' => 'text-align:center'),
- array('data' => drupal_render($fields), 'width' => '65%'),
- );
- }
- elseif ($entity_type == 'taxonomy_term') {
+
+ // REMOVED TEMPORARILY UNTIL REFACTOR OF LANGUAGE-SPECIFIC PROFILE UI IMPROVEMENTS.
+ //$label = variable_get('lingotek_enable_language_specific_profiles') ? $bundle['collapsible_label'] : $bundle['label'];
+ $label = '' . $bundle['label'] . '';
+
+ if ($entity_type == 'taxonomy_term') {
$row = array(
- array('data' => $bundle['label'], 'width' => '20%'),
+ array('data' => $label, 'width' => '20%'),
array('data' => drupal_render($profiles)),
array('data' => drupal_render($entity_specifics['translation_mode']), 'width' => '15%'),
array('data' => drupal_render($entity_specifics['translation_handling'])),
@@ -416,12 +450,11 @@ function lingotek_node_settings_row($entity_type, $bundle, $profiles, $fields, $
}
else {
$row = array(
- array('data' => $bundle['label'], 'width' => '20%'),
+ array('data' => $label, 'width' => '20%'),
array('data' => drupal_render($profiles)),
array('data' => drupal_render($fields), 'width' => '65%'),
);
}
-
return $row;
}
@@ -479,7 +512,6 @@ function lingotek_admin_add_entity_specific_changes(&$form, &$form_state, $entit
'#description' => t('Set all language neutral comments (and underlying fields) for enabled comment types to be @language.', array('@language' => language_default('name'))),
'#default_value' => 1, // default to enable (for use in setup) --- js will disable on settings by default
);
- //$form['translation_' . $entity_type]['types']['#suffix'] = t('Note: changing the profile will update all settings for existing comments except for the project, workflow, vault, and storage method (e.g. node/field).');
break;
case 'field_collection_item':
// add note about field collections being coupled with their parent entities
@@ -500,6 +532,7 @@ function lingotek_admin_entity_bundle_profiles_form_submit($form, &$form_state)
}
$enabled_fields = variable_get('lingotek_enabled_fields', array());
+
// Reset fields for the entity type but leave its existence there
$enabled_fields[$entity_type] = array();
$operations = array();
@@ -518,9 +551,12 @@ function lingotek_admin_entity_bundle_profiles_form_submit($form, &$form_state)
$content_type = $parts[0];
$content_field = $parts[1];
+ // Save the enabled fields, even if disabled, as one-offs could be
+ // enabled and will need to know which fields to translate.
+ $enabled_fields[$entity_type][$content_type][] = $content_field;
+
//check to make sure that the content type is enabled
if ($form_state['input']['profile_' . $content_type] != LingotekSync::PROFILE_DISABLED) {
- $enabled_fields[$entity_type][$content_type][] = $content_field;
// Set this content type to be translation-enabled only if currently disabled.
$currently_enabled_content_type = variable_get('language_content_type_' . $content_type, '0');
@@ -531,9 +567,14 @@ function lingotek_admin_entity_bundle_profiles_form_submit($form, &$form_state)
if ($field_based_translation) {
// Update the field via the Field API (Instead of the direct db_update)
$field = field_info_field($content_field);
+ if (!$field) {
+ continue;
+ }
$is_field_collection = key_exists($content_field, $field_collection_field_types);
$field['translatable'] = $is_field_collection ? 0 : 1;
- field_update_field($field);
+ if ($entity_type != 'menu_link') {
+ field_update_field($field);
+ }
}
}
}
@@ -547,7 +588,7 @@ function lingotek_admin_entity_bundle_profiles_form_submit($form, &$form_state)
$legacy_field = array_pop($field_array);
$content_type = implode('_', $field_array);
-//check to make sure that the content type is enabled
+ //check to make sure that the content type is enabled
if ($form_state['input']['profile_' . $content_type] != LingotekSync::PROFILE_DISABLED) {
// Do the actual title replacement
$bundle = $content_type;
@@ -583,6 +624,7 @@ function lingotek_admin_entity_bundle_profiles_form_submit($form, &$form_state)
}
}
$_SESSION['lingotek_setup_path'][] = lingotek_get_entity_setup_path($entity_type);
+
variable_set('lingotek_enabled_fields', $enabled_fields);
drupal_set_message(t('Your content types have been updated.'));
@@ -619,27 +661,13 @@ function lingotek_admin_entity_bundle_profiles_form_submit($form, &$form_state)
* Return an array of entity types with the number of each using the given profile
*/
function lingotek_admin_profile_usage($profile_id) {
- $entity_counts = array();
- $entities = lingotek_get_all_entities_by_profile($profile_id);
- // count up the entities by type
- foreach ($entities as $e) {
- if (isset($entity_counts[$e['type']])) {
- $entity_counts[$e['type']]++;
- }
- else {
- $entity_counts[$e['type']] = 1;
- }
- }
- return $entity_counts;
+ $profile = LingotekProfile::loadById($profile_id);
+ return $profile->getUsage();
}
function lingotek_admin_profile_usage_by_types($profile_id) {
- $bundles_using_profile = lingotek_get_bundles_by_profile_id($profile_id);
- $count_types = 0;
- foreach ($bundles_using_profile as $bup) {
- $count_types += count($bup);
- }
- return $count_types;
+ $profile = LingotekProfile::loadById($profile_id);
+ return $profile->getUsage($by_bundle = TRUE);
}
/**
@@ -718,16 +746,26 @@ function lingotek_admin_additional_translation_settings_form($form, &$form_state
'#value' => module_exists('i18nviews'),
);
+ $hidden_i18n_field_value = array(
+ '#id' => 'lingotek_i18n_field_enabled',
+ '#type' => 'hidden',
+ '#value' => module_exists('i18n_field'),
+ );
+
$options = array(
'lingotek_translate_config_blocks' => array(t('Blocks'), t('Include translation for all translatable blocks.') . drupal_render($prep_blocks_chbx)),
'lingotek_translate_config_taxonomies' => array(t('Taxonomy'), t('Include translation for all translatable taxonomy vocabularies and terms.') . drupal_render($prep_taxonomy_chbx)),
'lingotek_translate_config_menus' => array(t('Menus'), t('Include translation for all menus set to \'Translate and Localize\'.') . drupal_render($prep_menus_chbx)),
'lingotek_translate_config_views' => array(t('Views'), t('Include translation of all translatable strings within views. This will not generally include translation of all results generated by each view, which is usually configurable by selecting localizable fields within the view itself. (Note: You must have the i18nviews module enabled in order to use this.)') . drupal_render($hidden_i18nviews_value)),
- 'lingotek_translate_config_fields' => array(t('Field Labels'), t('Include translation of all translatable field labels. (Note: You must have the i18n_field sub-module enabled in order to use this.)')),
+ 'lingotek_translate_config_fields' => array(t('Field Labels'), t('Include translation of all translatable field labels. (Note: You must have the i18n_field sub-module enabled in order to use this.)') . drupal_render($hidden_i18n_field_value)),
'lingotek_translate_config_builtins' => array(t('Built-in Interface'), t('Include translation of built-in strings. (Note: Indexing all of these may take several minutes or longer.)') . drupal_render($fr)),
'lingotek_translate_config_misc' => array(t('Miscellaneous Strings'), t('Include translation of any other miscellaneous strings found by the Internationalization (i18n) module.')),
);
+ if (module_exists('webform') && module_exists('webform_localization')) {
+ $options['lingotek_translate_config_webform'] = array(t('Webform'), t('Include translation of Webform components. (Note: Requires Webform and Webform Localization modules.)'));
+ }
+
$defaults = array();
foreach (array_keys($options) as $config_type) {
@@ -742,117 +780,128 @@ function lingotek_admin_additional_translation_settings_form($form, &$form_state
);
$profiles = variable_get('lingotek_profiles');
- $config_profile = isset($profiles[LingotekSync::PROFILE_CONFIG]) ? $profiles[LingotekSync::PROFILE_CONFIG] : NULL;
-
$workflows = $api->listWorkflows();
- if ($config_profile) {
- if (is_array($workflows) && count($workflows) > 1 && $setup_complete) {
- $stored_profile = lingotek_get_profile_settings(LingotekSync::PROFILE_CONFIG);
- $stored_workflow_id = (isset($stored_profile['workflow_id']) ? $stored_profile['workflow_id'] : '');
- $selected_workflow_id = (isset($form_state['values']['addtl_workflow_id']) ? $form_state['values']['addtl_workflow_id'] : $stored_workflow_id);
- $curr_workflow = $api->getWorkflow($stored_workflow_id);
- $num_config_docs = count(LingotekConfigSet::getAllDocumentIds());
- if (!empty($curr_workflow)) {
- // append the current workflow to the top of the workflow list, if it's not already there
- $workflows = array($stored_workflow_id => $curr_workflow->name) + $workflows;
- }
+ $config_profile = LingotekProfile::loadById(LingotekSync::PROFILE_CONFIG);
- $form['additional_translation']['addtl_workflow_id'] = array(
- '#type' => 'select',
- '#title' => t('Workflow'),
- '#description' => t('This workflow will be used for handling these additional translation items.'),
- '#default_value' => $stored_workflow_id,
- '#options' => $workflows,
- '#ajax' => array(
- 'callback' => 'lingotek_config_default_workflow_form_callback',
- 'wrapper' => 'addtl-prefill-phases-div',
- 'method' => 'replace',
- 'effect' => 'fade',
- ),
- '#prefix' => '