Browse Source

updated admin_menu, entity_translation, addressfield, addressfield_token, autocomplete_deluxe

Bachir Soussi Chiadmi 5 years ago
parent
commit
33210e10f2
65 changed files with 3120 additions and 696 deletions
  1. 122 90
      sites/all/modules/contrib/admin/admin_menu/README.txt
  2. 3 4
      sites/all/modules/contrib/admin/admin_menu/admin_devel/admin_devel.info
  3. 4 5
      sites/all/modules/contrib/admin/admin_menu/admin_menu-rtl.css
  4. 8 4
      sites/all/modules/contrib/admin/admin_menu/admin_menu.admin.js
  5. 1 2
      sites/all/modules/contrib/admin/admin_menu/admin_menu.color.css
  6. 7 7
      sites/all/modules/contrib/admin/admin_menu/admin_menu.css
  7. 34 24
      sites/all/modules/contrib/admin/admin_menu/admin_menu.inc
  8. 3 4
      sites/all/modules/contrib/admin/admin_menu/admin_menu.info
  9. 8 4
      sites/all/modules/contrib/admin/admin_menu/admin_menu.js
  10. 8 1
      sites/all/modules/contrib/admin/admin_menu/admin_menu.map.inc
  11. 25 14
      sites/all/modules/contrib/admin/admin_menu/admin_menu.module
  12. 0 1
      sites/all/modules/contrib/admin/admin_menu/admin_menu.uid1.css
  13. 4 0
      sites/all/modules/contrib/admin/admin_menu/admin_menu_toolbar/admin_menu_toolbar-rtl.css
  14. 3 4
      sites/all/modules/contrib/admin/admin_menu/admin_menu_toolbar/admin_menu_toolbar.css
  15. 3 4
      sites/all/modules/contrib/admin/admin_menu/admin_menu_toolbar/admin_menu_toolbar.info
  16. 0 1
      sites/all/modules/contrib/admin/admin_menu/admin_menu_toolbar/admin_menu_toolbar.install
  17. 0 1
      sites/all/modules/contrib/admin/admin_menu/admin_menu_toolbar/admin_menu_toolbar.module
  18. 51 16
      sites/all/modules/contrib/admin/admin_menu/tests/admin_menu.test
  19. 27 6
      sites/all/modules/contrib/admin/entity_translation_export_import/entity_translation_export_import.admin.inc
  20. 3 3
      sites/all/modules/contrib/admin/entity_translation_export_import/entity_translation_export_import.info
  21. 175 89
      sites/all/modules/contrib/dev/addressfield_tokens/addressfield_tokens.components.inc
  22. 10 13
      sites/all/modules/contrib/dev/addressfield_tokens/addressfield_tokens.info
  23. 142 55
      sites/all/modules/contrib/dev/addressfield_tokens/addressfield_tokens.module
  24. 21 3
      sites/all/modules/contrib/dev/addressfield_tokens/addressfield_tokens.theme.inc
  25. 81 45
      sites/all/modules/contrib/dev/addressfield_tokens/addressfield_tokens.tokens.inc
  26. 24 15
      sites/all/modules/contrib/fields/addressfield/addressfield.address_formats.inc
  27. 152 68
      sites/all/modules/contrib/fields/addressfield/addressfield.administrative_areas.inc
  28. 2 2
      sites/all/modules/contrib/fields/addressfield/addressfield.devel_generate.inc
  29. 18 4
      sites/all/modules/contrib/fields/addressfield/addressfield.feeds.inc
  30. 3 4
      sites/all/modules/contrib/fields/addressfield/addressfield.info
  31. 5 0
      sites/all/modules/contrib/fields/addressfield/addressfield.migrate.inc
  32. 40 2
      sites/all/modules/contrib/fields/addressfield/addressfield.module
  33. 26 16
      sites/all/modules/contrib/fields/addressfield/addressfield.tokens.inc
  34. 3 4
      sites/all/modules/contrib/fields/addressfield/example/addressfield_example.info
  35. 24 0
      sites/all/modules/contrib/fields/addressfield/plugins/format/address-hide-administrative-area.inc
  36. 1 1
      sites/all/modules/contrib/fields/addressfield/plugins/format/address-hide-country.inc
  37. 24 0
      sites/all/modules/contrib/fields/addressfield/plugins/format/address-hide-locality.inc
  38. 6 1
      sites/all/modules/contrib/fields/addressfield/plugins/format/address.inc
  39. 0 0
      sites/all/modules/contrib/fields/autocomplete_deluxe/README.txt
  40. 18 15
      sites/all/modules/contrib/fields/autocomplete_deluxe/autocomplete_deluxe.api.php
  41. 0 0
      sites/all/modules/contrib/fields/autocomplete_deluxe/autocomplete_deluxe.css
  42. 3 3
      sites/all/modules/contrib/fields/autocomplete_deluxe/autocomplete_deluxe.info
  43. 0 0
      sites/all/modules/contrib/fields/autocomplete_deluxe/autocomplete_deluxe.js
  44. 0 0
      sites/all/modules/contrib/fields/autocomplete_deluxe/autocomplete_deluxe.module
  45. 77 3
      sites/all/modules/contrib/localisation/entity_translation/CHANGELOG.txt
  46. 9 7
      sites/all/modules/contrib/localisation/entity_translation/MAINTAINERS.txt
  47. 39 15
      sites/all/modules/contrib/localisation/entity_translation/entity_translation.admin.inc
  48. 14 0
      sites/all/modules/contrib/localisation/entity_translation/entity_translation.api.php
  49. 6 4
      sites/all/modules/contrib/localisation/entity_translation/entity_translation.info
  50. 16 2
      sites/all/modules/contrib/localisation/entity_translation/entity_translation.install
  51. 78 46
      sites/all/modules/contrib/localisation/entity_translation/entity_translation.module
  52. 472 0
      sites/all/modules/contrib/localisation/entity_translation/entity_translation.taxonomy.inc
  53. 3 4
      sites/all/modules/contrib/localisation/entity_translation/entity_translation_i18n_menu/entity_translation_i18n_menu.info
  54. 1 1
      sites/all/modules/contrib/localisation/entity_translation/entity_translation_i18n_menu/entity_translation_i18n_menu.module
  55. 24 7
      sites/all/modules/contrib/localisation/entity_translation/entity_translation_i18n_menu/entity_translation_i18n_menu.test
  56. 7 3
      sites/all/modules/contrib/localisation/entity_translation/entity_translation_upgrade/entity_translation_upgrade.admin.inc
  57. 117 0
      sites/all/modules/contrib/localisation/entity_translation/entity_translation_upgrade/entity_translation_upgrade.drush.inc
  58. 4 4
      sites/all/modules/contrib/localisation/entity_translation/entity_translation_upgrade/entity_translation_upgrade.info
  59. 163 0
      sites/all/modules/contrib/localisation/entity_translation/entity_translation_upgrade/entity_translation_upgrade.test
  60. 136 52
      sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler.inc
  61. 1 4
      sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler_factory.inc
  62. 820 3
      sites/all/modules/contrib/localisation/entity_translation/tests/entity_translation.test
  63. 4 4
      sites/all/modules/contrib/localisation/entity_translation/tests/entity_translation_test.info
  64. 31 0
      sites/all/modules/contrib/localisation/entity_translation/tests/entity_translation_test.install
  65. 6 2
      sites/all/modules/contrib/localisation/entity_translation/views/entity_translation_handler_relationship.inc

+ 122 - 90
sites/all/modules/contrib/admin/admin_menu/README.txt

@@ -1,65 +1,84 @@
+CONTENTS OF THIS FILE
+---------------------
 
--- SUMMARY --
+ * Introduction
+ * Requirements
+ * Installation
+ * Configuration
+ * Customization
+ * Troubleshooting
+ * FAQ
+ * Maintainers
+
+
+INTRODUCTION
+------------
 
 The Administration menu module displays the entire administrative menu tree (and
 most local tasks) in a drop-down menu, providing administrators one- or
 two-click access to most pages.  Other modules may also add menu links to the
 menu using hook_admin_menu_output_alter().
 
-For a full description of the module, visit the project page:
-  http://drupal.org/project/admin_menu
+For a full description of the project visit the project page:
+http://drupal.org/project/admin_menu
 
 To submit bug reports and feature suggestions, or to track changes:
-  http://drupal.org/project/issues/admin_menu
+http://drupal.org/project/issues/admin_menu
 
 
--- REQUIREMENTS --
+REQUIREMENTS
+------------
 
-None.
+No special requirements
 
 
--- INSTALLATION --
+INSTALLATION
+------------
 
-* Install as usual, see http://drupal.org/node/895232 for further information.
+Install as you would normally install a contributed Drupal. See:
+https://drupal.org/documentation/install/modules-themes/modules-7 for further
+information.
 
-* You likely want to disable Toolbar module, since its output clashes with
-  Administration menu.
+ * You likely want to disable Toolbar module, since its output clashes with
+ Administration menu.
 
 
--- CONFIGURATION --
+CONFIGURATION
+-------------
 
-* Configure user permissions in Administration » People » Permissions:
+ * Configure user permissions in Administration » People » Permissions:
 
-  - Use the administration pages and help (System module)
+   - Use the administration pages and help (System module)
 
-    The top-level administration categories require this permission to be
-    accessible. The administration menu will be empty unless this permission is
-    granted.
+     The top-level administration categories require this permission to be
+     accessible. The administration menu will be empty unless this permission is
+     granted.
 
-  - Access administration menu
+   - Access administration menu
 
-    Users in roles with the "Access administration menu" permission will see
-    the administration menu at the top of each page.
+     Users in roles with the "Access administration menu" permission will see
+     the administration menu at the top of each page.
 
-  - Display Drupal links
+   - Display Drupal links
 
-    Users in roles with the "Display drupal links" permission will receive
-    links to drupal.org issue queues for all enabled contributed modules. The
-    issue queue links appear under the administration menu icon.
+     Users in roles with the "Display drupal links" permission will receive
+     links to drupal.org issue queues for all enabled contributed modules. The
+     issue queue links appear under the administration menu icon.
 
-  Note that the menu items displayed in the administration menu depend on the
-  actual permissions of the viewing user. For example, the "People" menu item
-  is not displayed to a user who is not a member of a role with the "Administer
-  users" permission.
+     Note that the menu items displayed in the administration menu depend on the
+     actual permissions of the viewing user. For example, the "People" menu item
+     is not displayed to a user who is not a member of a role with the
+     "Administer users" permission.
 
-* Customize the menu settings in Administration » Configuration and modules »
-  Administration » Administration menu.
+ * Customize the menu settings in Administration » Configuration and modules »
+   Administration » Administration menu.
 
-* To prevent administrative menu items from appearing twice, you may hide the
-  "Management" menu block.
+ * To prevent administrative menu items from appearing twice, you may hide the
+   "Management" menu block.
 
 
--- CUSTOMIZATION --
+CUSTOMIZATION
+-------------
 
 * To override the default administration menu icon, you may:
 
@@ -82,12 +101,13 @@ None.
   body #admin-menu { font-size: 10px; }
 
 
--- TROUBLESHOOTING --
+TROUBLESHOOTING
+-------------
 
 * If the menu does not display, check the following:
 
-  - Are the "Access administration menu" and "Use the administration pages and help"
-    permissions enabled for the appropriate roles?
+  - Are the "Access administration menu" and "Use the administration pages and
+    help" permissions enabled for the appropriate roles?
 
   - Does html.tpl.php of your theme output the $page_bottom variable?
 
@@ -99,90 +119,102 @@ None.
   See http://drupal.org/node/195386 for further information.
 
 
--- FAQ --
+FAQ
+---
+
+ Q: When the administration menu module is enabled, blank space is added to the
+    bottom of my theme. Why?
 
-Q: When the administration menu module is enabled, blank space is added to the
-   bottom of my theme. Why?
+ A: This is caused by a long list of links to module issue queues at Drupal.org.
+    Use Administer >> User management >> Permissions to disable the "display
+    drupal links" permission for all appropriate roles. Note that since UID 1
+    automatically receives all permissions, the list of issue queue links cannot
+    be disabled for UID 1.
 
-A: This is caused by a long list of links to module issue queues at Drupal.org.
-   Use Administer >> User management >> Permissions to disable the "display
-   drupal links" permission for all appropriate roles. Note that since UID 1
-   automatically receives all permissions, the list of issue queue links cannot
-   be disabled for UID 1.
 
+ Q: After upgrading to 6.x-1.x, the menu disappeared. Why?
 
-Q: After upgrading to 6.x-1.x, the menu disappeared. Why?
+ A: You may need to regenerate your menu. Visit
+    http://example.com/admin/build/modules to regenerate your menu (substitute
+    your site name for example.com).
 
-A: You may need to regenerate your menu. Visit
-   http://example.com/admin/build/modules to regenerate your menu (substitute
-   your site name for example.com).
 
+ Q: Can I configure the administration menu module to display another menu (like
+    the Navigation menu, for instance)?
 
-Q: Can I configure the administration menu module to display another menu (like
-   the Navigation menu, for instance)?
+ A: No. As the name implies, administration menu module is for administrative
+    menu links only. However, you can copy and paste the contents of
+    admin_menu.css into your theme's stylesheet and replace #admin-menu with any
+    other menu block id (#block-menu-1, for example).
 
-A: No. As the name implies, administration menu module is for administrative
-   menu links only. However, you can copy and paste the contents of
-   admin_menu.css into your theme's stylesheet and replace #admin-menu with any
-   other menu block id (#block-menu-1, for example).
 
+ Q: Sometimes, the user counter displays a lot of anonymous users, but no spike
+    of users or requests appear in Google Analytics or other tracking tools.
 
-Q: Sometimes, the user counter displays a lot of anonymous users, but no spike
-   of users or requests appear in Google Analytics or other tracking tools.
+ A: If your site was concurrently spidered by search-engine robots, it may have
+    a significant number of anonymous users for a short time. Most web tracking
+    tools like Google Analytics automatically filter out these requests.
 
-A: If your site was concurrently spidered by search-engine robots, it may have
-   a significant number of anonymous users for a short time. Most web tracking
-   tools like Google Analytics automatically filter out these requests.
 
+ Q: I enabled "Aggregate and compress CSS files", but admin_menu.css is still
+    there. Is this normal?
 
-Q: I enabled "Aggregate and compress CSS files", but admin_menu.css is still
-   there. Is this normal?
+ A: Yes, this is the intended behavior. the administration menu module only
+    loads its stylesheet as needed (i.e., on page requests by logged-on,
+    administrative users).
 
-A: Yes, this is the intended behavior. the administration menu module only loads
-   its stylesheet as needed (i.e., on page requests by logged-on, administrative
-   users).
 
+ Q: Why are sub-menus not visible in Opera?
 
-Q: Why are sub-menus not visible in Opera?
+ A: In the Opera browser preferences under "web pages" there is an option to fit
+    to width. By disabling this option, sub-menus in the administration menu
+    should appear.
 
-A: In the Opera browser preferences under "web pages" there is an option to fit
-   to width. By disabling this option, sub-menus in the administration menu
-   should appear.
 
+ Q: How can the administration menu be hidden on certain pages?
 
-Q: How can the administration menu be hidden on certain pages?
+ A: You can suppress it by simply calling the following function in PHP:
+    module_invoke('admin_menu', 'suppress');
 
-A: You can suppress it by simply calling the following function in PHP:
+    However, this needs to happen as early as possible in the page request, so
+    placing it in the theming layer (resp. a page template file) is too late.
+    Ideally, the function is called in hook_init() in a custom module.  If you
+    do not have a custom module, placing it into some conditional code at the
+    top of template.php may work out, too.
 
-     module_invoke('admin_menu', 'suppress');
 
-   However, this needs to happen as early as possible in the page request, so
-   placing it in the theming layer (resp. a page template file) is too late.
-   Ideally, the function is called in hook_init() in a custom module.  If you do
-   not have a custom module, placing it into some conditional code at the top of
-   template.php may work out, too.
+Q: What does the "Administration Development Tools" module do?
 
+A: The Administration Development Tools adds a jQuery Debugger which allows
+   a developer to debug and inspect arbitrary data/variables in Firebug's
+   console, and also to access them again in the global window object
+   (optionally using a named identifier, e.g. window.debug.myValue).
+   Chainable via jQuery. Especially useful for re-accessing and debugging
+   selected data via Firebug's console.
 
--- CONTACT --
+
+MAINTAINERS
+-----------
 
 Current maintainers:
-* Daniel F. Kudwien (sun) - http://drupal.org/user/54136
-* Peter Wolanin (pwolanin) - http://drupal.org/user/49851
-* Stefan M. Kudwien (smk-ka) - http://drupal.org/user/48898
-* Dave Reid (Dave Reid) - http://drupal.org/user/53892
+ * Daniel F. Kudwien (sun) - http://drupal.org/user/54136
+ * Peter Wolanin (pwolanin) - http://drupal.org/user/49851
+ * Stefan M. Kudwien (smk-ka) - http://drupal.org/user/48898
+ * Dave Reid (Dave Reid) - http://drupal.org/user/53892
+ * Truls S. Yggeseth (truls1502) - http://drupal.org/user/325866
+ * Sebastian Siemssen (fubhy) - https://www.drupal.org/user/761344
 
 Major rewrite for Drupal 6 by Peter Wolanin (pwolanin).
 
 This project has been sponsored by:
-* UNLEASHED MIND
-  Specialized in consulting and planning of Drupal powered sites, UNLEASHED
-  MIND offers installation, development, theming, customization, and hosting
-  to get you started. Visit http://www.unleashedmind.com for more information.
-
-* Lullabot
-  Friendly Drupal experts providing professional consulting & education
-  services. Visit http://www.lullabot.com for more information.
+ * UNLEASHED MIND
+   Specialized in consulting and planning of Drupal powered sites, UNLEASHED
+   MIND offers installation, development, theming, customization, and hosting
+   to get you started. Visit http://www.unleashedmind.com for more information.
 
-* Acquia
-  Commercially Supported Drupal. Visit http://acquia.com for more information.
+ * Lullabot
+   Friendly Drupal experts providing professional consulting & education
+   services. Visit http://www.lullabot.com for more information.
 
+ * Acquia
+   Commercially Supported Drupal. Visit http://acquia.com for more information.

+ 3 - 4
sites/all/modules/contrib/admin/admin_menu/admin_devel/admin_devel.info

@@ -4,9 +4,8 @@ package = Administration
 core = 7.x
 scripts[] = admin_devel.js
 
-; Information added by Drupal.org packaging script on 2014-12-19
-version = "7.x-3.0-rc5"
+; Information added by Drupal.org packaging script on 2018-12-03
+version = "7.x-3.0-rc6"
 core = "7.x"
 project = "admin_menu"
-datestamp = "1419029284"
-
+datestamp = "1543859284"

+ 4 - 5
sites/all/modules/contrib/admin/admin_menu/admin_menu-rtl.css

@@ -1,4 +1,3 @@
-
 #admin-menu {
   text-align: right;
 }
@@ -25,7 +24,7 @@
   border-right: 0;
 }
 #admin-menu .dropdown .admin-menu-tab a {
-  border-left: 1px solid #52565E;
+  border-left: 1px solid #52565e;
   border-right: 0;
 }
 #admin-menu .dropdown li li a {
@@ -42,13 +41,13 @@
 /* Second-level lists */
 #admin-menu .dropdown li ul {
   left: auto;
-  right: -999em;
+  right: auto;
 }
 
 /* Third-and-above-level lists */
 #admin-menu .dropdown li li.expandable ul {
-  margin-left: 0;
-  margin-right: 160px;
+  margin-left: 0 !important;
+  margin-right: 160px !important;
 }
 
 /* Lists nested under hovered list items */

+ 8 - 4
sites/all/modules/contrib/admin/admin_menu/admin_menu.admin.js

@@ -1,4 +1,8 @@
-(function($) {
+/**
+ * @file
+ */
+
+(function ($) {
 
 /**
  * Live preview of Administration menu components.
@@ -45,9 +49,9 @@ Drupal.behaviors.adminMenuPermissionsSetupHelp = {
               // Figure out which is the other, check whether it still disabled,
               // and if so, ask whether to auto-enable it.
               var other = (this == $admin[index] ? $menu[index] : $admin[index]);
-              if (!other.checked && confirm(Drupal.t('Also allow !name role to !permission?', {
-                '!name': $roles[index].textContent,
-                '!permission': (this == $admin[index] ? menuPermission : adminPermission)
+              if (!other.checked && confirm(Drupal.t('Also allow @name role to @permission?', {
+                '@name': $roles[index].textContent,
+                '@permission': (this == $admin[index] ? menuPermission : adminPermission)
               }))) {
                 other.checked = 'checked';
               }

+ 1 - 2
sites/all/modules/contrib/admin/admin_menu/admin_menu.color.css

@@ -1,4 +1,3 @@
-
 /**
  * @file
  * Administration menu color override.
@@ -17,7 +16,7 @@
   border-right-color: #a91f1f;
 }
 #admin-menu ul li.admin-menu-tab a {
-  border-right-color: #52565E;
+  border-right-color: #52565e;
 }
 #admin-menu li li a {
   border-top-color: #801f1f;

+ 7 - 7
sites/all/modules/contrib/admin/admin_menu/admin_menu.css

@@ -1,4 +1,3 @@
-
 /**
  * @file
  * Administration menu.
@@ -16,6 +15,7 @@
   position: absolute;
   text-align: left;
   top: 0;
+  height: 30px;
   width: 100%;
 }
 #admin-menu-wrapper {
@@ -62,7 +62,7 @@ body.admin-menu {
 #admin-menu li > span {
   background: transparent none;
   border: none;
-  color: #EEE;
+  color: #eee;
   font-weight: normal;
   text-align: left; /* LTR */
   text-decoration: none;
@@ -74,7 +74,7 @@ body.admin-menu {
   padding: 4px 8px;
 }
 #admin-menu .dropdown .admin-menu-tab a {
-  border-right: 1px solid #52565E; /* LTR */
+  border-right: 1px solid #52565e; /* LTR */
 }
 #admin-menu .dropdown li li a {
   border-right: none; /* LTR */
@@ -147,7 +147,7 @@ body.admin-menu {
 
 /* Second-and-more-level hovering */
 #admin-menu .dropdown li li.expandable {
-  background: #45454A url(images/arrow.png) no-repeat 145px 6px;
+  background: #45454a url(images/arrow.png) no-repeat 145px 6px;
 }
 #admin-menu .dropdown li li:hover {
   background-color: #111;
@@ -155,19 +155,19 @@ body.admin-menu {
 #admin-menu .dropdown li li:hover a,
 #admin-menu .dropdown li li:hover li:hover a,
 #admin-menu .dropdown li li:hover li:hover li:hover a {
-  color: #FFF;
+  color: #fff;
 }
 #admin-menu .dropdown li li.expandable:hover a,
 #admin-menu .dropdown li li.expandable:hover li.expandable:hover a {
   border-color: #444;
-  color: #EEE;
+  color: #eee;
 }
 #admin-menu .dropdown li li.expandable:hover li a,
 #admin-menu .dropdown li li.expandable:hover li.expandable:hover li a {
   border-color: #323232;
 }
 #admin-menu .dropdown li li:hover li a {
-  color: #EEE;
+  color: #eee;
 }
 
 /* Search form */

+ 34 - 24
sites/all/modules/contrib/admin/admin_menu/admin_menu.inc

@@ -97,7 +97,7 @@ function admin_menu_tree_dynamic(array $expand_map) {
   $db_or = db_or();
   foreach ($plids as $path_plids) {
     $db_and = db_and();
-    // plids with value 0 may be ignored.
+    // Plids with value 0 may be ignored.
     foreach (array_filter($path_plids) as $column => $plid) {
       $db_and->condition($column, $plid);
     }
@@ -204,7 +204,7 @@ function admin_menu_merge_tree(array &$tree, array $tree_dynamic, array $expand_
         foreach ($load_functions as $index => $function) {
           if ($function) {
             if (is_array($function)) {
-              list($function,) = each($function);
+              $function = key($function);
             }
             // Add the loader function name minus "_load".
             $placeholder = '%' . substr($function, 0, -5);
@@ -269,7 +269,7 @@ function admin_menu_translate($router_item, $map) {
     // replace any other.
     // @todo Doing this instead leads to plenty of duplicate links below
     //   admin/structure/menu; likely a hidden recursion problem.
-    // $router_item['mlid'] = $router_item['href'] . $router_item['mlid'];
+    // $router_item['mlid'] = $router_item['href'] . $router_item['mlid'];.
     $router_item['mlid'] = $router_item['href'];
     // Turn menu callbacks into regular menu items to make them visible.
     if ($router_item['type'] == MENU_CALLBACK) {
@@ -278,10 +278,12 @@ function admin_menu_translate($router_item, $map) {
 
     // @see _menu_tree_check_access()
     $key = (50000 + $router_item['weight']) . ' ' . $router_item['title'] . ' ' . $router_item['mlid'];
-    return array($key => array(
-      'link' => $router_item,
-      'below' => array(),
-    ));
+    return array(
+      $key => array(
+        'link' => $router_item,
+        'below' => array(),
+      ),
+    );
   }
 
   return array();
@@ -461,20 +463,22 @@ function admin_menu_links_icon() {
     '#access' => user_access('display drupal links'),
     '#href' => 'http://drupal.org',
   );
-  // Add links to project issue queues.
-  foreach (module_list(FALSE, TRUE) as $module) {
-    $info = drupal_parse_info_file(drupal_get_path('module', $module) . '/' . $module . '.info');
-    if (!isset($info['project']) || isset($links['icon']['drupal.org'][$info['project']])) {
-      continue;
+  if (variable_get('admin_menu_issue_queues', TRUE)) {
+    // Add links to project issue queues.
+    foreach (module_list(FALSE, TRUE) as $module) {
+      $info = drupal_parse_info_file(drupal_get_path('module', $module) . '/' . $module . '.info');
+      if (!isset($info['project']) || isset($links['icon']['drupal.org'][$info['project']])) {
+        continue;
+      }
+      $links['icon']['drupal.org'][$info['project']] = array(
+        '#title' => t('@project issue queue', array('@project' => $info['name'])),
+        '#weight' => ($info['project'] == 'drupal' ? -10 : 0),
+        '#href' => 'http://drupal.org/project/issues/' . $info['project'],
+        '#options' => array(
+          'query' => array('version' => (isset($info['core']) ? $info['core'] : 'All')),
+        ),
+      );
     }
-    $links['icon']['drupal.org'][$info['project']] = array(
-      '#title' => t('@project issue queue', array('@project' => $info['name'])),
-      '#weight' => ($info['project'] == 'drupal' ? -10 : 0),
-      '#href' => 'http://drupal.org/project/issues/' . $info['project'],
-      '#options' => array(
-        'query' => array('version' => (isset($info['core']) ? $info['core'] : 'All')),
-      ),
-    );
   }
   // Add items to flush caches.
   $links['icon']['flush-cache'] = array(
@@ -570,7 +574,7 @@ function admin_menu_links_users() {
     '#description' => t('Current anonymous / authenticated users'),
     '#weight' => -90,
     '#attributes' => array('class' => array('admin-menu-action', 'admin-menu-users')),
-    '#href' => (user_access('administer users') ? 'admin/people/people' : 'user'),
+    '#href' => (user_access('administer users') ? 'admin/people' : 'user'),
   );
   return $links;
 }
@@ -658,7 +662,7 @@ function admin_menu_theme_settings() {
     '#default_value' => variable_get('admin_menu_tweak_modules', 0),
   );
   if (module_exists('util')) {
-    $form['tweaks']['admin_menu_tweak_modules']['#description'] .= '<br /><strong>' . t('If the Utility module was installed for this purpose, it can be safely disabled and uninstalled.') . '</strong>';
+    $form['tweaks']['admin_menu_tweak_modules']['#description'] = '<br /><strong>' . t('If the Utility module was installed for this purpose, it can be safely disabled and uninstalled.') . '</strong>';
   }
   $form['tweaks']['admin_menu_tweak_permissions'] = array(
     '#type' => 'checkbox',
@@ -685,6 +689,11 @@ function admin_menu_theme_settings() {
     '#title' => t('Cache menu in client-side browser'),
     '#default_value' => variable_get('admin_menu_cache_client', 1),
   );
+  $form['performance']['admin_menu_issue_queues'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Show Issue Queue links in icon menu'),
+    '#default_value' => variable_get('admin_menu_issue_queues', 1),
+  );
 
   return system_settings_form($form);
 }
@@ -763,18 +772,20 @@ function admin_menu_flush_cache($name = NULL) {
     if (!isset($caches[$name])) {
       return MENU_NOT_FOUND;
     }
+    $message = t('@title cache cleared.', array('@title' => $caches[$name]['title']));
   }
   else {
     $caches[$name] = array(
       'title' => t('Every'),
       'callback' => 'drupal_flush_all_caches',
     );
+    $message = t('All caches cleared.');
   }
   // Pass the cache to flush forward to the callback.
   $function = $caches[$name]['callback'];
   $function($name);
 
-  drupal_set_message(t('!title cache cleared.', array('!title' => $caches[$name]['title'])));
+  drupal_set_message($message);
 
   // The JavaScript injects a destination request parameter pointing to the
   // originating page, so the user is redirected back to that page. Without
@@ -907,4 +918,3 @@ function template_preprocess_admin_menu_icon(&$variables) {
 function theme_admin_menu_icon($variables) {
   return '<img class="admin-menu-icon" src="' . $variables['src'] . '" width="16" height="16" alt="' . $variables['alt'] . '" />';
 }
-

+ 3 - 4
sites/all/modules/contrib/admin/admin_menu/admin_menu.info

@@ -8,9 +8,8 @@ configure = admin/config/administration/admin_menu
 dependencies[] = system (>7.10)
 files[] = tests/admin_menu.test
 
-; Information added by Drupal.org packaging script on 2014-12-19
-version = "7.x-3.0-rc5"
+; Information added by Drupal.org packaging script on 2018-12-03
+version = "7.x-3.0-rc6"
 core = "7.x"
 project = "admin_menu"
-datestamp = "1419029284"
-
+datestamp = "1543859284"

+ 8 - 4
sites/all/modules/contrib/admin/admin_menu/admin_menu.js

@@ -1,4 +1,8 @@
-(function($) {
+/**
+ * @file
+ */
+
+(function ($) {
 
 Drupal.admin = Drupal.admin || {};
 Drupal.admin.behaviors = Drupal.admin.behaviors || {};
@@ -139,7 +143,7 @@ Drupal.admin.getCache = function (hash, onSuccess) {
  *
  * @see toolbar.js
  */
-Drupal.admin.height = function() {
+Drupal.admin.height = function () {
   var $adminMenu = $('#admin-menu');
   var height = $adminMenu.outerHeight();
   // In IE, Shadow filter adds some extra height, so we need to remove it from
@@ -161,7 +165,7 @@ Drupal.admin.height = function() {
 Drupal.admin.attachBehaviors = function (context, settings, $adminMenu) {
   if ($adminMenu.length) {
     $adminMenu.addClass('admin-menu-processed');
-    $.each(Drupal.admin.behaviors, function() {
+    $.each(Drupal.admin.behaviors, function () {
       this(context, settings, $adminMenu);
     });
   }
@@ -206,7 +210,7 @@ Drupal.admin.behaviors.replacements = function (context, settings, $adminMenu) {
  */
 Drupal.admin.behaviors.destination = function (context, settings, $adminMenu) {
   if (settings.admin_menu.destination) {
-    $('a.admin-menu-destination', $adminMenu).each(function() {
+    $('a.admin-menu-destination', $adminMenu).each(function () {
       this.search += (!this.search.length ? '?' : '&') + Drupal.settings.admin_menu.destination;
     });
   }

+ 8 - 1
sites/all/modules/contrib/admin/admin_menu/admin_menu.map.inc

@@ -80,7 +80,14 @@ function field_ui_admin_menu_map() {
         'access callback' => 'user_access',
         'access arguments' => array('administer site configuration'),
       );
-      if (!call_user_func_array($bundle_info['admin']['access callback'], $bundle_info['admin']['access arguments'])) {
+      $access_arguments = $bundle_info['admin']['access arguments'];
+      if (isset($bundle_info['admin']['real path'])) {
+        $menu_item = menu_get_item($bundle_info['admin']['real path']);
+        if (isset($menu_item['map'])) {
+          $access_arguments = menu_unserialize(serialize($access_arguments), $menu_item['map']);
+        }
+      }
+      if (!call_user_func_array($bundle_info['admin']['access callback'], $access_arguments)) {
         continue;
       }
 

+ 25 - 14
sites/all/modules/contrib/admin/admin_menu/admin_menu.module

@@ -63,7 +63,7 @@ function admin_menu_theme() {
 function admin_menu_menu() {
   // AJAX callback.
   // @see http://drupal.org/project/js
-  $items['js/admin_menu/cache'] = array(
+  $items['js/admin_menu/cache/%'] = array(
     'page callback' => 'admin_menu_js_cache',
     'delivery callback' => 'admin_menu_deliver',
     'access arguments' => array('access administration menu'),
@@ -78,7 +78,7 @@ function admin_menu_menu() {
     'file' => 'system.admin.inc',
     'file path' => drupal_get_path('module', 'system'),
   );
-  $items['admin/config/administration/admin_menu'] = array(
+  $items['admin/config/administration/admin-menu'] = array(
     'title' => 'Administration menu',
     'description' => 'Adjust administration menu settings.',
     'page callback' => 'drupal_get_form',
@@ -211,7 +211,7 @@ function admin_menu_page_build(&$page) {
     // @todo Drupal.behaviors.adminMenuMarginTop is obsolete, but
     //   hook_page_build() does not allow to set a CSS class on the body yet.
     // @see http://drupal.org/node/1473548, http://drupal.org/node/1194528
-    //$page['#attributes']['class'][] = 'admin-menu';
+    // $page['#attributes']['class'][] = 'admin-menu';
   }
   if ($setting = variable_get('admin_menu_position_fixed', 1)) {
     $settings['position_fixed'] = $setting;
@@ -230,7 +230,7 @@ function admin_menu_page_build(&$page) {
   if ($_GET['q'] == 'admin/modules' || strpos($_GET['q'], 'admin/modules/list') === 0) {
     $settings['tweak_modules'] = variable_get('admin_menu_tweak_modules', 0);
   }
-  if ($_GET['q'] == 'admin/people/permissions' || $_GET['q'] == 'admin/people/permissions/list') {
+  if (strpos($_GET['q'], 'admin/people/permissions') === 0) {
     $settings['tweak_permissions'] = variable_get('admin_menu_tweak_permissions', 0);
   }
 
@@ -502,7 +502,6 @@ function admin_menu_output($complete = FALSE) {
 
     // @todo Move the below callbacks into hook_admin_menu_build()
     //   implementations (and $module.admin_menu.inc).
-
     // Add administration menu.
     if (!empty($components['admin_menu.menu']) || $complete) {
       $content['menu'] = admin_menu_links_menu(admin_menu_tree('management'));
@@ -548,7 +547,10 @@ function admin_menu_output($complete = FALSE) {
 
   // Store the new hash for this user.
   if (!empty($_COOKIE['has_js']) && !$complete) {
-    admin_menu_cache_set($cid, md5($content));
+    $cache = cache_get($cid, 'cache_admin_menu');
+    if (!$cache || !isset($cache->data)) {
+      admin_menu_cache_set($cid, md5($content));
+    }
   }
 
   return $content;
@@ -603,11 +605,13 @@ function admin_menu_admin_menu_output_build(&$content) {
  * Implements hook_admin_menu_output_alter().
  */
 function admin_menu_admin_menu_output_alter(&$content) {
-  foreach ($content['menu'] as $key => $link) {
-    // Move local tasks on 'admin' into icon menu.
-    if ($key == 'admin/tasks' || $key == 'admin/index') {
-      $content['icon']['icon'][$key] = $link;
-      unset($content['menu'][$key]);
+  if (!empty($content['menu'])) {
+    foreach ($content['menu'] as $key => $link) {
+      // Move local tasks on 'admin' into icon menu.
+      if ($key == 'admin/tasks' || $key == 'admin/index') {
+        $content['icon']['icon'][$key] = $link;
+        unset($content['menu'][$key]);
+      }
     }
   }
 }
@@ -677,6 +681,13 @@ function theme_admin_menu_links($variables) {
         $elements[$path]['#options']['attributes']['class'][] = 'admin-menu-destination';
       }
 
+      // If the path has an alias replace the href with the alias.
+      if (module_exists('path')) {
+        if ($alias = drupal_get_path_alias($elements[$path]['#href'])) {
+          $elements[$path]['#href'] = $alias;
+        }
+      }
+
       $link = l($elements[$path]['#title'], $elements[$path]['#href'], $elements[$path]['#options']);
     }
     // Handle plain text items, but do not interfere with menu additions.
@@ -751,7 +762,7 @@ function admin_menu_translated_menu_link_alter(&$item, $map) {
     }
   }
 
-  // Don't waste cycles altering items that are not visible
+  // Don't waste cycles altering items that are not visible.
   if (!$item['access']) {
     return;
   }
@@ -795,8 +806,8 @@ function admin_menu_flush_caches($uid = NULL) {
   cache_clear_all($cid, 'cache_menu', TRUE);
   // Flush client-side cache hashes.
   drupal_static_reset('admin_menu_cache_get');
-  // db_table_exists() required for SimpleTest.
-  if (db_table_exists('cache_admin_menu')) {
+  // If cache_admin_menu is not empty, flush it.
+  if (!cache_is_empty('cache_admin_menu')) {
     cache_clear_all(isset($uid) ? $cid : '*', 'cache_admin_menu', TRUE);
   }
 }

+ 0 - 1
sites/all/modules/contrib/admin/admin_menu/admin_menu.uid1.css

@@ -1,4 +1,3 @@
-
 /**
  * @file
  * Administration menu color override for uid1.

+ 4 - 0
sites/all/modules/contrib/admin/admin_menu/admin_menu_toolbar/admin_menu_toolbar-rtl.css

@@ -0,0 +1,4 @@
+#admin-menu > div > .dropdown > li > a,
+#admin-menu > div > .dropdown > li > span {
+  border-left: 0;
+}

+ 3 - 4
sites/all/modules/contrib/admin/admin_menu/admin_menu_toolbar/admin_menu_toolbar.css

@@ -1,4 +1,3 @@
-
 /**
  * @file
  * Toolbar style for Administration menu.
@@ -63,8 +62,9 @@ body div#toolbar.toolbar {
   background: url(toolbar.png) no-repeat 0 -45px;
   text-indent: -9999px;
 }
-#admin-menu > div > .dropdown > li > a {
-  border-right: 0;
+#admin-menu > div > .dropdown > li > a,
+#admin-menu > div > .dropdown > li > span {
+  border-right: 0; /* LTR */
   margin-bottom: 4px;
   padding: 2px 10px 3px;
 }
@@ -142,4 +142,3 @@ body div#toolbar.toolbar {
 #admin-menu .shortcut-toolbar a {
   display: block;
 }
-

+ 3 - 4
sites/all/modules/contrib/admin/admin_menu/admin_menu_toolbar/admin_menu_toolbar.info

@@ -4,9 +4,8 @@ package = Administration
 core = 7.x
 dependencies[] = admin_menu
 
-; Information added by Drupal.org packaging script on 2014-12-19
-version = "7.x-3.0-rc5"
+; Information added by Drupal.org packaging script on 2018-12-03
+version = "7.x-3.0-rc6"
 core = "7.x"
 project = "admin_menu"
-datestamp = "1419029284"
-
+datestamp = "1543859284"

+ 0 - 1
sites/all/modules/contrib/admin/admin_menu/admin_menu_toolbar/admin_menu_toolbar.install

@@ -34,4 +34,3 @@ function admin_menu_toolbar_update_6300() {
     ->condition('name', 'admin_menu_toolbar')
     ->execute();
 }
-

+ 0 - 1
sites/all/modules/contrib/admin/admin_menu/admin_menu_toolbar/admin_menu_toolbar.module

@@ -115,4 +115,3 @@ function admin_menu_toolbar_admin_menu_output_alter(&$content) {
     $content['account']['account']['#options']['html'] = TRUE;
   }
 }
-

+ 51 - 16
sites/all/modules/contrib/admin/admin_menu/tests/admin_menu.test

@@ -16,7 +16,10 @@ class AdminMenuWebTestCase extends DrupalWebTestCase {
     'admin_menu' => 'access administration menu',
   );
 
-  function setUp() {
+  /**
+   *
+   */
+  public function setUp() {
     // Enable admin menu module and any other modules.
     $modules = func_get_args();
     $modules = isset($modules[0]) ? $modules[0] : $modules;
@@ -108,12 +111,17 @@ class AdminMenuWebTestCase extends DrupalWebTestCase {
     $xpath = '//div[@id="admin-menu"]/div/ul' . implode('/parent::li/ul', $xpath);
     $this->assertNoElementByXPath($xpath, $args, $message . ' link not found.');
   }
+
 }
 
 /**
  * Tests menu links depending on user permissions.
  */
 class AdminMenuPermissionsTestCase extends AdminMenuWebTestCase {
+
+  /**
+   *
+   */
   public static function getInfo() {
     return array(
       'name' => 'Menu link access permissions',
@@ -122,14 +130,17 @@ class AdminMenuPermissionsTestCase extends AdminMenuWebTestCase {
     );
   }
 
-  function setUp() {
+  /**
+   *
+   */
+  public function setUp() {
     parent::setUp(array('node'));
   }
 
   /**
    * Test that the links are added to the page (no JS testing).
    */
-  function testPermissions() {
+  public function testPermissions() {
     module_enable(array('contact'));
     $this->resetAll();
 
@@ -140,7 +151,7 @@ class AdminMenuPermissionsTestCase extends AdminMenuWebTestCase {
     // Create a user who
     // - can access content overview
     // - cannot access drupal.org links
-    // - cannot administer Contact module
+    // - cannot administer Contact module.
     $permissions = $this->basePermissions + array(
       'access content overview',
     );
@@ -156,7 +167,7 @@ class AdminMenuPermissionsTestCase extends AdminMenuWebTestCase {
     // Create a user "reversed" to the above; i.e., who
     // - cannot access content overview
     // - can access drupal.org links
-    // - can administer Contact module
+    // - can administer Contact module.
     $permissions = $this->basePermissions + array(
       'display drupal links',
       'administer contact forms',
@@ -172,7 +183,7 @@ class AdminMenuPermissionsTestCase extends AdminMenuWebTestCase {
   /**
    * Tests handling of links pointing to category/overview pages.
    */
-  function testCategories() {
+  public function testCategories() {
     // Create a user with minimum permissions.
     $admin_user = $this->drupalCreateUser($this->basePermissions);
     $this->drupalLogin($admin_user);
@@ -201,7 +212,7 @@ class AdminMenuPermissionsTestCase extends AdminMenuWebTestCase {
   /**
    * Tests that user role and permission changes are properly taken up.
    */
-  function testPermissionChanges() {
+  public function testPermissionChanges() {
     // Create a user who is able to change permissions.
     $permissions = $this->basePermissions + array(
       'administer permissions',
@@ -253,12 +264,17 @@ class AdminMenuPermissionsTestCase extends AdminMenuWebTestCase {
     // Verify that Structure » Content types does not appear.
     $this->assertNoLinkTrailByTitle(array(t('Structure'), t('Content types')));
   }
+
 }
 
 /**
  * Tests appearance, localization, and escaping of dynamic links.
  */
 class AdminMenuDynamicLinksTestCase extends AdminMenuWebTestCase {
+
+  /**
+   *
+   */
   public static function getInfo() {
     return array(
       'name' => 'Dynamic links',
@@ -267,14 +283,17 @@ class AdminMenuDynamicLinksTestCase extends AdminMenuWebTestCase {
     );
   }
 
-  function setUp() {
+  /**
+   *
+   */
+  public function setUp() {
     parent::setUp(array('node'));
   }
 
   /**
    * Tests node type links.
    */
-  function testNode() {
+  public function testNode() {
     $type = $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
     // Create a content-type with special characters.
     $type = $this->drupalCreateContentType(array('type' => 'special', 'name' => 'Cool & Special'));
@@ -324,7 +343,7 @@ class AdminMenuDynamicLinksTestCase extends AdminMenuWebTestCase {
   /**
    * Tests Add content links.
    */
-  function testNodeAdd() {
+  public function testNodeAdd() {
     $type = $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
 
     // Verify that "Add content" does not appear for unprivileged users.
@@ -359,12 +378,17 @@ class AdminMenuDynamicLinksTestCase extends AdminMenuWebTestCase {
       t('Add content'),
     ));
   }
+
 }
 
 /**
  * Tests appearance of different types of links.
  */
 class AdminMenuLinkTypesTestCase extends AdminMenuWebTestCase {
+
+  /**
+   *
+   */
   public static function getInfo() {
     return array(
       'name' => 'Link types',
@@ -373,7 +397,10 @@ class AdminMenuLinkTypesTestCase extends AdminMenuWebTestCase {
     );
   }
 
-  function setUp() {
+  /**
+   *
+   */
+  public function setUp() {
     parent::setUp(array('help'));
 
     $permissions = module_invoke_all('permission');
@@ -385,7 +412,7 @@ class AdminMenuLinkTypesTestCase extends AdminMenuWebTestCase {
   /**
    * Tests appearance of different router item link types.
    */
-  function testLinkTypes() {
+  public function testLinkTypes() {
     // Verify that MENU_NORMAL_ITEMs appear.
     $this->assertLinkTrailByTitle(array(
       t('Configuration'),
@@ -420,12 +447,17 @@ class AdminMenuLinkTypesTestCase extends AdminMenuWebTestCase {
       ':title' => t('Index'),
     ), "Icon » Index link found.");
   }
+
 }
 
 /**
  * Tests customized menu links.
  */
 class AdminMenuCustomizedTestCase extends AdminMenuWebTestCase {
+
+  /**
+   *
+   */
   public static function getInfo() {
     return array(
       'name' => 'Customized links',
@@ -434,7 +466,10 @@ class AdminMenuCustomizedTestCase extends AdminMenuWebTestCase {
     );
   }
 
-  function setUp() {
+  /**
+   *
+   */
+  public function setUp() {
     parent::setUp(array('menu'));
 
     $this->admin_user = $this->drupalCreateUser($this->basePermissions + array(
@@ -446,7 +481,7 @@ class AdminMenuCustomizedTestCase extends AdminMenuWebTestCase {
   /**
    * Test disabled custom links.
    */
-  function testCustomDisabled() {
+  public function testCustomDisabled() {
     $type = $this->drupalCreateContentType();
     $node = $this->drupalCreateNode(array('type' => $type->type));
     $text = $this->randomName();
@@ -488,7 +523,7 @@ class AdminMenuCustomizedTestCase extends AdminMenuWebTestCase {
   /**
    * Tests external links.
    */
-  function testCustomExternal() {
+  public function testCustomExternal() {
     // Add a custom link to the node to the menu.
     $edit = array(
       'link_path' => 'http://example.com',
@@ -516,5 +551,5 @@ class AdminMenuCustomizedTestCase extends AdminMenuWebTestCase {
       ':path' => $path,
     ))->fetchField();
   }
-}
 
+}

+ 27 - 6
sites/all/modules/contrib/admin/entity_translation_export_import/entity_translation_export_import.admin.inc

@@ -465,12 +465,33 @@ function entity_translation_export_import_import_translation($data){
   $bundle = $data['Bundle (Not Editable)'];
   $entity_id = $data['Entity ID (Not Editable)'];
 
-  $entities = entity_load($entity_type, array($entity_id));
-
-  // If cannot load entity.
-  if(empty($entities)){
-    drupal_set_message(t('Entity with id @id could not be found in database.', array('@id' => $entity_id)));
-    return FALSE;
+  if(empty($entity_id)) {
+    if ($entity_type == 'taxonomy_term') {
+      // Handle taxonomy term entity.
+      $vocab = taxonomy_vocabulary_machine_name_load($bundle);
+      $term = new stdClass();
+      $term->name = '';
+      $term->vid = $vocab->vid;
+      taxonomy_term_save($term);
+
+      $entities = entity_load($entity_type, array($term->tid));
+    }
+    else if($entity_type == 'node') {
+      // Handle node entity.
+      $node = new stdClass();
+      $node->type = $bundle;
+      node_object_prepare($node);  //Set some default values
+      $node->status = 1;
+      $node->promote = 0;
+      $node->sticky = 0;
+      $node->uid = $user->uid;
+     node_save($node);
+
+     $entities = entity_load($entity_type, array($node->nid));
+    }
+  }
+  else {
+    $entities = entity_load($entity_type, array($entity_id));
   }
 
   // Get the entity.

+ 3 - 3
sites/all/modules/contrib/admin/entity_translation_export_import/entity_translation_export_import.info

@@ -5,9 +5,9 @@ package = Multilingual - Entity Translation
 dependencies[] = entity
 dependencies[] = entity_translation
 
-; Information added by drupal.org packaging script on 2013-09-30
-version = "7.x-1.0-beta3+0-dev"
+; Information added by Drupal.org packaging script on 2017-02-08
+version = "7.x-1.0-beta4"
 core = "7.x"
 project = "entity_translation_export_import"
-datestamp = "1380577025"
+datestamp = "1486567689"
 

+ 175 - 89
sites/all/modules/contrib/dev/addressfield_tokens/addressfield_tokens.components.inc

@@ -1,13 +1,13 @@
 <?php
 /**
  * @file
- * Webform Component information for an address field type
+ * Webform Component information for an address field type.
  */
 
 /**
  * Specify the default properties of a component.
  *
- * @return
+ * @return array
  *   An array defining the default structure of a component.
  */
 function _webform_defaults_addressfield() {
@@ -23,6 +23,8 @@ function _webform_defaults_addressfield() {
       'attributes'                => array(),
       'description'               => '',
       'available_countries'       => array(),
+      'default_country'           => '',
+      'format_handlers'           => array(),
       'csv_separate'              => 0,
     ),
   );
@@ -30,21 +32,22 @@ function _webform_defaults_addressfield() {
 
 /**
  * Generate the form for editing a component.
+ *
  * Create a set of form elements to be displayed on the form for editing this
  * component. Use care naming the form items, as this correlates directly to the
  * database schema. The component "Name" and "Description" fields are added to
  * every component type and are not necessary to specify here (although they
  * may be overridden if desired).
  *
- * @param $component
+ * @param mixed $component
  *   A Webform component array.
  *
- * @return
+ * @return array
  *   An array of form items to be displayed on the edit component page
  */
 function _webform_edit_addressfield($component) {
   $form = array();
-  
+
   $form['extra']['available_countries'] = array(
     '#type' => 'select',
     '#multiple' => TRUE,
@@ -53,6 +56,21 @@ function _webform_edit_addressfield($component) {
     '#options' => _addressfield_country_options_list(),
     '#default_value' => $component['extra']['available_countries'],
   );
+  $form['extra']['default_country'] = array(
+    '#type' => 'select',
+    '#multiple' => FALSE,
+    '#title' => t('Default country'),
+    '#description' => t('Select which country should be selected as the default.'),
+    '#options' => array_merge(array(0 => t('- None -')), _addressfield_country_options_list()),
+    '#default_value' => $component['extra']['default_country'],
+  );
+  $form['extra']['format_handlers'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Format handlers'),
+    '#options' => addressfield_format_plugins_options(),
+    '#required' => TRUE,
+    '#default_value' => !empty($component['extra']['format_handlers']) ? $component['extra']['format_handlers'] : array('address'),
+  );
   $form['extra']['csv_separate'] = array(
     '#type' => 'radios',
     '#title' => t('CSV download'),
@@ -69,18 +87,21 @@ function _webform_edit_addressfield($component) {
 /**
  * Render a Webform component to be part of a form.
  *
- * @param $component
+ * @param mixed $component
  *   A Webform component array.
- * @param $value
+ * @param mixed $value
  *   If editing an existing submission or resuming a draft, this will contain
  *   an array of values to be shown instead of the default in the component
  *   configuration. This value will always be an array, keyed numerically for
  *   each value saved in this field.
- * @param $filter
+ * @param bool $filter
  *   Whether or not to filter the contents of descriptions and values when
  *   rendering the component. Values need to be unfiltered to be editable by
  *   Form Builder.
  *
+ * @return array
+ *   Form element.
+ *
  * @see _webform_client_form_add_component()
  */
 function _webform_render_addressfield($component, $value = NULL, $filter = TRUE) {
@@ -98,55 +119,98 @@ function _webform_render_addressfield($component, $value = NULL, $filter = TRUE)
       'description',
     ),
   );
-  
+
   $available = !empty($component['extra']['available_countries']) ? $component['extra']['available_countries'] : NULL;
-    
-  // Get the current address
-  if (!empty($value[0])) {
-    if (is_string($value[0])) {
-      $address = unserialize($value[0]);
+
+  // Get the current address.
+  $address = _addressfield_tokens_expand_value($value);
+  if (empty($address)) {
+    if (!empty($component['value'])) {
+      $address = $component['value'];
     }
     else {
-      $address = $value[0];
+      $address = _webform_addressfield($component['cid']);
     }
   }
-  elseif (!empty($component['value'])) {
-    $address = $component['value'];
-  }
-  else {
-    $address = _webform_addressfield($component['cid']);
-  }
   if (empty($address)) {
-    $address = addressfield_default_values($available);
+    $address = _webform_addressfield_default_values($available, $component);
   }
-  
+
   // Generate the address form.
   $context = array(
     'mode' => 'form',
+    'instance' => array(
+      'required' => $component['required'],
+    ),
+    'form_key' => $component['form_key'],
   );
-  $element += addressfield_generate($address, array('address'), $context);
-  
-  if (!empty($available)) {
-    $element['country']['#options'] = array_intersect_key($element['country']['#options'], $available);
+  $handlers = !empty($component['extra']['format_handlers']) ? $component['extra']['format_handlers'] : array('address');
+  $element += addressfield_generate($address, $handlers, $context);
+
+  if (empty($address['country'])) {
+    $element['street_block']['#access'] = FALSE;
+    $element['locality_block']['#access'] = FALSE;
+  }
+
+  if (isset($element['country'])) {
+    if (!empty($available)) {
+      $element['country']['#options'] = array_intersect_key($element['country']['#options'], $available);
+
+      // Hide the country element only if there is one option and the whole field
+      // is required, otherwise there will always be an additional None option.
+      // @see addressfield_format_address_hide_country()
+      if (!empty($handlers['address-hide-country']) && count($element['country']['#options']) == 1 && $component['required']) {
+        $element['country']['#access'] =  FALSE;
+      }
+    }
+    $element['country']['#default_value'] = $address['country'];
+    $element['country']['#element_validate'] = array('_webform_addressfield_country_validate');
+    $element['country']['#cid'] = $component['cid'];
+    $element['country']['#limit_validation_errors'] = array();
   }
-  $element['country']['#element_validate'] = array('_webform_addressfield_country_validate');
-  $element['country']['#cid'] = $component['cid'];
-  $element['country']['#limit_validation_errors'] = array();
-  
+
   $form_state = array();
-  drupal_alter('field_widget_addressfield_standard_form', $element, $form_state, $context); 
-  
+  drupal_alter('field_widget_addressfield_standard_form', $element, $form_state, $context);
+
   return $element;
 }
 
+function _webform_addressfield_default_values($available, $component) {
+  $default_country = !empty($component['extra']['default_country'])
+    ? $component['extra']['default_country']
+    : addressfield_tokens_default_country();
+  $default_values = array(
+    'country' => $default_country,
+    'name_line' => '',
+    'first_name' => '',
+    'last_name' => '',
+    'organisation_name' => '',
+    'administrative_area' => '',
+    'sub_administrative_area' => '',
+    'locality' => '',
+    'dependent_locality' => '',
+    'postal_code' => '',
+    'thoroughfare' => '',
+    'premise' => '',
+    'sub_premise' => '',
+    'data' => '',
+  );
+  return ($default_values);
+}
+
 /**
- * Stores an addressfield submitted in a webform component.  Ideally we should store
- * it in the $form_state instead, but there appears to be no way to get it to actually
- * pass through to _webform_render_addressfield().
- * 
- * @param $cid integer The ID of the webform component.
- * @param $address array If set, this address will be stored with the given $cid.
- * @return array The address stored with the given $cid, if there is one; otherwise, NULL.
+ * Stores an addressfield submitted in a webform component.
+ *
+ * Ideally store it in the $form_state instead, but there appears to be no way
+ * to get it to actually pass through to _webform_render_addressfield().
+ *
+ * @param int $cid
+ *   The ID of the webform component.
+ * @param mixed $address
+ *   If set, this address will be stored with the given $cid.
+ *
+ * @return array
+ *   The address stored with the given $cid, if there is one; otherwise, NULL.
  */
 function _webform_addressfield($cid, $address = NULL) {
   $out = &drupal_static(__FUNCTION__, array());
@@ -160,40 +224,41 @@ function _webform_addressfield($cid, $address = NULL) {
 }
 
 /**
- * Validates a country, and if it changes, rebuilds the form for the new country
+ * Validates a country, and if changed, rebuilds the form for the new country.
  */
 function _webform_addressfield_country_validate(&$element, &$form_state) {
   // If the country was changed, rebuild the form.
-  if ($element['#default_value'] != $element['#value']) {
+  if (!isset($element['#default_value']) || $element['#default_value'] != $element['#value']) {
     $form_state['rebuild'] = TRUE;
   }
-  
+
   $cid = $element['#cid'];
   $parents = $element['#parents'];
   array_pop($parents);
 
   // Search through the form values to find the current address.
   $address = drupal_array_get_nested_value($form_state['values'], $parents);
-  
+
   _webform_addressfield($cid, $address);
 }
 
 /**
  * Display the result of a submission for a component.
+ *
  * The output of this function will be displayed under the "Results" tab then
  * "Submissions". This should output the saved data in some reasonable manner.
  *
- * @param $component
+ * @param mixed $component
  *   A Webform component array.
- * @param $value
+ * @param mixed $value
  *   An array of information containing the submission result, directly
  *   correlating to the webform_submitted_data database table schema.
- * @param $format
+ * @param string $format
  *   Either 'html' or 'text'. Defines the format that the content should be
  *   returned as. Make sure that returned content is run through check_plain()
  *   or other filtering functions when returning HTML.
  *
- * @return
+ * @return array
  *   A renderable element containing at the very least these properties:
  *    - #title
  *    - #weight
@@ -205,27 +270,23 @@ function _webform_addressfield_country_validate(&$element, &$form_state) {
  *   (such as wrapping the text) or as HTML (ensuring consistent output).
  */
 function _webform_display_addressfield($component, $value, $format = 'html') {
-  $address = NULL;
-  if (isset($value[0])) {
-    $address = $value[0];
-    if (is_string($address)) {
-      $address = unserialize($address);
-    }
-  }
+  $address = _addressfield_tokens_expand_value($value);
   return array(
     '#title'          => $component['name'],
     '#weight'         => $component['weight'],
     '#theme'          => $format == 'html' ? 'addressfield_formatter' : 'addressfield_formatter__linear',
-    '#theme_wrappers' => $format == 'html' ? array('webform_element' ) : array('webform_element_text'),
+    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
     '#post_render'    => array('webform_element_wrapper'),
     '#component'      => $component,
     '#format'         => $format,
-    '#address'        => $address,
+    '#address'        => $address ? $address : NULL,
+    '#handlers'       => $component['extra']['format_handlers'],
   );
 }
 
 /**
  * A hook for changing the input values before saving to the database.
+ *
  * Webform expects a component to consist of a single field, or a single array
  * of fields. If you have a component that requires a deeper form tree
  * you must flatten the data into a single array using this callback
@@ -234,12 +295,12 @@ function _webform_display_addressfield($component, $value, $format = 'html') {
  * Note that Webform will save the result of this function directly into the
  * database.
  *
- * @param $component
+ * @param mixed $component
  *   A Webform component array.
- * @param $value
+ * @param mixed $value
  *   The POST data associated with the user input.
  *
- * @return
+ * @return array
  *   An array of values to be saved into the database. Note that this should be
  *   a numerically keyed array.
  */
@@ -249,88 +310,92 @@ function _webform_submit_addressfield($component, $value) {
 
 /**
  * Calculate and returns statistics about results for this component.
+ *
  * This takes into account all submissions to this webform. The output of this
  * function will be displayed under the "Results" tab then "Analysis".
  *
- * @param $component
+ * @param mixed $component
  *   An array of information describing the component, directly correlating to
  *   the webform_component database schema.
- * @param $sids
+ * @param mixed $sids
  *   An optional array of submission IDs (sid). If supplied, the analysis will
  *   be limited to these sids.
- * @param $single
+ * @param bool $single
  *   Boolean flag determining if the details about a single component are being
  *   shown. May be used to provided detailed information about a single
  *   component's analysis, such as showing "Other" options within a select list.
  *
- * @return
+ * @return array
  *   An array of data rows, each containing a statistic for this component's
  *   submissions.
  */
 function _webform_analysis_addressfield($component, $sids = array(), $single = FALSE) {
-  // TODO Update this function
-  
+  // @todo Update this function
+
   // Generate the list of options and questions.
   $query = db_select('webform_submitted_data', 'wsd')
     ->fields('wsd', array('data'))
     ->condition('nid', $component['nid'])
     ->condition('cid', $component['cid']);
-    
-  if ( count($sids) ) {
+
+  if (count($sids)) {
     $query->condition('sid', $sids, 'IN');
   }
   $non_blanks = 0;
   $submissions = 0;
   $results = $query->execute();
   foreach ($results as $row) {
-    if ( drupal_strlen(trim($row->data)) > 0 ) {
+    if (drupal_strlen(trim($row->data)) > 0) {
       $non_blanks++;
     }
     $submissions++;
   }
   $rows[0] = array(
     t('Left Blank'),
-    ( $submissions - $non_blanks )
+    ($submissions - $non_blanks),
   );
   $rows[1] = array(
     t('User entered value'),
-    $non_blanks
+    $non_blanks,
   );
-  return $rows;
+  return array('table_rows' => $rows);
 }
 
 /**
  * Return the result of a component value for display in a table.
+ *
  * The output of this function will be displayed under the "Results" tab then
  * "Table".
  *
- * @param $component
+ * @param mixed $component
  *   A Webform component array.
- * @param $value
+ * @param mixed $value
  *   An array of information containing the submission result, directly
  *   correlating to the webform_submitted_data database schema.
  *
- * @return
+ * @return string
  *   Textual output formatted for human reading.
  */
 function _webform_table_addressfield($component, $value) {
-  if (!empty($value[0])) {
-    return theme('addressfield_formatter', array( 'address' => $value[0] ));
+  $address = _addressfield_tokens_expand_value($value);
+  if ($address) {
+    return theme('addressfield_formatter', array('address' => $address));
   }
   return '';
 }
 
 /**
  * Return the header for this component to be displayed in a CSV file.
+ *
  * The output of this function will be displayed under the "Results" tab then
  * "Download".
  *
- * @param $component
+ * @param mixed $component
  *   A Webform component array.
- * @param $export_options
+ * @param mixed $export_options
  *   An array of options that may configure export of this field.
  *
- * @return
+ * @return array
  *   An array of data to be displayed in the first three rows of a CSV file, not
  *   including either prefixed or trailing commas.
  */
@@ -340,7 +405,6 @@ function _webform_csv_headers_addressfield($component, $export_options) {
     $header[0] = array();
     $header[1] = array();
     $header[2] = array();
-    
     foreach (addressfield_tokens_property_names() as $key => $name) {
       $header[0][] = '';
       $header[1][] = (empty($header[1])) ? $component['name'] : '';
@@ -349,7 +413,7 @@ function _webform_csv_headers_addressfield($component, $export_options) {
   }
   else {
     $header[0] = array('');
-    $header[1] = array();
+    $header[1] = array('');
     $header[2] = array($component['name']);
   }
   return $header;
@@ -357,34 +421,56 @@ function _webform_csv_headers_addressfield($component, $export_options) {
 
 /**
  * Format the submitted data of a component for CSV downloading.
+ *
  * The output of this function will be displayed under the "Results" tab then
  * "Download".
  *
- * @param $component
+ * @param mixed $component
  *   A Webform component array.
- * @param $export_options
+ * @param mixed $export_options
  *   An array of options that may configure export of this field.
- * @param $value
+ * @param mixed $value
  *   An array of information containing the submission result, directly
  *   correlating to the webform_submitted_data database schema.
  *
- * @return
+ * @return array
  *   An array of items to be added to the CSV file. Each value within the array
  *   will be another column within the file. This function is called once for
  *   every row of data.
  */
 function _webform_csv_data_addressfield($component, $export_options, $value) {
+  $address = _addressfield_tokens_expand_value($value);
   if (!empty($component['extra']['csv_separate']) && $component['extra']['csv_separate'] == 1) {
+    // Each address component should be in a separate column.
     $return = array();
     foreach (addressfield_tokens_property_names() as $key => $name) {
-      $return[] = (isset($value[0][$key])) ? $value[0][$key] : '';
+      $return[] = (isset($address[$key])) ? $address[$key] : '';
     }
     return $return;
   }
   else {
-    if (!empty($value[0])) {
-      return theme('addressfield_formatter__linear', array( 'address' => $value[0] ));
+    // The entire address should be displayed in the one column.
+    if ($address) {
+      return theme('addressfield_formatter__linear', array('address' => $address));
     }
     return '';
   }
 }
+
+/**
+ * Expand a raw address submission as loaded from the database to an array.
+ *
+ * @param string $value
+ *   An array of information containing the submission result, directly
+ *   correlating to the {webform_submitted_data} database schema.
+ *
+ * @return array|false
+ *   An associative array of address fields, or FALSE on failure.
+ */
+function _addressfield_tokens_expand_value($value) {
+  if (isset($value[0]) && is_string($value[0])) {
+    return unserialize($value[0]);
+  }
+  return FALSE;
+}
+

+ 10 - 13
sites/all/modules/contrib/dev/addressfield_tokens/addressfield_tokens.info

@@ -1,16 +1,13 @@
-
-name = Address Field Tokens
-description = Creates tokens for address fields, adds new addressfield renders, and adds webform integration.
-core = 7.x
-package = Fields
-
-dependencies[] = addressfield
-dependencies[] = entity_token
-dependencies[] = token
+name = Address Field Tokens
+description = Creates tokens for address fields, adds new addressfield renders, and adds webform integration.
+core = 7.x
+package = Fields
+dependencies[] = addressfield
+dependencies[] = entity_token
+dependencies[] = token
 
-; Information added by Drupal.org packaging script on 2014-10-29
-version = "7.x-1.5"
+; Information added by Drupal.org packaging script on 2018-10-11
+version = "7.x-1.13"
 core = "7.x"
 project = "addressfield_tokens"
-datestamp = "1414599829"
-
+datestamp = "1539260884"

+ 142 - 55
sites/all/modules/contrib/dev/addressfield_tokens/addressfield_tokens.module

@@ -4,9 +4,12 @@
  * Main components.
  */
 
+/**
+ * Implements hook_menu().
+ */
 function addressfield_tokens_menu() {
   $items = array();
-  
+
   $items['admin/config/regional/address'] = array(
     'title' => 'Addresses',
     'description' => 'Settings for address fields and tokens',
@@ -16,7 +19,7 @@ function addressfield_tokens_menu() {
     'file' => 'addressfield_tokens.admin.inc',
     'type' => MENU_NORMAL_ITEM,
   );
-  
+
   return $items;
 }
 
@@ -34,19 +37,31 @@ function addressfield_tokens_theme($existing, $type, $theme, $path) {
       'file' => 'addressfield_tokens.theme.inc',
     ),
     'addressfield_formatter__linear' => array(
-      'variables' => array('address' => NULL, 'premise' => TRUE, 'organisation_name' => TRUE, 'name_line' => TRUE),
+      'variables' => array(
+        'address' => NULL,
+        'premise' => TRUE,
+        'organisation_name' => TRUE,
+        'name_line' => TRUE,
+      ),
       'file' => 'addressfield_tokens.theme.inc',
     ),
     'addressfield_formatter__components' => array(
       'variables' => array(
         'address' => NULL,
-        'components' => array('thoroughfare', 'premise', 'locality', 'administrative_area', 'postal_code', 'country'),
+        'components' => array(
+          'thoroughfare',
+          'premise',
+          'locality',
+          'administrative_area',
+          'postal_code',
+          'country',
+        ),
         'separator' => ', ',
       ),
       'file' => 'addressfield_tokens.theme.inc',
     ),
   );
-  
+
   return $theme;
 }
 
@@ -75,7 +90,14 @@ function addressfield_tokens_field_formatter_info() {
       'label' => t('Address components'),
       'field types' => array('addressfield'),
       'settings' => array(
-        'components' => array('thoroughfare', 'premise', 'locality', 'administrative_area', 'postal_code', 'country'),
+        'components' => array(
+          'thoroughfare',
+          'premise',
+          'locality',
+          'administrative_area',
+          'postal_code',
+          'country',
+        ),
         'separator' => ', ',
       ),
     ),
@@ -103,14 +125,13 @@ function addressfield_tokens_field_formatter_settings_form($field, $instance, $v
     $element['separator'] = array(
       '#type' => 'textfield',
       '#title' => t('Separator'),
-      '#description' => t('The separator to use between components. Use \n for a line break.'),
+      '#description' => t('The separator to use between components. Use br tag for a line break.'),
       '#default_value' => $settings['separator'],
     );
   }
 
   return $element;
 }
-
 /**
  * Implements hook_field_formatter_settings_summary().
  */
@@ -132,7 +153,7 @@ function addressfield_tokens_field_formatter_settings_summary($field, $instance,
  */
 function addressfield_tokens_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
   $element = array();
-  
+
   switch ($display['type']) {
     case 'addressfield_citystate':
       $theme = array('addressfield_formatter__citystate', 'addressfield_formatter');
@@ -147,7 +168,7 @@ function addressfield_tokens_field_formatter_view($entity_type, $entity, $field,
         );
       }
       break;
-      
+
     case 'addressfield_linear':
       $theme = array('addressfield_formatter__linear', 'addressfield_formatter');
 
@@ -161,7 +182,7 @@ function addressfield_tokens_field_formatter_view($entity_type, $entity, $field,
         );
       }
       break;
-      
+
     case 'addressfield_country':
       foreach ($items as $delta => $item) {
         if (!empty($item['country'])) {
@@ -175,11 +196,11 @@ function addressfield_tokens_field_formatter_view($entity_type, $entity, $field,
         }
       }
       break;
-      
+
     case 'addressfield_state':
       foreach ($items as $delta => $item) {
         if (!empty($item['country']) && !empty($item['administrative_area'])) {
-          $state = _addressfield_tokens_state($item['country'], $item['administrative_area']);
+          $state = addressfield_tokens_state($item['country'], $item['administrative_area']);
           $element[$delta] = array(
             '#type' => 'markup',
             '#markup' => filter_xss($state),
@@ -189,19 +210,19 @@ function addressfield_tokens_field_formatter_view($entity_type, $entity, $field,
         }
       }
       break;
-      
+
     case 'addressfield_components':
       $theme = array('addressfield_formatter__components', 'addressfield_formatter');
       $settings = $display['settings'];
       foreach ($items as $delta => $item) {
         if (!empty($item['country'])) {
           array_unshift($theme, 'addressfield_formatter__components__' . $item['country']);
-        }      
+        }
         $element[$delta] = array(
           '#theme' => $theme,
           '#address' => array_map('filter_xss', $item),
           '#components' => $settings['components'],
-          '#separator' => filter_xss($settings['separator']),
+          '#separator' => filter_xss($settings['separator'], array('br')),
         );
       }
       break;
@@ -230,11 +251,31 @@ function addressfield_tokens_property_names() {
   return $names;
 }
 
+/**
+ * Generates token components.
+ *
+ * @return mixed
+ *   Array of components.
+ */
 function addressfield_tokens_components() {
   $comps = &drupal_static(__FUNCTION__, array());
   if (empty($comps)) {
     $names = addressfield_tokens_property_names();
-    foreach (array('first_name', 'last_name', 'name_line', 'organisation_name', 'thoroughfare', 'premise', 'locality', 'dependent_locality', 'administrative_area', 'sub_administrative_area', 'postal_code', 'country') as $key) {
+    $fields = array(
+      'first_name',
+      'last_name',
+      'name_line',
+      'organisation_name',
+      'thoroughfare',
+      'premise',
+      'locality',
+      'dependent_locality',
+      'administrative_area',
+      'sub_administrative_area',
+      'postal_code',
+      'country',
+    );
+    foreach ($fields as $key) {
       $comps[$key] = $names[$key];
       if (in_array($key, array('administrative_area', 'country'))) {
         $comps[$key . '_full'] = t('@name (full)', array(
@@ -248,14 +289,15 @@ function addressfield_tokens_components() {
 
 /**
  * Gets the list of countries from the locale settings in Drupal.
- * 
- * @return array An array of countries.  The keys are the 2-letter 
+ *
+ * @return array
+ *   An array of countries. The keys are the 2-letter
  *   abbreviations and the values are the full country names.
  */
 function _addressfield_tokens_countries() {
   $countries = &drupal_static(__FUNCTION__);
   if (empty($countries)) {
-    include_once('includes/locale.inc');
+    require_once DRUPAL_ROOT . '/includes/locale.inc';
     $countries = country_get_list();
   }
   return $countries;
@@ -263,14 +305,17 @@ function _addressfield_tokens_countries() {
 
 /**
  * Gets the name of the country with the given abbreviation.
- * 
- * @param string $country The 2-letter abbreviation of the country.
- * @return string The name of the country, or FALSE.
+ *
+ * @param string $country
+ *   The 2-letter abbreviation of the country.
+ *
+ * @return string
+ *   The name of the country, or FALSE.
  */
 function _addressfield_tokens_country($country) {
   $countries = _addressfield_tokens_countries();
-  
-  // Country abbreviations will always be two uppercase letters. 
+
+  // Country abbreviations will always be two uppercase letters.
   $country = drupal_strtoupper($country);
   if (!empty($country) && isset($countries[$country])) {
     return check_plain($countries[$country]);
@@ -279,11 +324,12 @@ function _addressfield_tokens_country($country) {
 }
 
 /**
- * Gets the abbreviation of the country with the given name
- * 
- * @param string
+ * Gets the abbreviation of the country with the given name.
+ *
+ * @param string $country
  *   The name of the country.
- * @return string $country
+ *
+ * @return string
  *   The 2-letter abbreviation of the country, or FALSE.
  */
 function _addressfield_tokens_country_abbr($country) {
@@ -297,55 +343,63 @@ function _addressfield_tokens_country_abbr($country) {
 
 /**
  * Gets the list of states in the given country.
- * 
- * @param string $country The 2-letter abbreviation of the country.
- * 
- * @return array An array of countries.  The keys are the 2-letter 
+ *
+ * @param string $country
+ *   The 2-letter abbreviation of the country.
+ *
+ * @return array
+ *   An array of countries. The keys are the 2-letter
  *   abbreviations and the values are the full country names.
  */
-function _addressfield_tokens_states($country) {
+function addressfield_tokens_states($country) {
+  global $language;
+  $langcode = $language->language;
   $states = &drupal_static(__FUNCTION__);
   $country = drupal_strtoupper($country);
   if (!isset($states[$country])) {
-    $cache = cache_get('addressfield_tokens_states');
+    $cache = cache_get('addressfield_tokens_states:' . $langcode);
     if ($cache) {
       $states = $cache->data;
     }
   }
   if (!isset($states[$country])) {
     $format = addressfield_generate(array('country' => $country), array('address'), array('mode' => 'render'));
-    
+
     if (isset($format['locality_block']['administrative_area']['#options'])) {
       $states[$country] = $format['locality_block']['administrative_area']['#options'];
     }
     else {
       $states[$country] = array();
     }
-    cache_set('addressfield_tokens_states', $states);
+    cache_set('addressfield_tokens_states:' . $langcode, $states);
   }
   return $states[$country];
 }
 
 /**
  * Gets the name of the state with the given abbreviation.
- * 
- * @param string $country The 2-letter abbreviation of the country.
- * @param string $state The 2-letter abbreviation of the state.
- * @return string The name of the state, or FALSE.
+ *
+ * @param string $country
+ *    The 2-letter abbreviation of the country.
+ * @param string $state
+ *   The 2-letter abbreviation of the state.
+ *
+ * @return string
+ *   The name of the state, or FALSE.
  */
-function _addressfield_tokens_state($country, $state) {
-  $states = _addressfield_tokens_states($country);
-  
-  // State abbreviations will usually be two uppercase letters. 
-  $state = drupal_strtoupper($state);
-  if (!empty($state) && !empty($states[$state])) {
+function addressfield_tokens_state($country, $state) {
+  $states = addressfield_tokens_states($country);
+
+  // State abbreviations will usually be two uppercase letters.
+  $state_upper = drupal_strtoupper($state);
+  if (!empty($state_upper) && !empty($states[$state_upper])) {
     return check_plain($states[$state]);
   }
   return check_plain($state);
 }
 
-/** 
- * Implements hook_webform_component_info(). 
+/**
+ * Implements hook_webform_component_info().
  */
 function addressfield_tokens_webform_component_info() {
   $components = array();
@@ -387,6 +441,15 @@ function addressfield_tokens_webform_component_info() {
   return $components;
 }
 
+/**
+ * Retrieves node components based on Node ID.
+
+ * @param int $nid
+ *   Node ID.
+ *
+ * @return mixed
+ *   Components.
+ */
 function _addressfield_tokens_webform_components($nid) {
   $components = &drupal_static(__FUNCTION__, array());
   if (!isset($components[$nid])) {
@@ -402,13 +465,14 @@ function _addressfield_tokens_webform_components($nid) {
 
 /**
  * Implements hook_webform_submission_load().
- */
+ * Commented out to solve issue https://www.drupal.org/project/addressfield_tokens/issues/2674752
+ *
 function addressfield_tokens_webform_submission_load(&$submissions) {
   $submissions_reset = reset($submissions);
   $nid = $submissions_reset->nid;
-  
+
   $components = _addressfield_tokens_webform_components($nid);
-    
+
   foreach ($submissions as $sid => $submission) {
     foreach ($components as $cid => $component) {
       if (!empty($submission->data[$cid])) {
@@ -421,17 +485,40 @@ function addressfield_tokens_webform_submission_load(&$submissions) {
           $data = empty($data) ? array() : unserialize($data);
           $addresses[$delta] = $data;
         }
-        drupal_array_set_nested_value($submission->data, $parents, $addresses);
+        if (count($addresses)) {
+          drupal_array_set_nested_value($submission->data, $parents, $addresses);
+        }
       }
     }
   }
 }
+**/
 
-/** 
- * Implements hook_webform_validator_alter(). 
+/**
+ * Implements hook_webform_validator_alter().
  */
 function addressfield_tokens_webform_validator_alter(&$validators) {
   $validators['unique']['component_types'][] = 'addressfield';
   $validators['oneoftwo']['component_types'][] = 'addressfield';
   $validators['oneofseveral']['component_types'][] = 'addressfield';
 }
+
+/**
+ * Implements hook_webform_hints_element_alter().
+ */
+function addressfield_tokens_webform_hints_element_alter(&$element, &$required_label)
+{
+  if ($element['#type'] == 'addressfield_container' || $element['#type'] == 'fieldset') {
+    $addressfield_tokens_fields_info = addressfield_tokens_field_formatter_info();
+    foreach ($addressfield_tokens_fields_info['addressfield_components']['settings']['components'] as $component) {
+      if (isset($element[$component])) {
+        if (isset($element[$component]['#options'])) {
+          $element[$component]['#empty_option'] = '- ' . $element[$component]['#title'] . $required_label . ' -';
+        }
+
+        $element[$component]['#attributes']['placeholder'] = $element[$component]['#title'] . $required_label;
+        $element[$component]['#title_display'] = 'invisible';
+      }
+    }
+  }
+}

+ 21 - 3
sites/all/modules/contrib/dev/addressfield_tokens/addressfield_tokens.theme.inc

@@ -11,7 +11,13 @@
  */
 function theme_addressfield_formatter($vars) {
   $address = $vars['address'];
+  if (isset($address['addressfield'])) {
+    $address = $address['addressfield'];
+  }
   $handlers = $vars['handlers'];
+  if (empty($handlers)) {
+    $handlers = array('address');
+  }
   
   $out = addressfield_generate($address, $handlers, array('mode' => 'render'));
   return '<div class="addressfield">' . render($out) . '</div>';
@@ -39,7 +45,7 @@ function theme_addressfield_formatter__citystate($vars) {
   
   // If there's no location, render an alternate
   if (empty($out)) {
-    $out[] = 'Undefined';
+    return '';
   }
   
   // Render the location components
@@ -56,6 +62,18 @@ function theme_addressfield_formatter__citystate($vars) {
 function theme_addressfield_formatter__linear($vars) {
   $loc = $vars['address'];
   
+  // If single line name is empty, construct it from first and last name.
+  if (empty($loc['name_line'])) {
+    $parts = array();
+    if (!empty($loc['first_name'])) {
+      $parts[] = $loc['first_name'];
+    }
+    if (!empty($loc['last_name'])) {
+      $parts[] = $loc['last_name'];
+    }
+    $loc['name_line'] = join(' ', $parts);
+  }
+
   // Determine which location components to render
   $out = array();
   if (!empty($loc['name_line']) && $vars['name_line']) {
@@ -103,9 +121,9 @@ function theme_addressfield_formatter__components($vars) {
       $out[$key] = _addressfield_tokens_country($loc['country']);
     }
     elseif ($key == 'administrative_area_full' && !empty($loc['country']) && !empty($loc['administrative_area'])) {
-      $out[$key] = _addressfield_tokens_state($loc['country'], $loc['administrative_area']);
+      $out[$key] = addressfield_tokens_state($loc['country'], $loc['administrative_area']);
     }
   }
   
   return implode($separator, $out);
-}
+}

+ 81 - 45
sites/all/modules/contrib/dev/addressfield_tokens/addressfield_tokens.tokens.inc

@@ -1,36 +1,37 @@
 <?php
+
 /**
- * @file Provides token replacements for address fields.
-*/
+ * @file
+ * Provides token replacements for address fields.
+ */
 
 /**
  * Implements hook_token_info_alter().
- * 
- * Attaches tokens to all addressfield properties.  The default names of each 
- * addressfield component can be altered by administrators according to the site's locale.
- * 
- * @param array $info The existing token info.
+ *
+ * Attaches tokens to all addressfield properties. The default names of each
+ * addressfield component can be altered by administrators according to the
+ * site's locale.
  */
 function addressfield_tokens_token_info_alter(&$info) {
-  // Define the address field token types 
+  // Define the address field token types.
   $info['types']['addressfield'] = array(
     'name' => t('Address field'),
     'description' => t('An address associated with an entity.'),
     'needs-data' => 'addressfield',
   );
-  
-  // Add tokens for each component of the address
-  $info['tokens'] += array( 'addressfield' => array() );
-  
+
+  // Add tokens for each component of the address.
+  $info['tokens'] += array('addressfield' => array());
+
   $props = addressfield_data_property_info();
   $names = addressfield_tokens_property_names();
   $params = array(
     '@default_country' => addressfield_tokens_default_country(),
   );
-  
+
   foreach ($props as $field => $data) {
     $fieldtoken = str_replace('_', '-', $field);
-    
+
     if (!empty($names[$field])) {
       $name = $names[$field];
       $descr = $data['label'];
@@ -38,7 +39,7 @@ function addressfield_tokens_token_info_alter(&$info) {
     else {
       $name = $data['label'];
       $descr = $name;
-      
+
       $matches = array();
       if (preg_match('/^(.*)\s+\(i\.e\.\s+(.*)\)$/', $name, $matches)) {
         $name = $matches[1];
@@ -54,7 +55,7 @@ function addressfield_tokens_token_info_alter(&$info) {
   }
   $info['tokens']['addressfield']['administrative-area']['name'] .= ' (abbreviation)';
   $info['tokens']['addressfield']['country']['name'] .= ' (abbreviation)';
-  
+
   // Add tokens for the formatted address and text-only version.
   $info['tokens']['addressfield'] += array(
     'full' => array(
@@ -83,7 +84,7 @@ function addressfield_tokens_token_info_alter(&$info) {
       'type' => 'text',
     ),
   );
-  
+
   // Add user tokens that are useful for MailChimp.
   if (module_exists('mailchimp')) {
     $info['tokens']['addressfield'] += array(
@@ -95,9 +96,23 @@ function addressfield_tokens_token_info_alter(&$info) {
     );
   }
 
-  // Attach tokens to all address fields
+  // Add extra text to webform submission values help.
+  if (array_key_exists('submission', $info['tokens'])) {
+    $info['tokens']['submission']['values']['description'] .= '
+      <div>
+      ' . t('For addressfield components you can also choose individual elements of the address using the syntax field_key:element, For example:') . '
+      <ul>
+        <li>[submission:values:address:thoroughfare]</li>
+        <li>[submission:values:address:locality]</li>
+        <li>[submission:values:address:administrative_area]</li>
+        <li>[submission:values:address:postal_code]</li>
+        <li>[submission:values:address:country]</li>
+      </ul>
+    </div>';
+  }
+
+  // Attach tokens to all address fields.
   $valid_types = entity_token_types();
-  $entity_info = entity_get_info();
 
   foreach ($valid_types as $token_type => $type) {
     foreach (entity_get_all_property_info($type) as $name => $property) {
@@ -116,14 +131,6 @@ function addressfield_tokens_token_info_alter(&$info) {
 
 /**
  * Implements hook_tokens().
- * 
- * @param string $type The type of tokens to replace.  We are looking for 'addressfield', but can also chain 
- *   addressfields onto entities that have addressfields as properties.
- * @param array $tokens The tokens to replace.
- * @param array $data The data to use as replacements.  We are looking for an 'addressfield' property.
- * @param array $options Additional options for the tokenizer.
- * 
- * @return array The replaced values.
  */
 function addressfield_tokens_tokens($type, $tokens, array $data = array(), array $options = array()) {
   $url_options = array();
@@ -140,27 +147,49 @@ function addressfield_tokens_tokens($type, $tokens, array $data = array(), array
   $replacements = array();
   $last_original = NULL;
 
-  // Process address field tokens
-  if ($type == 'addressfield' && !empty($data['addressfield'])) {
+  // Process webform submission addressfield tokens.
+  if ($type == 'submission' && !empty($data['webform-submission'])) {
+    $submission = $data['webform-submission'];
+    $node = isset($data['node']) ? $data['node'] : node_load($submission->nid);
+    $value_tokens = token_find_with_prefix($tokens, 'values');
+    // Loop through the components of the webform looking for addressfield
+    // components with the expected form_key.
+    foreach ($node->webform['components'] as $cid => $component) {
+      if ($component['type'] == 'addressfield' && isset($submission->data[$cid][0])) {
+        $address = $submission->data[$cid][0];
+        if (is_string($address)) {
+          $address = unserialize($address);
+        }
+        $address_tokens = token_find_with_prefix($value_tokens, $component['form_key']);
+        foreach ($address_tokens as $token => $original) {
+          if (isset($address[$token])) {
+            $replacements[$original] = $sanitize ? filter_xss($address[$token]) : $address[$token];
+          }
+        }
+      }
+    }
+  }
+  // Process address field tokens.
+  elseif ($type == 'addressfield' && !empty($data['addressfield'])) {
     foreach ($tokens as $name => $original) {
       $last_original = $original;
       $name = str_replace('-', '_', $name);
       $address = $data['addressfield'];
-      
+
       // If the address field exists, use it.
       if (isset($address[$name])) {
         $replacements[$original] = $sanitize ? filter_xss($address[$name]) : $address[$name];
       }
       else {
-        // Otherwise, it's a special token
+        // Otherwise, it's a special token.
         switch ($name) {
           case 'full':
             $render = addressfield_generate($address, array('address'), array(
-              'mode' => 'render', 
+              'mode' => 'render',
             ));
             $replacements[$original] = $sanitize ? filter_xss(drupal_render($render)) : drupal_render($render);
             break;
-            
+
           case 'text':
             $out = array();
             if (!empty($address['thoroughfare'])) {
@@ -182,7 +211,7 @@ function addressfield_tokens_tokens($type, $tokens, array $data = array(), array
             }
             $replacements[$original] = $sanitize ? filter_xss(implode("\n", $out)) : implode("\n", $out);
             break;
-            
+
           case 'city_state':
             $out = array();
             if (!empty($address['locality'])) {
@@ -194,20 +223,20 @@ function addressfield_tokens_tokens($type, $tokens, array $data = array(), array
             if (!empty($address['country']) && $address['country'] != addressfield_tokens_default_country()) {
               $out[] = _addressfield_tokens_country($address['country']);
             }
-            $replacements[$original] = $sanitize ? filter_xss(implode(", ", $out)) : implode(", ", $out); 
+            $replacements[$original] = $sanitize ? filter_xss(implode(", ", $out)) : implode(", ", $out);
             break;
-            
+
           case 'state_name':
             if (!empty($address['administrative_area']) && !empty($address['country'])) {
               if ($sanitize) {
-                $replacements[$original] = filter_xss(_addressfield_tokens_state($address['country'], $address['administrative_area']));
+                $replacements[$original] = filter_xss(addressfield_tokens_state($address['country'], $address['administrative_area']));
               }
               else {
-                $replacements[$original] = _addressfield_tokens_state($address['country'], $address['administrative_area']);
+                $replacements[$original] = addressfield_tokens_state($address['country'], $address['administrative_area']);
               }
             }
             break;
-            
+
           case 'country_name':
             if (!empty($address['country'])) {
               if ($sanitize) {
@@ -218,16 +247,23 @@ function addressfield_tokens_tokens($type, $tokens, array $data = array(), array
               }
             }
             break;
-          
+
           case 'mc_address':
-            $address_components = array('thoroughfare', 'premise', 'locality', 'administrative_area', 'postal_code', 'country');
+            $address_components = array(
+              'thoroughfare',
+              'premise',
+              'locality',
+              'administrative_area',
+              'postal_code',
+              'country',
+            );
             $mc_address = array();
             foreach ($address_components as $component) {
               if (!empty($address[$component])) {
                 $mc_address[] = check_plain($address[$component]);
               }
             }
-            // MailChimp requires the address to be a string of double-space 
+            // MailChimp requires the address to be a string of double-space
             // delimited address fields. (http://kb.mailchimp.com/article/how-do-i-set-up-the-address-field-type-for-import)
             $replacements[$original] = !empty($mc_address) ? implode('  ', $mc_address) : '';
             break;
@@ -242,7 +278,7 @@ function addressfield_tokens_tokens($type, $tokens, array $data = array(), array
     $token_types = entity_token_types();
     $info = token_info();
     if (isset($info['tokens'][$type])) {
-      // Otherwise, chain address fields attached to other entities
+      // Otherwise, chain address fields attached to other entities.
       foreach ($info['tokens'][$type] as $name => $token_info) {
         if (isset($token_info['type']) && $token_info['type'] == 'addressfield') {
           if ($chained_tokens = token_find_with_prefix($tokens, $name)) {
@@ -261,6 +297,6 @@ function addressfield_tokens_tokens($type, $tokens, array $data = array(), array
       }
     }
   }
-  
+
   return $replacements;
-}
+}

+ 24 - 15
sites/all/modules/contrib/fields/addressfield/addressfield.address_formats.inc

@@ -3,7 +3,7 @@
 /**
  * Contains the predefined address formats.
  *
- * Derived from Google's dataset: https://i18napis.appspot.com/address.
+ * Derived from Google's dataset: https://chromium-i18n.appspot.com/ssl-address.
  */
 
 /**
@@ -40,12 +40,13 @@ function addressfield_get_address_format($country_code) {
   // These formats differ from the default only by the presence of the
   // 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', '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',
-    'SN', 'SZ', 'TA', 'TJ', 'TM', 'TN', 'VA', 'VC', 'VG', 'XK', 'ZM',
+    'AC', 'AD', 'AF', 'AI', 'AL', 'AZ', 'BA', 'BB', 'BD', 'BG', 'BH', 'BM',
+    'BN', 'BT', 'CU', 'CR', 'CY', 'DO', 'DZ', 'EC', 'EH', 'ET', 'FO', 'GE',
+    'GN', 'GT', 'GW', 'HR', 'HM', 'HT', 'IL', 'IS', 'JO', 'KE', 'KG', 'KH',
+    'KP', 'KW', 'LA', 'LB', 'LK', 'LR', 'LS',  'MA', 'MC', 'MD', 'ME', 'MG',
+    'MK', 'MM', 'MT', 'MU', 'MV', 'NE', 'NP', 'OM', 'PK', 'PY', 'RO', 'RS',
+    'SA', 'SD', 'SI', 'SN', 'SZ', 'TA', 'TJ', 'TM', 'TN', 'TZ', 'VA', 'VC',
+    'VG', 'XK', 'ZM',
   );
   foreach ($countries_with_optional_postal_code as $code) {
     $address_formats[$code] = array(
@@ -71,6 +72,8 @@ function addressfield_get_address_format($country_code) {
   $address_formats['AE'] = array(
     'used_fields' => array('administrative_area'),
     'administrative_area_label' => t('Emirate'),
+    'render_administrative_area_value' => TRUE,
+    'required_fields' => array('administrative_area'),
   );
   $address_formats['AM'] = array(
     'used_fields' => array('locality', 'administrative_area', 'postal_code'),
@@ -114,7 +117,7 @@ function addressfield_get_address_format($country_code) {
     'used_fields' => array('locality', 'administrative_area', 'postal_code'),
   );
   $address_formats['CL'] = array(
-    'used_fields' => array('dependent_locality', 'locality', 'administrative_area', 'postal_code'),
+    'used_fields' => array('locality', 'administrative_area', 'postal_code'),
     'administrative_area_label' => t('State', array(), array('context' => 'Territory of a country')),
     'render_administrative_area_value' => TRUE,
   );
@@ -122,9 +125,11 @@ function addressfield_get_address_format($country_code) {
     'used_fields' => array('dependent_locality', 'locality', 'administrative_area', 'postal_code'),
     'required_fields' => array('locality', 'administrative_area'),
     'dependent_locality_label' => t('District'),
+    'render_administrative_area_value' => TRUE,
   );
   $address_formats['CO'] = array(
     'used_fields' => array('locality', 'administrative_area', 'postal_code'),
+    'required_fields' => array('locality', 'administrative_area'),
     'administrative_area_label' => t('Department', array(), array('context' => 'Territory of a country')),
   );
   $address_formats['CV'] = array(
@@ -142,6 +147,7 @@ function addressfield_get_address_format($country_code) {
     'used_fields' => array('locality', 'administrative_area', 'postal_code'),
     'required_fields' => array('locality', 'postal_code'),
     'administrative_area_label' => t('County'),
+    'render_administrative_area_value' => TRUE,
   );
   $address_formats['ES'] = array(
     'used_fields' => array('locality', 'administrative_area', 'postal_code'),
@@ -155,7 +161,7 @@ function addressfield_get_address_format($country_code) {
     'postal_code_label' => t('ZIP code'),
   );
   $address_formats['GB'] = array(
-    'used_fields' => array('locality', 'administrative_area', 'postal_code'),
+    'used_fields' => array('locality', 'postal_code'),
     'required_fields' => array('locality', 'postal_code'),
     'locality_label' => t('Town/City'),
     'administrative_area_label' => t('County'),
@@ -165,8 +171,8 @@ function addressfield_get_address_format($country_code) {
     'used_fields' => array('postal_code'),
   );
   $address_formats['GU'] = array(
-    'used_fields' => array('locality', 'administrative_area', 'postal_code'),
-    'required_fields' => array('locality', 'administrative_area', 'postal_code'),
+    'used_fields' => array('locality', 'postal_code'),
+    'required_fields' => array('locality', 'postal_code'),
     'administrative_area_label' => t('State', array(), array('context' => 'Territory of a country')),
     'postal_code_label' => t('ZIP code'),
   );
@@ -182,13 +188,15 @@ function addressfield_get_address_format($country_code) {
   );
   $address_formats['ID'] = array(
     'used_fields' => array('locality', 'administrative_area', 'postal_code'),
+    'required_fields' => array('administrative_area'),
     'locality_label' => t('City/Regency'),
     'render_administrative_area_value' => TRUE,
   );
   $address_formats['IE'] = array(
-    'used_fields' => array('locality', 'administrative_area'),
+    'used_fields' => array('dependent_locality', 'locality', 'administrative_area', 'postal_code'),
     'locality_label' => t('Town/City'),
     'administrative_area_label' => t('County'),
+    'postal_code_label' => t('Eircode'),
     'render_administrative_area_value' => TRUE,
   );
   $address_formats['IN'] = array(
@@ -293,7 +301,7 @@ function addressfield_get_address_format($country_code) {
     'used_fields' => array('locality', 'administrative_area', 'postal_code'),
   );
   $address_formats['NG'] = 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')),
   );
   $address_formats['NI'] = array(
@@ -330,6 +338,7 @@ function addressfield_get_address_format($country_code) {
   );
   $address_formats['PH'] = array(
     'used_fields' => array('dependent_locality', 'locality', 'administrative_area', 'postal_code'),
+    'render_administrative_area_value' => TRUE,
   );
   $address_formats['PR'] = array(
     'used_fields' => array('locality', 'postal_code'),
@@ -344,7 +353,7 @@ function addressfield_get_address_format($country_code) {
   );
   $address_formats['RU'] = array(
     'used_fields' => array('locality', 'administrative_area', 'postal_code'),
-    'required_fields' => array('locality', 'postal_code'),
+    'required_fields' => array('locality', 'administrative_area', 'postal_code'),
     'render_administrative_area_value' => TRUE,
   );
   $address_formats['SC'] = array(
@@ -389,7 +398,7 @@ function addressfield_get_address_format($country_code) {
   );
   $address_formats['UA'] = array(
     'used_fields' => array('locality', 'administrative_area', 'postal_code'),
-    'required_fields' => array('locality', 'postal_code'),
+    'required_fields' => array('locality', 'administrative_area', 'postal_code'),
     'administrative_area_label' => t('Region', array(), array('context' => 'Territory of a country')),
   );
   $address_formats['UM'] = array(

+ 152 - 68
sites/all/modules/contrib/fields/addressfield/addressfield.administrative_areas.inc

@@ -132,7 +132,7 @@ function _addressfield_get_administrative_areas_defaults() {
     'AT' => 'Atacama',
     'BI' => 'Biobío',
     'CO' => 'Coquimbo',
-    'LI' => 'Libertador General Bernardo O\'Higgins',
+    'LI' => "Libertador General Bernardo O'Higgins",
     'LL' => 'Los Lagos',
     'LR' => 'Los Ríos',
     'MA' => 'Magallanes y de la Antártica Chilena',
@@ -449,112 +449,112 @@ function _addressfield_get_administrative_areas_defaults() {
     'AL' => 'Alessandria',
     'AN' => 'Ancona',
     'AO' => 'Aosta',
-    'AP' => 'Ascoli Piceno',
-    'AQ' => "L'Aquila",
     'AR' => 'Arezzo',
+    'AP' => 'Ascoli Piceno',
     'AT' => 'Asti',
     'AV' => 'Avellino',
     'BA' => 'Bari',
-    'BG' => 'Bergamo',
-    'BI' => 'Biella',
+    'BT' => 'Barletta-Andria-Trani',
     'BL' => 'Belluno',
     'BN' => 'Benevento',
+    'BG' => 'Bergamo',
+    'BI' => 'Biella',
     'BO' => 'Bologna',
-    'BR' => 'Brindisi',
-    'BS' => 'Brescia',
-    'BT' => 'Barletta-Andria-Trani',
     'BZ' => 'Bolzano/Bozen',
+    'BS' => 'Brescia',
+    'BR' => 'Brindisi',
     'CA' => 'Cagliari',
+    'CL' => 'Caltanissetta',
     'CB' => 'Campobasso',
+    'CI' => 'Carbonia-Iglesias',
     'CE' => 'Caserta',
+    'CT' => 'Catania',
+    'CZ' => 'Catanzaro',
     'CH' => 'Chieti',
-    'CI' => 'Carbonia-Iglesias',
-    'CL' => 'Caltanissetta',
-    'CN' => 'Cuneo',
     'CO' => 'Como',
-    'CR' => 'Cremona',
     'CS' => 'Cosenza',
-    'CT' => 'Catania',
-    'CZ' => 'Catanzaro',
+    'CR' => 'Cremona',
+    'KR' => 'Crotone',
+    'CN' => 'Cuneo',
     'EN' => 'Enna',
-    'FC' => 'Forlì-Cesena',
+    'FM' => 'Fermo',
     'FE' => 'Ferrara',
-    'FG' => 'Foggia',
     'FI' => 'Firenze',
-    'FM' => 'Fermo',
+    'FG' => 'Foggia',
+    'FC' => 'Forlì-Cesena',
     'FR' => 'Frosinone',
     'GE' => 'Genova',
     'GO' => 'Gorizia',
     'GR' => 'Grosseto',
     'IM' => 'Imperia',
     'IS' => 'Isernia',
-    'KR' => 'Crotone',
-    'LC' => 'Lecco',
+    'AQ' => "L'Aquila",
+    'SP' => 'La Spezia',
+    'LT' => 'Latina',
     'LE' => 'Lecce',
+    'LC' => 'Lecco',
     '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',
+    'VS' => 'Medio Campidano',
+    'ME' => 'Messina',
+    'MI' => 'Milano',
+    'MO' => 'Modena',
+    'MB' => 'Monza e Brianza',
     'NA' => 'Napoli',
     'NO' => 'Novara',
     'NU' => 'Nuoro',
     'OG' => 'Ogliastra',
-    'OR' => 'Oristano',
     'OT' => 'Olbia-Tempio',
-    'PA' => 'Palermo',
-    'PC' => 'Piacenza',
+    'OR' => 'Oristano',
     'PD' => 'Padova',
-    'PE' => 'Pescara',
+    'PA' => 'Palermo',
+    'PR' => 'Parma',
+    'PV' => 'Pavia',
     'PG' => 'Perugia',
+    'PU' => 'Pesaro e Urbino',
+    'PE' => 'Pescara',
+    'PC' => 'Piacenza',
     'PI' => 'Pisa',
-    'PN' => 'Pordenone',
-    'PO' => 'Prato',
-    'PR' => 'Parma',
     'PT' => 'Pistoia',
-    'PU' => 'Pesaro e Urbino',
-    'PV' => 'Pavia',
+    'PN' => 'Pordenone',
     'PZ' => 'Potenza',
+    'PO' => 'Prato',
+    'RG' => 'Ragusa',
     'RA' => 'Ravenna',
     'RC' => 'Reggio Calabria',
     'RE' => 'Reggio Emilia',
-    'RG' => 'Ragusa',
     'RI' => 'Rieti',
-    'RM' => 'Roma',
     'RN' => 'Rimini',
+    'RM' => 'Roma',
     'RO' => 'Rovigo',
     'SA' => 'Salerno',
-    'SI' => 'Siena',
-    'SO' => 'Sondrio',
-    'SP' => 'La Spezia',
-    'SR' => 'Siracusa',
     'SS' => 'Sassari',
     'SV' => 'Savona',
+    'SI' => 'Siena',
+    'SR' => 'Siracusa',
+    'SO' => 'Sondrio',
     'TA' => 'Taranto',
     'TE' => 'Teramo',
-    'TN' => 'Trento',
+    'TR' => 'Terni',
     'TO' => 'Torino',
     'TP' => 'Trapani',
-    'TR' => 'Terni',
-    'TS' => 'Trieste',
+    'TN' => 'Trento',
     'TV' => 'Treviso',
+    'TS' => 'Trieste',
     'UD' => 'Udine',
     'VA' => 'Varese',
+    'VE' => 'Venezia',
     'VB' => 'Verbano-Cusio-Ossola',
     'VC' => 'Vercelli',
-    'VE' => 'Venezia',
-    'VI' => 'Vicenza',
     'VR' => 'Verona',
-    'VS' => 'Medio Campidano',
-    'VT' => 'Viterbo',
     'VV' => 'Vibo Valentia',
+    'VI' => 'Vicenza',
+    'VT' => 'Viterbo',
   );
   $administrative_areas['JM'] = array(
     '13' => 'Clarendon',
@@ -663,11 +663,11 @@ function _addressfield_get_administrative_areas_defaults() {
     'BCN' => 'Baja California',
     'BCS' => 'Baja California Sur',
     'CAM' => 'Campeche',
+    'CMX' => 'Ciudad de México',
     'COA' => 'Coahuila',
     'COL' => 'Colima',
     'CHP' => 'Chiapas',
     'CHH' => 'Chihuahua',
-    'DIF' => 'Distrito Federal',
     'DUG' => 'Durango',
     'MEX' => 'Estado de México',
     'GUA' => 'Guanajuato',
@@ -709,7 +709,7 @@ function _addressfield_get_administrative_areas_defaults() {
     '13' => t('Sarawak'),
     '10' => t('Selangor'),
     '11' => t('Terengganu'),
-    );
+  );
   $administrative_areas['PE'] = array(
     'AMA' => 'Amazonas',
     'ANC' => 'Ancash',
@@ -737,6 +737,90 @@ function _addressfield_get_administrative_areas_defaults() {
     'TUM' => 'Tumbes',
     'UCA' => 'Ucayali',
   );
+  $administrative_areas['PH'] = array(
+    'ABR' => 'Abra',
+    'AGN' => 'Agusan del Norte',
+    'AGS' => 'Agusan del Sur',
+    'AKL' => 'Aklan',
+    'ALB' => 'Albay',
+    'ANT' => 'Antique',
+    'APA' => 'Apayao',
+    'AUR' => 'Aurora',
+    'BAS' => 'Basilan',
+    'BAN' => 'Bataan',
+    'BTN' => 'Batanes',
+    'BTG' => 'Batangas',
+    'BEN' => 'Benguet',
+    'BIL' => 'Biliran',
+    'BOH' => 'Bohol',
+    'BUK' => 'Bukidnon',
+    'BUL' => 'Bulacan',
+    'CAG' => 'Cagayan',
+    'CAN' => 'Camarines Norte',
+    'CAS' => 'Camarines Sur',
+    'CAM' => 'Camiguin',
+    'CAP' => 'Capiz',
+    'CAT' => 'Catanduanes',
+    'CAV' => 'Cavite',
+    'CEB' => 'Cebu',
+    'COM' => 'Compostela Valley',
+    'NCO' => 'Cotabato',
+    'DAV' => 'Davao del Norte',
+    'DAS' => 'Davao del Sur',
+    'a9d' => 'Davao Occidental',
+    'DAO' => 'Davao Oriental',
+    'DIN' => 'Dinagat Islands',
+    'EAS' => 'Eastern Samar',
+    'GUI' => 'Guimaras',
+    'IFU' => 'Ifugao',
+    'ILN' => 'Ilocos Norte',
+    'ILS' => 'Ilocos Sur',
+    'ILI' => 'Iloilo',
+    'ISA' => 'Isabela',
+    'KAL' => 'Kalinga',
+    'LUN' => 'La Union',
+    'LAG' => 'Laguna',
+    'LAN' => 'Lanao del Norte',
+    'LAS' => 'Lanao del Sur',
+    'LEY' => 'Leyte',
+    'MAG' => 'Maguindanao',
+    'MAD' => 'Marinduque',
+    'MAS' => 'Masbate',
+    '00' => 'Metro Manila',
+    'MDC' => 'Mindoro Occidental',
+    'MDR' => 'Mindoro Oriental',
+    'MSC' => 'Misamis Occidental',
+    'MSR' => 'Misamis Oriental',
+    'MOU' => 'Mountain Province',
+    'NEC' => 'Negros Occidental',
+    'NER' => 'Negros Oriental',
+    'NSA' => 'Northern Samar',
+    'NUE' => 'Nueva Ecija',
+    'NUV' => 'Nueva Vizcaya',
+    'PLW' => 'Palawan',
+    'PAM' => 'Pampanga',
+    'PAN' => 'Pangasinan',
+    'QUE' => 'Quezon Province',
+    'QUI' => 'Quirino',
+    'RIZ' => 'Rizal',
+    'ROM' => 'Romblon',
+    'WSA' => 'Samar',
+    'SAR' => 'Sarangani',
+    'SIG' => 'Siquijor',
+    'SOR' => 'Sorsogon',
+    'SCO' => 'South Cotabato',
+    'SLE' => 'Southern Leyte',
+    'SUK' => 'Sultan Kudarat',
+    'SLU' => 'Sulu',
+    'SUN' => 'Surigao del Norte',
+    'SUR' => 'Surigao del Sur',
+    'TAR' => 'Tarlac',
+    'TAW' => 'Tawi-Tawi',
+    'ZMB' => 'Zambales',
+    'ZAN' => 'Zamboanga del Norte',
+    'ZAS' => 'Zamboanga del Sur',
+    'ZSI' => 'Zamboanga Sibuguey',
+  );
   $administrative_areas['RU'] = array(
     'MOW' => t('Moskva'),
     'SPE' => t('Sankt-Peterburg'),
@@ -931,31 +1015,31 @@ function _addressfield_get_administrative_areas_defaults() {
   );
   $administrative_areas['UA'] = array(
     '43' => t('Crimea'),
-    '05' => t('Vinnyts\'ka oblast'),
-    '07' => t('Volyns\'ka oblast'),
+    '05' => t("Vinnyts'ka oblast"),
+    '07' => t("Volyns'ka oblast"),
     '12' => t('Dnipropetrovsk Oblast'),
     '14' => t('Donetsk Oblast'),
-    '18' => t('Zhytomyrs\'ka oblast'),
-    '21' => t('Zakarpats\'ka oblast'),
-    '23' => t('Zaporiz\'ka oblast'),
-    '26' => t('Ivano-Frankivs\'ka oblast'),
-    '30' => t('Kiev Oblast'),
-    '35' => t('Kirovohrads\'ka oblast'),
-    '09' => t('Luhans\'ka oblast'),
+    '18' => t("Zhytomyrs'ka oblast"),
+    '21' => t("Zakarpats'ka oblast"),
+    '23' => t("Zaporiz'ka oblast"),
+    '26' => t("Ivano-Frankivs'ka oblast"),
+    '30' => t('Kyiv Oblast'),
+    '35' => t("Kirovohrads'ka oblast"),
+    '09' => t("Luhans'ka oblast"),
     '46' => t('Lviv Oblast'),
-    '48' => t('Mykolaivs\'ka oblast'),
+    '48' => t("Mykolaivs'ka oblast"),
     '51' => t('Odessa Oblast'),
-    '53' => t('Poltavs\'ka oblast'),
-    '56' => t('Rivnens\'ka oblast'),
-    '40' => t('Sevastopol\' city'),
-    '59' => t('Sums\'ka oblast'),
-    '61' => t('Ternopil\'s\'ka oblast'),
+    '53' => t("Poltavs'ka oblast"),
+    '56' => t("Rivnens'ka oblast"),
+    '40' => t("Sevastopol' city"),
+    '59' => t("Sums'ka oblast"),
+    '61' => t("Ternopil's'ka oblast"),
     '63' => t('Kharkiv Oblast'),
-    '65' => t('Khersons\'ka oblast'),
-    '68' => t('Khmel\'nyts\'ka oblast'),
-    '71' => t('Cherkas\'ka oblast'),
-    '77' => t('Chernivets\'ka oblast'),
-    '74' => t('Chernihivs\'ka oblast'),
+    '65' => t("Khersons'ka oblast"),
+    '68' => t("Khmel'nyts'ka oblast"),
+    '71' => t("Cherkas'ka oblast"),
+    '77' => t("Chernivets'ka oblast"),
+    '74' => t("Chernihivs'ka oblast"),
   );
   $administrative_areas['US'] = array(
     'AL' => t('Alabama'),

+ 2 - 2
sites/all/modules/contrib/fields/addressfield/addressfield.devel_generate.inc

@@ -41,9 +41,9 @@ function _addressfield_sample_addresses() {
   if (!isset($fields)) {
     $filepath = DRUPAL_ROOT . '/' . drupal_get_path('module', 'addressfield');
     $fields = array();
-    if ($handle = @fopen("$filepath/addresses.txt",'r')) {
+    if ($handle = @fopen("$filepath/addresses.txt", 'r')) {
       if (is_resource($handle)) {
-        while (($buffer = fgets($handle)) !== false) {
+        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(
             'country' => ($country == 'NULL') ? NULL : trim($country),

+ 18 - 4
sites/all/modules/contrib/fields/addressfield/addressfield.feeds.inc

@@ -36,10 +36,20 @@ function addressfield_feeds_processor_targets_alter(&$targets, $entity_type, $bu
  *   A string identifying the target on the node.
  * @param $values
  *   The value to populate the target with.
+ * @param array $mapping
+ *  Associative array of the mapping settings from the per mapping
+ *  configuration form.
  */
-function addressfield_set_target($source, $entity, $target, $values) {
+function addressfield_set_target($source, $entity, $target, $values, $mapping) {
+  $language = $mapping['language'];
   list($field_name, $sub_field) = explode(':', $target, 2);
 
+  // Field info and instance are required for setting default values.
+  $entity_type = $source->importer->processor->entityType();
+  list(, , $bundle_name) = entity_extract_ids($entity_type, $entity);
+  $info = field_info_field($field_name);
+  $instance = field_info_instance($entity_type, $field_name, $bundle_name);
+
   // Convert the values into an array if it isn't one already to correspond to
   // Drupal's handling of field value arrays.
   if (!is_array($values)) {
@@ -48,12 +58,16 @@ function addressfield_set_target($source, $entity, $target, $values) {
 
   // If the field is already set on the given entity, update the existing value
   // array. Otherwise start with a fresh field value array.
-  $field = isset($entity->$field_name) ? $entity->$field_name : array();
+  $field = isset($entity->{$field_name}) ? $entity->{$field_name} : array();
 
   // Loop over the field values array...
   foreach ($values as $delta => $value) {
-    $field[LANGUAGE_NONE][$delta][$sub_field] = $value;
+    // Set defaults for new values.
+    if (!isset($field[$language][$delta])) {
+      $field[$language][$delta] = addressfield_default_values($info, $instance);
+    }
+    $field[$language][$delta][$sub_field] = $value;
   }
 
-  $entity->$field_name = $field;
+  $entity->{$field_name} = $field;
 }

+ 3 - 4
sites/all/modules/contrib/fields/addressfield/addressfield.info

@@ -10,9 +10,8 @@ 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-10-07
-version = "7.x-1.2"
+; Information added by Drupal.org packaging script on 2018-10-26
+version = "7.x-1.3"
 core = "7.x"
 project = "addressfield"
-datestamp = "1444254070"
-
+datestamp = "1540579391"

+ 5 - 0
sites/all/modules/contrib/fields/addressfield/addressfield.migrate.inc

@@ -5,6 +5,11 @@
  * Base integration with the Migrate API class.
  */
 
+// Avoid issues when migrate module is disabled.
+if (!class_exists('MigrateFieldHandler')) {
+  return;
+}
+
 /**
  * Implements hook_migrate_api().
  */

+ 40 - 2
sites/all/modules/contrib/fields/addressfield/addressfield.module

@@ -52,6 +52,37 @@ function addressfield_module_implements_alter(&$implementations, $hook) {
   }
 }
 
+/**
+ * Returns a list of address fields optionally filtered by entity type.
+ *
+ * @param string $entity_type
+ *   Optional machine-name of an entity type to filter the returned array by.
+ *
+ * @return array
+ *   An array of address field mapping data.
+ */
+function addressfield_get_address_fields($entity_type = '') {
+  $fields = &drupal_static(__FUNCTION__ . '_' . $entity_type);
+
+  if (isset($fields)) {
+    return $fields;
+  }
+
+  // Get mapping data for all address fields.
+  $fields = array_filter(field_info_field_map(), 'addressfield_field_map_filter');
+
+  // Filter the list of fields by entity type if specified.
+  if (!empty($fields) && !empty($entity_type)) {
+    foreach ($fields as $field_name => $field) {
+      if (!isset($field['bundles'][$entity_type])) {
+        unset($fields[$field_name]);
+      }
+    }
+  }
+
+  return $fields;
+}
+
 /**
  * Returns TRUE if a field map array value represents an addressfield.
  *
@@ -305,7 +336,14 @@ function theme_addressfield_container($variables) {
   if (strlen($element['#children']) > 0) {
     $output = '<' . $element['#tag'] . drupal_attributes($element['#attributes']) . '>';
     $output .= $element['#children'];
-    $output .= '</' . $element['#tag'] . ">";
+    $output .= '</' . $element['#tag'] . '>';
+    // Add a linebreak to the HTML after a div. This is invisible on the
+    // rendered page but improves the appearance of address field output when
+    // HTML tags are stripped, such as by Views Data Export.
+    if ($element['#tag'] == 'div') {
+      $output .= PHP_EOL;
+    }
+
     return $output;
   }
   else {
@@ -446,7 +484,7 @@ function addressfield_field_presave($entity_type, $entity, $field, $instance, $l
     // spaces to single spaces.
     foreach ($item as $key => &$value) {
       if (!in_array($key, array('data')) && is_string($value)) {
-        $value = trim(str_replace('  ', ' ', $value));
+        $value = trim(preg_replace('/[[:blank:]]{2,}/u', ' ', $value));
       }
     }
   }

+ 26 - 16
sites/all/modules/contrib/fields/addressfield/addressfield.tokens.inc

@@ -89,11 +89,13 @@ function addressfield_token_info() {
  */
 function addressfield_token_info_alter(&$data) {
   // Loop over every address field on the site.
-  foreach (array_filter(field_info_field_map(), 'addressfield_field_map_filter') as $field_name => $field) {
-    foreach ($data['tokens'] as $group => $token){
-      if (isset($data['tokens'][$group][$field_name]) && is_array($data['tokens'][$group][$field_name])) {
-        // Set the token type for the field to use the addressfield child tokens.
-        $data['tokens'][$group][$field_name]['type'] = 'address-field';
+  foreach (addressfield_get_address_fields() as $field_name => $field) {
+    foreach (array($field_name, strtr($field_name, '_', '-')) as $name) {
+      foreach ($data['tokens'] as $group => $token) {
+        if (isset($data['tokens'][$group][$name]) && is_array($data['tokens'][$group][$name])) {
+          // Set the token type for the field to use the addressfield child tokens.
+          $data['tokens'][$group][$name]['type'] = 'address-field';
+        }
       }
     }
   }
@@ -212,19 +214,27 @@ function addressfield_tokens($type, $tokens, array $data = array(), array $optio
   // and helps us avoid having to do the entity detection ourselves.
   if ($type == 'entity') {
     // Loop over the address fields defined on the site.
-    foreach (array_filter(field_info_field_map(), 'addressfield_field_map_filter') as $field_name => $field) {
-      // If there are any address field tokens in the token list...
-      if ($addressfield_tokens = token_find_with_prefix($tokens, $field_name)) {
-        // If the current field is on the matching entity type...
-        if (!empty($field['bundles'][$data['entity_type']])) {
-          // Extract the format handlers selected in a representative instance
-          // settings form for use in formatting tokens.
-          $instance = field_info_instance($data['entity_type'], $field_name, reset($field['bundles'][$data['entity_type']]));
-          $format_handlers = $instance['widget']['settings']['format_handlers'];
+    foreach (addressfield_get_address_fields($data['entity_type']) as $field_name => $field) {
+      // If the current field is on the matching entity type...
+      if (!empty($field['bundles'][$data['entity_type']])) {
+        // Extract the format handlers selected in a representative instance
+        // settings form for use in formatting tokens.
+        $instance = field_info_instance($data['entity_type'], $field_name, reset($field['bundles'][$data['entity_type']]));
+        $format_handlers = $instance['widget']['settings']['format_handlers'];
+      }
+
+      foreach (array($field_name, strtr($field_name, '_', '-')) as $prefix) {
+        // If there are any address field tokens in the token list...
+        $addressfield_tokens = token_find_with_prefix($tokens, $prefix);
+
+        if (!$addressfield_tokens) {
+          continue;
         }
 
-        // Generate the necessary address field tokens for the entity.
-        $replacements += token_generate('address-field', $addressfield_tokens, array('address-field' => $data['entity']->$field_name, 'format_handlers' => $format_handlers), $options);
+        if (property_exists($data['entity'], $field_name)) {
+          // Generate the necessary address field tokens for the entity.
+          $replacements += token_generate('address-field', $addressfield_tokens, array('address-field' => $data['entity']->$field_name, 'format_handlers' => $format_handlers), $options);
+        }
       }
     }
   }

+ 3 - 4
sites/all/modules/contrib/fields/addressfield/example/addressfield_example.info

@@ -7,9 +7,8 @@ hidden = TRUE
 dependencies[] = ctools
 dependencies[] = addressfield
 
-; Information added by Drupal.org packaging script on 2015-10-07
-version = "7.x-1.2"
+; Information added by Drupal.org packaging script on 2018-10-26
+version = "7.x-1.3"
 core = "7.x"
 project = "addressfield"
-datestamp = "1444254070"
-
+datestamp = "1540579391"

+ 24 - 0
sites/all/modules/contrib/fields/addressfield/plugins/format/address-hide-administrative-area.inc

@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Hide the administrative area field.
+ */
+
+$plugin = array(
+  'title' => t('Hide the administrative area'),
+  'format callback' => 'addressfield_format_address_hide_administrative_area',
+  'type' => 'address',
+  'weight' => -84,
+);
+
+/**
+ * Format callback.
+ *
+ * @see CALLBACK_addressfield_format_callback()
+ */
+function addressfield_format_address_hide_administrative_area(&$format, $address, $context = array()) {
+  if (isset($format['locality_block']['administrative_area'])) {
+    $format['locality_block']['administrative_area']['#access'] = FALSE;
+  }
+}

+ 1 - 1
sites/all/modules/contrib/fields/addressfield/plugins/format/address-hide-country.inc

@@ -20,7 +20,7 @@ $plugin = array(
 function addressfield_format_address_hide_country(&$format, $address, $context = array()) {
   // Hide the country element only if the whole field is required, otherwise
   // there will always be an additional None option.
-  if ($context['mode'] == 'form' && $context['instance']['required']) {
+  if ($context['mode'] == 'form' && (empty($context['instance']) || $context['instance']['required'])) {
     if (!empty($format['country']['#options']) && count($format['country']['#options']) == 1) {
       $format['country']['#access'] =  FALSE;
     }

+ 24 - 0
sites/all/modules/contrib/fields/addressfield/plugins/format/address-hide-locality.inc

@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Hide the locality field.
+ */
+
+$plugin = array(
+  'title' => t('Hide the locality'),
+  'format callback' => 'addressfield_format_address_hide_locality',
+  'type' => 'address',
+  'weight' => -84,
+);
+
+/**
+ * Format callback.
+ *
+ * @see CALLBACK_addressfield_format_callback()
+ */
+function addressfield_format_address_hide_locality(&$format, $address, $context = array()) {
+  if (isset($format['locality_block']['locality'])) {
+    $format['locality_block']['locality']['#access'] = FALSE;
+  }
+}

+ 6 - 1
sites/all/modules/contrib/fields/addressfield/plugins/format/address.inc

@@ -240,7 +240,12 @@ function addressfield_format_address_generate(&$format, $address, $context = arr
   if (in_array($address['country'], $countries_postal_code_after_locality)) {
     // Take the widget out of the array.
     $postal_code_widget = $format['locality_block']['postal_code'];
-    $postal_code_widget['#prefix'] = ' ';
+
+    // If the postal code not in its own row, add a separating space.
+    if (empty($postal_code_widget['#tag'])) {
+      $postal_code_widget['#prefix'] = ' ';
+    }
+
     unset($format['locality_block']['postal_code']);
 
     // Add it back.

+ 0 - 0
sites/all/modules/contrib/fields/autocomplete_deluxe/README.txt


+ 18 - 15
sites/all/modules/contrib/fields/autocomplete_deluxe/autocomplete_deluxe.api.php

@@ -1,5 +1,4 @@
 <?php
-// $Id$
 
 /**
  * @file
@@ -12,24 +11,26 @@
  * When you want to use the Autocomplete Deluxe element, you have to choose
  * between two types sources for the suggestion data: Ajax Callbacks or Lists.
  * You can set the source type by using the appropriate options:
- * - #autocomplete_deluxe_path expects a string with an url, that points to the ajax
- *   callback. The response should be encoded as json(like for the core
+ * - #autocomplete_deluxe_path expects a string with an url, that points to the
+ *   ajax callback. The response should be encoded as json (like for the core
  *   autocomplete).
- * - #autocomplete_options needs an array in the form of an array(similar to #options in core
- *   for selects or checkboxes): array('a', 'b', 'c') or array(1 => 'a', 2 =>
- *   'b', 3 => 'c').
+ * - #autocomplete_options needs an array in the form of an array (similar to
+ *   #options in core for selects or checkboxes): array('a', 'b', 'c') or
+ *   array(1 => 'a', 2 => 'b', 3 => 'c').
  *
- * Besides this two, there are three other options, wich autocomplete deluxe
+ * Besides these two, there are four other options which autocomplete deluxe
  * accepts:
  * - #multiple Indicates whether the user may select more than one item. Expects
  *   TRUE or FALSE, by default it is set to FALSE.
- * - #autocomplete_multiple_delimiter If #multiple is TRUE, then you can use
- *   this option to set a seperator for multiple values. By default a string
- *   with the follwing content will be used: ', '.
- * - #autocomplete_min_length Indicates how many characters must be entered
- *   until, the suggesion list can be opened. Especially helpfull, when your
+ * - #delimiter If #multiple is TRUE, then you can use this option to set a
+ *   seperator for multiple values. By default a string with the following
+ *   content will be used: ', '.
+ * - #min_length Indicates how many characters must be entered
+ *   until, the suggesion list can be opened. Especially helpful, when your
  *   ajax callback returns only valid suggestion for a minimum characters.
  *   The default is 0.
+ * - #not_found_message A message text which will be displayed, if the entered
+ *   term was not found.
  */
 function somefunction() {
   switch ($type) {
@@ -38,16 +39,18 @@ function somefunction() {
         '#type' => 'autocomplete_deluxe',
         '#autocomplete_options' => $options,
         '#multiple' => FALSE,
-        '#autocomplete_min_length' => 0,
+        '#min_length' => 0,
       );
       break;
+
     case 'ajax':
       $element = array(
         '#type' => 'autocomplete_deluxe',
         '#autocomplete_deluxe_path' => url('some_uri', array('absolute' => TRUE)),
         '#multiple' => TRUE,
-        '#autocomplete_min_length' => 1,
-        '#autocomplete_multiple_delimiter' => '|',
+        '#min_length' => 1,
+        '#delimiter' => '|',
+        '#not_found_message' => "The term '@term' will be added.",
       );
       break;
   }

+ 0 - 0
sites/all/modules/contrib/fields/autocomplete_deluxe/autocomplete_deluxe.css


+ 3 - 3
sites/all/modules/contrib/fields/autocomplete_deluxe/autocomplete_deluxe.info

@@ -5,9 +5,9 @@ core = 7.x
 files[] = autocomplete_deluxe.module
 dependencies[] = taxonomy
 
-; Information added by Drupal.org packaging script on 2017-01-11
-version = "7.x-2.2"
+; Information added by Drupal.org packaging script on 2017-07-25
+version = "7.x-2.3"
 core = "7.x"
 project = "autocomplete_deluxe"
-datestamp = "1484128687"
+datestamp = "1501005546"
 

+ 0 - 0
sites/all/modules/contrib/fields/autocomplete_deluxe/autocomplete_deluxe.js


+ 0 - 0
sites/all/modules/contrib/fields/autocomplete_deluxe/autocomplete_deluxe.module


+ 77 - 3
sites/all/modules/contrib/localisation/entity_translation/CHANGELOG.txt

@@ -1,9 +1,83 @@
 
 Entity Translation 7.x-1.x, xxxx-xx-xx
 --------------------------------------
-#2189567 by stefanos.petrakis, jmuzz: Fixed problems enabling and disabling translation on
-  a field with revisions enabled.
-#2798721 by gnucifer: Path scheme not initialized on delete translation confirmation form.
+#3025770 by sudheeshps, patelmayank7552, stefanos.petrakis: PHP 7.0
+  Compatibility
+#2536292 by plopesc, stefanos.petrakis: "Warning: array_merge(): Argument #2 is
+  not an array in entity_translation_menu_alter" When 'page arguments' or
+  'access arguments' are not defined in the original item
+#2921298 by Stevel, stefanos.petrakis: Missing test dependencies
+
+
+Entity Translation 7.x-1.0, 2018-04-01
+--------------------------------------
+(no change)
+
+
+Entity Translation 7.x-1.0-rc1, 2018-03-21
+------------------------------------------
+#2927815 by Skabbkladden, dawehner: Infinite loop with language neutral alias
+  and pathauto.
+#2890683 by tobiberlin, stefanos.petrakis: entity_translation_field_attach_form()
+  adding unwanted fields to form.
+#2907366 by swati.nuna: Invalid hook hook_translation_info() mentioned in
+  docblock for entity_translation_edit_form_info().
+#1799770 by plach, bforchhammer: Update id and bundle when setting a wrapped
+  entity.
+#2339315 by plach: Added documentation for
+  hook_entity_translation_source_field_state_alter().
+#1506054 by plach, Owen Barton: Taxonomy term reference: language-aware widget
+  and autocomplete.
+#2907275 by jalpesh: CSS class name misspelled in entity_translation_overview().
+
+
+Entity Translation 7.x-1.0-beta7, 2017-08-21
+--------------------------------------------
+#2903195 by stefanos.petrakis, BAHbKA, plach: Enabling translation for not
+  empty taxonomy vocabulary.
+#2425825 by jamesrward: Update from before beta4 fails.
+#2900094 by joseph.olstad: code sniffer drupal.org recommended code syntax
+  fixes.
+#2883805 by mikran: entity_translation_update_7008 is broken when taxonomy
+  module is not enabled.
+#2877074 by plach, stefanos.petrakis, joseph.olstad: Refactor the
+  entity_translation_language() callback to make it bundle-specific.
+#2743685 by stefanos.petrakis, bwaindwain: Pathauto update for all translations
+  for a single node.
+#2899658 by joseph.olstad, stefanos.petrakis: entity_translation_upgrade_do
+  needs to automatically create the entity_translation row for the source
+  language in entity_translation.
+#1800158 by meichr: Entity Translation Upgrade, drush extension.
+#2885858 by StephaneQ: Can't delete taxonomy term translation since beta6
+  update.
+#2572203 by mattew: Wrong query generated when several Translations
+  relationships are used.
+#2824255 by ccarrascal, plach: Notice: Undefined index for language in
+  setTranslation().
+#2750179 by wadmiraal: Allowed default translation handler to be completely
+  overridden.
+#2307937 by meichr, joseph.olstad: Batch API needs $context['results'] handled
+  as an array, not a value.
+#1175170 by hgoto, Pisco, alberto56: Optionally enable disabled languages for
+  entity translation.
+#2870524 by stefanos.petrakis, joseph.olstad: Field copy fails with content
+  translation for fields with entity translation enabled.
+
+
+Entity Translation 7.x-1.0-beta6, 2017-03-03
+--------------------------------------------
+#2849464 by plach, czigor, stefanos.petrakis: Added an API to set the active
+  language.
+#2438615 by David_Rothstein, matthiasm11: New nodes are always created using
+  LANGUAGE_NONE (only changed to the correct language during form submission).
+#2820454 by Dylan Donkersgoed: PHP notice when attaching single field
+  with field_attach_form.
+#2826297 by Thomas Cys, dwebpoint, stefanos.petrakis: 'clone' is a reserved
+  keyword introduced in PHP version 5.0 and cannot be invoked as a function.
+#2189567 by stefanos.petrakis, jmuzz: Fixed problems enabling and disabling
+  translation on a field with revisions enabled.
+#2798721 by gnucifer: Path scheme not initialized on delete translation
+  confirmation form.
 #2215771 by colan, stefanos.petrakis: Fixed "Undefined index: translate in
   EntityTranslationDefaultHandler->entityForm()".
 #1829636 by bforchhammer, stefanos.petrakis: Fixed "All languages" suffix not

+ 9 - 7
sites/all/modules/contrib/localisation/entity_translation/MAINTAINERS.txt

@@ -9,8 +9,9 @@ Project maintainers
 The Entity translation maintainers oversee the development of the project as a
 whole. The project maintainers for Entity translation are:
 
-- 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>
+- Stefanos Petrakis 'stefanos.petrakis' <https://www.drupal.org/u/stefanospetrakis>
 
 
 Component maintainers
@@ -25,14 +26,15 @@ http://drupal.org/node/363367 to find out how to become a component maintainer.
 Current component maintainers for Entity translation:
 
 Base system
-- Francesco Placella 'plach' <http://drupal.org/user/183211>
-- Benedikt Forchhammer 'bforchhammer' <http://drupal.org/user/216396>
+- Francesco Placella 'plach' <https://www.drupal.org/u/plach>
+- Benedikt Forchhammer 'bforchhammer' <https://www.drupal.org/u/bforchhammer>
+- Stefanos Petrakis 'stefanos.petrakis' <https://www.drupal.org/u/stefanospetrakis>
 
 Menu integration
-- Benedikt Forchhammer 'bforchhammer' <http://drupal.org/user/216396>
+- Benedikt Forchhammer 'bforchhammer' <https://www.drupal.org/u/bforchhammer>
 
 Views integration
-- Fabian Sörqvist 'fabsor' <http://drupal.org/user/255704>
+- Fabian Sörqvist 'fabsor' <https://www.drupal.org/u/fabsor>
 
 Node translation upgrade
-- Francesco Placella 'plach' <http://drupal.org/user/183211>
+- Francesco Placella 'plach' <https://www.drupal.org/u/plach>

+ 39 - 15
sites/all/modules/contrib/localisation/entity_translation/entity_translation.admin.inc

@@ -18,6 +18,13 @@ function entity_translation_admin_form($form, $form_state) {
     '#default_value' => variable_get('locale_field_language_fallback', TRUE),
   );
 
+  $form['entity_translation_languages_enabled'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Use only enabled languages'),
+    '#description' => t('If checked, disabled languages will not show up as available languages. This setting does not apply to content types that are configured to use the Multilingual content (i18n_node) module as this module provides its own configuration.'),
+    '#default_value' => variable_get('entity_translation_languages_enabled', FALSE),
+  );
+
   $form['entity_translation_show_fallback_on_overview_pages'] = array(
     '#type' => 'checkbox',
     '#title' => t('Show fallback statuses on overview pages'),
@@ -45,7 +52,7 @@ function entity_translation_admin_form($form, $form_state) {
   );
 
   $_null = NULL;
-  list($items, ) = menu_router_build();
+  list($items,) = menu_router_build();
   _entity_translation_validate_path_schemes($_null, FALSE, $items);
 
   foreach (entity_get_info() as $entity_type => $info) {
@@ -316,7 +323,7 @@ function entity_translation_overview($entity_type, $entity, $callback = NULL) {
           $link = isset($add_links->links[$langcode]['href']) ? $add_links->links[$langcode] : array('href' => $add_path, 'language' => $language);
           $link['query'] = isset($_GET['destination']) ? drupal_get_destination() : FALSE;
           $options[] = $translatable ? l(t('add'), $link['href'], $link) : t('No translatable fields');
-          $classes[] = $translatable ? '' : 'non-traslatable';
+          $classes[] = $translatable ? '' : 'non-translatable';
         }
         $status = t('Not translated');
         // Show fallback information if required.
@@ -389,7 +396,7 @@ function _entity_translation_label($entity_type, $entity, $langcode = NULL) {
 /**
  * Theme wrapper for the entity translation language page.
  */
-function theme_entity_translation_overview($variables){
+function theme_entity_translation_overview($variables) {
   $rows = $variables['rows'];
   return theme('table', array(
     'rows' => $rows,
@@ -400,7 +407,7 @@ function theme_entity_translation_overview($variables){
 /**
  * Theme wrapper for the entity translation language outdated translation.
  */
-function theme_entity_translation_overview_outdated($variables){
+function theme_entity_translation_overview_outdated($variables) {
   $message = $variables['message'];
   return ' - <span class="marker">' . $message . '</span>';
 }
@@ -410,7 +417,7 @@ function theme_entity_translation_overview_outdated($variables){
  */
 function entity_translation_delete_confirm($form, $form_state, $entity_type, $entity, $langcode) {
   $handler = entity_translation_get_handler($entity_type, $entity);
-  $handler->setFormLanguage($langcode);
+  $handler->setActiveLanguage($langcode);
   $handler->initPathScheme();
   $languages = language_list();
 
@@ -452,7 +459,7 @@ function entity_translation_delete_confirm_submit($form, &$form_state) {
   $form_state['redirect'] = $handler->getTranslatePath();
 }
 
-/*
+/**
  * Confirm form for changing field translatability.
  */
 function entity_translation_translatable_form($form, &$form_state, $field_name) {
@@ -547,7 +554,7 @@ function entity_translation_translatable_form_submit($form, $form_state) {
   batch_set($batch);
 }
 
-/*
+/**
  * Toggle translatability of the given field.
  *
  * This is called from a batch operation, but should only run once per field.
@@ -602,12 +609,28 @@ function entity_translation_translatable_batch($translatable, $field_name, $copy
     ->range($offset, $limit)
     ->execute();
 
-  foreach ($result as $entity_type => $revisions) {
-    foreach ($revisions as $revision) {
-      // $revision is a partial entity object that will be used as an array of
-      // conditions.
-      $conditions = (array) $revision;
-      $entity = reset(entity_load($entity_type, FALSE, $conditions));
+  foreach ($result as $entity_type => $partial_entities) {
+
+    // Load all revisionable entities' revisions.
+    if (EntityTranslationDefaultHandler::isEntityTypeRevisionable($entity_type)) {
+      $entities = array();
+      // Extract the revision identifier from the entity's definition.
+      $entity_info = entity_get_info($entity_type);
+      $revision_id_key = $entity_info['entity keys']['revision'];
+      // Load each revisionable entity's revision using $conditions, which
+      // should include the revision id information.
+      foreach ($partial_entities as $partial_entity) {
+        $conditions = (array) $partial_entity;
+        $revision_condition = array_intersect_key($conditions, array($revision_id_key => $revision_id_key));
+        $entity_revisions = entity_load($entity_type, FALSE, $revision_condition);
+        $entities[] = reset($entity_revisions);
+      }
+    }
+    else {
+      $entities = entity_load($entity_type, array_keys($partial_entities));
+    }
+
+    foreach ($entities as $entity) {
       $context['sandbox']['progress']++;
       $handler = entity_translation_get_handler($entity_type, $entity);
       $langcode = $handler->getLanguage();
@@ -626,9 +649,10 @@ function entity_translation_translatable_batch($translatable, $field_name, $copy
       if ($translatable && isset($entity->{$field_name}[LANGUAGE_NONE])) {
         // If the field is being switched to translatable and has data for
         // LANGUAGE_NONE then we need to move the data to the right language.
-
+        // In case the 'Copy translations' option was selected, move the
+        // available LANGUAGE_NONE field data into all existing translation
+        // languages, otherwise only into the entity's language.
         $translations = $handler->getTranslations();
-
         if ($copy_all_languages && !empty($translations->data)) {
           foreach ($translations->data as $translation) {
             $entity->{$field_name}[$translation['language']] = $entity->{$field_name}[LANGUAGE_NONE];

+ 14 - 0
sites/all/modules/contrib/localisation/entity_translation/entity_translation.api.php

@@ -164,3 +164,17 @@ function hook_entity_translation_delete($entity_type, $entity, $langcode) {
  */
 function hook_entity_translation_delete_revision($entity_type, $entity, $langcode) {
 }
+
+/**
+ * Allows to sets the right values in the form state when adding a translation.
+ */
+function hook_entity_translation_source_field_state_alter(&$field_state) {
+  if (isset($field_state['entity'])) {
+    module_load_include('inc', 'entity', 'includes/entity.ui');
+    foreach ($field_state['entity'] as $delta => $entity) {
+      if ($entity instanceof FieldCollectionItemEntity) {
+        $field_state['entity'][$delta] = entity_ui_clone_entity('field_collection_item', $entity);
+      }
+    }
+  }
+}

+ 6 - 4
sites/all/modules/contrib/localisation/entity_translation/entity_translation.info

@@ -5,6 +5,9 @@ core = 7.x
 configure = admin/config/regional/entity_translation
 dependencies[] = locale (>7.14)
 
+test_dependencies[] = pathauto:pathauto
+test_dependencies[] = title:title
+
 files[] = includes/translation.handler_factory.inc
 files[] = includes/translation.handler.inc
 files[] = includes/translation.handler.comment.inc
@@ -23,9 +26,8 @@ files[] = views/entity_translation_handler_filter_language.inc
 files[] = views/entity_translation_handler_filter_translation_exists.inc
 files[] = views/entity_translation_handler_field_field.inc
 
-; Information added by Drupal.org packaging script on 2016-09-28
-version = "7.x-1.0-beta5+15-dev"
+; Information added by Drupal.org packaging script on 2019-01-20
+version = "7.x-1.0+5-dev"
 core = "7.x"
 project = "entity_translation"
-datestamp = "1475057941"
-
+datestamp = "1548022384"

+ 16 - 2
sites/all/modules/contrib/localisation/entity_translation/entity_translation.install

@@ -175,6 +175,9 @@ function entity_translation_install() {
 
   // Enable revision support for entity translation.
   variable_set('entity_translation_revision_enabled', TRUE);
+
+  // Enable taxonomy autocomplete support.
+  variable_set('entity_translation_taxonomy_autocomplete', TRUE);
 }
 
 /**
@@ -356,7 +359,11 @@ function entity_translation_update_7006() {
     'not null' => FALSE,
     'description' => 'The entity revision id this translation relates to',
   );
-  db_add_field('entity_translation', 'revision_id', $spec);
+
+  // Create revision id column if it doesn't exist already.
+  if (!db_field_exists('entity_translation', 'revision_id')) {
+    db_add_field('entity_translation', 'revision_id', $spec);
+  }
 
   // Create the entity translation revision schema.
   $table = array(
@@ -429,7 +436,11 @@ function entity_translation_update_7006() {
     'primary key' => array('entity_type', 'revision_id', 'language'),
     'indexes'=> array('revision_id' => array('revision_id')),
   );
-  db_create_table('entity_translation_revision', $table);
+
+  // Create entity translation revision table if it doesn't exist already.
+  if (!db_table_exists('entity_translation_revision')) {
+    db_create_table('entity_translation_revision', $table);
+  }
 }
 
 /**
@@ -452,6 +463,9 @@ function entity_translation_update_7007() {
  * through it.
  */
 function entity_translation_update_7008() {
+  if (!module_exists('taxonomy')) {
+    return;
+  }
   // According to EXPLAIN joining {taxonomy_vocabulary} here makes the query
   // perform way worse, so we just split into two quick ones.
   $query = "SELECT t.vid

+ 78 - 46
sites/all/modules/contrib/localisation/entity_translation/entity_translation.module

@@ -244,6 +244,13 @@ function entity_translation_menu() {
     'file' => 'entity_translation.admin.inc',
   );
 
+  $items['entity_translation/taxonomy_term/autocomplete'] = array(
+    'title' => 'Entity translation autocomplete',
+    'page callback' => 'entity_translation_taxonomy_term_autocomplete',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+
   return $items;
 }
 
@@ -457,7 +464,11 @@ function entity_translation_menu_alter(&$items) {
           // Replace the main edit callback with our proxy implementation to set
           // form language to the current language and check access.
           $entity_position = array_search($scheme['path wildcard'], $edit_path_parts);
-          $original_item = $edit_item;
+          // Make sure incoming page and access arguments are arrays.
+          $original_item = $edit_item + array(
+            'page arguments' => array(),
+            'access arguments' => array(),
+          );
           $args = array($entity_type, $entity_position, FALSE, $original_item);
           $edit_item['page callback'] = 'entity_translation_edit_page';
           $edit_item['page arguments'] = array_merge($args, $original_item['page arguments']);
@@ -550,7 +561,7 @@ function entity_translation_edit_page() {
   $handler = entity_translation_get_handler($entity_type, $entity);
   $handler->initPathScheme();
   $langcode = entity_translation_get_existing_language($entity_type, $entity, $langcode);
-  $handler->setFormLanguage($langcode);
+  $handler->setActiveLanguage($langcode);
 
   // Display the entity edit form.
   return _entity_translation_callback($edit_form_item['page callback'], $args, $edit_form_item);
@@ -693,7 +704,7 @@ function entity_translation_add_page() {
 
   $handler = entity_translation_get_handler($entity_type, $entity);
   $handler->initPathScheme();
-  $handler->setFormLanguage($langcode);
+  $handler->setActiveLanguage($langcode);
   $handler->setSourceLanguage($source);
 
   // Display the entity edit form.
@@ -918,7 +929,7 @@ function entity_translation_field_language_alter(&$display_language, $context) {
     if (isset($translations->data[$context['language']]) && !entity_translation_access($entity_type, $translations->data[$context['language']])) {
       list(, , $bundle) = entity_extract_ids($entity_type, $entity);
       $instances = field_info_instances($entity_type, $bundle);
-      $entity = clone($entity);
+      $entity = clone $entity;
 
       foreach ($translations->data as $langcode => $translation) {
         if ($langcode == $context['language'] || !entity_translation_access($entity_type, $translations->data[$langcode])) {
@@ -1194,7 +1205,7 @@ function entity_translation_field_attach_form($entity_type, $entity, &$form, &$f
   if (empty($form['#entity_translation_source_form']) && entity_translation_enabled($entity_type, $bundle)) {
     $handler = entity_translation_get_handler($entity_type, $entity);
     $langcode = !empty($langcode) ? $langcode : $handler->getLanguage();
-    $form_langcode = $handler->getFormLanguage();
+    $form_langcode = $handler->getActiveLanguage();
     $translations = $handler->getTranslations();
     $update_langcode = $form_langcode && ($form_langcode != $langcode);
     $source = $handler->getSourceLanguage();
@@ -1217,7 +1228,7 @@ function entity_translation_field_attach_form($entity_type, $entity, &$form, &$f
         // language information from source to target language, this way the
         // user can find the form items already populated with the source values
         // while the field form element holds the correct language information.
-        if ($field['translatable']) {
+        if ($field['translatable'] && isset($form[$field_name])) {
           $element = &$form[$field_name];
           $element['#entity_type'] = $entity_type;
           $element['#entity'] = $entity;
@@ -1253,11 +1264,14 @@ function entity_translation_field_attach_form($entity_type, $entity, &$form, &$f
       list(, , $bundle) = entity_extract_ids($entity_type, $entity);
       foreach (field_info_instances($entity_type, $bundle) as $instance) {
         $field_name = $instance['field_name'];
-        $field = field_info_field($field_name);
-        // If access is not set or is granted we check whether the user has
-        // access to shared fields.
-        $form[$field_name]['#access'] = (!isset($form[$field_name]['#access']) || $form[$field_name]['#access']) && ($field['translatable'] || $shared_access);
-        $form[$field_name]['#multilingual'] = (boolean) $field['translatable'];
+        // Check if a field is part of the form array.
+        if (isset($form[$field_name])) {
+          $field = field_info_field($field_name);
+          // If access is not set or is granted we check whether the user has
+          // access to shared fields.
+          $form[$field_name]['#access'] = (!isset($form[$field_name]['#access']) || $form[$field_name]['#access']) && ($field['translatable'] || $shared_access);
+          $form[$field_name]['#multilingual'] = (boolean) $field['translatable'];
+        }
       }
     }
 
@@ -1491,7 +1505,7 @@ function entity_translation_form_alter(&$form, &$form_state) {
       if (!$handler->isNewEntity()) {
         $handler->entityForm($form, $form_state);
         $translations = $handler->getTranslations();
-        $form_langcode = $handler->getFormLanguage();
+        $form_langcode = $handler->getActiveLanguage();
         if (!isset($translations->data[$form_langcode]) || count($translations->data) > 1) {
           // Hide shared form elements if the user is not allowed to edit them.
           $handler->entityFormSharedElements($form);
@@ -1520,7 +1534,7 @@ function entity_translation_form_alter(&$form, &$form_state) {
 function entity_translation_entity_form_source_language_submit($form, &$form_state) {
   $handler = entity_translation_entity_form_get_handler($form, $form_state);
   $langcode = $form_state['values']['source_language']['language'];
-  $path = "{$handler->getEditPath()}/add/$langcode/{$handler->getFormLanguage()}";
+  $path = "{$handler->getEditPath()}/add/$langcode/{$handler->getActiveLanguage()}";
   $options = array();
   if (isset($_GET['destination'])) {
     $options['query'] = drupal_get_destination();
@@ -1536,7 +1550,7 @@ function entity_translation_entity_form_source_language_submit($form, &$form_sta
  */
 function entity_translation_entity_form_delete_translation_submit($form, &$form_state) {
   $handler = entity_translation_entity_form_get_handler($form, $form_state);
-  $path = "{$handler->getTranslatePath()}/delete/{$handler->getFormLanguage()}";
+  $path = "{$handler->getTranslatePath()}/delete/{$handler->getActiveLanguage()}";
   $options = array();
   if (isset($_GET['destination'])) {
     $options['query'] = drupal_get_destination();
@@ -1564,7 +1578,7 @@ function entity_translation_entity_form_language_update($element, &$form_state,
   // needed when responding to an AJAX request where the languages cannot be set
   // from the usual page callback.
   if (!empty($form_state['entity_translation']['form_langcode'])) {
-    $handler->setFormLanguage($form_state['entity_translation']['form_langcode']);
+    $handler->setActiveLanguage($form_state['entity_translation']['form_langcode']);
   }
   // When responding to an AJAX request we should ignore any change in the
   // language widget as it may alter the field language expected by the AJAX
@@ -1597,6 +1611,9 @@ function entity_translation_field_attach_submit($entity_type, $entity, $form, &$
     // Update the wrapped entity with the submitted values.
     $handler->setEntity($entity);
     $handler->entityFormSubmit($form, $form_state);
+
+    // Process in-place translations for the taxonomy autocomplete widget.
+    entity_translation_taxonomy_term_field_attach_submit($entity_type, $entity, $form, $form_state);
   }
 }
 
@@ -1671,7 +1688,7 @@ function theme_entity_translation_language_tabs($variables) {
  * Adds an option to enable field synchronization.
  * Enable a selector to choose whether a field is translatable.
  */
-function entity_translation_form_field_ui_field_edit_form_alter(&$form, $form_state) {
+function entity_translation_form_field_ui_field_edit_form_alter(&$form, &$form_state) {
   $instance = $form['#instance'];
   $entity_type = $instance['entity_type'];
   $field_name = $instance['field_name'];
@@ -1691,7 +1708,8 @@ function entity_translation_form_field_ui_field_edit_form_alter(&$form, $form_st
   $label = t('Field translation');
   $title = t('Users may translate all occurrences of this field:') . _entity_translation_field_desc($field);
 
-  if (field_has_data($field)) {
+  $form_state['field_has_data'] = field_has_data($field);
+  if ($form_state['field_has_data']) {
     $path = "admin/config/regional/entity_translation/translatable/$field_name";
     $status = $translatable ? $title : (t('All occurrences of this field are untranslatable:') . _entity_translation_field_desc($field));
     $link_title = !$translatable ? t('Enable translation') : t('Disable translation');
@@ -1719,6 +1737,11 @@ function entity_translation_form_field_ui_field_edit_form_alter(&$form, $form_st
       '#default_value' => $translatable,
     );
   }
+
+  $function = 'entity_translation_form_field_ui_field_edit_' . $instance['widget']['type'] . '_form_alter';
+  if (function_exists($function)) {
+    $function($form, $form_state);
+  }
 }
 
 /**
@@ -1821,32 +1844,37 @@ function entity_translation_settings($entity_type, $bundle) {
  * Entity language callback.
  *
  * This callback changes the entity language from the actual one to the active
- * form language. This overriding allows to obtain language dependent form
- * widgets where multilingual values are supported (e.g. field or path alias
- * widgets) even if the code was not originally written with supporting multiple
- * values per language in mind.
+ * language. This overriding allows to obtain language dependent form widgets
+ * where multilingual values are supported (e.g. field or path alias widgets)
+ * even if the code was not originally written with supporting multiple values
+ * per language in mind.
  *
  * The main drawback of this approach is that code needing to access the actual
  * language in the entity form build/validation/submit workflow cannot rely on
  * the entity_language() function. On the other hand in these scenarios assuming
- * the presence of Entity translation should be safe, thus being able to rely on
- * the EntityTranslationHandlerInterface::getLanguage() method.
+ * the presence of Entity translation should be safe, thus developers can rely
+ * on the EntityTranslationHandlerInterface::getLanguage() method.
  *
- * @param $entity_type
+ * @param string $entity_type
  *    The the type of the entity.
- * @param $entity
+ * @param object $entity
  *    The entity whose language has to be returned.
  *
- * @return
+ * @return string
  *   A valid language code.
  */
 function entity_translation_language($entity_type, $entity) {
   $handler = entity_translation_get_handler($entity_type, $entity);
-  if (empty($handler)) {
+  if (!$handler) {
     return LANGUAGE_NONE;
   }
-  $langcode = $handler->getFormLanguage();
-  return !empty($langcode) ? $langcode : $handler->getLanguage();
+  if (entity_translation_enabled($entity_type, $entity)) {
+    $langcode = $handler->getActiveLanguage();
+    return $langcode ? $langcode : $handler->getLanguage();
+  }
+  else {
+    return $handler->getLanguage();
+  }
 }
 
 /**
@@ -1862,15 +1890,8 @@ function entity_translation_language($entity_type, $entity) {
  *   A class implementing EntityTranslationHandlerInterface.
  */
 function entity_translation_get_handler($entity_type = NULL, $entity = NULL) {
-  if (class_exists('EntityTranslationHandlerFactory')) {
-    $factory = EntityTranslationHandlerFactory::getInstance();
-    return empty($entity) ? $factory->getLastHandler($entity_type) : $factory->getHandler($entity_type, $entity);
-  }
-  // @todo BC layer. Remove before the first stable release.
-  elseif (!empty($entity_type) && is_object($entity)) {
-    $entity_info = entity_get_info($entity_type);
-    return new EntityTranslationDefaultHandler($entity_type, $entity_info, $entity);
-  }
+  $factory = EntityTranslationHandlerFactory::getInstance();
+  return empty($entity) ? $factory->getLastHandler($entity_type) : $factory->getHandler($entity_type, $entity);
 }
 
 /**
@@ -1915,7 +1936,7 @@ function entity_translation_current_form_get_handler() {
 }
 
 /**
- * Returns an array of edit form info as defined in hook_translation_info().
+ * Returns an array of edit form info as defined in hook_entity_info().
  *
  * @param $form
  *   The entity edit form.
@@ -2027,7 +2048,7 @@ function entity_translation_entity_uuid_presave(&$entity, $entity_type) {
 }
 
 /**
- * Implement hook_pathauto_alias_alter().
+ * Implements hook_pathauto_alias_alter().
  *
  * When bulk-updating aliases for nodes automatically create a path for every
  * translation.
@@ -2037,17 +2058,20 @@ function entity_translation_pathauto_alias_alter(&$alias, array &$context) {
   $entity_type = $context['module'];
 
   // Ensure that we are dealing with a bundle having entity translation enabled.
-  if ($context['op'] == 'bulkupdate' && !empty($info[$entity_type]['token type']) && !empty($context['data'][$info[$entity_type]['token type']])) {
+  if (in_array($context['op'], array('bulkupdate', 'update')) && !empty($info[$entity_type]['token type']) && !empty($context['data'][$info[$entity_type]['token type']])) {
     $entity = $context['data'][$info[$entity_type]['token type']];
     if (entity_translation_enabled($entity_type, $entity)) {
       $translations = entity_translation_get_handler($entity_type, $entity)->getTranslations();
-      // Only create extra aliases if we are working on the original language to
-      // avoid infinite recursion.
-      if ($context['language'] == $translations->original) {
+      // To avoid infinite recursion, remember the starting language.
+      static $pathauto_start_language;
+      if (!$pathauto_start_language) {
+        $pathauto_start_language = $context['language'];
+      }
+      if ($context['language'] == $pathauto_start_language && $context['language'] != LANGUAGE_NONE) {
         foreach ($translations->data as $language => $translation) {
-          // We already have an alias for the original language, so let's not
+          // We already have an alias for the starting language, so let's not
           // create another one.
-          if ($language == $translations->original) {
+          if ($language == $pathauto_start_language) {
             continue;
           }
           pathauto_create_alias($entity_type, $context['op'], $context['source'], $context['data'], $context['type'], $language);
@@ -2085,3 +2109,11 @@ function entity_translation_entity_save($entity_type, $entity) {
     field_attach_update($entity_type, $entity);
   }
 }
+
+/**
+ * Implements hook_field_attach_prepare_translation_alter().
+ */
+function entity_translation_field_attach_prepare_translation_alter(&$entity, $context) {
+  $handler = entity_translation_get_handler('node', $entity);
+  $handler->setActiveLanguage($context['langcode']);
+}

+ 472 - 0
sites/all/modules/contrib/localisation/entity_translation/entity_translation.taxonomy.inc

@@ -40,6 +40,9 @@ function entity_translation_taxonomy_term_menu_alter(&$items, $backup) {
   $items['taxonomy/term/%taxonomy_term/translate']['access callback'] = 'entity_translation_taxonomy_term_tab_access';
   $items['taxonomy/term/%taxonomy_term/translate']['file'] = 'entity_translation.admin.inc';
   $items['taxonomy/term/%taxonomy_term/translate']['module'] = 'entity_translation';
+
+  // Delete translation callback.
+  $items['taxonomy/term/%taxonomy_term/translate/delete/%entity_translation_language']['access arguments'] = $access_arguments;
 }
 
 /**
@@ -94,3 +97,472 @@ function entity_translation_form_taxonomy_form_vocabulary_submit($form, &$form_s
   variable_set('entity_translation_taxonomy', $info);
 }
 
+/**
+ * Returns a translated label for the specified taxonomy term.
+ *
+ * @param object $term
+ *   A taxonomy term object.
+ * @param string $langcode
+ *   The language the label should be translated in.
+ *
+ * @return string
+ *   The translated taxonomy term label.
+ *
+ * @internal This is supposed to be used only by the ET taxonomy integration
+ *   code, as it might be removed/replaced in any moment of the ET lifecycle.
+ */
+function _entity_translation_taxonomy_label($term, $langcode) {
+  $entity_type = 'taxonomy_term';
+  if (function_exists('title_entity_label')) {
+    $label = title_entity_label($term, $entity_type, $langcode);
+  }
+  else {
+    $label = entity_label($entity_type, $term);
+  }
+  return (string) $label;
+}
+
+/**
+ * Implements entity_translation_form_field_ui_field_edit_WIDGET_TYPE_form_alter().
+ *
+ * {@inheritdoc}
+ */
+function entity_translation_form_field_ui_field_edit_taxonomy_autocomplete_form_alter(&$form, &$form_state) {
+  $key = 'entity_translation_taxonomy_autocomplete_translate';
+  $instance = $form['#instance'];
+  $field_name = $instance['field_name'];
+  $entity_type = $instance['entity_type'];
+  $field = field_info_field($field_name);
+  $translatable = field_is_translatable($entity_type, $field);
+  $bundle = !empty($field['settings']['allowed_values'][0]['vocabulary']) ? $field['settings']['allowed_values'][0]['vocabulary'] : NULL;
+  $access = variable_get('entity_translation_taxonomy_autocomplete', FALSE);
+
+  // Add a checkbox to toggle in-place translation for autocomplete widgets.
+  $form['instance']['settings'][$key] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enable in-place translation of terms'),
+    '#description' => t('Check this option if you wish to use translation forms to perform in-place translation for terms entered in the original language.'),
+    '#default_value' => !$translatable && !empty($form['#instance']['settings'][$key]),
+    '#access' => $access && (!$form_state['field_has_data'] || !$translatable) && entity_translation_enabled('taxonomy_term', $bundle),
+    '#states' => array(
+      'visible' => array(':input[name="field[translatable]"]' => array('checked' => FALSE)),
+    ),
+    '#weight' => -8,
+  );
+}
+
+/**
+ * Checks whether in-place translation is enabled for the autocomplete widget.
+ *
+ * @param array $element
+ *   The widget form element.
+ * @param array $form_state
+ *   The form state array.
+ *
+ * @return bool
+ *   TRUE if in-place translation is enabled, FALSE otherwise.
+ */
+function _entity_translation_taxonomy_autocomplete_translation_enabled($element, $form_state) {
+  $field = field_info_field($element['#field_name']);
+  if (field_is_translatable($element['#entity_type'], $field)) {
+    return FALSE;
+  }
+
+  list($id, , $bundle) = entity_extract_ids($element['#entity_type'], $element['#entity']);
+  if (!$id) {
+    return FALSE;
+  }
+
+  $entity_type = 'taxonomy_term';
+  $parent_handler = entity_translation_get_handler($element['#entity_type'], $element['#entity']);
+  $active_langcode = $parent_handler->getActiveLanguage();
+  $translations = $parent_handler->getTranslations();
+  $entity_langcode = isset($translations->original) ? $translations->original : LANGUAGE_NONE;
+  $instance = field_info_instance($element['#entity_type'], $field['field_name'], $bundle);
+
+  // We need to make sure that we are not dealing with a translation form.
+  // However checking the active language is not enough, because the user may
+  // have changed the entity language.
+  return
+    (isset($form_state['entity_translation']['is_translation']) ?
+      $form_state['entity_translation']['is_translation'] : ($active_langcode != $entity_langcode)) &&
+    !empty($instance['settings']['entity_translation_taxonomy_autocomplete_translate']) &&
+    (user_access('translate any entity') || user_access("translate $entity_type entities"));
+}
+
+/**
+ * Implements hook_field_widget_WIDGET_TYPE_form_alter().
+ *
+ * {@inheritdoc}
+ */
+function entity_translation_field_widget_taxonomy_autocomplete_form_alter(&$element, &$form_state, $context) {
+  // The autocomplete widget is also displayed in the field configuration form,
+  // in which case we do not need to perform any alteration. To preserve BC, by
+  // default we enable our taxonomy autocomplete override only on new sites.
+  if (!isset($element['#entity']) || !variable_get('entity_translation_taxonomy_autocomplete', FALSE)) {
+    return;
+  }
+
+  // We will need to translate term names, if Title is enabled and configured
+  // for this vocabulary.
+  $entity_type = 'taxonomy_term';
+  $field = field_widget_field($element, $form_state);
+  $bundle = !empty($field['settings']['allowed_values'][0]['vocabulary']) ? $field['settings']['allowed_values'][0]['vocabulary'] : NULL;
+  if ($bundle && entity_translation_enabled($entity_type, $bundle)) {
+    $parent_handler = entity_translation_get_handler($element['#entity_type'], $element['#entity']);
+    $langcode = $parent_handler->getActiveLanguage();
+    $terms = array_values(_entity_translation_taxonomy_autocomplete_widget_get_terms($element));
+
+    // If we are using the regular autocomplete behavior also in translation
+    // forms, we need to set our custom callback.
+    if (!_entity_translation_taxonomy_autocomplete_translation_enabled($element, $form_state)) {
+      $element['#autocomplete_path'] = 'entity_translation/' . $entity_type . '/autocomplete/' . $langcode . '/' . $element['#field_name'];
+      $translations = $parent_handler->getTranslations();
+      if (isset($translations->original) && $translations->original != $langcode) {
+        $labels = array();
+        foreach ($terms as $delta => $term) {
+          $labels[] = _entity_translation_taxonomy_label($term, $langcode);
+        }
+        $element['#default_value'] = implode(', ', $labels);
+      }
+    }
+    // Otherwise we just provide the in-place translation widget.
+    else {
+      $element['#type'] = 'fieldset';
+      $element['#description'] = t('Enter one translation for each term');
+      $element['#access'] = (bool) $terms;
+      foreach ($terms as $delta => $term) {
+        $element[$delta] = array(
+          '#type' => 'textfield',
+          '#default_value' => _entity_translation_taxonomy_label($term, $langcode),
+          '#required' => TRUE,
+          '#tid' => $term->tid,
+        );
+      }
+      $element['#process'][] = 'entity_translation_taxonomy_autocomplete_process';
+    }
+
+    // The native term save logic is performed at widget validation level, so we
+    // just replace the validation handler to provide our logic instead.
+    $element['#element_validate'] = array_values(array_diff($element['#element_validate'], array('taxonomy_autocomplete_validate')));
+    $element['#element_validate'][] = 'entity_translation_taxonomy_autocomplete_validate';
+  }
+}
+
+/**
+ * Returns the terms referenced by the taxonomy autocomplete widget field.
+ *
+ * @param array $element
+ *   The taxonomy autocomplete form element.
+ *
+ * @return object[]
+ *   An associative array of taxonomy term object keyed by their identifiers.
+ */
+function _entity_translation_taxonomy_autocomplete_widget_get_terms($element) {
+  $items = isset($element['#entity']->{$element['#field_name']}[$element['#language']]) ?
+    $element['#entity']->{$element['#field_name']}[$element['#language']] : array();
+  $tids = array_map(function ($item) { return $item['tid']; }, $items);
+  return taxonomy_term_load_multiple($tids);
+}
+
+/**
+ * Process callback for the ET taxonomy autocomplete widget.
+ *
+ * {@inheritdoc}
+ */
+function entity_translation_taxonomy_autocomplete_process($element) {
+  // The in-place translation widget makes sense only for untranslatable field,
+  // which may have the "(all languages)" label suffix. In this case it would be
+  // confusing so we need to revert that.
+  $instance = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
+  $element['#title'] = check_plain($instance['label']);
+  return $element;
+}
+
+/**
+ * Entity translation taxonomy autocomplete callback.
+ *
+ * @param string $langcode
+ *   The input language.
+ * @param string $field_name
+ *   The name of the term reference field.
+ * @param string $tags_typed
+ *   (optional) A comma-separated list of term names entered in the
+ *   autocomplete form element. Only the last term is used for autocompletion.
+ *   Defaults to an empty string.
+ *
+ * @see taxonomy_autocomplete()
+ */
+function entity_translation_taxonomy_term_autocomplete($langcode = NULL, $field_name = '', $tags_typed = '') {
+  // If the request has a '/' in the search text, then the menu system will have
+  // split it into multiple arguments, recover the intended $tags_typed.
+  $args = func_get_args();
+  // Shift off the $langcode and $field_name arguments.
+  array_shift($args);
+  array_shift($args);
+  $tags_typed = implode('/', $args);
+
+  // Make sure the field exists and is a taxonomy field.
+  if (!($field = field_info_field($field_name)) || $field['type'] !== 'taxonomy_term_reference') {
+    // Error string. The JavaScript handler will realize this is not JSON and
+    // will display it as debugging information.
+    print t('Taxonomy field @field_name not found.', array('@field_name' => $field_name));
+    exit;
+  }
+
+  // The user enters a comma-separated list of tags. We only autocomplete the
+  // last tag.
+  $tags_typed = drupal_explode_tags($tags_typed);
+  $tag_last = drupal_strtolower(array_pop($tags_typed));
+
+  $term_matches = array();
+  if ($tag_last != '') {
+    if (!isset($langcode) || $langcode == LANGUAGE_NONE) {
+      $langcode = $GLOBALS['language_content']->language;
+    }
+
+    // Part of the criteria for the query come from the field's own settings.
+    $vocabulary = _entity_translation_taxonomy_reference_get_vocabulary($field);
+
+    $entity_type = 'taxonomy_term';
+    $query = new EntityFieldQuery();
+    $query->addTag('taxonomy_term_access');
+    $query->entityCondition('entity_type', $entity_type);
+
+    // If the Title module is enabled and the taxonomy term name is replaced for
+    // the current bundle, we can look for translated names, otherwise we fall
+    // back to the regular name property.
+    if (module_invoke('title', 'field_replacement_enabled', $entity_type, $vocabulary->machine_name, 'name')) {
+      $name_field = 'name_field';
+      $language_group = 0;
+      // Do not select already entered terms.
+      $column = 'value';
+      if (!empty($tags_typed)) {
+        $query->fieldCondition($name_field, $column, $tags_typed, 'NOT IN', NULL, $language_group);
+      }
+      $query->fieldCondition($name_field, $column, $tag_last, 'CONTAINS', NULL, $language_group);
+      $query->fieldLanguageCondition($name_field, array($langcode, LANGUAGE_NONE), NULL, NULL, $language_group);
+    }
+    else {
+      $name_field = 'name';
+      // Do not select already entered terms.
+      if (!empty($tags_typed)) {
+        $query->propertyCondition($name_field, $tags_typed, 'NOT IN');
+      }
+      $query->propertyCondition($name_field, $tag_last, 'CONTAINS');
+    }
+
+    // Select rows that match by term name.
+    $query->propertyCondition('vid', $vocabulary->vid);
+    $query->range(0, 10);
+    $result = $query->execute();
+
+    // Populate the results array.
+    $prefix = count($tags_typed) ? drupal_implode_tags($tags_typed) . ', ' : '';
+    $terms = !empty($result[$entity_type]) ? taxonomy_term_load_multiple(array_keys($result[$entity_type])) : array();
+    foreach ($terms as $tid => $term) {
+      $name = _entity_translation_taxonomy_label($term, $langcode);
+      $n = $name;
+      // Term names containing commas or quotes must be wrapped in quotes.
+      if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) {
+        $n = '"' . str_replace('"', '""', $name) . '"';
+      }
+      $term_matches[$prefix . $n] = check_plain($name);
+    }
+  }
+
+  drupal_json_output($term_matches);
+}
+
+/**
+ * Returns the vocabulary enabled for the specified taxonomy reference field.
+ *
+ * @param array $field
+ *   A field definition.
+ *
+ * @return object|null
+ *   A vocabulary object or NULL if none is found.
+ */
+function _entity_translation_taxonomy_reference_get_vocabulary($field) {
+  $vocabulary = NULL;
+  if (!empty($field['settings']['allowed_values'])) {
+    $vids = array();
+    $vocabularies = taxonomy_vocabulary_get_names();
+    foreach ($field['settings']['allowed_values'] as $tree) {
+      $vids[] = $vocabularies[$tree['vocabulary']]->vid;
+    }
+    $vocabulary = taxonomy_vocabulary_load(reset($vids));
+  }
+  return $vocabulary;
+}
+
+/**
+ * Form element validate handler for taxonomy term autocomplete element.
+ *
+ * {@inheritdoc}
+ *
+ * @see taxonomy_autocomplete_validate()
+ */
+function entity_translation_taxonomy_autocomplete_validate($element, &$form_state) {
+  $value = array();
+  list($id) = entity_extract_ids($element['#entity_type'], $element['#entity']);
+  $is_new = !isset($id);
+
+  // This is the language of the parent entity, that we will be applying to new
+  // terms.
+  $parent_handler = entity_translation_get_handler($element['#entity_type'], $element['#entity']);
+  $langcode = !empty($form_state['entity_translation']['form_langcode']) ?
+    $form_state['entity_translation']['form_langcode'] : $parent_handler->getActiveLanguage();
+
+  // Handle in-place translation.
+  if (_entity_translation_taxonomy_autocomplete_translation_enabled($element, $form_state)) {
+    // The referenced terms cannot change, so we just need to collect their term
+    // identifiers. We also build a map of the corresponding deltas for later
+    // use.
+    $deltas = array();
+    foreach (element_children($element) as $delta) {
+      $tid = $element[$delta]['#tid'];
+      $deltas[$tid] = $delta;
+      $value[$delta]['tid'] = $tid;
+    }
+
+    // Save term translations.
+    $entity_type = 'taxonomy_term';
+    $name_field = 'name_field';
+    $source_langcode = $parent_handler->getSourceLanguage();
+    // This is a validation handler, so we must defer the actual save to the
+    // submit phase.
+    $terms_to_save = &$form_state['entity_translation']['taxonomy_autocomplete'][$element['#entity_type']][$id][$element['#field_name']];
+    foreach (taxonomy_term_load_multiple(array_keys($deltas)) as $term) {
+      // This is also the right context to perform validation.
+      $term_translation = $element[$deltas[$term->tid]]['#value'];
+      if (!$term_translation) {
+        $instance = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
+        drupal_set_message(t('The translations for %field_label cannot be empty.', array('%field_label' => $instance['label'])), 'error', FALSE);
+        continue;
+      }
+
+      $handler = entity_translation_get_handler($entity_type, $term);
+      $translations = $handler->getTranslations();
+      $term_langcode = $handler->getLanguage();
+      $typed_langcode = $term_langcode != LANGUAGE_NONE ? $langcode : $term_langcode;
+
+      // Create a new translation in the active language, if it is missing.
+      if (!isset($translations->data[$typed_langcode]) && $typed_langcode != LANGUAGE_NONE) {
+        $translation = array(
+          'language' => $typed_langcode,
+          'source' => $source_langcode,
+          'uid' => $GLOBALS['user']->uid,
+          'status' => 1,
+          'created' => REQUEST_TIME,
+          'changed' => REQUEST_TIME,
+        );
+        $translation_values = array(
+          $name_field => array($typed_langcode => array(array('value' => $term_translation))),
+        );
+        $handler->setTranslation($translation, $translation_values);
+        $terms_to_save[] = $term;
+      }
+      // Otherwise we just update the existing translation, if it has changed.
+      // If the term is language-neutral, we just update its main value. This is
+      // expected to happen normally, but could when referencing existing terms.
+      elseif ($term_translation != _entity_translation_taxonomy_label($term, $typed_langcode)) {
+        $term->{$name_field}[$typed_langcode][0]['value'] = $term_translation;
+        $terms_to_save[] = $term;
+      }
+    }
+  }
+  // Autocomplete widgets do not send their tids in the form, so we must detect
+  // them here and process them independently.
+  elseif ($tags = $element['#value']) {
+    $entity_type = 'taxonomy_term';
+    $field = field_widget_field($element, $form_state);
+    $vocabulary = _entity_translation_taxonomy_reference_get_vocabulary($field);
+    $typed_tags = drupal_explode_tags($tags);
+
+    // Collect existing terms by name.
+    $existing_terms = array();
+    foreach (_entity_translation_taxonomy_autocomplete_widget_get_terms($element) as $term) {
+      $name = _entity_translation_taxonomy_label($term, $langcode);
+      $existing_terms[$name] = $term;
+    }
+
+    // Select terms that match by the (translated) name.
+    $query = new EntityFieldQuery();
+    $query->addTag('taxonomy_term_access');
+    $query->entityCondition('entity_type', $entity_type);
+    $query->propertyCondition('vid', $vocabulary->vid);
+    if ($langcode != LANGUAGE_NONE && module_invoke('title', 'field_replacement_enabled', $entity_type, $vocabulary->machine_name, 'name')) {
+      $language_group = 0;
+      // Do not select already entered terms.
+      $name_field = 'name_field';
+      $column = 'value';
+      $query->fieldCondition($name_field, $column, $typed_tags, NULL, NULL, $language_group);
+      // When we are creating a new entity, we cannot filter by active language,
+      // as that may have not be applied to the autocomplete query.
+      if (!$is_new) {
+        $query->fieldLanguageCondition($name_field, array($langcode, LANGUAGE_NONE), NULL, NULL, $language_group);
+      }
+    }
+    else {
+      $query->propertyCondition('name', $typed_tags);
+    }
+    $result = $query->execute();
+
+    // When we are creating a new entity, the language used for the autocomplete
+    // query is the current content language, so we should use that to update
+    // the map of existing terms.
+    if (!empty($result[$entity_type])) {
+      $typed_langcode = !$is_new ? $langcode : $GLOBALS['language_content']->language;
+      foreach (taxonomy_term_load_multiple(array_keys($result[$entity_type])) as $term) {
+        $name = _entity_translation_taxonomy_label($term, $typed_langcode);
+        $existing_terms[$name] = $term;
+      }
+    }
+
+    // Now collect the identifiers for the various terms and update the taxonomy
+    // reference field values.
+    foreach ($typed_tags as $delta => $typed_tag) {
+      // See if the term exists in the chosen vocabulary and return the tid.
+      // Otherwise create a new 'autocreate' term for insert/update.
+      if (isset($existing_terms[$typed_tag])) {
+        $term = $existing_terms[$typed_tag];
+      }
+      else {
+        $term = (object) array(
+          'tid' => 'autocreate',
+          'vid' => $vocabulary->vid,
+          'name' => $typed_tag,
+          'vocabulary_machine_name' => $vocabulary->machine_name,
+        );
+        $handler = entity_translation_get_handler($entity_type, $term);
+        $handler->setOriginalLanguage($langcode);
+        $handler->initTranslations();
+      }
+      $value[] = (array) $term;
+    }
+  }
+
+  form_set_value($element, $value, $form_state);
+}
+
+/**
+ * Term-specific implementation of hook_field_attach_submit().
+ */
+function entity_translation_taxonomy_term_field_attach_submit($entity_type, $entity, $form, &$form_state) {
+  // Finally save in-place translations
+  if (!empty($form_state['entity_translation']['taxonomy_autocomplete'])) {
+    foreach ($form_state['entity_translation']['taxonomy_autocomplete'] as $entity_type => $entity_type_data) {
+      foreach ($entity_type_data as $id => $field_name_data) {
+        foreach ($field_name_data as $field_name => $term_data) {
+          if (!is_array($term_data)) {
+            continue;
+          }
+          foreach ($term_data as $term) {
+            entity_translation_entity_save('taxonomy_term', $term);
+          }
+        }
+      }
+    }
+  }
+}

+ 3 - 4
sites/all/modules/contrib/localisation/entity_translation/entity_translation_i18n_menu/entity_translation_i18n_menu.info

@@ -7,9 +7,8 @@ dependencies[] = i18n
 dependencies[] = i18n_menu
 files[] = entity_translation_i18n_menu.test
 
-; Information added by Drupal.org packaging script on 2016-09-28
-version = "7.x-1.0-beta5+15-dev"
+; Information added by Drupal.org packaging script on 2019-01-20
+version = "7.x-1.0+5-dev"
 core = "7.x"
 project = "entity_translation"
-datestamp = "1475057941"
-
+datestamp = "1548022384"

+ 1 - 1
sites/all/modules/contrib/localisation/entity_translation/entity_translation_i18n_menu/entity_translation_i18n_menu.module

@@ -164,7 +164,7 @@ function entity_translation_i18n_menu_form(&$form, &$form_state) {
       $default = isset($source_menu['language']) && $source_menu['language'] != LANGUAGE_NONE;
       $languages = language_list();
       $handler = entity_translation_entity_form_get_handler($form, $form_state);
-      $langcode = $handler->getFormLanguage();
+      $langcode = $handler->getActiveLanguage();
       $language_name = isset($languages[$langcode]) ? t($languages[$langcode]->name) : t('current');
 
       $form['menu']['#multilingual'] = TRUE;

+ 24 - 7
sites/all/modules/contrib/localisation/entity_translation/entity_translation_i18n_menu/entity_translation_i18n_menu.test

@@ -125,23 +125,36 @@ class EntityTranslationMenuTranslationTestCase extends EntityTranslationTestCase
     $this->assertText($link_title, 'New menu link title found: ' . $link_title);
   }
 
+  /**
+   * Asserts a link with a given label and title is found in the page.
+   */
+  function assertLinkWithTitleAttribute($label, $title) {
+    $links = $this->xpath('//a[normalize-space(text())=:label and normalize-space(@title)=:title]', array(
+      ':label' => $label,
+      ':title' => $title,
+    ));
+    $this->assert(isset($links[0]));
+  }
+
   /**
    * Test if menu localization works.
    */
   function testMenuLocalization() {
     // Create Basic page in English.
     $link_title_en = $this->randomName();
-    $node = $this->createPage($link_title_en, NULL, 'en');
+    $link_description_en = $this->randomName() . ' & htmlentity';
+    $node = $this->createPage($link_title_en, $link_description_en, 'en');
 
     // Submit translation in Spanish.
     $link_title_es = $this->randomName();
-    $node_translation = $this->createTranslation($node, $link_title_es, NULL, 'es');
+    $link_description_es = $this->randomName() . ' & htmlentity';
+    $node_translation = $this->createTranslation($node, $link_title_es, $link_description_es, 'es');
 
     // Check menu links in both languages.
     $this->get('en', '<front>');
-    $this->assertText($link_title_en);
+    $this->assertLinkWithTitleAttribute($link_title_en, $link_description_en);
     $this->get('es', '<front>');
-    $this->assertText($link_title_es);
+    $this->assertLinkWithTitleAttribute($link_title_es, $link_description_es);
 
     // Edit English menu link.
     $link_title_en2 = $this->randomName();
@@ -149,15 +162,19 @@ class EntityTranslationMenuTranslationTestCase extends EntityTranslationTestCase
 
     // Check that Spanish menu link has not changed.
     $this->get('es', '<front>');
-    $this->assertText($link_title_es);
+    $this->assertLinkWithTitleAttribute($link_title_es, $link_description_es);
 
     // Edit Spanish menu link.
     $link_title_es2 = $this->randomName();
     $this->editPage($node, $link_title_es, $link_title_es2, 'es');
 
-    // Check that English menu link has not changed.
+    // Check that English menu link has changed.
     $this->get('en', '<front>');
-    $this->assertText($link_title_en2);
+    $this->assertLinkWithTitleAttribute($link_title_en2, $link_description_en);
+
+    // Check that Spanish menu link has changed.
+    $this->get('es', '<front>');
+    $this->assertLinkWithTitleAttribute($link_title_es2, $link_description_es);
 
     // Delete Spanish translation and check that the respective menu item has
     // been deleted as well.

+ 7 - 3
sites/all/modules/contrib/localisation/entity_translation/entity_translation_upgrade/entity_translation_upgrade.admin.inc

@@ -34,8 +34,8 @@ function entity_translation_upgrade_start($types) {
  */
 function entity_translation_upgrade_end($success, $results, $operations, $elapsed) {
   if (!empty($results)) {
-    $message = format_plural($results, '1 node translation successfully upgraded.', '@count node translations successfully upgraded.');
-    watchdog('entity translation upgrade', '@count node translations successfully upgraded.', array('@count' => $results), WATCHDOG_INFO);
+    $message = format_plural($results['total'], '1 node translation successfully upgraded.', '@count node translations successfully upgraded.');
+    watchdog('entity translation upgrade', '@count node translations successfully upgraded.', array('@count' => $results['total']), WATCHDOG_INFO);
   }
   else {
     $message = t('No node translation available for the upgrade.');
@@ -91,6 +91,10 @@ function entity_translation_upgrade_do($types, &$context) {
       $node = $nodes[$nid];
       $original = $nodes[$node->tnid];
       $handler = entity_translation_get_handler('node', $original);
+      // Instantiate the data and original properties of the translations.
+      if (empty($handler->getTranslations()->data)) {
+        $handler->initTranslations();
+      }
 
       if (!isset($instances[$node->type])) {
         $instances[$node->type] = field_info_instances('node', $node->type);
@@ -185,7 +189,7 @@ function entity_translation_upgrade_do($types, &$context) {
     $context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total'];
 
     if ($context['finished'] >= 1) {
-      $context['results'] = $context['sandbox']['total'];
+      $context['results']['total'] = $context['sandbox']['total'];
     }
   }
 }

+ 117 - 0
sites/all/modules/contrib/localisation/entity_translation/entity_translation_upgrade/entity_translation_upgrade.drush.inc

@@ -0,0 +1,117 @@
+<?php
+
+/**
+ * Implements hook_drush_command().
+ */
+function entity_translation_upgrade_drush_command() {
+  $items = array();
+
+  $items['entity-translation-upgrade'] = array(
+    'description' => "Upgrades all nodes of the specified content type from Content Translation to Entity Translation.",
+    'arguments' => array(
+      'content_type' => 'Content type of nodes to be upgraded.',
+    ),
+    'examples' => array(
+      'drush entity-translation-upgrade article' => 'Upgrades all nodes of content type "article" from Content Translation to Entity Translation.',
+    ),
+    'aliases' => array('etu'),
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_drush_help().
+ *
+ * @param
+ *   A string with the help section
+ *
+ * @return
+ *   A string with the help text for the entity-translation-upgrade command
+ */
+function entity_translation_upgrade_drush_help($section) {
+  switch ($section) {
+    case 'drush:entity-translation-upgrade':
+      return dt("Brief help for Drush command entity-translation-upgrade.");
+
+    case 'meta:entity_translation_upgrade:title':
+      return dt("Entity Translation Upgrade commands");
+
+    case 'meta:entity_translation_upgrade:summary':
+      return dt("Upgrading nodes to Entity Translation.");
+  }
+}
+
+/**
+ * Implements drush_hook_COMMAND().
+ *
+ * @param
+ *   The content type of which the nodes shall be upgraded
+ *
+ * Runs the batch upgrading nodes of the specified content_type to Entity
+ * Translation. Lets user choose content type from a list, if argument has
+ * not been provided.
+ */
+function drush_entity_translation_upgrade($content_type = "") {
+  // Get all installed content types.
+  $available_types = array();
+  $available_types_chose = array();
+  $available_types_str = '';
+  foreach (node_type_get_types() as $type) {
+    $available_types[$type->type] = $type->type;
+    $available_types_chose[$type->type] = $type->name;
+    if (strlen($available_types_str) > 0) {
+      $available_types_str .= ', ';
+    }
+    $available_types_str .= $type->type;
+  }
+
+  // If argument content_type is empty, prompt user for content type.
+  if (!$content_type) {
+    $content_type = drush_choice($available_types_chose, dt('Choose the content type of the nodes to be upgraded to Entity Translation:'));
+  }
+
+  // Do content type argument checks.
+  if (!$content_type) {
+    return TRUE;
+  }
+  if (strlen($available_types_str) == 0) {
+    return drush_set_error(dt('Entity Translation Upgrade cannot run as no content type has been installed.'));
+  }
+  if (!in_array($content_type, $available_types)) {
+    return drush_set_error(dt('"@content_type" is not a valid content type machine name. Please use one of these installed content types as argument: @available_types_str.', array('@content_type' => $content_type, '@available_types_str' => $available_types_str)));
+  }
+
+  // Start batch to upgrade nodes of the specified content type.
+  $types = array($content_type => $content_type);
+  $batch = array(
+    'operations' => array(
+      array('entity_translation_upgrade_do', array($types)),
+      array('entity_translation_upgrade_complete', array()),
+    ),
+    'finished' => 'entity_translation_upgrade_drush_end',
+    'file' => drupal_get_path('module', 'entity_translation_upgrade') . '/entity_translation_upgrade.admin.inc',
+    'progressive' => FALSE,
+  );
+  batch_set($batch);
+  drush_backend_batch_process();
+}
+
+/**
+ * This is the 'finished' batch callback, drush version.
+ */
+function entity_translation_upgrade_drush_end($success, $results, $operations, $elapsed) {
+  // Print result messages.
+  if (!empty($results)) {
+    $message = format_plural($results['total'], '1 node translation successfully upgraded.', '@count node translations successfully upgraded.');
+    $severity = 'ok';
+    watchdog('Entity Translation upgrade', '@count node translations successfully upgraded.', array('@count' => $results['total']), WATCHDOG_INFO);
+  }
+  else {
+    $message = t('No node translation available for the upgrade.');
+    $severity = 'warning';
+  }
+
+  drush_log($message, $severity);
+}

+ 4 - 4
sites/all/modules/contrib/localisation/entity_translation/entity_translation_upgrade/entity_translation_upgrade.info

@@ -3,10 +3,10 @@ description = Provides an upgrade path from node-based translation to field-base
 package = Multilingual - Entity Translation
 core = 7.x
 dependencies[] = entity_translation
+files[] = entity_translation_upgrade.test
 
-; Information added by Drupal.org packaging script on 2016-09-28
-version = "7.x-1.0-beta5+15-dev"
+; Information added by Drupal.org packaging script on 2019-01-20
+version = "7.x-1.0+5-dev"
 core = "7.x"
 project = "entity_translation"
-datestamp = "1475057941"
-
+datestamp = "1548022384"

+ 163 - 0
sites/all/modules/contrib/localisation/entity_translation/entity_translation_upgrade/entity_translation_upgrade.test

@@ -0,0 +1,163 @@
+<?php
+/**
+ * @file
+ * Tests for Entity Translation module.
+ */
+
+/**
+ * Tests for the upgrade translation process.
+ */
+class EntityTranslationUpgradeTestCase extends EntityTranslationTestCase {
+
+  /**
+   * Return the test information.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Translation upgrade',
+      'description' => 'Tests for the upgrade from Content Translation to Entity Translation.',
+      'group' => 'Entity translation',
+      'dependencies' => array(),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('locale', 'translation', 'translation_test', 'entity_translation', 'entity_translation_upgrade');
+    $this->getAdminUser(array(
+      'toggle field translatability',
+      'administer entity translation',
+    ));
+    $this->getTranslatorUser(array(
+      'translate content',
+    ));
+    $this->login($this->getAdminUser());
+    $this->addLanguage('en');
+    $this->addLanguage('es');
+    $this->configureContentTypeForContentTranslation();
+    $this->enableUrlLanguageDetection();
+    $this->login($this->getTranslatorUser());
+  }
+
+  /**
+   * Configure the "Basic page" content type for entity translation tests.
+   */
+  public function configureContentTypeForContentTranslation() {
+    // Configure the "Basic page" content type to use multilingual support with
+    // content translation.
+    $edit = array();
+    $edit['language_content_type'] = TRANSLATION_ENABLED;
+    $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
+    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.'));
+
+  }
+
+  /**
+   * Toggle body field's translatability.
+   */
+  public function makeBodyFieldTranslatable() {
+    $edit = array();
+    $this->drupalGet('admin/structure/types/manage/page/fields/body');
+    $this->clickLink('Enable translation');
+    $this->drupalPost(NULL, array(), t('Confirm'));
+    $this->assertRaw(t('Data successfully processed.'), t('Body field have been made translatable.'));
+  }
+
+  /**
+   * @see TranslationTestCase::createPage
+   */
+  function createContentTranslationPage($title, $body, $language = NULL) {
+    $edit = array();
+    $langcode = LANGUAGE_NONE;
+    $edit["title"] = $title;
+    $edit["body[$langcode][0][value]"] = $body;
+    if (!empty($language)) {
+      $edit['language'] = $language;
+    }
+    $this->drupalPost('node/add/page', $edit, t('Save'));
+    $this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), 'Basic page created.');
+
+    // Check to make sure the node was created.
+    $node = $this->drupalGetNodeByTitle($title);
+    $this->assertTrue($node, 'Node found in database.');
+
+    return $node;
+  }
+
+  /**
+   * @see TranslationTestCase::createTranslation
+   */
+  function createContentTranslationTranslation($node, $title, $body, $language) {
+    $this->drupalGet('node/add/page', array('query' => array('translation' => $node->nid, 'target' => $language)));
+
+    $langcode = LANGUAGE_NONE;
+    $body_key = "body[$langcode][0][value]";
+    $this->assertFieldByXPath('//input[@id="edit-title"]', $node->title, "Original title value correctly populated.");
+    $this->assertFieldByXPath("//textarea[@name='$body_key']", $node->body[LANGUAGE_NONE][0]['value'], "Original body value correctly populated.");
+
+    $edit = array();
+    $edit["title"] = $title;
+    $edit[$body_key] = $body;
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), 'Translation created.');
+
+    // Check to make sure that translation was successful.
+    $translation = $this->drupalGetNodeByTitle($title);
+    $this->assertTrue($translation, 'Node found in database.');
+    $this->assertTrue($translation->tnid == $node->nid, 'Translation set id correctly stored.');
+
+    return $translation;
+  }
+
+  /**
+   * Tests copying of source node's body value in the add translation form page.
+   */
+  public function testUpgradeContentToEntityTranslation() {
+    // Create Basic page in English.
+    $node_title = $this->randomName();
+    $node_body = $this->randomName();
+    $node = $this->createContentTranslationPage($node_title, $node_body, 'en');
+
+    // Submit translation in Spanish.
+    $this->drupalGet('node/' . $node->nid . '/translate');
+    $node_translation_title = $this->randomName();
+    $node_translation_body = $this->randomName();
+    $node_translation = $this->createContentTranslationTranslation($node, $node_translation_title, $node_translation_body, 'es');
+
+    // Make Body field translatable before we run the upgrade.
+    $this->login($this->getAdminUser());
+    $this->makeBodyFieldTranslatable();
+
+    // Run the upgrade for all Page nodes.
+    $edit = array(
+      'types[page]' => 'page',
+    );
+    $this->drupalPost('admin/config/regional/entity_translation', $edit, t('Upgrade'));
+
+    // Switch to our translator user.
+    $this->login($this->getTranslatorUser());
+
+    // Check that the unpublished target node triggers a redirect.
+    $this->drupalGet('node/' . $node_translation->nid);
+    $headers = $this->drupalGetHeaders(TRUE);
+    list(, $status) = explode(' ', $headers[0][':status'], 3);
+    $this->assertEqual($status, 301, 'Expected response code was sent.');
+    $languages = language_list();
+    $this->assertEqual($this->getUrl(), url('node/' . $node->nid, array('absolute' => TRUE, 'language' => $languages['es'])), 'entity_translation_upgrade_redirect() redirected to expected URL.');
+
+    // Check that the body is displayed when the active language is English.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertRaw($node_body, t('Body field displayed correctly in the source language.'));
+
+    // Check that the translated body is displayed when the active language is Spanish.
+    $this->drupalGet('es/node/' . $node->nid);
+    $this->assertRaw($node_translation_body, t('Body field displayed correctly in the target language.'));
+
+    // Check that the edit forms are initialized correctly in the target language.
+    $this->drupalGet('node/' . $node->nid . '/edit');
+    $this->assertFieldByXPath("//textarea[@name='body[en][0][value]']", $node_body, "Body field correctly instantiated with the value of the source language.");
+    $this->drupalGet('es/node/' . $node->nid . '/edit');
+    $this->assertFieldByXPath("//textarea[@name='body[es][0][value]']", $node_translation_body, "Body field correctly instantiated with the value of the target language.");
+
+  }
+
+}

+ 136 - 52
sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler.inc

@@ -98,6 +98,62 @@ interface EntityTranslationHandlerInterface {
    */
   public function getLanguage();
 
+  /**
+   * Sets the active language.
+   *
+   * This is the language that determines which translation should be considered
+   * "active" for the wrapped entity. The "Entity Translation" module uses this
+   * information to implement the UI-based translation workflow. Other modules
+   * can rely on it to implement their own entity translation-related logic.
+   *
+   * This will affect which language is returned by the core "entity_language()"
+   * function.
+   *
+   * @param string $langcode
+   *   The active language code.
+   *
+   * @see entity_language()
+   * @see entity_translation_language()
+   * @see ::getActiveLanguage()
+   */
+  public function setActiveLanguage($langcode);
+
+  /**
+   * Returns the active language.
+   *
+   * @return string
+   *   The active language for the wrapped entity.
+   *
+   * @see ::setActiveLanguage()
+   */
+  public function getActiveLanguage();
+
+  /**
+   * Sets the active form language.
+   *
+   * @param string $langcode
+   *   The active form language code.
+   *
+   * @deprecated in 7.x-1.0-beta6, will be removed before 7.x-1.0. Use
+   *   ::setActiveLanguage() instead.
+   *
+   * @see ::setActiveLanguage()
+   */
+  public function setFormLanguage($langcode);
+
+  /**
+   * Retrieves the active form language.
+   *
+   * @return string
+   *   The active form language code.
+   *
+   * @deprecated in 7.x-1.0-beta6, will be removed before 7.x-1.0. Use
+   *   ::getActiveLanguage() instead.
+   *
+   * @see ::getActiveLanguage()
+   */
+  public function getFormLanguage();
+
   /**
    * Returns the translation object key for the wrapped entity type.
    */
@@ -109,7 +165,7 @@ interface EntityTranslationHandlerInterface {
   public function getDefaultLanguage();
 
   /**
-   * Sets the language of the orginal translation.
+   * Sets the language of the original translation.
    *
    * @param $langcode
    *   The language code of the original content values.
@@ -272,16 +328,6 @@ interface EntityTranslationHandlerInterface {
    */
   public function isAliasEnabled();
 
-  /**
-   * Sets the active form language.
-   */
-  public function setFormLanguage($langcode);
-
-  /**
-   * Retrieves the active form language.
-   */
-  public function getFormLanguage();
-
   /**
    * Sets the source language for the translation being created.
    */
@@ -364,19 +410,19 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
    */
   protected $children = array();
 
-  private $entityForm;
-  private $translating;
-  private $outdated;
-  private $formLanguage;
-  private $sourceLanguage;
+  protected $entityForm;
+  protected $translating;
+  protected $outdated;
+  protected $activeLanguage;
+  protected $sourceLanguage;
 
-  private $pathScheme;
-  private $pathWildcard;
-  private $basePath;
-  private $editPath;
-  private $translatePath;
-  private $viewPath;
-  private $routerMap;
+  protected $pathScheme;
+  protected $pathWildcard;
+  protected $basePath;
+  protected $editPath;
+  protected $translatePath;
+  protected $viewPath;
+  protected $routerMap;
 
   /**
    * Initializes an instance of the translation handler.
@@ -396,7 +442,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
     $this->entityForm = FALSE;
     $this->translating = FALSE;
     $this->outdated = FALSE;
-    $this->formLanguage = FALSE;
+    $this->activeLanguage = FALSE;
     $this->sourceLanguage = FALSE;
     $this->pathScheme = 'default';
     $this->routerMap = array();
@@ -481,7 +527,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
   public function addChild($entity_type, $entity) {
     if (!empty($this->factory)) {
       $handler = $this->factory->getHandler($entity_type, $entity);
-      $handler->setFormLanguage($this->getFormLanguage());
+      $handler->setActiveLanguage($this->getActiveLanguage());
       $handler->setSourceLanguage($this->getSourceLanguage());
       // Avoid registering more than one child handler for each entity.
       $hid = $this->factory->getHandlerId($entity_type, $entity);
@@ -632,6 +678,12 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
       throw new Exception('Invalid translation language');
     }
 
+    // $args will be used later on in a call to notifyChildren(). We need
+    // to call func_get_args() before any modifications to the function's
+    // arguments take place. This is due to changes in PHP 7.0 and onwards.
+    // @see http://php.net/manual/en/function.func-get-args.php#refsect1-function.func-get-args-notes
+    $args = func_get_args();
+
     $translations = $this->getTranslations();
     $langcode = $translation['language'];
 
@@ -658,13 +710,12 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
       foreach (field_info_instances($this->entityType, $this->bundle) as $instance) {
         $field_name = $instance['field_name'];
         $field = field_info_field($field_name);
-        if ($field['translatable'] && isset($values[$field_name])) {
+        if ($field['translatable'] && isset($values[$field_name][$langcode])) {
           $this->entity->{$field_name}[$langcode] = $values[$field_name][$langcode];
         }
       }
     }
 
-    $args = func_get_args();
     $this->notifyChildren(__FUNCTION__, $args);
   }
 
@@ -803,6 +854,55 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function setActiveLanguage($langcode) {
+    // @todo To fully preserve BC, we proxy the call to the deprecated
+    //   ::setFormLanguage method. This will keep things working even when it
+    //   has been overridden. Inline its implementation here upon removal.
+    $this->setFormLanguage($langcode);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getActiveLanguage() {
+    // @todo To fully preserve BC, we proxy the call to the deprecated
+    //   ::getFormLanguage method. This will keep things working even when it
+    //   has been overridden. Inline its implementation here upon removal.
+    return $this->getFormLanguage();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setFormLanguage($langcode) {
+    $this->activeLanguage = $langcode;
+    $args = func_get_args();
+    $this->notifyChildren(__FUNCTION__, $args);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormLanguage() {
+    if (!empty($this->activeLanguage)) {
+      return $this->activeLanguage;
+    }
+    // For new entities the active language should match the default language.
+    // The language stored with the entity itself (for example, $node->language)
+    // may not be reliable since the function creating the entity object will
+    // not know which language "Entity Translation" is configured to create the
+    // entity in.
+    elseif ($this->isNewEntity()) {
+      return $this->getDefaultLanguage();
+    }
+    else {
+      return $this->getLanguage();
+    }
+  }
+
   /**
    * @see EntityTranslationHandlerInterface::getLanguageKey()
    */
@@ -952,7 +1052,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
     if ($outdated) {
       $translations = $this->getTranslations();
       foreach ($translations->data as $langcode => &$translation) {
-        if ($langcode != $this->getFormLanguage()) {
+        if ($langcode != $this->getActiveLanguage()) {
           $translation['translate'] = 1;
         }
       }
@@ -1097,7 +1197,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
    */
   public function getSharedFieldsAccess() {
     $settings = entity_translation_settings($this->entityType, $this->bundle);
-    return ($settings['shared_fields_original_only'] == FALSE || $this->getLanguage() == $this->getFormLanguage()) &&
+    return ($settings['shared_fields_original_only'] == FALSE || $this->getLanguage() == $this->getActiveLanguage()) &&
       (!entity_translation_workflow_enabled() || user_access('edit translation shared fields') || user_access("edit {$this->entityType} translation shared fields"));
   }
 
@@ -1108,22 +1208,6 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
     return !empty($this->entityInfo['translation']['entity_translation']['alias']);
   }
 
-  /**
-   * @see EntityTranslationHandlerInterface::setFormLanguage()
-   */
-  public function setFormLanguage($langcode) {
-    $this->formLanguage = $langcode;
-    $args = func_get_args();
-    $this->notifyChildren(__FUNCTION__, $args);
-  }
-
-  /**
-   * @see EntityTranslationHandlerInterface::getFormLanguage()
-   */
-  public function getFormLanguage() {
-    return !empty($this->formLanguage) ? $this->formLanguage : $this->getLanguage();
-  }
-
   /**
    * @see EntityTranslationHandlerInterface::setSourceLanguage()
    */
@@ -1161,7 +1245,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
   public function entityForm(&$form, &$form_state) {
     $this->entityForm = TRUE;
     $translations = $this->getTranslations();
-    $form_langcode = $this->getFormLanguage();
+    $form_langcode = $this->getActiveLanguage();
     $langcode = $this->getLanguage();
     $is_translation = $this->isTranslationForm();
     $new_translation = !isset($translations->data[$form_langcode]);
@@ -1461,7 +1545,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
     $language_key = $this->getLanguageKey();
     if (isset($form_state['values'][$language_key]) && !$this->isTranslationForm()) {
       $langcode = $form_state['values'][$language_key];
-      $this->setFormLanguage($langcode);
+      $this->setActiveLanguage($langcode);
     }
   }
 
@@ -1474,7 +1558,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
     }
 
     $this->updateFormLanguage($form_state);
-    $form_langcode = $this->getFormLanguage();
+    $form_langcode = $this->getActiveLanguage();
 
     foreach (field_info_instances($this->entityType, $this->bundle) as $instance) {
       $field_name = $instance['field_name'];
@@ -1496,7 +1580,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
    * @see EntityTranslationHandlerInterface::entityFormSubmit()
    */
   public function entityFormSubmit($form, &$form_state) {
-    $form_langcode = $this->getFormLanguage();
+    $form_langcode = $this->getActiveLanguage();
     $translations = $this->getTranslations();
     $is_translation = !empty($form_state['entity_translation']['is_translation']);
     $new_translation = !isset($translations->data[$form_langcode]);
@@ -1551,7 +1635,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
 
     if (count($translations->data) > 0) {
       $languages = language_list();
-      $form_langcode = $this->getFormLanguage();
+      $form_langcode = $this->getActiveLanguage();
       $language_tabs = array();
 
       if ($this->getSourceLanguage()) {
@@ -1624,7 +1708,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
    * Returns TRUE if an entity translation is being edited.
    */
   protected function isTranslationForm() {
-    return !$this->isNewEntity() && $this->getFormLanguage() != $this->getLanguage();
+    return !$this->isNewEntity() && $this->getActiveLanguage() != $this->getLanguage();
   }
 
   /**
@@ -1653,7 +1737,7 @@ class EntityTranslationDefaultHandler implements EntityTranslationHandlerInterfa
    *
    * @throws Exception
    */
-  private function initPathVariables() {
+  protected function initPathVariables() {
     if (empty($this->pathScheme) || !isset($this->entityInfo['translation']['entity_translation']['path schemes'][$this->pathScheme])) {
       throw new Exception("Cannot initialize entity translation path variables (invalid path scheme).");
     }

+ 1 - 4
sites/all/modules/contrib/localisation/entity_translation/includes/translation.handler_factory.inc

@@ -87,10 +87,7 @@ class EntityTranslationHandlerFactory {
     if (!isset($this->handlers[$entity_type][$id])) {
       $entity_info = entity_get_info($entity_type);
       $class = $entity_info['translation']['entity_translation']['class'];
-      // @todo Remove the fourth parameter once 3rd-party translation handlers
-      //   have been fixed and no longer require the deprecated entity_id
-      //   parameter.
-      $handler = new $class($entity_type, $entity_info, $entity, NULL);
+      $handler = new $class($entity_type, $entity_info, $entity);
       $handler->setFactory($this);
       $this->handlers[$entity_type][$id] = $handler;
     }

+ 820 - 3
sites/all/modules/contrib/localisation/entity_translation/tests/entity_translation.test

@@ -14,6 +14,9 @@ class EntityTranslationTestCase extends DrupalWebTestCase {
   protected $admin_user;
   protected $translator_user;
 
+  /**
+   * {@inheritdoc}
+   */
   function setUp() {
     $args = func_get_args();
     call_user_func_array(array('parent', 'setUp'), $args);
@@ -133,6 +136,19 @@ class EntityTranslationTestCase extends DrupalWebTestCase {
     }
   }
 
+  /**
+   * Disable a language which is in the language list.
+   *
+   * @param string $langcode
+   *   The code of the language to disable, which must exist.
+   */
+  function disableLanguage($langcode) {
+    $edit = array(
+      'enabled[' . $langcode . ']' => FALSE,
+    );
+    $this->drupalPost('admin/config/regional/language', $edit, 'Save configuration');
+  }
+
   /**
    * Install a specified language if it has not been already, otherwise make sure that the language is enabled.
    *
@@ -190,7 +206,7 @@ class EntityTranslationTestCase extends DrupalWebTestCase {
 
     // Check if the setting works.
     $this->drupalGet('node/add/page');
-    $this->assertFieldById('edit-body-und-add-more', t('Add another item'), t('Add another item button found.'));
+    $this->assertFieldById('edit-body-en-add-more', t('Add another item'), t('Add another item button found.'));
   }
 
   /**
@@ -205,9 +221,8 @@ class EntityTranslationTestCase extends DrupalWebTestCase {
    */
   function createPage($title, $body, $langcode) {
     $edit = array();
-    $language_none = LANGUAGE_NONE;
     $edit["title"] = $title;
-    $edit["body[$language_none][0][value]"] = $body;
+    $edit["body[$langcode][0][value]"] = $body;
     $edit['language'] = $langcode;
     $this->drupalPost('node/add/page', $edit, t('Save'));
     $this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), t('Basic page created.'));
@@ -270,10 +285,27 @@ class EntityTranslationTranslationTestCase extends EntityTranslationTestCase {
     $this->login($this->getAdminUser());
     $this->addLanguage('en');
     $this->addLanguage('es');
+    $this->addLanguage('fr');
+    $this->disableLanguage('fr');
     $this->configureContentType();
     $this->login($this->getTranslatorUser());
   }
 
+  /**
+   * Test disabled languages.
+   *
+   * Make sure disabled languages are not accessible in the language list when
+   * the option entity_translation_languages_enabled is enabled.
+   */
+  function testDisabledLanguages() {
+    $this->drupalGet('node/add/page');
+    $this->assertRaw('value="fr"', 'French is available even if the language is disabled');
+
+    variable_set('entity_translation_languages_enabled', TRUE);
+    $this->drupalGet('node/add/page');
+    $this->assertNoRaw('value="fr"', 'French is not available when the language is disabled and the option entity_translation_languages_enabled is enabled.');
+  }
+
   /**
    * Test if field based translation works.
    *
@@ -525,3 +557,788 @@ class EntityTranslationHookTestCase extends EntityTranslationTestCase {
     return $info;
   }
 }
+
+/**
+ * Tests that entity translation handler hierarchy works properly.
+ */
+class EntityTranslationHierarchyTestCase extends EntityTranslationTestCase {
+
+  /**
+   * Return the test information.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity translation hierarchy',
+      'description' => 'Tests that entity translation handler hierarchy works properly.',
+      'group' => 'Entity translation',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp() {
+    parent::setUp('locale', 'entity_translation');
+  }
+
+  /**
+   * Tests the handler hierarchy.
+   */
+  public function testHierarchy() {
+    $entity_type = 'node';
+    $node = $this->drupalCreateNode();
+    $factory = EntityTranslationHandlerFactory::getInstance();
+    $handler = $factory->getHandler($entity_type, $node);
+
+    $children = array();
+    foreach (range(0, 4) as $index) {
+      $children[$index] = $this->drupalCreateNode();
+      $handler->addChild($entity_type, $children[$index]);
+    }
+
+    $langcode = 'it';
+    $handler->setActiveLanguage($langcode);
+    foreach ($children as $child) {
+      $child_handler = $factory->getHandler($entity_type, $child);
+      $this->assertEqual($child_handler->getActiveLanguage(), $langcode);
+    }
+
+    $rm_index = mt_rand(0, count($children) - 1);
+    $handler->removeChild($entity_type, $children[$rm_index]);
+
+    $langcode = 'fr';
+    $handler->setActiveLanguage($langcode);
+    foreach ($children as $index => $child) {
+      $child_handler = $factory->getHandler($entity_type, $child);
+      $this->assertEqual($child_handler->getActiveLanguage() == $langcode, $index != $rm_index);
+    }
+
+    // @todo Test the other properties.
+  }
+
+}
+
+/**
+ * Basic tests for nodes using both content and entity translation.
+ */
+class EntityTranslationContentTranslationTestCase extends EntityTranslationTestCase {
+
+  /**
+   * Return the test information.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Content and entity translation',
+      'description' => 'Basic tests for nodes using both content and entity translatio.',
+      'group' => 'Entity translation',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    // Activate modules and unset users.
+    parent::setUp('locale', 'translation', 'translation_test', 'entity_translation');
+    // Create admin and translator users with one extra permission,
+    // namely the 'translate content' permission.
+    // These getters works also as setters.
+    $this->getAdminUser(array(
+      'translate content',
+    ));
+    $this->getTranslatorUser(array(
+      'translate content',
+    ));
+    $this->login($this->getAdminUser());
+    $this->addLanguage('en');
+    $this->addLanguage('es');
+    $this->enableUrlLanguageDetection();
+    $this->configureContentType();
+    $this->login($this->getTranslatorUser());
+  }
+
+  /**
+   * Configure the "Basic page" content type for entity translation tests.
+   */
+  public function configureContentType() {
+    // Configure the "Basic page" content type to use multilingual support with
+    // content translation.
+    $edit = array();
+    $edit['language_content_type'] = TRANSLATION_ENABLED;
+    $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
+    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.'));
+
+    // Toggle body field's translatability.
+    $edit = array();
+    $edit['field[translatable]'] = 1;
+    $this->drupalPost('admin/structure/types/manage/page/fields/body', $edit, t('Save settings'));
+    $this->assertRaw(t('Saved %field configuration.', array('%field' => 'Body')), t('Body field settings have been updated.'));
+  }
+
+  /**
+   * @see TranslationTestCase::createPage()
+   */
+  function createPage($title, $body, $language = NULL) {
+    $edit = array();
+    $langcode = LANGUAGE_NONE;
+    $edit["title"] = $title;
+    $edit["body[$langcode][0][value]"] = $body;
+    if (!empty($language)) {
+      $edit['language'] = $language;
+    }
+    $this->drupalPost('node/add/page', $edit, t('Save'));
+    $this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), 'Basic page created.');
+
+    // Check to make sure the node was created.
+    $node = $this->drupalGetNodeByTitle($title);
+    $this->assertTrue($node, 'Node found in database.');
+
+    return $node;
+  }
+
+  /**
+   * Tests copying of source node's body value in the add translation form page.
+   */
+  public function testCopyFieldsUsingContentTranslation() {
+    // Create Basic page in English.
+    $node_title = $this->randomName();
+    $node_body = $this->randomName();
+    $node = $this->createPage($node_title, $node_body, 'en');
+
+    // Check that the edit form correctly copies over the field's values from
+    // the source node.
+    $target_language = 'es';
+    $this->drupalGet('node/add/page', array('query' => array('translation' => $node->nid, 'target' => $target_language)));
+    $body_key = "body[${target_language}][0][value]";
+    $this->assertFieldByXPath("//textarea[@name='$body_key']", $node_body, "Body field correctly instantiated with the value of the source language.");
+  }
+
+}
+
+/**
+ * Tests for integration of Entity Translation with other modules.
+ */
+class EntityTranslationIntegrationTestCase extends EntityTranslationTestCase {
+
+  /**
+   * Return the test information.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Integration with other modules',
+      'description' => 'Tests for integration of Entity Translation with other modules.',
+      'group' => 'Entity translation',
+      // We need to add this to the test_dependencies[] as well.
+      'dependencies' => array('pathauto'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    // Activate modules.
+    parent::setUp('locale', 'entity_translation');
+    // Create admin and translator users with one extra permission,
+    // namely the 'administer content' permission for the admin, to
+    // allow enabling the pathauto module during testing. The
+    // Translator user needs to be able to create url aliases.
+    $this->getAdminUser(array(
+      'administer modules',
+    ));
+    $this->getTranslatorUser(array(
+      'create url aliases',
+    ));
+    $this->login($this->getAdminUser());
+    $this->addLanguage('en');
+    $this->addLanguage('es');
+    $this->enableUrlLanguageDetection();
+    $this->configureContentType();
+    $this->login($this->getTranslatorUser());
+  }
+
+  /**
+   * Returns the role id of an $account object.
+   */
+  protected function getUserRole($account) {
+    return reset($account->roles);
+  }
+
+  /**
+   * Tests Pathauto integration.
+   */
+  public function testPathautoIntegration() {
+    $languages = language_list();
+
+    // Enable the path module to add aliases manually.
+    $this->login($this->getAdminUser());
+    if (!module_exists('path')) {
+      module_enable(array('path'));
+    }
+    $this->login($this->getTranslatorUser());
+
+    // Create Basic page in English.
+    $node_title = $this->randomName();
+    $node_body = $this->randomName();
+    $node = $this->createPage($node_title, $node_body, 'en');
+    $node_alias = $this->randomName();
+    $edit = array(
+      'path[alias]' => $node_alias,
+    );
+    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
+
+    // Submit translation in Spanish.
+    $node_translation_body = $this->randomName();
+    $this->createTranslation($node, $node_title, $node_translation_body, 'es');
+    $node_translation_alias = $this->randomName();
+    $edit = array(
+      'path[alias]' => $node_translation_alias,
+    );
+    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'), array('language' => $languages['es']));
+
+    // Enable the pathauto module.
+    $this->login($this->getAdminUser());
+    if (!module_exists('pathauto')) {
+      module_enable(array('pathauto'));
+    }
+    $admin_rid = $this->getUserRole($this->getAdminUser());
+    user_role_grant_permissions($admin_rid, array('administer url aliases', 'administer pathauto'));
+    $translator_rid = $this->getUserRole($this->getTranslatorUser());
+    user_role_grant_permissions($translator_rid, array('create url aliases'));
+    $this->login($this->getTranslatorUser());
+
+    // Create pathauto alias for source node.
+    $edit = array(
+      'path[pathauto]' => TRUE,
+    );
+    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
+    // Clear the static caches in case they interfere.
+    drupal_lookup_path('wipe');
+    $node_pathauto_alias = pathauto_node_update_alias($node, 'return');
+    $node_translation_pathauto_alias = pathauto_node_update_alias($node, 'return', array('language' => 'es'));
+
+    // Check that the new alias for the translation matches the
+    // pathauto's logic.
+    $this->assertEqual($this->getUrl(), url(drupal_get_path_alias($node_pathauto_alias), array('absolute' => TRUE)));
+
+    // Check that a pathauto alias was created for the source and
+    // matches the pathauto's logic.
+    $this->drupalGet('node/' . $node->nid, array('language' => $languages['es']));
+    $this->assertEqual($this->getUrl(), url(drupal_get_path_alias($node_translation_pathauto_alias), array('absolute' => TRUE, 'language' => $languages['es'])));
+
+    // Delete the two aliases.
+    path_delete(array('source' => 'node/' . $node->nid));
+
+    // Create pathauto alias for the translation of the node.
+    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'), array('language' => $languages['es']));
+    // Clear the static caches in case they interfere.
+    drupal_lookup_path('wipe');
+    $node_pathauto_alias = pathauto_node_update_alias($node, 'return');
+    $node_translation_pathauto_alias = pathauto_node_update_alias($node, 'return', array('language' => 'es'));
+
+    // Check that the new alias for the translation matches the
+    // pathauto's logic.
+    $this->assertEqual($this->getUrl(), url(drupal_get_path_alias($node_translation_pathauto_alias), array('absolute' => TRUE, 'language' => $languages['es'])));
+
+    // Check that a pathauto alias was created for the source and
+    // matches the pathauto's logic.
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertEqual($this->getUrl(), url(drupal_get_path_alias($node_pathauto_alias), array('absolute' => TRUE)));
+  }
+
+}
+
+/**
+ * Tests for enabling fields to use Entity Translation or disabling them.
+ */
+class EntityTranslationToggleFieldsTranslatabilityTestCase extends EntityTranslationTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Fields translatability toggling',
+      'description' => 'Tests for enabling fields to use Entity Translation or disabling them.',
+      'group' => 'Entity translation',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    // Activate modules.
+    parent::setUp('locale', 'taxonomy', 'entity_translation', 'entity_translation_test');
+    $this->login($this->getAdminUser(array(
+      'administer taxonomy',
+      'toggle field translatability',
+    )));
+    $this->login($this->getTranslatorUser(array(
+      'administer taxonomy',
+    )));
+  }
+
+  /**
+   * Configure the "Basic page" content type for entity translation tests.
+   */
+  protected function configureContentTypeForRevisions() {
+    // Configure the "Basic page" content type to use revisions.
+    $edit = array(
+      'node_options[revision]' => 1,
+    );
+    $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
+    $this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.'));
+  }
+
+  /**
+   * Create a "Basic page" in the specified language.
+   *
+   * @param $title
+   *   Title of the basic page in the specified language.
+   * @param $body
+   *   Body of the basic page in the specified language.
+   */
+  protected function createUntranslatedPage($title, $body) {
+    $edit = array(
+      'title' => $title,
+      'body[und][0][value]' => $body,
+    );
+    $this->drupalPost('node/add/page', $edit, t('Save'));
+    $this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), t('Basic page created.'));
+
+    // Check to make sure the node was created.
+    $node = $this->drupalGetNodeByTitle($title);
+    $this->assertTrue($node, t('Node found in database.'));
+
+    return $node;
+  }
+
+  /**
+   * Create a "Tags" term in the specified language.
+   *
+   * @param $name
+   *   Name of the term.
+   * @param $description
+   *   Description of the term.
+   * @param $text
+   *   Content for the field_simple_text field.
+   */
+  protected function createUntranslatedTag($name, $description, $text) {
+    $edit = array(
+      'name' => $name,
+      'description[value]' => $description,
+      "field_simple_text[und][0][value]" => $text,
+    );
+    $this->drupalPost('admin/structure/taxonomy/tags/add', $edit, t('Save'));
+
+    // Check to make sure the term was created.
+    $term = current(entity_load('taxonomy_term', FALSE, array('name' => $name), TRUE));
+    $this->assertTrue($term, t('Term found in database.'));
+
+    return $term;
+  }
+
+  /**
+   * Tests toggling translatability on fields with data (non-revisionable).
+   */
+  public function testTogglingFieldsWithDataNonRevisionable() {
+    // Create an untranslated Basic page.
+    $node_title = $this->randomName();
+    $node_body = $this->randomName();
+    $node = $this->createUntranslatedPage($node_title, $node_body);
+    $this->assert(isset($node->body[LANGUAGE_NONE]), t('Found body field data in LANGUAGE_NONE as expected.'));
+    $this->assertEqual($node->body[LANGUAGE_NONE][0]['value'], $node_body);
+
+    // Create an untranslated Tags term.
+    $term_name = $this->randomName();
+    $term_description = $this->randomName();
+    $term_simple_text = $this->randomName();
+    $term = $this->createUntranslatedTag($term_name, $term_description, $term_simple_text);
+    $this->assert(isset($term->field_simple_text[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
+    $this->assertEqual($term->field_simple_text[LANGUAGE_NONE][0]['value'], $term_simple_text);
+
+    // Enable translation for field body and check field migration.
+    $this->login($this->getAdminUser());
+    $this->drupalGet('admin/structure/types/manage/page/fields/body');
+    $this->clickLink('Enable translation');
+    $this->drupalPost(NULL, array(), t('Confirm'));
+    $node = current(entity_load('node', FALSE, array('title' => $node_title), TRUE));
+    $this->assert(isset($node->body['en']), t('Found field data in English as expected.'));
+    $this->assertEqual($node->body['en'][0]['value'], $node_body);
+    $this->assert(!isset($node->body[LANGUAGE_NONE]), t('No field data in LANGUAGE_NONE found.'));
+
+    // Disable translation for body field and check field reverse migration.
+    $this->drupalGet('admin/structure/types/manage/page/fields/body');
+    $this->clickLink('Disable translation');
+    $this->drupalPost(NULL, array(), t('Confirm'));
+    $node = current(entity_load('node', FALSE, array('title' => $node_title), TRUE));
+    $this->assert(isset($node->body[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
+    $this->assertEqual($node->body[LANGUAGE_NONE][0]['value'], $node_body);
+    $this->assert(!isset($node->body['en']), t('No field data in English found.'));
+
+    // Enable translation for field_simple_text and check field migration.
+    $this->drupalGet('admin/structure/taxonomy/tags/fields/field_simple_text');
+    $this->clickLink('Enable translation');
+    $this->drupalPost(NULL, array(), t('Confirm'));
+    // Clear the field cache in order to load current field data.
+    field_info_cache_clear();
+    // Load the term and check that the fields data are under 'en'.
+    $term = current(entity_load('taxonomy_term', FALSE, array('name' => $term_name), TRUE));
+    $this->assert(isset($term->field_simple_text['en']), t('Found field data in English as expected.'));
+    $this->assertEqual($term->field_simple_text['en'][0]['value'], $term_simple_text);
+    $this->assert(!isset($term->field_simple_text[LANGUAGE_NONE]), t('No field data in LANGUAGE_NONE found.'));
+
+    // Disable translation for field_simple_text.
+    $this->drupalGet('admin/structure/taxonomy/tags/fields/field_simple_text');
+    $this->clickLink('Disable translation');
+    $this->drupalPost(NULL, array(), t('Confirm'));
+
+    // Load the term and check that the fields data are under LANGUAGE_NONE.
+    $term = current(entity_load('taxonomy_term', FALSE, array('name' => $term_name), TRUE));
+    $this->assert(isset($term->field_simple_text[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
+    $this->assertEqual($term->field_simple_text[LANGUAGE_NONE][0]['value'], $term_simple_text);
+    $this->assert(!isset($term->field_simple_text['en']), t('No field data in English found.'));
+  }
+
+  /**
+   * Tests toggling translatability on fields with data (revisionable).
+   */
+  public function testTogglingFieldsWithDataRevisionable() {
+    // Enable revisions for Basic pages.
+    $this->login($this->getAdminUser());
+    $this->configureContentTypeForRevisions();
+
+    // Create an untranslated Basic page.
+    $this->login($this->getTranslatorUser());
+    $node_title = $this->randomName();
+    $node_body = $this->randomName();
+    $node = $this->createUntranslatedPage($node_title, $node_body);
+    $this->assert(isset($node->body[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
+    $this->assertEqual($node->body[LANGUAGE_NONE][0]['value'], $node_body);
+
+    // Create a new revision for the page.
+    $edit_revision = array(
+      'title' => $this->randomName(),
+    );
+    $this->drupalPost('node/' . $node->nid . '/edit', $edit_revision, t('Save'));
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assert($node->vid == $node->nid + 1, t('Correct vid attached to the node object.'));
+
+    // Enable translation for field body and check field migration on all
+    // revisions.
+    $this->login($this->getAdminUser());
+    $this->drupalGet('admin/structure/types/manage/page/fields/body');
+    $this->clickLink('Enable translation');
+    $this->drupalPost(NULL, array(), t('Confirm'));
+    $node_current_revision = current(entity_load('node', FALSE, array('vid' => $node->vid), TRUE));
+    $this->assert(isset($node_current_revision->body['en']), t('Found field data in English as expected.'));
+    $this->assertEqual($node_current_revision->body['en'][0]['value'], $node_body);
+    $this->assert(!isset($node_current_revision->body[LANGUAGE_NONE]), t('No field data in LANGUAGE_NONE found.'));
+    $node_previous_revision = current(entity_load('node', FALSE, array('vid' => ($node->vid - 1)), TRUE));
+    $this->assert(isset($node_previous_revision->body['en']), t('Found field data in English as expected.'));
+    $this->assertEqual($node_previous_revision->body['en'][0]['value'], $node_body);
+    $this->assert(!isset($node_previous_revision->body[LANGUAGE_NONE]), t('No field data in LANGUAGE_NONE found.'));
+
+    // Disable translation for field_body.
+    $this->drupalGet('admin/structure/types/manage/page/fields/body');
+    $this->clickLink('Disable translation');
+    $this->drupalPost(NULL, array(), t('Confirm'));
+
+    // Disable translation for field body and check field reverse migration on
+    // all revisions.
+    $node_current_revision = current(entity_load('node', FALSE, array('vid' => $node->vid), TRUE));
+    $this->assert(isset($node_current_revision->body[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
+    $this->assertEqual($node_current_revision->body[LANGUAGE_NONE][0]['value'], $node_body);
+    $this->assert(!isset($node_current_revision->body['en']), t('No field data in English found.'));
+    $node_previous_revision = current(entity_load('node', FALSE, array('vid' => ($node->vid - 1)), TRUE));
+    $this->assert(isset($node_previous_revision->body[LANGUAGE_NONE]), t('Found field data in LANGUAGE_NONE as expected.'));
+    $this->assertEqual($node_previous_revision->body[LANGUAGE_NONE][0]['value'], $node_body);
+    $this->assert(!isset($node_previous_revision->body['en']), t('No field data in English found.'));
+  }
+
+}
+
+/**
+ * Tests for the taxonomy autocomplete translation modes.
+ */
+class EntityTranslationTaxonomyAutocompleteTestCase extends EntityTranslationTestCase {
+
+  /**
+   * Returns the test information.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity translation taxonomy autocomplete',
+      'description' => 'Tests for the taxonomy autocomplete translation modes.',
+      'group' => 'Entity translation',
+      'dependencies' => array('title'),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp() {
+    parent::setUp('locale', 'entity_translation', 'taxonomy', 'title');
+    $this->login($this->getAdminUser(array(
+      'administer taxonomy',
+      'administer entity translation',
+    )));
+    $this->addLanguage('en');
+    $this->addLanguage('it');
+    $this->addLanguage('fr');
+    $this->enableUrlLanguageDetection();
+    $this->configureVocabulary();
+    $this->configureContentType();
+  }
+
+  /**
+   * Makes the "Tags" vocabulary translatable.
+   */
+  function configureVocabulary() {
+    $edit = array(
+      'entity_translation_entity_types[taxonomy_term]' => TRUE,
+    );
+    $this->drupalPost('admin/config/regional/entity_translation', $edit, t('Save configuration'));
+
+    $edit = array(
+      'entity_translation_taxonomy' => TRUE,
+    );
+    $this->drupalPost('admin/structure/taxonomy/tags/edit', $edit, t('Save'));
+
+    $edit = array(
+      'enabled' => TRUE,
+    );
+    $this->drupalPost('admin/structure/taxonomy/tags/fields/replace/name', $edit, t('Save settings'));
+
+    $edit = array(
+      'enabled' => TRUE,
+    );
+    $this->drupalPost('admin/structure/taxonomy/tags/fields/replace/description', $edit, t('Save settings'));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function configureContentType() {
+    parent::configureContentType();
+
+    // Create an untranslatable term reference field with unlimited cardinality.
+    $edit = array(
+      'fields[_add_new_field][label]' => 'Test tags',
+      'fields[_add_new_field][field_name]' => 'test_tags',
+      'fields[_add_new_field][type]' => 'taxonomy_term_reference',
+      'fields[_add_new_field][widget_type]' => 'taxonomy_autocomplete',
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));
+
+    $edit = array(
+      'field[settings][allowed_values][0][vocabulary]' => 'tags',
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields/field_test_tags/field-settings', $edit, t('Save field settings'));
+
+    // Verify the in-place translation option is available.
+    $this->drupalGet('admin/structure/types/manage/page/fields/field_test_tags');
+    $this->assertRaw(t('Enable in-place translation of terms'));
+
+    $edit = array(
+      'field[cardinality]' => FIELD_CARDINALITY_UNLIMITED,
+    );
+    $this->drupalPost(NULL, $edit, t('Save settings'));
+
+    // Ensure entity info is up-to-date.
+    drupal_flush_all_caches();
+  }
+
+  /**
+   * Enables in-place translation.
+   */
+  function enableInPlaceTranslation() {
+    $edit = array(
+      'instance[settings][entity_translation_taxonomy_autocomplete_translate]' => TRUE,
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields/field_test_tags', $edit, t('Save settings'));
+  }
+
+  /**
+   * Tests that in-place translation works as expected.
+   */
+  function testInPlaceTranslation() {
+    $this->enableInPlaceTranslation();
+    $this->login($this->getTranslatorUser(array(
+      'administer taxonomy',
+    )));
+
+    $values = array(
+      'Red' => 'Rosso',
+      'Green' => 'Verde',
+      'Blue' => 'Blu',
+    );
+
+    // Create an English node with a few new tags.
+    $edit = array(
+      'title' => 'Test 1',
+      'field_test_tags[' . LANGUAGE_NONE . ']' => implode(', ', array_keys($values)),
+      'language' => 'en',
+    );
+    $this->drupalPost('node/add/page', $edit, t('Save'));
+    $node = $this->drupalGetNodeByTitle($edit['title']);
+
+    // Create an Italian translation and translate the English tags.
+    $this->drupalGet('node/' . $node->nid . '/translate');
+    $this->clickLink('add', 1);
+    $edit = array();
+    foreach (array_values($values) as $delta => $value) {
+      $edit['field_test_tags[' . LANGUAGE_NONE . '][' . $delta . ']'] = $value;
+    }
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // Verify that the Italian values are correctly stored/displayed.
+    foreach ($values as $original => $translation) {
+      $this->assertRaw($translation);
+    }
+
+    // Verify that the original English values were correctly retained.
+    $this->drupalGet('node/' . $node->nid);
+    foreach ($values as $original => $translation) {
+      $this->assertRaw($original);
+    }
+  }
+
+  /**
+   * That the autocomplete works with translated terms.
+   */
+  function testTranslatedAutocomplete() {
+    $this->login($this->getTranslatorUser(array(
+      'administer taxonomy',
+    )));
+
+    $vocabulary = taxonomy_vocabulary_machine_name_load('tags');
+    $entity_type = 'taxonomy_term';
+    $existing_values = array();
+    $translated_values = array(
+      'en' => array(
+        'Red' => 'Rosso',
+        'Green' => 'Verde',
+      ),
+      'it' => array(
+        'Blu' => 'Blue',
+      ),
+    );
+    $langcodes = array_keys($translated_values);
+
+    // Create a few existing tags with different original language and translate
+    // them accordingly.
+    foreach ($translated_values as $langcode => $values) {
+      title_active_language($langcode);
+      $translation_langcode = current(array_diff($langcodes, array($langcode)));
+
+      foreach ($values as $original => $translation) {
+        $term = (object) array(
+          'vid' => $vocabulary->vid,
+          'vocabulary_machine_name' => $vocabulary->machine_name,
+          'name' => $original,
+          'name_field' => array(
+            $langcode => array(array('value' => $original)),
+            $translation_langcode => array(array('value' => $translation)),
+          ),
+        );
+        $translation = array(
+          'language' => $translation_langcode,
+          'source' => $langcode,
+          'status' => TRUE,
+        );
+
+        $handler = entity_translation_get_handler($entity_type, $term);
+        $handler->setOriginalLanguage($langcode);
+        $handler->initTranslations();
+        $handler->setTranslation($translation);
+        taxonomy_term_save($term);
+
+        $existing_values[$term->name_field['en'][0]['value']] = $term->name_field['it'][0]['value'];
+      }
+    }
+
+    // Verify that the English autocomplete route returns results for terms
+    // originally created in English.
+    $this->autocompleteGet('en', 'Re');
+    $this->assertRaw('Red');
+    $this->assertRaw('Green');
+
+    // Verify that the English autocomplete route returns results for terms
+    // translated into English.
+    $this->autocompleteGet('en', 'Blu');
+    $this->assertRaw('Blue');
+
+    // Verify that the Italian autocomplete route returns results for terms
+    // originally created in Italian.
+    $this->autocompleteGet('it', 'Blu');
+    $this->assertRaw('Blu');
+    $this->assertNoRaw('Blue');
+
+    // Verify that the Italian autocomplete route returns results for terms
+    // translated into Italian.
+    $this->autocompleteGet('it', 'R');
+    $this->assertRaw('Rosso');
+    $this->assertRaw('Verde');
+
+    // Verify that existing tags are correctly referenced and new tags are
+    // correctly created, when saving an English node.
+    $new_values = array(
+      'Cyan' => 'Ciano',
+      'Magenta' => 'Magenta',
+      'Yellow' => 'Giallo',
+      'Black' => 'Nero',
+    );
+    $all_values = $existing_values + $new_values;
+
+    $edit = array(
+      'title' => 'Test 1',
+      'field_test_tags[' . LANGUAGE_NONE . ']' => implode(', ', array_keys($all_values)),
+      'language' => 'en',
+    );
+    $this->drupalPost('node/add/page', $edit, t('Save'));
+    foreach ($all_values as $original => $translation) {
+      $this->assertRaw($original);
+    }
+
+    // Verify that existing translated tags are correctly referenced and new
+    // tags are correctly created, when translated the node into Italian.
+    $node = $this->drupalGetNodeByTitle($edit['title']);
+    $this->drupalGet('node/' . $node->nid . '/translate');
+    $this->clickLink('add', 1);
+    $edit = array(
+      'field_test_tags[' . LANGUAGE_NONE . ']' => implode(', ', $all_values),
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    foreach ($all_values as $original => $translation) {
+      $this->assertRaw($translation);
+    }
+
+    // Verify that existing (translated) tags were preserved, while new Italian
+    // tags replaced the corresponding English versions.
+    $this->drupalGet('node/' . $node->nid);
+    foreach ($existing_values as $original => $translation) {
+      $this->assertRaw($original);
+    }
+    foreach ($new_values as $original => $translation) {
+      $this->assertRaw($translation);
+    }
+  }
+
+  /**
+   * Performs a GET request to the autocomplete path.
+   *
+   * @param string $langcode
+   *   The language to use to query results.
+   * @param string $query
+   *   The search query string.
+   */
+  protected function autocompleteGet($langcode, $query) {
+    $path = 'entity_translation/taxonomy_term/autocomplete/' . $langcode . '/field_test_tags/' . $query;
+    $languages = language_list();
+    $this->drupalGet($path, array('language' => $languages[$langcode]));
+  }
+
+}

+ 4 - 4
sites/all/modules/contrib/localisation/entity_translation/tests/entity_translation_test.info

@@ -4,11 +4,11 @@ core = 7.x
 package = Testing
 hidden = TRUE
 dependencies[] = entity_translation
+
 files[] = entity_translation_test.module
 
-; Information added by Drupal.org packaging script on 2016-09-28
-version = "7.x-1.0-beta5+15-dev"
+; Information added by Drupal.org packaging script on 2019-01-20
+version = "7.x-1.0+5-dev"
 core = "7.x"
 project = "entity_translation"
-datestamp = "1475057941"
-
+datestamp = "1548022384"

+ 31 - 0
sites/all/modules/contrib/localisation/entity_translation/tests/entity_translation_test.install

@@ -5,3 +5,34 @@
  * Installation functionality for Entity Translation testing module.
  */
 
+/**
+ * Implements hook_install().
+ */
+function entity_translation_test_install() {
+  // Create a simple text field, attached to taxonomy_terms.
+  field_info_cache_clear();
+
+  $field = array(
+    'field_name' => 'field_simple_text',
+    'type' => 'text',
+    'cardinality' => 1,
+  );
+  field_create_field($field);
+
+  $instance = array(
+    'field_name' => $field['field_name'],
+    'label' => ucfirst(str_replace('_', ' ', $field['field_name'])),
+    'entity_type' => 'taxonomy_term',
+    'bundle' => 'tags',
+    'widget' => array(
+      'type' => 'text_textfield',
+    ),
+    'display' => array(
+      'default' => array(
+        'type' => 'text_default',
+      ),
+    ),
+  );
+  field_create_instance($instance);
+
+}

+ 6 - 2
sites/all/modules/contrib/localisation/entity_translation/views/entity_translation_handler_relationship.inc

@@ -1,7 +1,8 @@
 <?php
+
 /**
  * @file
- * Contains the relationship plugin for relating entities to translation metadata.
+ * Contains a views plugin for relating entities to translation metadata.
  */
 
 /**
@@ -27,7 +28,10 @@ class entity_translation_handler_relationship extends views_handler_relationship
     $alias = $def['table'] . '_' . $this->table;
     // We need to add a condition on entity type to the join to avoid getting
     // relationships to entities with other types.
-    $join->extra = "$alias.entity_type = '{$def['entity type']}'";
+    $join->extra = array(
+      array('field' => 'entity_type', 'value' => $def['entity type']),
+    );
     $this->alias = $this->query->add_relationship($alias, $join, 'entity_translation', $this->relationship);
   }
+
 }