Browse Source

updated ctools, panels, date, diff

Bachir Soussi Chiadmi 7 years ago
parent
commit
9acef9d37e
100 changed files with 1625 additions and 760 deletions
  1. 0 166
      sites/all/modules/contrib/content/diff/CHANGELOG.txt
  2. 19 14
      sites/all/modules/contrib/content/diff/DiffEngine.php
  3. 38 23
      sites/all/modules/contrib/content/diff/css/diff.boxes.css
  4. 39 16
      sites/all/modules/contrib/content/diff/css/diff.default.css
  5. 36 14
      sites/all/modules/contrib/content/diff/diff.admin.inc
  6. 56 6
      sites/all/modules/contrib/content/diff/diff.api.php
  7. 36 18
      sites/all/modules/contrib/content/diff/diff.css
  8. 30 52
      sites/all/modules/contrib/content/diff/diff.diff.inc
  9. 4 3
      sites/all/modules/contrib/content/diff/diff.info
  10. 30 13
      sites/all/modules/contrib/content/diff/diff.install
  11. 159 8
      sites/all/modules/contrib/content/diff/diff.module
  12. 102 69
      sites/all/modules/contrib/content/diff/diff.pages.inc
  13. 14 7
      sites/all/modules/contrib/content/diff/diff.theme.inc
  14. 7 4
      sites/all/modules/contrib/content/diff/diff.tokens.inc
  15. 19 1
      sites/all/modules/contrib/content/diff/includes/file.inc
  16. 19 1
      sites/all/modules/contrib/content/diff/includes/image.inc
  17. 192 95
      sites/all/modules/contrib/content/diff/includes/node.inc
  18. 148 0
      sites/all/modules/contrib/content/diff/includes/user.inc
  19. 54 47
      sites/all/modules/contrib/content/diff/js/diff.js
  20. 4 1
      sites/all/modules/contrib/content/diff/readme.txt
  21. 3 3
      sites/all/modules/contrib/dev/ctools/bulk_export/bulk_export.info
  22. 1 0
      sites/all/modules/contrib/dev/ctools/css/button.css
  23. 4 1
      sites/all/modules/contrib/dev/ctools/ctools.api.php
  24. 11 3
      sites/all/modules/contrib/dev/ctools/ctools.info
  25. 3 3
      sites/all/modules/contrib/dev/ctools/ctools_access_ruleset/ctools_access_ruleset.info
  26. 3 3
      sites/all/modules/contrib/dev/ctools/ctools_ajax_sample/ctools_ajax_sample.info
  27. 3 3
      sites/all/modules/contrib/dev/ctools/ctools_custom_content/ctools_custom_content.info
  28. 3 3
      sites/all/modules/contrib/dev/ctools/ctools_plugin_example/ctools_plugin_example.info
  29. 1 1
      sites/all/modules/contrib/dev/ctools/drush/ctools.drush.inc
  30. 8 2
      sites/all/modules/contrib/dev/ctools/includes/content.inc
  31. 0 1
      sites/all/modules/contrib/dev/ctools/includes/context-access-admin.inc
  32. 11 6
      sites/all/modules/contrib/dev/ctools/includes/context.inc
  33. 21 17
      sites/all/modules/contrib/dev/ctools/includes/plugins.inc
  34. 3 1
      sites/all/modules/contrib/dev/ctools/includes/uuid.inc
  35. 1 1
      sites/all/modules/contrib/dev/ctools/page_manager/help/getting-started.html
  36. 6 0
      sites/all/modules/contrib/dev/ctools/page_manager/page_manager.admin.inc
  37. 3 3
      sites/all/modules/contrib/dev/ctools/page_manager/page_manager.info
  38. 9 0
      sites/all/modules/contrib/dev/ctools/page_manager/plugins/tasks/page.admin.inc
  39. 1 0
      sites/all/modules/contrib/dev/ctools/plugins/arguments/terms.inc
  40. 3 3
      sites/all/modules/contrib/dev/ctools/plugins/content_types/block/block.inc
  41. 101 0
      sites/all/modules/contrib/dev/ctools/plugins/content_types/node_context/node_book_menu.inc
  42. 6 6
      sites/all/modules/contrib/dev/ctools/plugins/content_types/node_context/node_book_nav.inc
  43. 3 3
      sites/all/modules/contrib/dev/ctools/stylizer/stylizer.info
  44. 3 3
      sites/all/modules/contrib/dev/ctools/term_depth/term_depth.info
  45. 25 1
      sites/all/modules/contrib/dev/ctools/tests/context.test
  46. 1 1
      sites/all/modules/contrib/dev/ctools/tests/css.test
  47. 1 1
      sites/all/modules/contrib/dev/ctools/tests/css_cache.test
  48. 1 1
      sites/all/modules/contrib/dev/ctools/tests/ctools.plugins.test
  49. 1 1
      sites/all/modules/contrib/dev/ctools/tests/ctools_export_test/ctools_export.test
  50. 3 3
      sites/all/modules/contrib/dev/ctools/tests/ctools_export_test/ctools_export_test.info
  51. 3 3
      sites/all/modules/contrib/dev/ctools/tests/ctools_plugin_test.info
  52. 1 1
      sites/all/modules/contrib/dev/ctools/tests/math_expression.test
  53. 1 1
      sites/all/modules/contrib/dev/ctools/tests/math_expression_stack.test
  54. 1 1
      sites/all/modules/contrib/dev/ctools/tests/object_cache.test
  55. 3 3
      sites/all/modules/contrib/dev/ctools/views_content/views_content.info
  56. 27 2
      sites/all/modules/contrib/fields/date/date.field.inc
  57. 4 3
      sites/all/modules/contrib/fields/date/date.info
  58. 8 0
      sites/all/modules/contrib/fields/date/date.install
  59. 4 1
      sites/all/modules/contrib/fields/date/date.migrate.inc
  60. 6 1
      sites/all/modules/contrib/fields/date/date.module
  61. 6 4
      sites/all/modules/contrib/fields/date/date.theme
  62. 25 6
      sites/all/modules/contrib/fields/date/date_admin.inc
  63. 3 3
      sites/all/modules/contrib/fields/date/date_all_day/date_all_day.info
  64. 3 3
      sites/all/modules/contrib/fields/date/date_api/date_api.info
  65. 20 6
      sites/all/modules/contrib/fields/date/date_api/date_api.module
  66. 2 2
      sites/all/modules/contrib/fields/date/date_api/date_api_elements.inc
  67. 11 2
      sites/all/modules/contrib/fields/date/date_api/theme/theme.inc
  68. 3 3
      sites/all/modules/contrib/fields/date/date_context/date_context.info
  69. 18 14
      sites/all/modules/contrib/fields/date/date_elements.inc
  70. 3 3
      sites/all/modules/contrib/fields/date/date_migrate/date_migrate.info
  71. 3 3
      sites/all/modules/contrib/fields/date/date_migrate/date_migrate_example/date_migrate_example.info
  72. 3 3
      sites/all/modules/contrib/fields/date/date_popup/date_popup.info
  73. 8 0
      sites/all/modules/contrib/fields/date/date_popup/date_popup.js
  74. 24 4
      sites/all/modules/contrib/fields/date/date_popup/date_popup.module
  75. 3 3
      sites/all/modules/contrib/fields/date/date_repeat/date_repeat.info
  76. 1 1
      sites/all/modules/contrib/fields/date/date_repeat/tests/date_repeat_form.test
  77. 3 3
      sites/all/modules/contrib/fields/date/date_repeat_field/date_repeat_field.info
  78. 3 3
      sites/all/modules/contrib/fields/date/date_tools/date_tools.info
  79. 1 1
      sites/all/modules/contrib/fields/date/date_tools/tests/date_tools.test
  80. 3 3
      sites/all/modules/contrib/fields/date/date_views/date_views.info
  81. 27 1
      sites/all/modules/contrib/fields/date/date_views/includes/date_views_filter_handler.inc
  82. 1 1
      sites/all/modules/contrib/fields/date/date_views/includes/date_views_plugin_pager.inc
  83. 2 2
      sites/all/modules/contrib/fields/date/date_views/theme/theme.inc
  84. 1 1
      sites/all/modules/contrib/fields/date/tests/date_api.test
  85. 1 1
      sites/all/modules/contrib/fields/date/tests/date_field.test
  86. 30 0
      sites/all/modules/contrib/fields/date/tests/date_form.test
  87. 1 0
      sites/all/modules/contrib/fields/date/tests/date_migrate.test
  88. 14 0
      sites/all/modules/contrib/fields/date/tests/date_test/date_test.info
  89. 40 0
      sites/all/modules/contrib/fields/date/tests/date_test/date_test.module
  90. 29 4
      sites/all/modules/contrib/fields/date/tests/date_timezone.test
  91. 1 1
      sites/all/modules/contrib/panels/panels/KNOWN_ISSUES.txt
  92. 1 1
      sites/all/modules/contrib/panels/panels/README.txt
  93. 0 1
      sites/all/modules/contrib/panels/panels/css/panels-dashboard.css
  94. 0 1
      sites/all/modules/contrib/panels/panels/css/panels.css
  95. 2 3
      sites/all/modules/contrib/panels/panels/css/panels_admin.css
  96. 14 17
      sites/all/modules/contrib/panels/panels/css/panels_dnd.css
  97. 0 1
      sites/all/modules/contrib/panels/panels/css/panels_page.css
  98. 1 1
      sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.i18n.inc
  99. 3 3
      sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.info
  100. 4 3
      sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.module

+ 0 - 166
sites/all/modules/contrib/content/diff/CHANGELOG.txt

@@ -1,166 +0,0 @@
-
-CHANGELOG for Diff 7.x-2.0+13-dev to 7.x-3.x
-============================================
-
-1) System variable names have been changed
-------------------------------------------
-
-Considerable changes have occurred.
-
-2) hook_diff() was removed
---------------------------
-
-This has been replaced by hook_entity_diff() as of Diff 7.x-3.x.
-
-3) Field diffs are handled independently by Diff and the field module
----------------------------------------------------------------------
-
-Field modules SHOULD NOT implement hook_entity_diff().
-
-This is complicated and costly in terms of performance.
-
-Two new field callbacks are defined to handle these.
-
-  a) MODULE_field_diff_view_prepare()
-
-  Optional: If you need to load data, use MODULE_field_diff_view_prepare().
-
-  b) MODULE_field_diff_view()
-
-  Recommended: You should implement this to generate the compared data.
-
-If there is no corresponding hook for a field, the field comparison will try
-to guess the value using $item['safe_value'] or $item['value'] properties.
-
-If you need to make this configurable, there are two additional hooks:
-
-  c) MODULE_field_diff_default_options($field_type)
-  
-  You should define any additioal settings here. This shares a global namespace
-  of the diff module, so you can overwrite core Diff settings here too.
-  
-  In saying that, take care not to accidentially do this.
-  
-  d) MODULE_field_diff_options_form($field_type, $settings)
-  
-  This is where you insert Form API elements to configure your option settings.
-
-4) Field diffs are now configurable
------------------------------------
-
-Each field type defined by core have configurable settings to control the
-rendering of the comparison.
-
-  a) Global configuration
-
-  An administration page has been added to handle field type default settings.
-  
-  This is the preferred way to configure field settings are these are global to
-  all fields of this type.
-
-  b) View mode display options
-
-  The display "Diff comparison" is used to control the fields that are displayed 
-  when comparing different revisions.
-
-  The following is a walk-through on how you would configure the Basic page
-  (page) content types field configuration.
-
-  - Enable "Diff comparison" custom view mode
-
-    Navigate to admin/structure/types/manage/page/display and look at the
-    Custom Display Settings for this view mode. Check and save.
-
-  - Configure the display
-
-    After Saving this page, a new tab appears "Diff comparison", click this or
-    navigate directly to admin/structure/types/manage/page/display/diff_standard
-
-    - You can hide or show the fields that you want to display when doing 
-      comparisons.
-    - If the field has no inbuilt diff support, then the renderred field items
-      will be compared.
-
-5) Standard comparison preview / Inline diff view setting
----------------------------------------------------------
-
-You can set the view modes used to compare the rendered node. This can be found
-in the Diff settings in the Content Type settings page.
-
-6) Optional CSS and new Boxes styles
-------------------------------------
-
-This takes the styles from WikiPedia to really spice up the diff page.
-
-7) Optional JScript extras
---------------------------
-
-This spices up the revision checkboxes on the revisions page.
-
-8) Simple past revision token support
--------------------------------------
-
-Use-case, email notifications when content has changes. If these support tokens,
-then you can embed Diffs into these emails.
-
-9) Extensive string review
---------------------------
-See http://drupal.org/node/1785742
-
-
-10) Inline block settings changes
----------------------------------
-The inline block settings are now in the block configuration page.
-
-11) And much more...
---------------------
-
-The complete change log follows:
-
-Diff 7.x-2.x
-    o #888680 by Deciphered, Alan D.: Allow modules to interact via drupal_alter()
-    o #1280892 by Alan D., crea: Diff should track the variables that it defines
-    o #1304658 by Alan D., kari.kaariainen: Remove links and comments from the comparison preview
-    o #1122206 by binford2k, Alan D.: Notices thrown by DiffEngine::process_chunk()
-    o #1175064 by zilverdistel, Alan D.: Provide variables for leading and trailing context
-    o #1673864 by Alan D.: Allow users to bypass the admin theme when viewing comparisons
-    o #1673876 by Alan D.: Use Drupal autoloading for classes
-    o #1673856 by Alan D.: Use hook_form_BASE_FORM_ID_alter() rather than hook_form_alter()
-    o #1673856 by Alan D.: Normalise line endings
-    o #114308 by Alan D.: add jQuery for hiding radios that shouldn't show diffs
-    o #1688840 by Alan D.: Enable new JScript behaviour by default
-    o #372957 by erykmynn, JuliaKM, lsrzj, andrew_rs, alexpott, et al: HTML Strip for Diff, WYSIWYG Friendly
-      (This was refactored in the 7.x-3.x branch from the commited 7.x-2.x code)    
-    o #521212 by Alan D., blakehall: Make diff comparison page themable
-    o #1671484 by Alan D.: Show number of lines changed on revisions page
-    o #114699 by smokris, Alan D.: Diff module should support Token
-    o #372957 by c31ck: display either Hide or Show based on what clicking it will do at any time (HTML Strip for Diff)
-      This was altered for the 7.x-3.x branch.
-    o #1807510 & #1825202: Simplify Diff administration
-    o #1812162 by mitchell, Alan D.: 'Highlight changes' block appears on edit form
-
-    Node to Entity changes
-    ----------------------
-    These are roughly tracked in the meta issue #1365750 Generalize API and Integrate with core field types
-
-    o (no issue) by Alan D.: Use entity specific system variables.
-    o (no issue) by Alan D.: View mode code, new hooks, new API. Massive patch!
-
-    Resolves:
-    o #248778: Taxonomy diff
-    o #1550698: Diff of "select from list" fields shows change in key, not change in value
-    o #1458814: File (and image) field support
-    o #1418760: Optional setting to honour the display settings
-    o #1347316: Selectable view mode for inline diffs and "Current revision" display view mode
-    o #1458906: Improve performances (of existing 7.x-2.x field rendering)
-    o #1424162: Diff in Taxonomy term description
-    o #1211282: Image diff support
-
-The following patches will be posted in the corresponding project queues once
-the 7.x-3.x branch is released:
-    o #1595702 by Alan D., mbilbille: Support of field collection module
-    o #1350604 by Alan D., johaziel: Datetime diff
-    o (no issue) by Alan D.: Email field Diff support
-    o (no issue) by Alan D.: Countries Diff support
-    o (no issue) by Alan D.: Name field Diff support
-    o (no issue) by Alan D.: Link field Diff support

+ 19 - 14
sites/all/modules/contrib/content/diff/DiffEngine.php

@@ -41,7 +41,7 @@ class _DiffOp {
 class _DiffOp_Copy extends _DiffOp {
   var $type = 'copy';
 
-  function _DiffOp_Copy($orig, $closing = FALSE) {
+  function __construct($orig, $closing = FALSE) {
     if (!is_array($closing)) {
       $closing = $orig;
     }
@@ -62,7 +62,7 @@ class _DiffOp_Copy extends _DiffOp {
 class _DiffOp_Delete extends _DiffOp {
   var $type = 'delete';
 
-  function _DiffOp_Delete($lines) {
+  function __construct($lines) {
     $this->orig = $lines;
     $this->closing = FALSE;
   }
@@ -80,7 +80,7 @@ class _DiffOp_Delete extends _DiffOp {
 class _DiffOp_Add extends _DiffOp {
   var $type = 'add';
 
-  function _DiffOp_Add($lines) {
+  function __construct($lines) {
     $this->closing = $lines;
     $this->orig = FALSE;
   }
@@ -98,7 +98,7 @@ class _DiffOp_Add extends _DiffOp {
 class _DiffOp_Change extends _DiffOp {
   var $type = 'change';
 
-  function _DiffOp_Change($orig, $closing) {
+  function __construct($orig, $closing) {
     $this->orig = $orig;
     $this->closing = $closing;
   }
@@ -215,11 +215,17 @@ class _DiffEngine {
       // Find deletes & adds.
       $delete = array();
       while ($xi < $n_from && $this->xchanged[$xi]) {
-        $delete[] = $from_lines[$xi++];
+        $_fl = $from_lines[$xi++];
+        if (strlen($_fl)) {
+          $delete[] = $_fl;
+        }
       }
       $add = array();
       while ($yi < $n_to && $this->ychanged[$yi]) {
-        $add[] = $to_lines[$yi++];
+        $_tl = $to_lines[$yi++];
+        if (strlen($_tl)) {
+          $add[] = $_tl;
+        }
       }
       if ($delete && $add) {
         $edits[] = new _DiffOp_Change($delete, $add);
@@ -576,7 +582,7 @@ class Diff {
    *      (Typically these are lines from a file.)
    * @param $to_lines array An array of strings.
    */
-  function Diff($from_lines, $to_lines) {
+  function __construct($from_lines, $to_lines) {
     $eng = new _DiffEngine;
     $this->edits = $eng->diff($from_lines, $to_lines);
     //$this->_check($from_lines, $to_lines);
@@ -735,12 +741,11 @@ class MappedDiff extends Diff {
    * @param $mapped_to_lines array This array should
    *  have the same number of elements as $to_lines.
    */
-  function MappedDiff($from_lines, $to_lines, $mapped_from_lines, $mapped_to_lines) {
-
+  function __construct($from_lines, $to_lines, $mapped_from_lines, $mapped_to_lines) {
     assert(sizeof($from_lines) == sizeof($mapped_from_lines));
     assert(sizeof($to_lines) == sizeof($mapped_to_lines));
 
-    $this->Diff($mapped_from_lines, $mapped_to_lines);
+    parent::__construct($mapped_from_lines, $mapped_to_lines);
 
     $xi = $yi = 0;
     for ($i = 0; $i < sizeof($this->edits); $i++) {
@@ -950,7 +955,7 @@ define('NBSP', '&#160;');      // iso-8859-x non-breaking space.
  * @subpackage DifferenceEngine
  */
 class _HWLDF_WordAccumulator {
-  function _HWLDF_WordAccumulator() {
+  function __construct() {
     $this->_lines = array();
     $this->_line = '';
     $this->_group = '';
@@ -1016,11 +1021,11 @@ class WordLevelDiff extends MappedDiff {
     return 10000;
   }
 
-  function WordLevelDiff($orig_lines, $closing_lines) {
+  function __construct($orig_lines, $closing_lines) {
     list($orig_words, $orig_stripped) = $this->_split($orig_lines);
     list($closing_words, $closing_stripped) = $this->_split($closing_lines);
 
-    $this->MappedDiff($orig_words, $closing_words, $orig_stripped, $closing_stripped);
+    parent::__construct($orig_words, $closing_words, $orig_stripped, $closing_stripped);
   }
 
   function _split($lines) {
@@ -1095,7 +1100,7 @@ class DrupalDiffFormatter extends DiffFormatter {
     'offset' => array('x' => 0, 'y' => 0),
   );
 
-  function DrupalDiffFormatter() {
+  function __construct() {
     $this->leading_context_lines = variable_get('diff_context_lines_leading', 2);
     $this->trailing_context_lines = variable_get('diff_context_lines_trailing', 2);
   }

+ 38 - 23
sites/all/modules/contrib/content/diff/css/diff.boxes.css

@@ -1,5 +1,6 @@
-
-html.js .diff-js-hidden { display: none; }
+html.js .diff-js-hidden {
+  display: none;
+}
 
 /* Reset as many core themes as possible */
 table.diff {
@@ -8,7 +9,7 @@ table.diff {
   border: 0 none;
   width: 98%;
   border-spacing: 5px;
-  table-layout: fixed ;
+  table-layout: fixed;
   border-collapse: separate;
 }
 table.diff tr td:last-child {
@@ -24,10 +25,13 @@ table.diff th {
   border-spacing: 4px;
   padding: 4px 8px;
 }
-table.diff tr, table.diff tr.even {
+table.diff tr,
+table.diff tr.even {
   background: none;
 }
-table.diff tr th, table.diff tr th a, table.diff tr th a:hover {
+table.diff tr th,
+table.diff tr th a,
+table.diff tr th a:hover {
   color: inherit;
   font-weight: bold;
 }
@@ -37,28 +41,34 @@ table.diff tr.odd {
   border-style: none;
   background: transparent;
 }
-table.diff th a { display: inline; }
+table.diff th a {
+  display: inline;
+}
 
 /* Main theming */
-table.diff, td.diff-number {
-  background-color: white
+table.diff,
+td.diff-number {
+  background-color: white;
 }
 
 table.diff td.diff-lineno {
-  font-weight: bold
+  font-weight: bold;
 }
 
-table.diff td.diff-addedline, table.diff td.diff-deletedline, table.diff td.diff-context {
+table.diff td.diff-addedline,
+table.diff td.diff-deletedline,
+table.diff td.diff-context {
   font-size: 88%;
   vertical-align: top;
   white-space: -moz-pre-wrap;
-  white-space: pre-wrap
+  white-space: pre-wrap;
 }
 
-table.diff td.diff-addedline, table.diff td.diff-deletedline {
+table.diff td.diff-addedline,
+table.diff td.diff-deletedline {
   border-style: solid;
   border-width: 1px 1px 1px 4px;
-  border-radius: 0.33em
+  border-radius: 0.33em;
 }
 
 table.diff td.diff-context {
@@ -76,45 +86,46 @@ table.diff td.diff-addedline {
 }
 
 table.diff td.diff-deletedline {
-  border-color: #ffe49c
+  border-color: #ffe49c;
 }
 
 .diffchange {
   font-weight: bold;
-  text-decoration: none
+  text-decoration: none;
 }
 
-table.diff td.diff-addedline .diffchange, table.diff td.diff-deletedline .diffchange {
+table.diff td.diff-addedline .diffchange,
+table.diff td.diff-deletedline .diffchange {
   border-radius: 0.33em;
-  padding: 0.25em 0
+  padding: 0.25em 0;
 }
 
 table.diff td.diff-addedline .diffchange {
-  background: #d8ecff
+  background: #d8ecff;
 }
 
 table.diff td.diff-deletedline .diffchange {
-  background: #feeec8
+  background: #feeec8;
 }
 
 table.diff table.diff td {
-  padding: 0.33em 0.66em
+  padding: 0.33em 0.66em;
 }
 
 table.diff td.diff-marker {
   width: 2%;
   text-align: right;
   font-weight: bold;
-  font-size: 1.25em  
+  font-size: 1.25em;
 }
 
 table.diff col.diff-content {
-  width: 48%
+  width: 48%;
 }
 
 table.diff table.diff td div {
   word-wrap: break-word;
-  overflow: auto
+  overflow: auto;
 }
 td.diff-prevlink {
   text-align: left;
@@ -122,3 +133,7 @@ td.diff-prevlink {
 td.diff-nextlink {
   text-align: right;
 }
+
+table.diff-revisions tr.revision-published td {
+  background-color: #aaffaa;
+}

+ 39 - 16
sites/all/modules/contrib/content/diff/css/diff.default.css

@@ -1,30 +1,47 @@
-
-html.js .diff-js-hidden { display: none; }
+html.js .diff-js-hidden {
+  display: none;
+}
 
 /**
  * Inline diff metadata
  */
 .diff-inline-metadata {
-  padding:4px;
-  border:1px solid #ddd;
-  background:#fff;
-  margin:0px 0px 10px;
+  padding: 4px;
+  border: 1px solid #ddd;
+  background: #fff;
+  margin: 0 0 10px;
 }
 
-.diff-inline-legend { font-size:11px; }
+.diff-inline-legend {
+  font-size: 11px;
+}
 
 .diff-inline-legend span,
-.diff-inline-legend label { margin-right:5px; }
+.diff-inline-legend label {
+  margin-right: 5px;
+}
 
 /**
  * Inline diff markup
  */
-span.diff-deleted { color:#ccc; }
-span.diff-deleted img { border: solid 2px #ccc; }
-span.diff-changed { background:#ffb; }
-span.diff-changed img { border:solid 2px #ffb; }
-span.diff-added { background:#cfc; }
-span.diff-added img { border: solid 2px #cfc; }
+span.diff-deleted {
+  color: #ccc;
+}
+span.diff-deleted img {
+  border: solid 2px #ccc;
+}
+span.diff-changed {
+  background: #ffb;
+}
+span.diff-changed img {
+  border: solid 2px #ffb;
+}
+span.diff-added {
+  background: #cfc;
+}
+span.diff-added img {
+  border: solid 2px #cfc;
+}
 
 /**
  * Traditional split diff theming
@@ -35,7 +52,8 @@ table.diff {
   table-layout: fixed;
   width: 100%;
 }
-table.diff tr.even, table.diff tr.odd {
+table.diff tr.even,
+table.diff tr.odd {
   background-color: inherit;
   border: none;
 }
@@ -45,7 +63,8 @@ td.diff-prevlink {
 td.diff-nextlink {
   text-align: right;
 }
-td.diff-section-title, div.diff-section-title {
+td.diff-section-title,
+div.diff-section-title {
   background-color: #f0f0ff;
   font-size: 0.83em;
   font-weight: bold;
@@ -84,3 +103,7 @@ table.diff td div {
 table.diff td {
   padding: 0.1ex 0.4em;
 }
+
+table.diff-revisions tr.revision-published td {
+  background-color: #aaffaa;
+}

+ 36 - 14
sites/all/modules/contrib/content/diff/diff.admin.inc

@@ -20,17 +20,6 @@ function diff_admin_settings($form, $form_state) {
     '#empty_option' => t('- None -'),
     '#description' => t('Alter the CSS used when displaying diff results.'),
   );
-  $form['diff_default_state_node'] = array(
-    '#type' => 'select',
-    '#title' => t('Diff default state'),
-    '#default_value' => variable_get('diff_default_state_node', 'raw'),
-    '#options' => array(
-      'raw' => t('HTML view'),
-      'raw_plain' => t('Plain view'),
-    ),
-    '#empty_option' => t('- None -'),
-    '#description' => t('Default display to show when viewing a diff, html tags in diffed result or as plain text.'),
-  );
   $form['diff_radio_behavior'] = array(
     '#type' => 'select',
     '#title' => t('Diff radio behavior'),
@@ -68,17 +57,50 @@ function diff_admin_settings($form, $form_state) {
 function diff_admin_global_entity_settings($form, $form_state, $entity_type) {
   $entity_info = entity_get_info($entity_type);
   drupal_set_title(t('Diff settings for %entity_label entities', array('%entity_label' => $entity_info['label'])), PASS_THROUGH);
+
+  if ($options = module_invoke_all('entity_diff_options', $entity_type)) {
+    $form['diff_additional_options_' . $entity_type] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Property options'),
+      '#default_value' => variable_get('diff_additional_options_' . $entity_type, array()),
+      '#options' => $options,
+    );
+  }
+  else {
+    $form['diff_additional_options_' . $entity_type] = array(
+      '#type' => 'value',
+      '#value' => array(),
+    );
+  }
+
   $form['diff_show_header_' . $entity_type] = array(
     '#type' => 'checkbox',
-    '#title' => t('Show entity label header'),
+    '#title' => t('Show entity label row header'),
     '#default_value' => variable_get('diff_show_header_' . $entity_type, 1),
   );
+  if (user_access('administer permissions')) {
+    $admin_link = l(t('View the administration theme'), 'admin/people/permissions', array('fragment' => 'edit-view-the-administration-theme'));
+  }
+  else {
+    $admin_link = t('View the administration theme');
+  }
   $form['diff_admin_path_' . $entity_type] = array(
     '#type' => 'checkbox',
-    '#title' => t('Treat diff pages as administrative'),
-    '#description' => t('Diff pages are treated as administrative pages by default, although it is up to each module to enforce this and to implement this optional setting.'),
+    '#title' => t('Use administration theme'),
+    '#description' => t('This option will enable users with the <em>!link</em> permission to use the admin theme when doing comparisons.', array('!link' => $admin_link)),
     '#default_value' => variable_get('diff_admin_path_' . $entity_type, 1),
   );
+  $form['diff_default_state_' . $entity_type] = array(
+    '#type' => 'select',
+    '#title' => t('Diff default state'),
+    '#default_value' => variable_get('diff_default_state_' . $entity_type, 'raw'),
+    '#options' => array(
+      'raw' => t('HTML view'),
+      'raw_plain' => t('Plain view'),
+    ),
+    '#empty_option' => t('- None -'),
+    '#description' => t('Default display to show when viewing a diff, html tags in diffed result or as plain text.'),
+  );
   return system_settings_form($form);
 }
 

+ 56 - 6
sites/all/modules/contrib/content/diff/diff.api.php

@@ -11,27 +11,75 @@
  */
 
 /**
- * Allow modules to provide a comparison about entities.
+ * Allow modules to provide a comparison about entity properties.
  *
  * @param object $old_entity
  *   The older entity revision.
+ *
  * @param object $new_entity
  *   The newer entity revision.
+ *
  * @param array $context
  *   An associative array containing:
  *   - entity_type: The entity type; e.g., 'node' or 'user'.
- *   - view_mode: The view mode to use. Defaults to FALSE.
+ *   - old_entity: The older entity.
+ *   - new_entity: The newer entity.
+ *   - view_mode: The view mode to use. Defaults to FALSE. If no view mode is
+ *                given, the recommended fallback view mode is 'default'.
+ *   - states: An array of view states. These could be one of:
+ *     - raw: The raw value of the diff, the classic 7.x-2.x view.
+ *     - rendered: The rendered HTML as determined by the view mode. Only
+ *                 return markup for this state if the value is normally shown
+ *                 by this view mode. The user will most likely be able to see
+ *                 the raw or raw_plain state, so this is optional.
+ *
+ *                 The rendering state is a work in progress.
+ *
+ *     Conditionally, you can get these states, but setting these will override
+ *     the user selectable markdown method.
+ *
+ *     - raw_plain: As raw, but text should be markdowned.
+ *     - rendered_plain: As rendered, but text should be markdowned.
  *
  * @return array
  *   An associative array of values keyed by the entity property.
  *
- * @todo
- *   Investiagate options and document these.
+ *   This is effectively an unnested Form API-like structure.
+ *
+ *   States are returned as follows:
+ *
+ *   $results['line'] = array(
+ *     '#name' => t('Line'),
+ *     '#states' => array(
+ *       'raw' => array(
+ *         '#old' => '<p class="line">This was the old line number [tag].</p>',
+ *         '#new' => '<p class="line">This is the new line [tag].</p>',
+ *       ),
+ *       'rendered' => array(
+ *         '#old' => '<p class="line">This was the old line number <span class="line-number">57</span>.</p>',
+ *         '#new' => '<p class="line">This is the new line <span class="line-number">57</span>.</p>',
+ *       ),
+ *     ),
+ *   );
+ *
+ *   For backwards compatibility, no changes are required to support states,
+ *   but it is recommended to provide a better UI for end users.
+ *
+ *   For example, the following example is equivalent to returning the raw
+ *   state from the example above.
+ *
+ *   $results['line'] = array(
+ *     '#name' => t('Line'),
+ *     '#old' => '<p class="line">This was the old line number [tag].</p>',
+ *     '#new' => '<p class="line">This is the new line [tag].</p>',
+ *   );
  */
 function hook_entity_diff($old_entity, $new_entity, $context) {
+  $results = array();
+
   if ($context['entity_type'] == 'node') {
     $type = node_type_get_type($new_entity);
-    $result['title'] = array(
+    $results['title'] = array(
       '#name' => $type->title_label,
       '#old' => array($old_entity->title),
       '#new' => array($new_entity->title),
@@ -41,6 +89,8 @@ function hook_entity_diff($old_entity, $new_entity, $context) {
       ),
     );
   }
+
+  return $results;
 }
 
 /**
@@ -57,7 +107,7 @@ function hook_entity_diff($old_entity, $new_entity, $context) {
  *
  * @see hook_entity_diff()
  */
-function hook_entity_diff_alter($entity_diffs, $context) {
+function hook_entity_diff_alter(&$entity_diffs, $context) {
 }
 
 /**

+ 36 - 18
sites/all/modules/contrib/content/diff/diff.css

@@ -1,30 +1,46 @@
-
-html.js .diff-js-hidden { display:none; }
+html.js .diff-js-hidden {
+  display:none;
+}
 
 /**
  * Inline diff metadata
  */
 .diff-inline-metadata {
-  padding:4px;
-  border:1px solid #ddd;
-  background:#fff;
-  margin:0px 0px 10px;
-  }
-
-.diff-inline-legend { font-size:11px; }
+  padding: 4px;
+  border: 1px solid #ddd;
+  background: #fff;
+  margin: 0 0 10px;
+}
 
+.diff-inline-legend {
+  font-size: 11px;
+}
 .diff-inline-legend span,
-.diff-inline-legend label { margin-right:5px; }
+.diff-inline-legend label {
+  margin-right: 5px;
+}
 
 /**
  * Inline diff markup
  */
-span.diff-deleted { color:#ccc; }
-span.diff-deleted img { border: solid 2px #ccc; }
-span.diff-changed { background:#ffb; }
-span.diff-changed img { border:solid 2px #ffb; }
-span.diff-added { background:#cfc; }
-span.diff-added img { border: solid 2px #cfc; }
+span.diff-deleted {
+  color: #ccc;
+}
+span.diff-deleted img {
+  border: solid 2px #ccc;
+}
+span.diff-changed {
+  background: #ffb;
+}
+span.diff-changed img {
+  border: solid 2px #ffb;
+}
+span.diff-added {
+  background: #cfc;
+}
+span.diff-added img {
+  border: solid 2px #cfc;
+}
 
 /**
  * Traditional split diff theming
@@ -35,7 +51,8 @@ table.diff {
   table-layout: fixed;
   width: 100%;
 }
-table.diff tr.even, table.diff tr.odd {
+table.diff tr.even,
+table.diff tr.odd {
   background-color: inherit;
   border: none;
 }
@@ -45,7 +62,8 @@ td.diff-prevlink {
 td.diff-nextlink {
   text-align: right;
 }
-td.diff-section-title, div.diff-section-title {
+td.diff-section-title,
+div.diff-section-title {
   background-color: #f0f0ff;
   font-size: 0.83em;
   font-weight: bold;

+ 30 - 52
sites/all/modules/contrib/content/diff/diff.diff.inc

@@ -12,17 +12,6 @@
  *
  * This manually invokes hook_diff() to avoid a function name clash with the
  * PHP 5 (>= 5.3.0) date_diff() function or the Dates modules implementation.
- *
- * @param object $old_entity
- *   The older node revision.
- * @param object $new_entity
- *   The newer node revision.
- * @param array $context
- *   An associative array containing:
- *   - entity_type: The entity type; e.g., 'node' or 'user'.
- *   - old_entity: The older entity.
- *   - new_entity: The newer entity.
- *   - view_mode: The view mode to use. Defaults to FALSE.
  */
 function diff_entity_diff($old_entity, $new_entity, $context) {
   $return = array();
@@ -52,11 +41,13 @@ function diff_entity_diff($old_entity, $new_entity, $context) {
  *   - old_entity: The older entity.
  *   - new_entity: The newer entity.
  *   - view_mode: The view mode to use. Defaults to FALSE.
+ * @param string $default_langcode
+ *   (optional) Language code to force comparison in.
  *
  * @return array
  *   An associative array of values keyed by the field name and delta value.
  */
-function diff_entity_fields_diff($old_entity, $new_entity, $context) {
+function diff_entity_fields_diff($old_entity, $new_entity, $context, $default_langcode = NULL) {
   $result = array();
 
   $entity_type = $context['entity_type'];
@@ -65,7 +56,7 @@ function diff_entity_fields_diff($old_entity, $new_entity, $context) {
   $field_context = $context;
 
   $actual_mode = FALSE;
-  list(,, $bundle_name) = entity_extract_ids($entity_type, $new_entity);
+  list(, , $bundle_name) = entity_extract_ids($entity_type, $new_entity);
   $instances = field_info_instances($entity_type, $bundle_name);
 
   // Some fields piggy back the display settings, so we need to fake these by
@@ -98,7 +89,7 @@ function diff_entity_fields_diff($old_entity, $new_entity, $context) {
 
     // We provide a loose check on the field access.
     if (field_access('view', $field, $entity_type) || field_access('edit', $field, $entity_type)) {
-      $langcode = field_language($entity_type, $new_entity, $field_name);
+      $langcode = $default_langcode ? $default_langcode : field_language($entity_type, $new_entity, $field_name);
 
       $field_context['language'] = $langcode;
       $field_context['field'] = $field;
@@ -136,10 +127,18 @@ function diff_entity_fields_diff($old_entity, $new_entity, $context) {
         $func = 'diff_field_diff_view';
       }
 
+      // Copy the static ID cache to ensure this is the same for each comparison.
+      $original_html_ids = drupal_static('drupal_html_id');
+      $html_ids = &drupal_static('drupal_html_id');
+
       // These callbacks should be independent of revision.
       $old_context = $field_context;
       $old_context['entity'] = $old_entity;
       $old_values = $func($old_items, $old_context);
+
+      // Restores the ID cache to the original.
+      $html_ids = $original_html_ids;
+
       $new_context = $field_context;
       $new_context['entity'] = $new_entity;
       $new_values = $func($new_items, $new_context);
@@ -200,22 +199,29 @@ function diff_entity_fields_diff($old_entity, $new_entity, $context) {
  *   An array of strings representing the value, keyed by delta index.
  */
 function diff_field_diff_view($items, $context) {
+  // Prevent unnecessary rendering of the field. This also prevents issues
+  // where field_view_field() will use a language fallback for display that
+  // may not match the requested diff comparison language.
+  if (!$items) {
+    return array();
+  }
+
   $diff_items = array();
-   $entity = clone $context['entity'];
-   $langcode = field_language($context['entity_type'], $entity, $context['field']['field_name']);
-   $view_mode = empty($context['view_mode']) ? 'diff_standard' : $context['view_mode'];
-   $element = field_view_field($context['entity_type'], $entity, $context['field']['field_name'], $view_mode, $langcode);
-
-   foreach (element_children($element) as $delta) {
-     $diff_items[$delta] = drupal_render($element[$delta]);
-   }
+  $entity = clone $context['entity'];
+  $langcode = field_language($context['entity_type'], $entity, $context['field']['field_name']);
+  $view_mode = empty($context['view_mode']) ? 'diff_standard' : $context['view_mode'];
+  $element = field_view_field($context['entity_type'], $entity, $context['field']['field_name'], $view_mode, $langcode);
+
+  foreach (element_children($element) as $delta) {
+    $diff_items[$delta] = drupal_render($element[$delta]);
+  }
   return $diff_items;
 }
 
 /**
  * Helper function to get the settings for a given field or formatter.
  *
- * @param array $context
+ * @param array $field_context
  *   This will get the settings for a field.
  *   - field (required): The field that the items belong to.
  *   - entity: The entity that we are looking up.
@@ -274,31 +280,6 @@ function diff_global_settings_form(&$subform, $form_state, $type, $settings) {
     ),
   );
 
-  /*
-This would be cool, but to do anything else than inline with the text appears
-to be very hard, requiring a refactoring of both the modules API but also the
-DiffFormatter and Diff classes. Diff 8.x-4.x maybe.
-
-  $subform['show_delta'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Show delta values'),
-    '#default_value' => $settings['show_delta'],
-  );
-  $subform['delta_format'] = array(
-    '#type' => 'radios',
-    '#title' => t('Delta insertion method'),
-    '#default_value' => $settings['delta_format'],
-    '#options' => array(
-      'inline' => t('Prefix to item'),
-      'row' => t('Individual row'),
-    ),
-    '#states' => array(
-      'invisible' => array(
-        "input[id$='show-delta']" => array('checked' => FALSE),
-      ),
-    ),
-  );
-  */
 }
 
 /**
@@ -323,11 +304,8 @@ function _diff_field_default_settings($module, $field_type, $settings = array())
     'markdown' => function_exists($func) ? '' : 'drupal_html_to_text',
     'line_counter' => '',
     'show_header' => 1,
-    // Can we? This seems too hard to track in the DiffFormatter as all we
-    // have is a string or an array of strings.
-    //'show_delta' => 0,
-    //'delta_format' => 'row',
   );
+
   return $settings;
 }
 

+ 4 - 3
sites/all/modules/contrib/content/diff/diff.info

@@ -1,12 +1,13 @@
 name = Diff
 description = Show differences between content revisions.
 core = 7.x
+configure = admin/config/content/diff
 
 files[] = DiffEngine.php
 
-; Information added by drupal.org packaging script on 2012-11-13
-version = "7.x-3.2"
+; Information added by Drupal.org packaging script on 2016-12-20
+version = "7.x-3.3"
 core = "7.x"
 project = "diff"
-datestamp = "1352784357"
+datestamp = "1482211686"
 

+ 30 - 13
sites/all/modules/contrib/content/diff/diff.install

@@ -5,6 +5,14 @@
  * Provides uninstallation functions.
  */
 
+/**
+ * Implements hook_install().
+ */
+function diff_install() {
+  user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('diff view changes'));
+  user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('diff view changes'));
+}
+
 /**
  * Implements hook_uninstall().
  */
@@ -16,6 +24,7 @@ function diff_uninstall() {
     'diff_view_mode_',
     'diff_admin_path_',
     'diff_default_state_',
+    'diff_additional_options_',
   );
   foreach ($prefixes as $prefix) {
     db_delete('variable')
@@ -55,27 +64,19 @@ function diff_update_7300() {
   }
 }
 
-/**
- * Removed diff_update_7301().
- */
-
-/**
- * Removed diff_update_7302().
- */
-
 /**
  * Renames some internal settings names.
  */
 function diff_update_7303() {
-  // Get current values
+  // Get current values.
   $radio = variable_get('diff_script_revisioning', 'simple');
   $leading = variable_get('diff_leading_context_lines', 2);
   $trailing = variable_get('diff_trailing_context_lines', 2);
-  // Create new variable names
+  // Create new variable names.
   variable_set('diff_radio_behavior', $radio);
   variable_set('diff_context_lines_leading', $leading);
   variable_set('diff_context_lines_trailing', $trailing);
-  // Delete old variables
+  // Delete old variables.
   variable_del('diff_script_revisioning');
   variable_del('diff_leading_context_lines');
   variable_del('diff_trailing_context_lines');
@@ -88,8 +89,8 @@ function diff_update_7304() {
   // This is now always applied to text fields.
   variable_del('diff_normalise_text');
 
-  // Merge the content type settings for the inline diff block into a single variable.
-  // diff_update_7300() - show_diff_inline_TYPE to diff_show_diff_inline_node_TYPE
+  // Merge the content type settings for the inline diff block into a single
+  // variable.
   $node_types = array_keys(node_type_get_types());
   $enabled_types = array();
   foreach ($node_types as $node_type) {
@@ -122,3 +123,19 @@ function diff_update_7305() {
       ->condition('name', db_like('diff_view_mode_inline_') . '%', 'LIKE')
       ->execute();
 }
+
+/**
+ * Sets the optional additional node properties to render so that the title
+ * still shows by default when doing node comparisons.
+ */
+function diff_update_7306() {
+  variable_set('diff_additional_options_node', array('title' => 'title'));
+}
+
+/**
+ * Grants access to the Diff "View Changes" button permission to all users.
+ */
+function diff_update_7307() {
+  user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('diff view changes'));
+  user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('diff view changes'));
+}

+ 159 - 8
sites/all/modules/contrib/content/diff/diff.module

@@ -39,11 +39,14 @@ function diff_help($path, $arg) {
     case 'admin/help#diff':
       $output = '<p>' . t('The Diff module replaces the normal <em>Revisions</em> node tab. Diff enhances the listing of revisions with an option to view the differences between any two content revisions. Access to this feature is controlled with the <em>View revisions</em> permission. The feature can be disabled for an entire content type on the content type configuration page. Diff also provides an optional <em>View changes</em> button while editing a node.') . '</p>';
       return $output;
+
     case 'node/%/revisions/%/view':
       // The translated strings should match node_help('node/%/revisions').
       return '<p>' . t('Revisions allow you to track differences between multiple versions of your content, and revert back to older versions.') . '</p>';
+
     case 'node/%/revisions/view/%/%':
       return '<p>' . t('Comparing two revisions:') . '</p>';
+
   }
 }
 
@@ -104,8 +107,7 @@ function diff_menu() {
     'page callback' => 'diff_latest',
     'page arguments' => array(1),
     'type' => MENU_LOCAL_TASK,
-    'access callback' => 'diff_node_revision_access',
-    'access arguments' => array(1),
+    'access arguments' => array('access content'),
     'tab_parent' => 'node/%/revisions/view',
     'file' => 'diff.pages.inc',
   );
@@ -152,10 +154,20 @@ function diff_menu() {
   );
 
   $items['admin/config/content/diff/entities/node'] = array(
-    'title' => 'Node',
+    'title' => 'Nodes',
+    'description' => 'Node comparison settings.',
     'type' => MENU_DEFAULT_LOCAL_TASK,
     'weight' => -10,
   );
+  $items['admin/config/content/diff/entities/user'] = array(
+    'title' => 'Users',
+    'description' => 'User diff settings.',
+    'file' => 'diff.admin.inc',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('diff_admin_global_entity_settings', 'user'),
+    'access arguments' => array('administer site configuration'),
+    'type' => MENU_LOCAL_TASK,
+  );
 
   return $items;
 }
@@ -197,6 +209,18 @@ function diff_node_revision_access($node, $op = 'view') {
   return $may_revision_this_type && _node_revision_access($node, $op);
 }
 
+/**
+ * Implements hook_permission().
+ */
+function diff_permission() {
+  return array(
+    'diff view changes' => array(
+      'title' => t('Access %view button', array('%view' => t('View changes'))),
+      'description' => t('Controls access to the %view button when editing content.', array('%view' => t('View changes'))),
+    ),
+  );
+}
+
 /**
  * Implements hook_hook_info().
  */
@@ -238,6 +262,28 @@ function diff_entity_info_alter(&$entity_info) {
   }
 }
 
+/**
+ * Returns a list of all the existing revision numbers.
+ *
+ * Clone of node_revision_list() with revision status included. This would be
+ * an additional join in Drupal 8.x to the {node_field_revision} table.
+ *
+ * @param object $node
+ *   The node object.
+ *
+ * @return array
+ *   An associative array keyed by node revision number.
+ */
+function diff_node_revision_list($node) {
+  $revisions = array();
+  $result = db_query('SELECT r.vid, r.title, r.log, r.uid, n.vid AS current_vid, r.status AS status, r.timestamp, u.name FROM {node_revision} r LEFT JOIN {node} n ON n.vid = r.vid INNER JOIN {users} u ON u.uid = r.uid WHERE r.nid = :nid ORDER BY r.vid DESC', array(':nid' => $node->nid));
+  foreach ($result as $revision) {
+    $revisions[$revision->vid] = $revision;
+  }
+
+  return $revisions;
+}
+
 /**
  * Implements hook_block_info().
  */
@@ -287,7 +333,7 @@ function diff_block_view($delta) {
     $enabled_types = variable_get('diff_show_diff_inline_node_bundles', array());
     if (!empty($enabled_types[$node->type])) {
       $block = array();
-      $revisions = node_revision_list($node);
+      $revisions = diff_node_revision_list($node);
       if (count($revisions) > 1) {
         $block['subject'] = t('Highlight changes');
         $block['content'] = drupal_get_form('diff_inline_form', $node, $revisions);
@@ -302,7 +348,7 @@ function diff_block_view($delta) {
  */
 function diff_node_view_alter(&$build) {
   $node = $build['#node'];
-  if (user_access('view revisions') && in_array($node->type, variable_get('diff_show_diff_inline_node_bundles', array()))) {
+  if (user_access('view revisions') && in_array($node->type, variable_get('diff_show_diff_inline_node_bundles', array()), TRUE)) {
     // Ugly but cheap way to check that we are viewing a node's revision page.
     if (arg(2) === 'revisions' && arg(3) === $node->vid) {
       module_load_include('inc', 'diff', 'diff.pages');
@@ -320,7 +366,9 @@ function diff_node_view_alter(&$build) {
 function diff_form_node_form_alter(&$form, $form_state) {
   // Add a 'View changes' button on the node edit form.
   $node = $form['#node'];
-  if (variable_get('diff_show_preview_changes_node_' . $node->type, TRUE) && !empty($node->nid)) {
+  if (variable_get('diff_show_preview_changes_node_' . $node->type, TRUE)
+      && user_access('diff view changes')
+      && !empty($node->nid)) {
     $form['actions']['preview_changes'] = array(
       '#type' => 'submit',
       '#value' => t('View changes'),
@@ -347,6 +395,9 @@ function diff_form_node_type_form_alter(&$form, $form_state) {
       '#title' => t('Show <em>View changes</em> button on node edit form'),
       '#weight' => 10,
       '#default_value' => variable_get('diff_show_preview_changes_node_' . $type->type, TRUE),
+      '#description' => t('You can refine access using the "!perm" permission.', array(
+        '!perm' => t('Access %view button', array('%view' => t('View changes'))),
+      )),
     );
     $form['diff']['diff_enable_revisions_page_node'] = array(
       '#type' => 'checkbox',
@@ -430,7 +481,7 @@ function diff_node_form_build_preview_changes($form, &$form_state) {
   $changes = theme('table__diff__preview', array(
     'header' => $header,
     'rows' => $rows,
-    'attributes' => array('class' => 'diff'),
+    'attributes' => array('class' => array('diff')),
     'colgroups' => _diff_default_cols(),
     'sticky' => FALSE,
   ));
@@ -440,6 +491,24 @@ function diff_node_form_build_preview_changes($form, &$form_state) {
   $form_state['rebuild'] = TRUE;
 }
 
+/**
+ * Implementation of hook_features_pipe_COMPONENT_alter().
+ */
+function diff_features_pipe_node_alter(&$pipe, $data, $export) {
+  if (!empty($data)) {
+    $variables = array(
+      'diff_show_preview_changes_node',
+      'diff_enable_revisions_page_node',
+      'diff_view_mode_preview_node',
+    );
+    foreach ($data as $node_type) {
+      foreach ($variables as $variable_name) {
+        $pipe['variable'][] = $variable_name . '_' . $node_type;
+      }
+    }
+  }
+}
+
 /**
  * Implements hook_theme().
  */
@@ -483,7 +552,7 @@ function diff_theme() {
  *   The source string to compare from.
  * @param string $b
  *   The target string to compare to.
- * @param boolean $show_header
+ * @param bool $show_header
  *   Display diff context headers. For example, "Line x".
  * @param array $line_stats
  *   This structure tracks line numbers across multiple calls to DiffFormatter.
@@ -621,3 +690,85 @@ function diff_build_attachments($jscript = FALSE) {
   }
   return $attachments;
 }
+
+/**
+ * Implements hook_entity_diff() on behalf of the Node module.
+ */
+function node_entity_diff($old_node, $new_node, $context) {
+  $result = array();
+  if ($context['entity_type'] == 'node') {
+    module_load_include('inc', 'diff', 'includes/node');
+    $options = variable_get('diff_additional_options_node', array('title' => 'title'));
+    foreach (node_entity_diff_options('node') as $key => $option_label) {
+      if (!empty($options[$key])) {
+        $func = '_node_entity_diff_additional_options_' . $key;
+        $result[$key] = $func($old_node, $new_node, $context);
+      }
+    }
+  }
+  return $result;
+}
+
+/**
+ * Implements hook_entity_diff_options() on behalf of the Node module.
+ */
+function node_entity_diff_options($entity_type) {
+  if ($entity_type == 'node') {
+    $options = array(
+      'title' => t('Title field'),
+      // Author field is either the owner or revision creator, neither capture
+      // a change in the author field.
+      'author' => t('Author'),
+      'revision_author' => t('Revision author'),
+      'type' => t('Node type'),
+      'publishing_flags' => t('Publishing options'),
+      // More fields that currently can not be tracked.
+      'created' => t('Created date'),
+      'changed' => t('Updated date'),
+      'revision_timestamp' => t('Revision timestamp'),
+    );
+    if (module_exists('comment')) {
+      $options['comment'] = t('Comment setting');
+    }
+    return $options;
+  }
+}
+
+/**
+ * Implements hook_entity_diff() on behalf of the User module.
+ */
+function user_entity_diff($old_user, $new_user, $context) {
+  $result = array();
+  if ($context['entity_type'] == 'user') {
+    module_load_include('inc', 'diff', 'includes/user');
+    $options = variable_get('diff_additional_options_user', array(
+      'name' => 'name',
+      'mail' => 'mail',
+      'status' => 'status',
+    ));
+    foreach (user_entity_diff_options('user') as $key => $option_label) {
+      if (!empty($options[$key])) {
+        $func = '_user_entity_diff_additional_options_' . $key;
+        $result[$key] = $func($old_user, $new_user, $context);
+      }
+    }
+  }
+  return $result;
+}
+
+/**
+ * Implements hook_entity_diff_options() on behalf of the User module.
+ */
+function user_entity_diff_options($entity_type) {
+  if ($entity_type == 'user') {
+    $options = array(
+      'name' => t('Username'),
+      'mail' => t('E-mail address'),
+      'roles' => t('Roles'),
+      'status' => t('Status'),
+      'timezone' => t('Time zone'),
+      'password' => t('Password Hash'),
+    );
+    return $options;
+  }
+}

+ 102 - 69
sites/all/modules/contrib/content/diff/diff.pages.inc

@@ -10,6 +10,9 @@
  */
 function diff_latest($node) {
   $revisions = node_revision_list($node);
+  if (count($revisions) < 2 || !diff_node_revision_access($node, 'view')) {
+    drupal_goto('node/' . $node->nid);
+  }
   $new = array_shift($revisions);
   $old = array_shift($revisions);
   drupal_goto("node/{$node->nid}/revisions/view/{$old->vid}/{$new->vid}");
@@ -35,19 +38,20 @@ function diff_node_revisions($form, $form_state, $node) {
     '#value' => $node->nid,
   );
 
-  $revision_list = node_revision_list($node);
+  $revision_list = diff_node_revision_list($node);
+  $revision_count = count($revision_list);
 
-  if (count($revision_list) > REVISION_LIST_SIZE) {
+  if ($revision_count > REVISION_LIST_SIZE) {
     // If the list of revisions is longer than the number shown on one page
     // split the array.
     $page = isset($_GET['page']) ? $_GET['page'] : '0';
-    $revision_chunks = array_chunk(node_revision_list($node), REVISION_LIST_SIZE);
+    $revision_chunks = array_chunk($revision_list, REVISION_LIST_SIZE);
     $revisions = $revision_chunks[$page];
     // Set up global pager variables as would 'pager_query' do.
     // These variables are then used in the theme('pager') call later.
     global $pager_page_array, $pager_total, $pager_total_items;
-    $pager_total_items[0] = count($revision_list);
-    $pager_total[0] = ceil(count($revision_list) / REVISION_LIST_SIZE);
+    $pager_total_items[0] = $revision_count;
+    $pager_total[0] = ceil($revision_count / REVISION_LIST_SIZE);
     $pager_page_array[0] = max(0, min($page, ((int) $pager_total[0]) - 1));
   }
   else {
@@ -73,6 +77,7 @@ function diff_node_revisions($form, $form_state, $node) {
         '#markup' => t('!date by !username', array(
           '!date' => l(format_date($revision->timestamp, 'small'), "node/$node->nid"),
           '!username' => theme('username', array('account' => $revision)))) . $revision_log,
+        '#revision' => $revision,
       );
     }
     else {
@@ -82,6 +87,7 @@ function diff_node_revisions($form, $form_state, $node) {
           '!date' => $diff_date,
           '!username' => theme('username', array('account' => $revision)))
         ) . $revision_log,
+        '#revision' => $revision,
       );
       if ($revert_permission) {
         $operations[] = array(
@@ -117,23 +123,13 @@ function diff_node_revisions($form, $form_state, $node) {
 
   $form['submit'] = array('#type' => 'submit', '#value' => t('Compare'));
 
-  if (count($revision_list) > REVISION_LIST_SIZE) {
+  if ($revision_count > REVISION_LIST_SIZE) {
     $form['#suffix'] = theme('pager');
   }
   $form['#attached'] = diff_build_attachments(TRUE);
   return $form;
 }
 
-/**
- * Submit code for input form to select two revisions.
- */
-function diff_node_revisions_submit($form, &$form_state) {
-  // The ids are ordered so the old revision is always on the left.
-  $old_vid = min($form_state['values']['old'], $form_state['values']['new']);
-  $new_vid = max($form_state['values']['old'], $form_state['values']['new']);
-  $form_state['redirect'] = 'node/' . $form_state['values']['nid'] . '/revisions/view/' . $old_vid . '/' . $new_vid;
-}
-
 /**
  * Validation for input form to select two revisions.
  */
@@ -145,14 +141,27 @@ function diff_node_revisions_validate($form, &$form_state) {
   }
 }
 
+/**
+ * Submit code for input form to select two revisions.
+ */
+function diff_node_revisions_submit($form, &$form_state) {
+  // The ids are ordered so the old revision is always on the left.
+  $old_vid = min($form_state['values']['old'], $form_state['values']['new']);
+  $new_vid = max($form_state['values']['old'], $form_state['values']['new']);
+  if (isset($_GET['destination'])) {
+    unset($_GET['destination']);
+  }
+  $form_state['redirect'] = 'node/' . $form_state['values']['nid'] . '/revisions/view/' . $old_vid . '/' . $new_vid;
+}
+
 /**
  * Create a comparison for the node between versions 'old_vid' and 'new_vid'.
  *
  * @param object $node
- *   Node on which to perform comparison
- * @param integer $old_vid
+ *   Node on which to perform comparison.
+ * @param int $old_vid
  *   Version ID of the old revision.
- * @param integer $new_vid
+ * @param int $new_vid
  *   Version ID of the new revision.
  */
 function diff_diffs_show($node, $old_vid, $new_vid, $state = NULL) {
@@ -161,7 +170,7 @@ function diff_diffs_show($node, $old_vid, $new_vid, $state = NULL) {
 
   $default_state = variable_get('diff_default_state_node', 'raw');
   if (empty($state)) {
-  	$state = $default_state;
+    $state = $default_state;
   }
   $state = str_replace('-', '_', $state);
   if (!array_key_exists($state, diff_available_states())) {
@@ -279,7 +288,7 @@ function diff_diffs_show($node, $old_vid, $new_vid, $state = NULL) {
     }
     $build['diff_preview']['header']['#markup'] = $header;
     // Don't include node links or comments when viewing the diff.
-    $build['diff_preview']['content'] = node_view($new_node, $view_mode);
+    $build['diff_preview']['content'] = function_exists('entity_view') ? entity_view('node', array($new_node), $view_mode) : node_view($new_node, $view_mode);
     if (isset($build['diff_preview']['content']['links'])) {
       unset($build['diff_preview']['content']['links']);
     }
@@ -291,33 +300,33 @@ function diff_diffs_show($node, $old_vid, $new_vid, $state = NULL) {
 }
 
 /**
- * Creates an array of rows which represent the difference between nodes.
+ * Creates an array of rows which represent the difference between two entities.
  *
- * @param object $old_node
- *   Node for comparison which will be displayed on the left side.
- * @param object $new_node
- *   Node for comparison which will be displayed on the right side.
- * @param boolean $state
- *   The state to render for the diff.
+ * @param object $left_entity
+ *   Entity for comparison which will be displayed on the left side.
+ * @param object $right_entity
+ *   Entity for comparison which will be displayed on the right side.
+ * @param array $context
+ *   The context used to render the diff.
  */
-function _diff_body_rows($old_node, $new_node, $state = 'raw') {
+function diff_entity_body_rows($entity_type, $left_entity, $right_entity, $context = array()) {
   // This is an unique index only, so no need for drupal_static().
   static $table_row_counter = 0;
 
   if ($theme = variable_get('diff_theme', 'default')) {
     drupal_add_css(drupal_get_path('module', 'diff') . "/css/diff.{$theme}.css");
   }
-  module_load_include('inc', 'diff', 'includes/node');
 
   $rows = array();
   $any_visible_change = FALSE;
-  $context = array(
-    'entity_type' => 'node',
-    'states' => array($state),
+  $context += array(
+    'entity_type' => $entity_type,
+    'states' => array('raw'),
     'view_mode' => 'diff_standard',
   );
+  $state = current($context['states']);
 
-  $node_diffs = diff_compare_entities($old_node, $new_node, $context);
+  $entity_diffs = diff_compare_entities($left_entity, $right_entity, $context);
 
   // Track line numbers between multiple diffs.
   $line_stats = array(
@@ -326,19 +335,19 @@ function _diff_body_rows($old_node, $new_node, $state = 'raw') {
   );
 
   // Render diffs for each.
-  foreach ($node_diffs as $node_diff) {
-    $show_header = !empty($node_diff['#name']);
+  foreach ($entity_diffs as $entity_diff) {
+    $show_header = !empty($entity_diff['#name']);
     // These are field level settings.
-    if ($show_header && isset($node_diff['#settings']['show_header'])) {
-      $show_header = $show_header && $node_diff['#settings']['show_header'];
+    if ($show_header && isset($entity_diff['#settings']['show_header'])) {
+      $show_header = $show_header && $entity_diff['#settings']['show_header'];
     }
 
     // Line counting and line header options.
-    if (empty($node_diff['#settings']['line_counter'])) {
+    if (empty($entity_diff['#settings']['line_counter'])) {
       $line_counter = FALSE;
     }
     else {
-      $line_counter = $node_diff['#settings']['line_counter'];
+      $line_counter = $entity_diff['#settings']['line_counter'];
     }
     // Every call to 'line' resets the counters.
     if ($line_counter) {
@@ -354,8 +363,8 @@ function _diff_body_rows($old_node, $new_node, $state = 'raw') {
       $line_stats_ref = NULL;
     }
 
-    list($old, $new) = diff_extract_state($node_diff, $state);
-    if ($node_diff_rows = diff_get_rows($old, $new, $line_counter && $line_counter != 'hidden', $line_stats_ref)) {
+    list($left, $right) = diff_extract_state($entity_diff, $state);
+    if ($entity_diff_rows = diff_get_rows($left, $right, $line_counter && $line_counter != 'hidden', $line_stats_ref)) {
       if ($line_counter && $line_counter != 'line') {
         $line_stats['offset']['x'] += $line_stats_ref['counter']['x'];
         $line_stats['offset']['y'] += $line_stats_ref['counter']['y'];
@@ -363,7 +372,7 @@ function _diff_body_rows($old_node, $new_node, $state = 'raw') {
       if ($show_header) {
         $rows['diff-header-' . $table_row_counter++] = array(
           array(
-            'data' => t('Changes to %name', array('%name' => $node_diff['#name'])),
+            'data' => t('Changes to %name', array('%name' => $entity_diff['#name'])),
             'class' => 'diff-section-title',
             'colspan' => 4,
           ),
@@ -371,7 +380,7 @@ function _diff_body_rows($old_node, $new_node, $state = 'raw') {
       }
       // To avoid passing counter to the Diff engine, index rows manually here
       // to allow modules to interact with the table. i.e. no array_merge().
-      foreach ($node_diff_rows as $row) {
+      foreach ($entity_diff_rows as $row) {
         $rows['diff-row-' . $table_row_counter++] = $row;
       }
       $any_visible_change = TRUE;
@@ -385,19 +394,28 @@ function _diff_body_rows($old_node, $new_node, $state = 'raw') {
         'colspan' => 4,
       ),
     );
-    // @todo: revise this.
-    // Needed to keep safari happy.
-    $rows['diff-empty-' . $table_row_counter++] = array(
-      array('data' => ''),
-      array('data' => ''),
-      array('data' => ''),
-      array('data' => ''),
-    );
   }
-
   return $rows;
 }
 
+/**
+ * Creates an array of rows which represent the difference between nodes.
+ *
+ * @param object $old_node
+ *   Node for comparison which will be displayed on the left side.
+ * @param object $new_node
+ *   Node for comparison which will be displayed on the right side.
+ * @param bool $state
+ *   The state to render for the diff.
+ */
+function _diff_body_rows($old_node, $new_node, $state = 'raw') {
+  $context = array(
+    'states' => array($state),
+    'view_mode' => 'diff_standard',
+  );
+  return diff_entity_body_rows('node', $old_node, $new_node, $context);
+}
+
 /**
  * Generic callback to compare two entities.
  */
@@ -460,6 +478,9 @@ function diff_compare_entities($left_entity, $right_entity, $context) {
   if (!isset($diff['#sorted'])) {
     uasort($diff, 'element_sort');
   }
+  else {
+    unset($diff['#sorted']);
+  }
 
   // Process the array and get line counts per field.
   array_walk($diff, 'diff_process_state_lines');
@@ -467,6 +488,9 @@ function diff_compare_entities($left_entity, $right_entity, $context) {
   return $diff;
 }
 
+/**
+ * Helper function to get line counts per field.
+ */
 function diff_process_state_lines(&$diff, $key) {
   foreach ($diff['#states'] as $state => $data) {
     if (isset($data['#old'])) {
@@ -509,20 +533,29 @@ function diff_markdown_state(&$diff, $state) {
   }
 
   if (!isset($plain_old) && isset($old)) {
-    if (is_array($old)) {
-      $diff['#states'][$state . '_plain']['#old'] = $markdown ? array_map($markdown, $old) : $old;
-    }
-    else {
-      $diff['#states'][$state . '_plain']['#old'] = $markdown ? $markdown($old) : $old;
-    }
+    $diff['#states'][$state . '_plain']['#old'] = _diff_apply_markdown($markdown, $old);
   }
   if (!isset($plain_new) && isset($new)) {
-    if (is_array($new)) {
-      $diff['#states'][$state . '_plain']['#new'] = $markdown ? array_map($markdown, $new) : $new;
-    }
-    else {
-      $diff['#states'][$state . '_plain']['#new'] = $markdown ? $markdown($new) : $new;
+    $diff['#states'][$state . '_plain']['#new'] = _diff_apply_markdown($markdown, $new);
+  }
+}
+
+/**
+ * Helper function to clear newlines from the content.
+ */
+function _diff_apply_markdown($markdown, $items) {
+  if (!$markdown) {
+    return $items;
+  }
+  if (is_array($items)) {
+    $items = array_map($markdown, $items);
+    foreach ($items as &$item) {
+      $item = trim($item, "\n");
     }
+    return $items;
+  }
+  else {
+    return trim($markdown($items), "\n");
   }
 }
 
@@ -534,7 +567,7 @@ function diff_markdown_state(&$diff, $state) {
  * @param int $vid
  *   Version ID to look for.
  *
- * @return boolean|integer
+ * @return bool|int
  *   Returns FALSE if $vid is the last entry.
  */
 function _diff_get_next_vid($node_revisions, $vid) {
@@ -553,10 +586,10 @@ function _diff_get_next_vid($node_revisions, $vid) {
  *
  * @param array $node_revisions
  *   Array of node revision IDs in descending order.
- * @param integer $vid
+ * @param int $vid
  *   Version ID to look for.
  *
- * @return boolean|integer
+ * @return bool|int
  *   Returns FALSE if $vid is the first entry.
  */
 function _diff_get_previous_vid($node_revisions, $vid) {
@@ -615,13 +648,13 @@ function _diff_default_header($old_header = '', $new_header = '') {
  * normally rendered content of the specified revision.
  */
 function diff_inline_show($node, $vid = 0, $metadata = TRUE) {
-  $new_node = $vid ? node_load($node->nid, $vid, TRUE) : clone $node;
+  $new_node = $vid ? node_load($node->nid, $vid) : clone $node;
   node_build_content($new_node);
   $new = drupal_render($new_node->content);
 
   $old = $vid ? _diff_get_previous_vid(node_revision_list($node), $vid) : 0;
   if ($old) {
-    $old_node = node_load($node->nid, $old, TRUE);
+    $old_node = node_load($node->nid, $old);
     node_build_content($old_node);
     $old = drupal_render($old_node->content);
     $output = $metadata ? theme('diff_inline_metadata', array('node' => $new_node)) : '';

+ 14 - 7
sites/all/modules/contrib/content/diff/diff.theme.inc

@@ -48,14 +48,21 @@ function theme_diff_node_revisions($vars) {
           'data' => drupal_render($form['diff']['new'][$key]),
           'class' => array('revision-current'),
         );
+        $revision = $form['info'][$key]['#revision'];
+        if ($revision && !empty($revision->status)) {
+          $message = t('This is the published revision.');
+        }
+        else {
+          $message = t('This is the current revision.');
+        }
         $row[] = array(
-          'data' => t('current revision'),
+          'data' => '<strong>' . $message . '</strong>',
           'class' => array('revision-current'),
           'colspan' => '2',
         );
         $rows[] = array(
           'data' => $row,
-          'class' => array('error diff-revision'),
+          'class' => array('revision-published diff-revision'),
         );
       }
     }
@@ -64,17 +71,13 @@ function theme_diff_node_revisions($vars) {
     'header' => $header,
     'rows' => $rows,
     'sticky' => FALSE,
-    'attributes' => array('class' => 'diff-revisions'),
+    'attributes' => array('class' => array('diff-revisions')),
   ));
 
   $output .= drupal_render_children($form);
   return $output;
 }
 
-/**
- * Theme functions
- */
-
 /**
  * Theme function for a header line in the diff.
  */
@@ -139,11 +142,15 @@ function theme_diff_inline_chunk($vars) {
   switch ($vars['type']) {
     case 'add':
       return "<span class='diff-added'>{$vars['text']}</span>";
+
     case 'change':
       return "<span class='diff-changed'>{$vars['text']}</span>";
+
     case 'delete':
       return "<span class='diff-deleted'>{$vars['text']}</span>";
+
     default:
       return $vars['text'];
+
   }
 }

+ 7 - 4
sites/all/modules/contrib/content/diff/diff.tokens.inc

@@ -38,13 +38,13 @@ function diff_tokens($type, $tokens, array $data = array(), array $options = arr
         // Basic diff standard comparison information.
         case 'diff':
         case 'diff-markdown':
-          $revisons = node_revision_list($node);
-          if (count($revisons) == 1) {
+          $revisions = node_revision_list($node);
+          if (count($revisions) == 1) {
             $replacements[$original] = t('(No previous revision available.)');
           }
           else {
             module_load_include('inc', 'diff', 'diff.pages');
-            $old_vid = _diff_get_previous_vid($revisons, $node->vid);
+            $old_vid = _diff_get_previous_vid($revisions, $node->vid);
             $state = $name == 'diff' ? 'raw' : 'raw_plain';
             $build = diff_diffs_show($node, $old_vid, $node->vid, $state);
             unset($build['diff_table']['#rows']['states']);
@@ -52,7 +52,10 @@ function diff_tokens($type, $tokens, array $data = array(), array $options = arr
             unset($build['diff_preview']);
 
             $output = drupal_render_children($build);
-            $replacements[$original] = $sanitize ? check_plain($output) : $output;
+            if ($sanitize) {
+              $output = filter_xss($output, array('a', 'em', 'strong', 'cite', 'blockquote', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd', 'table', 'tr', 'th', 'td'));
+            }
+            $replacements[$original] = $output;
           }
           break;
 

+ 19 - 1
sites/all/modules/contrib/content/diff/includes/file.inc

@@ -67,7 +67,8 @@ function file_field_diff_view($items, $context) {
       if ($settings['compare_display_field'] && !empty($field['settings']['display_field'])) {
         $output['display'] = $item['display'] ? t('Displayed') : t('Hidden');
       }
-      $diff_items[$delta] = implode('; ', $output);
+      $separator = $settings['property_separator'] == 'nl' ? "\n" : $settings['property_separator'];
+      $diff_items[$delta] = implode($separator, $output);
     }
   }
 
@@ -82,6 +83,7 @@ function file_field_diff_default_options($field_type) {
     'show_id' => 0,
     'compare_display_field' => 0,
     'compare_description_field' => 0,
+    'property_separator' => '; ',
   );
 }
 
@@ -107,5 +109,21 @@ function file_field_diff_options_form($field_type, $settings) {
     '#default_value' => $settings['compare_display_field'],
     '#description' => t('This is only used if the "Enable <em>Display</em> field" is checked in the field settings.'),
   );
+  $options_form['property_separator'] = array(
+    '#type' => 'select',
+    '#title' => t('Property separator'),
+    '#default_value' => $settings['property_separator'],
+    '#description' => t('Provides the ability to show properties inline or across multiple lines.'),
+    '#options' => array(
+      ', ' => t('Comma (,)'),
+      '; ' => t('Semicolon (;)'),
+      ' ' => t('Space'),
+      'nl' => t('New line'),
+    ),
+  );
+  // Allow users to set their own separator using variable_set().
+  if (!isset($options_form['#options'][$settings['property_separator']])) {
+    $options_form['#options'][$settings['property_separator']] = $settings['property_separator'];
+  }
   return $options_form;
 }

+ 19 - 1
sites/all/modules/contrib/content/diff/includes/image.inc

@@ -68,7 +68,8 @@ function image_field_diff_view($items, $context) {
       if ($settings['show_id']) {
         $output[] = t('File ID: !fid', $t_args);
       }
-      $diff_items[$delta] = implode('; ', $output);
+      $separator = $settings['property_separator'] == 'nl' ? "\n" : $settings['property_separator'];
+      $diff_items[$delta] = implode($separator, $output);
     }
   }
 
@@ -83,6 +84,7 @@ function image_field_diff_default_options($field_type) {
     'show_id' => 0,
     'compare_alt_field' => 0,
     'compare_title_field' => 0,
+    'property_separator' => '; ',
   );
 }
 
@@ -108,5 +110,21 @@ function image_field_diff_options_form($field_type, $settings) {
     '#default_value' => $settings['compare_title_field'],
     '#description' => t('This is only used if the "Enable <em>Title</em> field" is checked in the instance settings.'),
   );
+  $options_form['property_separator'] = array(
+    '#type' => 'select',
+    '#title' => t('Property separator'),
+    '#default_value' => $settings['property_separator'],
+    '#description' => t('Provides the ability to show properties inline or across multiple lines.'),
+    '#options' => array(
+      ', ' => t('Comma (,)'),
+      '; ' => t('Semicolon (;)'),
+      ' ' => t('Space'),
+      'nl' => t('New line'),
+    ),
+  );
+  // Allow users to set their own separator using variable_set().
+  if (!isset($options_form['#options'][$settings['property_separator']])) {
+    $options_form['#options'][$settings['property_separator']] = $settings['property_separator'];
+  }
   return $options_form;
 }

+ 192 - 95
sites/all/modules/contrib/content/diff/includes/node.inc

@@ -6,102 +6,199 @@
  */
 
 /**
- * Implements hook_entity_diff().
- *
- * This function compares core node properties. This is currently limited to:
- *   - title: The title of the node.
- *
- * @param object $old_node
- *   The older node revision.
- * @param object $new_node
- *   The newer node revision.
- * @param array $context
- *   An associative array containing:
- *   - entity_type: The entity type; e.g., 'node' or 'user'.
- *   - old_entity: The older entity.
- *   - new_entity: The newer entity.
- *   - view_mode: The view mode to use. Defaults to FALSE. If no view mode is
- *                given, the recommended fallback view mode is 'default'.
- *   - states: An array of view states. These could be one of:
- *     - raw: The raw value of the diff, the classic 7.x-2.x view.
- *     - rendered: The rendered HTML as determined by the view mode. Only
- *                 return markup for this state if the value is normally shown
- *                 by this view mode. The user will most likely be able to see
- *                 the raw or raw_plain state, so this is optional.
- *
- *                 The rendering state is a work in progress.
- *
- *     Conditionally, you can get these states, but setting these will override
- *     the user selectable markdown method.
- *
- *     - raw_plain: As raw, but text should be markdowned.
- *     - rendered_plain: As rendered, but text should be markdowned.
- *
- * @return array
- *   An associative array of values keyed by the entity property.
- *
- *   This is effectively an unnested Form API-like structure.
- *
- *   States are returned as follows:
- *
- *   $results['line'] = array(
- *     '#name' => t('Line'),
- *     '#states' => array(
- *       'raw' => array(
- *         '#old' => '<p class="line">This was the old line number [tag].</p>',
- *         '#new' => '<p class="line">This is the new line [tag].</p>',
- *       ),
- *       'rendered' => array(
- *         '#old' => '<p class="line">This was the old line number <span class="line-number">57</span>.</p>',
- *         '#new' => '<p class="line">This is the new line <span class="line-number">57</span>.</p>',
- *       ),
- *     ),
- *   );
- *
- *   For backwards compatability, no changes are required to support states,
- *   but it is recommended to provide a better UI for end users.
- *
- *   For example, the following example is equivalent to returning the raw
- *   state from the example above.
- *
- *   $results['line'] = array(
- *     '#name' => t('Line'),
- *     '#old' => '<p class="line">This was the old line number [tag].</p>',
- *     '#new' => '<p class="line">This is the new line [tag].</p>',
- *   );
+ * Private callback function to render the title field.
  */
-function node_entity_diff($old_node, $new_node, $context) {
-  $result = array();
-  if ($context['entity_type'] == 'node') {
-    $type = node_type_get_type($new_node);
-    $result['title'] = array(
-      '#name' => $type->title_label,
-      '#states' => array(),
-      '#weight' => -5,
-      '#settings' => array(
-        // Global setting - 'diff_show_header_' . $entity_type
-        'show_header' => variable_get('diff_show_header_node', 1),
-      ),
-    );
-    foreach ($context['states'] as $state) {
-      switch ($state) {
-        case 'rendered':
-          $result['title']['#states'][$state] = array(
-            '#old' => l($old_node->title, 'node/' . $old_node->title),
-            '#new' => l($new_node->title, 'node/' . $new_node->title),
-          );
-          break;
-
-        // We specify a default so that the title is allows compared.
-        case 'raw':
-        default:
-          $result['title']['#states'][$state] = array(
-            '#old' => array($old_node->title),
-            '#new' => array($new_node->title),
-          );
-          break;
-      }
+function _node_entity_diff_additional_options_title($old_node, $new_node, $context) {
+  $type = node_type_get_type($new_node);
+  $row = array(
+    '#name' => $type->title_label,
+    '#states' => array(),
+    '#weight' => -5,
+    '#settings' => array(
+      'show_header' => variable_get('diff_show_header_node', 1),
+    ),
+  );
+  foreach ($context['states'] as $state) {
+    switch ($state) {
+      case 'rendered':
+        $row['#states'][$state] = array(
+          '#old' => l($old_node->title, 'node/' . $old_node->title),
+          '#new' => l($new_node->title, 'node/' . $new_node->title),
+        );
+        break;
+
+      // We specify a default so that the title is allows compared.
+      case 'raw':
+      default:
+        $row['#states'][$state] = array(
+          '#old' => array($old_node->title),
+          '#new' => array($new_node->title),
+        );
+        break;
     }
   }
-  return $result;
+  return $row;
+}
+
+/**
+ * Private callback function to render the type field.
+ */
+function _node_entity_diff_additional_options_type($old_node, $new_node, $context) {
+  $row = array(
+    '#name' => t('Content type'),
+    '#states' => array(),
+    '#weight' => -4,
+    '#settings' => array(),
+  );
+  $old_type = node_type_get_type($old_node);
+  $new_type = node_type_get_type($new_node);
+
+  foreach ($context['states'] as $state) {
+    $row['#states'][$state] = array(
+      '#old' => array($old_type ? $old_type->name : t('Deleted type !type', array('!type' => $old_node->type))),
+      '#new' => array($new_type ? $new_type->name : t('Deleted type !type', array('!type' => $new_node->type))),
+    );
+  }
+  return $row;
+}
+
+/**
+ * Private callback function to render the author field.
+ */
+function _node_entity_diff_additional_options_author($old_node, $new_node, $context) {
+  $old_author = user_load($old_node->uid);
+  $new_author = user_load($new_node->uid);
+  return _node_entity_diff_additional_options_account(t('Author'), $old_author, $new_author, $context, -4);
+}
+
+/**
+ * Private callback function to render the revision_author field.
+ */
+function _node_entity_diff_additional_options_revision_author($old_node, $new_node, $context) {
+  $old_author = user_load($old_node->revision_uid);
+  $new_author = user_load($new_node->revision_uid);
+  return _node_entity_diff_additional_options_account(t('Revision author'), $old_author, $new_author, $context, -3.9);
+}
+
+/**
+ * Private callback function to render the author field.
+ */
+function _node_entity_diff_additional_options_account($label, $old_author, $new_author, $context, $weight = 0) {
+  $row = array(
+    '#name' => $label,
+    '#states' => array(),
+    '#weight' => $weight,
+    '#settings' => array(),
+  );
+  foreach ($context['states'] as $state) {
+    $row['#states'][$state] = array(
+      '#old' => array($old_author ? format_username($old_author) : t('Deleted user')),
+      '#new' => array($new_author ? format_username($new_author) : t('Deleted user')),
+    );
+  }
+  return $row;
+}
+
+/**
+ * Private callback function to render the status, sticky and published field.
+ */
+function _node_entity_diff_additional_options_publishing_flags($old_node, $new_node, $context) {
+  $row = array(
+    '#name' => t('Publishing options'),
+    '#states' => array(),
+    '#weight' => -3,
+    '#settings' => array(),
+  );
+  $old_options = array($old_node->status ? t('Published') : t('Unpublished'));
+  if ($old_node->promote) {
+    $old_options[] = t('Promoted to front page');
+  }
+  if ($old_node->sticky) {
+    $old_options[] = t('Sticky at top of lists');
+  }
+
+  $new_options = array($new_node->status ? t('Published') : t('Unpublished'));
+  if ($new_node->promote) {
+    $new_options[] = t('Promoted to front page');
+  }
+  if ($new_node->sticky) {
+    $new_options[] = t('Sticky at top of lists');
+  }
+
+  foreach ($context['states'] as $state) {
+    $row['#states'][$state] = array(
+      '#old' => $old_options,
+      '#new' => $new_options,
+    );
+  }
+  return $row;
+}
+
+/**
+ * Private callback function to render the created field.
+ */
+function _node_entity_diff_additional_options_created($old_node, $new_node, $context) {
+  return _node_entity_diff_additional_options_date_field(t('Created timestamp'), $old_node->created, $new_node->created, $context, -1);
+}
+
+/**
+ * Private callback function to render the changed field.
+ */
+function _node_entity_diff_additional_options_changed($old_node, $new_node, $context) {
+  return _node_entity_diff_additional_options_date_field(t('Changed timestamp'), $old_node->changed, $new_node->changed, $context, -1);
+}
+
+/**
+ * Private callback function to render the revision_timestamp field.
+ */
+function _node_entity_diff_additional_options_revision_timestamp($old_node, $new_node, $context) {
+  return _node_entity_diff_additional_options_date_field(t('Revision timestamp'), $old_node->revision_timestamp, $new_node->revision_timestamp, $context, -1);
+}
+
+/**
+ * Helper function to render the date flags.
+ */
+function _node_entity_diff_additional_options_date_field($label, $old_date, $new_date, $context, $weight = 0) {
+  $row = array(
+    '#name' => $label,
+    '#states' => array(),
+    '#weight' => $weight,
+    '#settings' => array(),
+  );
+
+  foreach ($context['states'] as $state) {
+    $row['#states'][$state] = array(
+      '#old' => array(format_date($old_date)),
+      '#new' => array(format_date($new_date)),
+    );
+  }
+  return $row;
+}
+
+/**
+ * Private callback function to render the comment field.
+ */
+function _node_entity_diff_additional_options_comment($old_node, $new_node, $context) {
+  if (!module_exists('comment')) {
+    return array();
+  }
+  $row = array(
+    '#name' => t('Comment setting'),
+    '#states' => array(),
+    '#weight' => -1,
+    '#settings' => array(),
+  );
+  $options = array(
+    COMMENT_NODE_OPEN => t('Open'),
+    COMMENT_NODE_CLOSED => t('Closed'),
+    COMMENT_NODE_HIDDEN => t('Hidden'),
+  );
+
+  foreach ($context['states'] as $state) {
+    $row['#states'][$state] = array(
+      '#old' => array($options[$old_node->comment]),
+      '#new' => array($options[$new_node->comment]),
+    );
+  }
+  return $row;
 }

+ 148 - 0
sites/all/modules/contrib/content/diff/includes/user.inc

@@ -0,0 +1,148 @@
+<?php
+
+/**
+ * @file
+ * Provide diff functions for the user module.
+ *
+ * Note as users do not have revisions enabled, most use cases for comparisons
+ * will be between two different users.
+ */
+
+/**
+ * Private callback function to render the name field.
+ */
+function _user_entity_diff_additional_options_name($old_user, $new_user, $context) {
+  $row = array(
+    '#name' => t('Username'),
+    '#states' => array(),
+    '#weight' => -5,
+    '#settings' => array(
+      'show_header' => variable_get('diff_show_header_user', 1),
+    ),
+  );
+  foreach ($context['states'] as $state) {
+    switch ($state) {
+      case 'rendered':
+        $row['#states'][$state] = array(
+          '#old' => theme('username', array('account' => $old_user)),
+          '#new' => theme('username', array('account' => $old_user)),
+        );
+        break;
+
+      // We specify a default so that the name is always compared.
+      case 'raw':
+      default:
+        $row['#states'][$state] = array(
+          '#old' => array($old_user->name),
+          '#new' => array($new_user->name),
+        );
+        break;
+    }
+  }
+  return $row;
+}
+
+/**
+ * Private callback function to render the mail field.
+ */
+function _user_entity_diff_additional_options_mail($old_user, $new_user, $context) {
+  $row = array(
+    '#name' => t('E-mail address'),
+    '#states' => array(),
+    '#weight' => -4,
+    '#settings' => array(),
+  );
+
+  foreach ($context['states'] as $state) {
+    $row['#states'][$state] = array(
+      '#old' => array($old_user->mail),
+      '#new' => array($new_user->mail),
+    );
+  }
+  return $row;
+}
+
+/**
+ * Private callback function to render the status field.
+ */
+function _user_entity_diff_additional_options_status($old_user, $new_user, $context) {
+  $row = array(
+    '#name' => t('Status'),
+    '#states' => array(),
+    '#weight' => -3,
+    '#settings' => array(),
+  );
+
+  foreach ($context['states'] as $state) {
+    $row['#states'][$state] = array(
+      '#old' => array($old_user->status ? t('Active') : t('Blocked')),
+      '#new' => array($new_user->status ? t('Active') : t('Blocked')),
+    );
+  }
+  return $row;
+}
+
+/**
+ * Private callback function to render the timezone field.
+ */
+function _user_entity_diff_additional_options_timezone($old_user, $new_user, $context) {
+  $row = array(
+    '#name' => t('Time zone'),
+    '#states' => array(),
+    '#weight' => -1,
+    '#settings' => array(),
+  );
+  $system_time_zones = system_time_zones(TRUE);
+  $old_zone = isset($old_user->timezone) ? $old_user->timezone : '';
+  $new_zone = isset($new_user->timezone) ? $new_user->timezone : '';
+
+  foreach ($context['states'] as $state) {
+    $row['#states'][$state] = array(
+      '#old' => array(isset($system_time_zones[$old_zone]) ? $system_time_zones[$old_zone] : t('- None selected -')),
+      '#new' => array(isset($system_time_zones[$new_zone]) ? $system_time_zones[$new_zone] : t('- None selected -')),
+    );
+  }
+  return $row;
+}
+
+/**
+ * Private callback function to render the password field.
+ */
+function _user_entity_diff_additional_options_password($old_user, $new_user, $context) {
+  $row = array(
+    '#name' => t('Password Hash'),
+    '#states' => array(),
+    '#weight' => -1,
+    '#settings' => array(),
+  );
+
+  foreach ($context['states'] as $state) {
+    $row['#states'][$state] = array(
+      '#old' => array($old_user->pass),
+      '#new' => array($new_user->pass),
+    );
+  }
+  return $row;
+}
+
+/**
+ * Private callback function to render the roles field.
+ */
+function _user_entity_diff_additional_options_roles($old_user, $new_user, $context) {
+  $row = array(
+    '#name' => t('Roles'),
+    '#states' => array(),
+    '#weight' => -1,
+    '#settings' => array(),
+  );
+
+  $roles = user_roles(TRUE);
+  unset($roles[DRUPAL_AUTHENTICATED_RID]);
+  foreach ($context['states'] as $state) {
+    $row['#states'][$state] = array(
+      '#old' => array(implode("\n", array_intersect_key($roles, $old_user->roles))),
+      '#new' => array(implode("\n", array_intersect_key($roles, $new_user->roles))),
+    );
+  }
+  return $row;
+}

+ 54 - 47
sites/all/modules/contrib/content/diff/js/diff.js

@@ -1,58 +1,65 @@
 (function ($) {
 
-Drupal.behaviors.diffRevisions = {
-  attach: function (context, settings) {
-    var $rows = $('table.diff-revisions tbody tr');
-    function updateDiffRadios() {
-      var newTd = false;
-      var oldTd = false;
-      if (!$rows.length) {
-        return true;
-      }
-      $rows.removeClass('selected').each(function() {
-        var $row = $(this);
-        $row.removeClass('selected');
-        var $inputs = $row.find('input[type="radio"]');
-        var $oldRadio = $inputs.filter('[name="old"]').eq(0);
-        var $newRadio = $inputs.filter('[name="new"]').eq(0);
-        if (!$oldRadio.length || !$newRadio.length) {
+  "use strict";
+  
+  Drupal.behaviors.diffRevisions = {
+    attach: function (context, settings) {
+      var $rows = $('table.diff-revisions tbody tr');
+      function updateDiffRadios() {
+        var newTd = false;
+        var oldTd = false;
+        if (!$rows.length) {
           return true;
         }
-        if ($oldRadio.attr('checked')) {
-          oldTd = true;
-          $row.addClass('selected');
-          $oldRadio.css('visibility', 'visible');
-          $newRadio.css('visibility', 'hidden');
-        } else if ($newRadio.attr('checked')) {
-          newTd = true;
-          $row.addClass('selected');
-          $oldRadio.css('visibility', 'hidden');
-          $newRadio.css('visibility', 'visible');
-        } else {
-          if (Drupal.settings.diffRevisionRadios == 'linear') {
-            if (newTd && oldTd) {
-              $oldRadio.css('visibility', 'visible');
-              $newRadio.css('visibility', 'hidden');
-            } else if (newTd) {
+        $rows.removeClass('selected').each(function() {
+          var $row = $(this);
+          $row.removeClass('selected');
+          var $inputs = $row.find('input[type="radio"]');
+          var $oldRadio = $inputs.filter('[name="old"]').eq(0);
+          var $newRadio = $inputs.filter('[name="new"]').eq(0);
+          if (!$oldRadio.length || !$newRadio.length) {
+            return true;
+          }
+          if ($oldRadio.attr('checked')) {
+            oldTd = true;
+            $row.addClass('selected');
+            $oldRadio.css('visibility', 'visible');
+            $newRadio.css('visibility', 'hidden');
+          }
+          else if ($newRadio.attr('checked')) {
+            newTd = true;
+            $row.addClass('selected');
+            $oldRadio.css('visibility', 'hidden');
+            $newRadio.css('visibility', 'visible');
+          }
+          else {
+            if (Drupal.settings.diffRevisionRadios == 'linear') {
+              if (newTd && oldTd) {
+                $oldRadio.css('visibility', 'visible');
+                $newRadio.css('visibility', 'hidden');
+              }
+              else if (newTd) {
+                $newRadio.css('visibility', 'visible');
+                $oldRadio.css('visibility', 'visible');
+              }
+              else {
+                $newRadio.css('visibility', 'visible');
+                $oldRadio.css('visibility', 'hidden');
+              }
+            }
+            else {
               $newRadio.css('visibility', 'visible');
               $oldRadio.css('visibility', 'visible');
-            } else {
-              $newRadio.css('visibility', 'visible');
-              $oldRadio.css('visibility', 'hidden');
             }
-          } else {
-            $newRadio.css('visibility', 'visible');
-            $oldRadio.css('visibility', 'visible');
           }
-        }
-      });
-      return true;
-    }
-    if (Drupal.settings.diffRevisionRadios) {
-      $rows.find('input[name="new"], input[name="old"]').click(updateDiffRadios);
-      updateDiffRadios();
+        });
+        return true;
+      }
+      if (Drupal.settings.diffRevisionRadios) {
+        $rows.find('input[name="new"], input[name="old"]').click(updateDiffRadios);
+        updateDiffRadios();
+      }
     }
-  }
-};
+  };
 
 })(jQuery);

+ 4 - 1
sites/all/modules/contrib/content/diff/readme.txt

@@ -58,13 +58,16 @@ e.g. http://www.example.com/admin/structure/types/manage/page
   
     i) "Show View changes button on node edit form" adds a new "Preview" like
         submit button to node editing pages. This shows a diff preview.
+        
+        This can be conditionally restricted per role using the user permission
+        "Access View changes button".
   
     ii) "Enable the Revisions page for this content type" adds the revisioning
          tab to content. This allows users to compare between various revisions
          that they have access to.
   
     iii) "Standard comparison preview" option allows you to control how the most
-          current revision is show on the revision comparision page.
+          current revision is shown on the revision comparison page.
        
   b) Publishing options
 

+ 3 - 3
sites/all/modules/contrib/dev/ctools/bulk_export/bulk_export.info

@@ -6,9 +6,9 @@ package = Chaos tool suite
 version = CTOOLS_MODULE_VERSION
 
 
-; Information added by Drupal.org packaging script on 2016-10-16
-version = "7.x-1.11"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
 core = "7.x"
 project = "ctools"
-datestamp = "1476581654"
+datestamp = "1479787162"
 

+ 1 - 0
sites/all/modules/contrib/dev/ctools/css/button.css

@@ -19,6 +19,7 @@
 .ctools-button-processed .ctools-content ul {
   list-style-image: none;
   list-style-type: none;
+  margin-left: 0;
 }
 
 .ctools-button-processed li {

+ 4 - 1
sites/all/modules/contrib/dev/ctools/ctools.api.php

@@ -199,7 +199,10 @@ function hook_ctools_render_alter(&$info, &$page, &$context) {
  * or categories or to rename content on specific sites.
  */
 function hook_ctools_content_subtype_alter($subtype, $plugin) {
-  $subtype['render last'] = TRUE;
+  // Force a particular subtype of a particular plugin to render last.
+  if ($plugin['module'] == 'some_plugin_module' && $plugin['name'] == 'some_plugin_name' && $subtype['subtype_id'] == 'my_subtype_id') {
+    $subtype['render last'] = TRUE;
+  }
 }
 
 /**

+ 11 - 3
sites/all/modules/contrib/dev/ctools/ctools.info

@@ -6,11 +6,19 @@ files[] = includes/context.inc
 files[] = includes/css-cache.inc
 files[] = includes/math-expr.inc
 files[] = includes/stylizer.inc
+
+; Tests.
+files[] = tests/context.test
+files[] = tests/css.test
 files[] = tests/css_cache.test
+files[] = tests/ctools.plugins.test
+files[] = tests/math_expression.test
+files[] = tests/math_expression_stack.test
+files[] = tests/object_cache.test
 
-; Information added by Drupal.org packaging script on 2016-10-16
-version = "7.x-1.11"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
 core = "7.x"
 project = "ctools"
-datestamp = "1476581654"
+datestamp = "1479787162"
 

+ 3 - 3
sites/all/modules/contrib/dev/ctools/ctools_access_ruleset/ctools_access_ruleset.info

@@ -5,9 +5,9 @@ package = Chaos tool suite
 version = CTOOLS_MODULE_VERSION
 dependencies[] = ctools
 
-; Information added by Drupal.org packaging script on 2016-10-16
-version = "7.x-1.11"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
 core = "7.x"
 project = "ctools"
-datestamp = "1476581654"
+datestamp = "1479787162"
 

+ 3 - 3
sites/all/modules/contrib/dev/ctools/ctools_ajax_sample/ctools_ajax_sample.info

@@ -5,9 +5,9 @@ version = CTOOLS_MODULE_VERSION
 dependencies[] = ctools
 core = 7.x
 
-; Information added by Drupal.org packaging script on 2016-10-16
-version = "7.x-1.11"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
 core = "7.x"
 project = "ctools"
-datestamp = "1476581654"
+datestamp = "1479787162"
 

+ 3 - 3
sites/all/modules/contrib/dev/ctools/ctools_custom_content/ctools_custom_content.info

@@ -5,9 +5,9 @@ package = Chaos tool suite
 version = CTOOLS_MODULE_VERSION
 dependencies[] = ctools
 
-; Information added by Drupal.org packaging script on 2016-10-16
-version = "7.x-1.11"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
 core = "7.x"
 project = "ctools"
-datestamp = "1476581654"
+datestamp = "1479787162"
 

+ 3 - 3
sites/all/modules/contrib/dev/ctools/ctools_plugin_example/ctools_plugin_example.info

@@ -8,9 +8,9 @@ dependencies[] = page_manager
 dependencies[] = advanced_help
 core = 7.x
 
-; Information added by Drupal.org packaging script on 2016-10-16
-version = "7.x-1.11"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
 core = "7.x"
 project = "ctools"
-datestamp = "1476581654"
+datestamp = "1479787162"
 

+ 1 - 1
sites/all/modules/contrib/dev/ctools/drush/ctools.drush.inc

@@ -64,7 +64,7 @@ function ctools_drush_command() {
       'machine names' => 'Space separated list of exportables you want to view.',
     ),
     'options' => array(
-      'indent' => 'The string to use for indentation when dispalying the exportable export code. Defaults to \'\'.',
+      'indent' => 'The string to use for indentation when displaying the exportable export code. Defaults to \'\'.',
       'no-colour' => 'Remove any colour formatting from export string output. Ideal if you are sending the output of this command to a file.',
       'module' => $module_text,
       'all' => $all_text,

+ 8 - 2
sites/all/modules/contrib/dev/ctools/includes/content.inc

@@ -155,6 +155,11 @@ function ctools_content_get_subtypes($type) {
   // Walk through the subtypes and ensure minimal settings are
   // retained.
   foreach ($subtypes as $id => $subtype) {
+    // Ensure that the 'subtype_id' value exists.
+    if (!isset($subtype['subtype_id'])) {
+      $subtype['subtype_id'] = $id;
+    }
+
     // Use exact name since this is a modify by reference.
     ctools_content_prepare_subtype($subtypes[$id], $plugin);
   }
@@ -217,6 +222,7 @@ function ctools_content_prepare_subtype(&$subtype, $plugin) {
     }
   }
 
+  // Trigger hook_ctools_content_subtype_alter().
   drupal_alter('ctools_content_subtype', $subtype, $plugin);
 }
 
@@ -241,8 +247,8 @@ function ctools_content_prepare_subtype(&$subtype, $plugin) {
  *   Any incoming content, if this display is a wrapper.
  *
  * @return
- *   The content as rendered by the plugin. This content should be an array
- *   with the following possible keys:
+ *   The content as rendered by the plugin, or NULL.
+ *   This content should be an object with the following possible properties:
  *   - title: The safe to render title of the content.
  *   - title_heading: The title heading.
  *   - content: The safe to render HTML content.

+ 0 - 1
sites/all/modules/contrib/dev/ctools/includes/context-access-admin.inc

@@ -367,7 +367,6 @@ function ctools_access_ajax_edit($fragment = NULL, $id = NULL) {
     'contexts' => $contexts,
     'title' => t('Edit criteria'),
     'ajax' => TRUE,
-    'ajax' => TRUE,
     'modal' => TRUE,
     'modal return' => TRUE,
   );

+ 11 - 6
sites/all/modules/contrib/dev/ctools/includes/context.inc

@@ -676,14 +676,19 @@ function ctools_context_keyword_substitute($string, $keywords, $contexts, $conve
         }
       }
 
-      if (empty($context_keywords[$context]) || !empty($context_keywords[$context]->empty)) {
-        $keywords['%' . $keyword] = '';
-      }
-      else if (!empty($converter)) {
-        $keywords['%' . $keyword] = ctools_context_convert_context($context_keywords[$context], $converter, $converter_options);
+      if (!isset($context_keywords[$context])) {
+        $keywords['%' . $keyword] = '%' . $keyword;
       }
       else {
-        $keywords['%' . $keyword] = $context_keywords[$keyword]->title;
+        if (empty($context_keywords[$context]) || !empty($context_keywords[$context]->empty)) {
+          $keywords['%' . $keyword] = '';
+        }
+        else if (!empty($converter)) {
+          $keywords['%' . $keyword] = ctools_context_convert_context($context_keywords[$context], $converter, $converter_options);
+        }
+        else {
+          $keywords['%' . $keyword] = $context_keywords[$keyword]->title;
+        }
       }
     }
   }

+ 21 - 17
sites/all/modules/contrib/dev/ctools/includes/plugins.inc

@@ -200,18 +200,18 @@ function ctools_plugin_api_get_hook($owner, $api) {
 /**
  * Fetch a group of plugins by name.
  *
- * @param $module
- *   The name of the module that utilizes this plugin system. It will be
- *   used to call hook_ctools_plugin_$plugin() to get more data about the plugin.
- * @param $type
+ * @param string $module
+ *   The name of the module that utilizes this plugin system. It will be used to
+ *   get more data about the plugin as defined on hook_ctools_plugin_type().
+ * @param string $type
  *   The type identifier of the plugin.
- * @param $id
+ * @param string $id
  *   If specified, return only information about plugin with this identifier.
  *   The system will do its utmost to load only plugins with this id.
  *
- * @return
- *   An array of information arrays about the plugins received. The contents
- *   of the array are specific to the plugin.
+ * @return array
+ *   An array of information arrays about the plugins received. The contents of
+ *   the array are specific to the plugin.
  */
 function ctools_get_plugins($module, $type, $id = NULL) {
   // Store local caches of plugins and plugin info so we don't have to do full
@@ -224,10 +224,14 @@ function ctools_get_plugins($module, $type, $id = NULL) {
 
   $info = ctools_plugin_get_plugin_type_info();
 
-  // Bail out noisily if an invalid module/type combination is requested.
   if (!isset($info[$module][$type])) {
-    watchdog('ctools', 'Invalid plugin module/type combination requested: module @module and type @type', array('@module' => $module, '@type' => $type), WATCHDOG_ERROR);
-    return array();
+    // If we don't find the plugin we attempt a cache rebuild before bailing out
+    $info = ctools_plugin_get_plugin_type_info(TRUE);
+    // Bail out noisily if an invalid module/type combination is requested.
+    if (!isset($info[$module][$type])) {
+      watchdog('ctools', 'Invalid plugin module/type combination requested: module @module and type @type', array('@module' => $module, '@type' => $type), WATCHDOG_ERROR);
+      return array();
+    }
   }
 
   // Make sure our plugins array is populated.
@@ -235,8 +239,8 @@ function ctools_get_plugins($module, $type, $id = NULL) {
     $plugins[$module][$type] = array();
   }
 
-  // Attempt to shortcut this whole piece of code if we already have
-  // the requested plugin:
+  // Attempt to shortcut this whole piece of code if we already have the
+  // requested plugin:
   if ($id && array_key_exists($id, $plugins[$module][$type])) {
     return $plugins[$module][$type][$id];
   }
@@ -271,8 +275,8 @@ function ctools_get_plugins($module, $type, $id = NULL) {
     $plugins[$module][$type] = ctools_plugin_load_hooks($info[$module][$type]);
   }
 
-  // Then see if we should load all files. We only do this if we
-  // want a list of all plugins or there was a cache miss.
+  // Then see if we should load all files. We only do this if we want a list of
+  // all plugins or there was a cache miss.
   if (empty($setup[$module][$type]) && ($build_cache || !$id)) {
     $setup[$module][$type] = TRUE;
     $plugins[$module][$type] = array_merge($plugins[$module][$type], ctools_plugin_load_includes($info[$module][$type]));
@@ -296,8 +300,8 @@ function ctools_get_plugins($module, $type, $id = NULL) {
   }
 
 
-  // If we were told earlier that this is cacheable and the cache was
-  // empty, give something back.
+  // If we were told earlier that this is cacheable and the cache was empty,
+  // give something back.
   if ($build_cache) {
     cache_set("plugins:$module:$type", $plugins[$module][$type], $info[$module][$type]['cache table']);
   }

+ 3 - 1
sites/all/modules/contrib/dev/ctools/includes/uuid.inc

@@ -9,7 +9,9 @@
 /**
  * Pattern for detecting a valid UUID.
  */
-define('UUID_PATTERN', '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}');
+if (!defined('UUID_PATTERN')) {
+  define('UUID_PATTERN', '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}');
+}
 
 /**
  * Generates a UUID using the Windows internal GUID generator.

+ 1 - 1
sites/all/modules/contrib/dev/ctools/page_manager/help/getting-started.html

@@ -4,7 +4,7 @@ Note: this page is currently very preliminary. Please visit <a href="http://drup
 This is a quick summary:
 
 <ul>
-<li>Visit administer >> site building >> pages to get to the primary page manager interface.</li>
+<li>Visit administer >> structure >> pages to get to the primary page manager interface.</li>
 <li>You can add custom pages for your basic landing pages, front pages, whatever you like for normal content display.</li>
 <li>You can use the system pages to create finer control of how taxonomy vocabularies, nodes and user profiles are displayed.</li>
 <li>When you add your first custom page, do not bother with the optional features. You will not need these until you get to more advanced tasks.</li>

+ 6 - 0
sites/all/modules/contrib/dev/ctools/page_manager/page_manager.admin.inc

@@ -1688,6 +1688,12 @@ function page_manager_handler_clone_submit(&$form, &$form_state) {
 
   page_manager_handler_add_to_page($form_state['page'], $handler, $form_state['values']['title']);
 
+  // Variant is cloned and added to the Page. Ensure the uuids are re-generated.
+  panels_panel_context_get_display($handler);
+  if (isset($handler->conf['display']) && method_exists($handler->conf['display'], 'clone_display')) {
+    $handler->conf['display'] = $handler->conf['display']->clone_display();
+  }
+
   $plugin = page_manager_get_task_handler($handler->handler);
   // It has no forms at all. Add the variant and go to its first operation.
   $keys = array_keys($plugin['operations']);

+ 3 - 3
sites/all/modules/contrib/dev/ctools/page_manager/page_manager.info

@@ -5,9 +5,9 @@ dependencies[] = ctools
 package = Chaos tool suite
 version = CTOOLS_MODULE_VERSION
 
-; Information added by Drupal.org packaging script on 2016-10-16
-version = "7.x-1.11"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
 core = "7.x"
 project = "ctools"
-datestamp = "1476581654"
+datestamp = "1479787162"
 

+ 9 - 0
sites/all/modules/contrib/dev/ctools/page_manager/plugins/tasks/page.admin.inc

@@ -1462,6 +1462,15 @@ function page_manager_page_form_clone_submit(&$form, &$form_state) {
   $original->path = $form_state['values']['path'];
 
   $handlers = !empty($form_state['values']['handlers']) ? $form_state['page']->handlers : FALSE;
+  // Ensure the handler uuids are re-generated.
+  if ($handlers) {
+    foreach ($handlers as &$handler) {
+      if (isset($handler->conf['display']) && method_exists($handler->conf['display'], 'clone_display')) {
+        $handler->conf['display'] = $handler->conf['display']->clone_display();
+      }
+    }
+  }
+
   // Export the handler, which is a fantastic way to clean database IDs out of it.
   $export = page_manager_page_export($original, $handlers);
   ob_start();

+ 1 - 0
sites/all/modules/contrib/dev/ctools/plugins/arguments/terms.inc

@@ -65,6 +65,7 @@ function ctools_terms_breadcrumb($conf, $context) {
     return;
   }
 
+  $current = new stdClass();
   $current->tid = $context->tids[0];
   $breadcrumb = array();
   while ($parents = taxonomy_get_parents($current->tid)) {

+ 3 - 3
sites/all/modules/contrib/dev/ctools/plugins/content_types/block/block.inc

@@ -372,9 +372,9 @@ function profile_ctools_block_info($module, $delta, &$info) {
 }
 
 function book_ctools_block_info($module, $delta, &$info) {
-  // Hide the book navigation block which isn't as rich as what we can
-  // do with context.
-  $info = NULL;
+  $info['title'] = t('Book navigation menu');
+  $info['icon'] = 'icon_core_block_menu.png';
+  $info['category'] = t('Node');
 }
 
 function blog_ctools_block_info($module, $delta, &$info) {

+ 101 - 0
sites/all/modules/contrib/dev/ctools/plugins/content_types/node_context/node_book_menu.inc

@@ -0,0 +1,101 @@
+<?php
+
+if (module_exists('book')) {
+  /**
+   * Plugins are described by creating a $plugin array which will be used
+   * by the system that includes this file.
+   */
+  $plugin = array(
+    'single' => TRUE,
+    'title' => t('Book navigation menu'),
+    'icon' => '../block/icon_core_block_menu.png',
+    'description' => t('The book menu belonging to the current book node.'),
+    'required context' => new ctools_context_required(t('Node'), 'node'),
+    'category' => t('Node'),
+  );
+}
+
+function ctools_node_book_menu_content_type_render($subtype, $conf, $panel_args, $context) {
+  $node = isset($context->data) ? clone($context->data) : NULL;
+  $block = new stdClass();
+  $block->module = 'book_menu';
+
+  if ($conf['override_title']) {
+    $block->title = t($conf['override_title_text']);
+  }
+  else {
+    $block->title = t('Book navigation menu');
+  }
+  if ($node) {
+    $block->delta = $node->nid;
+    // TODO: the value is not available somehow?!?
+    $book_block_mode = isset($conf['book_block_mode']) ? $conf['book_block_mode'] : 'book pages';
+
+    // Code below is taken from function book_block_view().
+    $current_bid = empty($node->book['bid']) ? 0 : $node->book['bid'];
+
+    if ($book_block_mode === 'all pages') {
+      $block->subject = t('Book navigation');
+      $book_menus = array();
+      $pseudo_tree = array(0 => array('below' => FALSE));
+      foreach (book_get_books() as $book_id => $book) {
+        if ($book['bid'] === $current_bid) {
+          // If the current page is a node associated with a book, the menu
+          // needs to be retrieved.
+          $book_menus[$book_id] = menu_tree_output(menu_tree_all_data($node->book['menu_name'], $node->book));
+        }
+        else {
+          // Since we know we will only display a link to the top node, there
+          // is no reason to run an additional menu tree query for each book.
+          $book['in_active_trail'] = FALSE;
+          // Check whether user can access the book link.
+          $book_node = node_load($book['nid']);
+          $book['access'] = node_access('view', $book_node);
+          $pseudo_tree[0]['link'] = $book;
+          $book_menus[$book_id] = menu_tree_output($pseudo_tree);
+        }
+      }
+      $book_menus['#theme'] = 'book_all_books_block';
+      $block->content = $book_menus;
+    }
+    elseif ($current_bid) {
+      // Only display this block when the user is browsing a book.
+      $select = db_select('node', 'n')
+          ->fields('n', array('title'))
+          ->condition('n.nid', $node->book['bid'])
+          ->addTag('node_access');
+      $title = $select->execute()->fetchField();
+      // Only show the block if the user has view access for the top-level node.
+      if ($title) {
+        $tree = menu_tree_all_data($node->book['menu_name'], $node->book);
+        // There should only be one element at the top level.
+        $data = array_shift($tree);
+        // TODO: subject is not rendered
+        $block->subject = theme('book_title_link', array('link' => $data['link']));
+        $block->content = ($data['below']) ? menu_tree_output($data['below']) : '';
+      }
+    }
+  }
+  else {
+    $block->content = t('Book navigation pager goes here.');
+    $block->delta = 'unknown';
+  }
+
+  return $block;
+}
+
+function ctools_node_book_menu_content_type_admin_title($subtype, $conf, $context) {
+  return t('"@s" book navigation pager', array('@s' => $context->identifier));
+}
+
+function ctools_node_book_menu_content_type_edit_form($form, &$form_state) {
+  // Grab block form from the book module.
+  $block_form = book_block_configure($delta = '');
+  // TODO: this does not work yet.
+  //       See TODO in: ctools_node_book_menu_content_type_render
+  if (isset($form_state['input']['book_block_mode'])) {
+    $block_form['book_block_mode']['#default_value'] = $form_state['input']['book_block_mode'];
+  }
+  $form += $block_form;
+  return $form;
+}

+ 6 - 6
sites/all/modules/contrib/dev/ctools/plugins/content_types/node_context/node_book_nav.inc

@@ -7,9 +7,9 @@ if (module_exists('book')) {
    */
   $plugin = array(
     'single' => TRUE,
-    'title' => t('Book navigation'),
-    'icon' => 'icon_node.png',
-    'description' => t('The navigation menu the book the node belongs to.'),
+    'title' => t('Book navigation pager'),
+    'icon' => '../block/icon_core_booknavigation.png',
+    'description' => t('The navigational pager and sub pages of the current book node.'),
     'required context' => new ctools_context_required(t('Node'), 'node'),
     'category' => t('Node'),
   );
@@ -20,13 +20,13 @@ function ctools_node_book_nav_content_type_render($subtype, $conf, $panel_args,
   $block = new stdClass();
   $block->module = 'book_nav';
 
-  $block->title = t('Book navigation');
+  $block->title = t('Book navigation pager');
   if ($node) {
     $block->content = isset($node->book) ? theme('book_navigation', array('book_link' => $node->book)) : '';
     $block->delta = $node->nid;
   }
   else {
-    $block->content = t('Book navigation goes here.');
+    $block->content = t('Book navigation pager goes here.');
     $block->delta = 'unknown';
   }
 
@@ -34,7 +34,7 @@ function ctools_node_book_nav_content_type_render($subtype, $conf, $panel_args,
 }
 
 function ctools_node_book_nav_content_type_admin_title($subtype, $conf, $context) {
-  return t('"@s" book navigation', array('@s' => $context->identifier));
+  return t('"@s" book navigation pager', array('@s' => $context->identifier));
 }
 
 function ctools_node_book_nav_content_type_edit_form($form, &$form_state) {

+ 3 - 3
sites/all/modules/contrib/dev/ctools/stylizer/stylizer.info

@@ -6,9 +6,9 @@ version = CTOOLS_MODULE_VERSION
 dependencies[] = ctools
 dependencies[] = color
 
-; Information added by Drupal.org packaging script on 2016-10-16
-version = "7.x-1.11"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
 core = "7.x"
 project = "ctools"
-datestamp = "1476581654"
+datestamp = "1479787162"
 

+ 3 - 3
sites/all/modules/contrib/dev/ctools/term_depth/term_depth.info

@@ -5,9 +5,9 @@ dependencies[] = ctools
 package = Chaos tool suite
 version = CTOOLS_MODULE_VERSION
 
-; Information added by Drupal.org packaging script on 2016-10-16
-version = "7.x-1.11"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
 core = "7.x"
 project = "ctools"
-datestamp = "1476581654"
+datestamp = "1479787162"
 

+ 25 - 1
sites/all/modules/contrib/dev/ctools/tests/context.test

@@ -5,7 +5,7 @@ class CtoolsContextKeywordsSubstitutionTestCase extends DrupalWebTestCase {
     return array(
       'name' => 'Keywords substitution',
       'description' => 'Verify that keywords are properly replaced with data.',
-      'group' => 'Chaos Tools Suite',
+      'group' => 'ctools',
     );
   }
 
@@ -51,6 +51,30 @@ class CtoolsContextKeywordsSubstitutionTestCase extends DrupalWebTestCase {
         "%{$node->title}",
         t('Keyword after escaped and unescaped percent sign has been replaced.'),
       ),
+      '%%foo:bar' => array(
+        "%foo:bar",
+        t('Non-existant context ignored.'),
+      ),
+      'There was about 20%-30% difference in price.' => array(
+        'There was about 20%-30% difference in price.',
+        t('Non-keyword percent sign left untouched.'),
+      ),
+      'href="my%20file%2dname.pdf"' => array(
+        'href="my%20file%2dname.pdf"',
+        t('HTTP URL escape left untouched.'),
+      ),
+      'href="my%a0file%fdname.pdf"' => array(
+        'href="my%a0file%fdname.pdf"',
+        t('HTTP URL escape (high-chars) left untouched.'),
+      ),
+      '<a href="http://www.example.com/here%20is%20a%20pdf.pdf">Click here!</a>' => array(
+        '<a href="http://www.example.com/here%20is%20a%20pdf.pdf">Click here!</a>',
+        t('HTTP URL escape percent sign left untouched in HTML.'),
+      ),
+      'SELECT * FROM {table} WHERE field = "%s"' => array(
+        'SELECT * FROM {table} WHERE field = "%s"',
+        t('SQL percent sign left untouched.'),
+      ),
     );
     foreach ($checks as $string => $expectations) {
       list($expected_result, $message) = $expectations;

+ 1 - 1
sites/all/modules/contrib/dev/ctools/tests/css.test

@@ -12,7 +12,7 @@ class CtoolsCssTestCase extends DrupalWebTestCase {
     return array(
       'name' => 'CSS Tools tests',
       'description' => '...',
-      'group' => 'Chaos Tools Suite',
+      'group' => 'ctools',
     );
   }
 

+ 1 - 1
sites/all/modules/contrib/dev/ctools/tests/css_cache.test

@@ -16,7 +16,7 @@ class CtoolsObjectCache extends DrupalWebTestCase {
     return array(
       'name' => 'Ctools CSS cache',
       'description' => 'Tests the custom CSS cache handler.',
-      'group' => 'Chaos Tools Suite',
+      'group' => 'ctools',
     );
   }
 

+ 1 - 1
sites/all/modules/contrib/dev/ctools/tests/ctools.plugins.test

@@ -12,7 +12,7 @@ class CtoolsPluginsGetInfoTestCase extends DrupalWebTestCase {
     return array(
       'name' => 'Get plugin info',
       'description' => 'Verify that plugin type definitions can properly set and overide values.',
-      'group' => 'Chaos Tools Suite',
+      'group' => 'ctools',
     );
   }
 

+ 1 - 1
sites/all/modules/contrib/dev/ctools/tests/ctools_export_test/ctools_export.test

@@ -14,7 +14,7 @@ class CtoolsExportCrudTestCase extends DrupalWebTestCase {
     return array(
       'name' => 'CTools export CRUD tests',
       'description' => 'Test the CRUD functionality for the ctools export system.',
-      'group' => 'Chaos Tools Suite',
+      'group' => 'ctools',
     );
   }
 

+ 3 - 3
sites/all/modules/contrib/dev/ctools/tests/ctools_export_test/ctools_export_test.info

@@ -8,9 +8,9 @@ hidden = TRUE
 
 files[] = ctools_export.test
 
-; Information added by Drupal.org packaging script on 2016-10-16
-version = "7.x-1.11"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
 core = "7.x"
 project = "ctools"
-datestamp = "1476581654"
+datestamp = "1479787162"
 

+ 3 - 3
sites/all/modules/contrib/dev/ctools/tests/ctools_plugin_test.info

@@ -12,9 +12,9 @@ files[] = math_expression.test
 files[] = math_expression_stack.test
 hidden = TRUE
 
-; Information added by Drupal.org packaging script on 2016-10-16
-version = "7.x-1.11"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
 core = "7.x"
 project = "ctools"
-datestamp = "1476581654"
+datestamp = "1479787162"
 

+ 1 - 1
sites/all/modules/contrib/dev/ctools/tests/math_expression.test

@@ -13,7 +13,7 @@ class CtoolsMathExpressionTestCase extends DrupalWebTestCase {
     return array(
       'name' => 'CTools math expression tests',
       'description' => 'Test the math expression library of ctools.',
-      'group' => 'Chaos Tools Suite',
+      'group' => 'ctools',
     );
   }
 

+ 1 - 1
sites/all/modules/contrib/dev/ctools/tests/math_expression_stack.test

@@ -13,7 +13,7 @@ class CtoolsMathExpressionStackTestCase extends DrupalWebTestCase {
     return array(
       'name' => 'CTools math expression stack tests',
       'description' => 'Test the stack class of the math expression library.',
-      'group' => 'Chaos Tools Suite',
+      'group' => 'ctools',
     );
   }
 

+ 1 - 1
sites/all/modules/contrib/dev/ctools/tests/object_cache.test

@@ -12,7 +12,7 @@ class CtoolsObjectCache extends DrupalWebTestCase {
     return array(
       'name' => 'Ctools object cache storage',
       'description' => 'Verify that objects are written, readable and lockable.',
-      'group' => 'Chaos Tools Suite',
+      'group' => 'ctools',
     );
   }
 

+ 3 - 3
sites/all/modules/contrib/dev/ctools/views_content/views_content.info

@@ -10,9 +10,9 @@ files[] = plugins/views/views_content_plugin_display_ctools_context.inc
 files[] = plugins/views/views_content_plugin_display_panel_pane.inc
 files[] = plugins/views/views_content_plugin_style_ctools_context.inc
 
-; Information added by Drupal.org packaging script on 2016-10-16
-version = "7.x-1.11"
+; Information added by Drupal.org packaging script on 2016-11-22
+version = "7.x-1.12"
 core = "7.x"
 project = "ctools"
-datestamp = "1476581654"
+datestamp = "1479787162"
 

+ 27 - 2
sites/all/modules/contrib/fields/date/date.field.inc

@@ -28,6 +28,7 @@ function date_field_formatter_info() {
       'settings' => array(
         'interval' => 2,
         'interval_display' => 'time ago',
+        'use_end_date' => false,
       ),
     ),
     'date_plain' => array(
@@ -207,7 +208,7 @@ function date_field_formatter_view($entity_type, $entity, $field, $instance, $la
           $variables['item'] = $item;
           $variables['dates'] = date_formatter_process($formatter, $entity_type, $entity, $field, $instance, $langcode, $item, $display);
           $variables['attributes'] = !empty($rdf_mapping) ? rdf_rdfa_attributes($rdf_mapping, $item['value']) : array();
-          $variables['show_remaining_days'] = $display['settings']['show_remaining_days'];
+          $variables['show_remaining_days'] = isset($display['settings']['show_remaining_days']) ? $display['settings']['show_remaining_days'] : FALSE;
           $output = theme('date_display_combination', $variables);
           if (!empty($output)) {
             $element[$delta] = array('#markup' => $output);
@@ -322,7 +323,7 @@ function date_field_widget_info() {
   }
 
   // The date text widget should use an increment of 1.
-  $info['date_text']['increment'] = 1;
+  $info['date_text']['settings']['increment'] = 1;
 
   return $info;
 }
@@ -462,6 +463,14 @@ function date_field_instance_settings_form($field, $instance) {
   return _date_field_instance_settings_form($field, $instance);
 }
 
+/**
+ * Form validation handler for _date_field_instance_settings_form().
+ */
+function date_field_instance_settings_form_validate(&$form, &$form_state) {
+  module_load_include('inc', 'date', 'date_admin');
+  return _date_field_instance_settings_form_validate($form, $form_state);
+}
+
 /**
  * Implements hook_field_widget_settings_form().
  */
@@ -470,6 +479,14 @@ function date_field_widget_settings_form($field, $instance) {
   return _date_field_widget_settings_form($field, $instance);
 }
 
+/**
+ * Form validation handler for _date_field_widget_settings_form().
+ */
+function date_field_widget_settings_form_validate(&$form, &$form_state) {
+  module_load_include('inc', 'date', 'date_admin');
+  return _date_field_widget_settings_form_validate($form, $form_state);
+}
+
 /**
  * Implements hook_field_settings_form().
  */
@@ -478,6 +495,14 @@ function date_field_settings_form($field, $instance, $has_data) {
   return _date_field_settings_form($field, $instance, $has_data);
 }
 
+/**
+ * Form validation handler for _date_field_settings_form().
+ */
+function date_field_settings_validate(&$form, &$form_state) {
+  module_load_include('inc', 'date', 'date_admin');
+  return _date_field_settings_validate($form, $form_state);
+}
+
 /**
  * Implements hook_content_migrate_field_alter().
  *

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

@@ -13,10 +13,11 @@ files[] = tests/date_validation.test
 files[] = tests/date_timezone.test
 files[] = tests/date_views_pager.test
 files[] = tests/date_views_popup.test
+files[] = tests/date_form.test
 
-; Information added by Drupal.org packaging script on 2015-09-08
-version = "7.x-2.9"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
 core = "7.x"
 project = "date"
-datestamp = "1441727353"
+datestamp = "1491562090"
 

+ 8 - 0
sites/all/modules/contrib/fields/date/date.install

@@ -204,3 +204,11 @@ function date_update_7004() {
   field_cache_clear();
   drupal_set_message(t('Date text widgets have been updated to use an increment of 1.'));
 }
+
+/**
+ * Revisited: Date text widgets should always use an increment of 1.
+ */
+function date_update_7005() {
+  // @see https://www.drupal.org/node/1355256
+  date_update_7004();
+}

+ 4 - 1
sites/all/modules/contrib/fields/date/date.migrate.inc

@@ -1,10 +1,13 @@
 <?php
-
 /**
  * @file
  * Support for migration into Date fields.
  */
 
+if (!class_exists('MigrateFieldHandler')) {
+  return;
+}
+
 /**
  * Implements hook_migrate_api().
  */

+ 6 - 1
sites/all/modules/contrib/fields/date/date.module

@@ -443,7 +443,12 @@ function date_formatter_format($formatter, $settings, $granularity = array(), $l
       return 'date_plain';
 
     default:
-      $format = date_format_type_format($format_type, $langcode);
+      if ($format_type == 'custom') {
+        $format = $settings['custom_date_format'];
+      }
+      else {
+        $format = date_format_type_format($format_type, $langcode);
+      }
       break;
   }
 

+ 6 - 4
sites/all/modules/contrib/fields/date/date.theme

@@ -349,10 +349,10 @@ function theme_date_display_range($variables) {
   }
 
   // Wrap the result with the attributes.
-  $output = '<div class="date-display-range">' . t('!start-date to !end-date', array(
+  $output = '<span class="date-display-range">' . t('!start-date to !end-date', array(
     '!start-date' => $start_date,
     '!end-date' => $end_date,
-  )) . '</div>';
+  )) . '</span>';
 
   // Add remaining message and return.
   return $output . $show_remaining_days;
@@ -378,6 +378,8 @@ function theme_date_display_interval($variables) {
     'end_date' => $dates['value2']['local']['object'],
     'interval' => $options['interval'],
     'interval_display' => $options['interval_display'],
+    'use_end_date' => !empty($options['use_end_date']) ?
+      $options['use_end_date'] : FALSE,
   );
 
   if ($return = theme('date_time_ago', $time_ago_vars)) {
@@ -398,9 +400,9 @@ function theme_date_combo($variables) {
 
   // Group start/end items together in fieldset.
   $fieldset = array(
-    '#title' => field_filter_xss(t($element['#title'])) . ' ' . ($element['#delta'] > 0 ? intval($element['#delta'] + 1) : ''),
+    '#title' => field_filter_xss(t($element['#title'])) . ($element['#delta'] > 0 ? ' ' . intval($element['#delta'] + 1) : ''),
     '#value' => '',
-    '#description' => !empty($element['#fieldset_description']) ? $element['#fieldset_description'] : '',
+    '#description' => !empty($element['#description']) ? $element['#description'] : '',
     '#attributes' => array('class' => array('date-combo')),
     '#children' => $element['#children'],
   );

+ 25 - 6
sites/all/modules/contrib/fields/date/date_admin.inc

@@ -14,15 +14,24 @@ function date_default_formatter_settings_form($field, $instance, $view_mode, $fo
   $formatter = $display['type'];
   $form = array();
 
+  $date_formats = date_format_type_options();
   $form['format_type'] = array(
     '#title' => t('Choose how users view dates and times:'),
     '#type' => 'select',
-    '#options' => date_format_type_options(),
+    '#options' => $date_formats + array('custom' => t('Custom')),
     '#default_value' => $settings['format_type'],
     '#description' => t('To add or edit options, visit <a href="@date-time-page">Date and time settings</a>.', array('@date-time-page' => url('admin/config/regional/date-time'))),
     '#weight' => 0,
   );
 
+  $form['custom_date_format'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Custom date format'),
+    '#description' => t('If "Custom", see the <a href="@url" target="_blank">PHP manual</a> for date formats. Otherwise, enter the number of different time units to display, which defaults to 2.', array('@url' => 'http://php.net/manual/function.date.php')),
+    '#default_value' => isset($settings['custom_date_format']) ? $settings['custom_date_format'] : '',
+    '#dependency' => array('edit-options-settings-format-type' => array('custom')),
+  );
+
   $form['fromto'] = array(
     '#title' => t('Display:'),
     '#type' => 'select',
@@ -116,6 +125,14 @@ function date_interval_formatter_settings_form($field, $instance, $view_mode, $f
     '#default_value' => $settings['interval_display'],
     '#weight' => 0,
   );
+  if (!empty($field['settings']['todate'])) {
+    $form['use_end_date'] = array(
+      '#title' => t('Use End date'),
+      '#description' => 'Use the End date, instead of the start date',
+      '#type' => 'checkbox',
+      '#default_value' => $settings['use_end_date'],
+    );
+  }
   return $form;
 }
 
@@ -186,7 +203,9 @@ function date_interval_formatter_settings_summary($field, $instance, $view_mode)
   $display = $instance['display'][$view_mode];
   $settings = $display['settings'];
   $formatter = $display['type'];
-  $summary[] = t('Display time ago, showing @interval units.', array('@interval' => $settings['interval']));
+  $field = ($settings['use_end_date'] == 1) ? 'End' : 'Start';
+  $summary[] = t('Display time ago, showing @interval units. Using @field Date',
+      array('@interval' => $settings['interval'], '@field' => $field));
 
   return $summary;
 }
@@ -273,7 +292,7 @@ function _date_field_instance_settings_form($field, $instance) {
 /**
  * Form validation handler for _date_field_instance_settings_form().
  */
-function date_field_instance_settings_form_validate(&$form, &$form_state) {
+function _date_field_instance_settings_form_validate(&$form, &$form_state) {
   $settings = $form_state['values']['instance']['settings'];
 
   if ($settings['default_value'] == 'strtotime') {
@@ -459,7 +478,7 @@ function _date_field_widget_settings_form($field, $instance) {
 /**
  * Form validation handler for _date_field_widget_settings_form().
  */
-function date_field_widget_settings_form_validate(&$form, &$form_state) {
+function _date_field_widget_settings_form_validate(&$form, &$form_state) {
   // The widget settings are in the wrong place in the form because of #tree on
   // the top level.
   $settings = $form_state['values']['instance']['widget']['settings'];
@@ -561,7 +580,7 @@ function _date_field_settings_form($field, $instance, $has_data) {
   $form['cache_enabled'] = array(
     '#type' => 'checkbox',
     '#title' => t('Cache dates'),
-    '#description' => t('Date objects can be created and cached as date fields are loaded rather than when they are displayed to improve performance.'),
+    '#description' => t('Date objects can be created and cached as date fields are loaded, rather than when they are displayed, to improve performance.'),
     '#default_value' => !empty($settings['cache_enabled']),
     '#weight' => 10,
   );
@@ -594,7 +613,7 @@ function _date_field_settings_form($field, $instance, $has_data) {
 /**
  * Form validation handler for _date_field_settings_form().
  */
-function date_field_settings_validate(&$form, &$form_state) {
+function _date_field_settings_validate(&$form, &$form_state) {
   $field = &$form_state['values']['field'];
 
   if ($field['settings']['tz_handling'] == 'none') {

+ 3 - 3
sites/all/modules/contrib/fields/date/date_all_day/date_all_day.info

@@ -5,9 +5,9 @@ dependencies[] = date
 package = Date/Time
 core = 7.x
 
-; Information added by Drupal.org packaging script on 2015-09-08
-version = "7.x-2.9"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
 core = "7.x"
 project = "date"
-datestamp = "1441727353"
+datestamp = "1491562090"
 

+ 3 - 3
sites/all/modules/contrib/fields/date/date_api/date_api.info

@@ -9,9 +9,9 @@ stylesheets[all][] = date.css
 files[] = date_api.module
 files[] = date_api_sql.inc
 
-; Information added by Drupal.org packaging script on 2015-09-08
-version = "7.x-2.9"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
 core = "7.x"
 project = "date"
-datestamp = "1441727353"
+datestamp = "1491562090"
 

+ 20 - 6
sites/all/modules/contrib/fields/date/date_api/date_api.module

@@ -1833,9 +1833,10 @@ function date_format_interval($date, $granularity = 2, $display_ago = TRUE) {
 /**
  * A date object for the current time.
  *
- * @param object $timezone
- *   (optional) Optionally force time to a specific timezone, defaults to user
- *   timezone, if set, otherwise site timezone. Defaults to NULL.
+ * @param object|string|null $timezone
+ *   (optional) PHP DateTimeZone object, string or NULL allowed. Optionally
+ *   force time to a specific timezone, defaults to user timezone, if set,
+ *   otherwise site timezone. Defaults to NULL.
  *
  * @param bool $reset
  *   (optional) Static cache reset.
@@ -1844,11 +1845,16 @@ function date_format_interval($date, $granularity = 2, $display_ago = TRUE) {
  *   The current time as a date object.
  */
 function date_now($timezone = NULL, $reset = FALSE) {
+  $static_var = __FUNCTION__ . $timezone;
+  if ($timezone instanceof DateTimeZone) {
+    $static_var = __FUNCTION__ . $timezone->getName();
+  }
+
   if ($reset) {
-    drupal_static_reset(__FUNCTION__ . $timezone);
+    drupal_static_reset($static_var);
   }
 
-  $now = &drupal_static(__FUNCTION__ . $timezone);
+  $now = &drupal_static($static_var);
 
   if (!isset($now)) {
     $now = new DateObject('now', $timezone);
@@ -1920,7 +1926,12 @@ function date_days_in_month($year, $month) {
   // Pick a day in the middle of the month to avoid timezone shifts.
   $datetime = date_pad($year, 4) . '-' . date_pad($month) . '-15 00:00:00';
   $date = new DateObject($datetime);
-  return $date->format('t');
+  if ($date->errors) {
+    return FALSE;
+  }
+  else {
+    return $date->format('t');
+  }
 }
 
 /**
@@ -2075,6 +2086,9 @@ function date_iso_week_range($week, $year) {
   date_timezone_set($min_date, date_default_timezone_object());
 
   // Find the first day of the first ISO week in the year.
+  // If it's already a Monday, date_modify won't add a Monday,
+  // it will remain the same day. So add a Sunday first, then a Monday.
+  date_modify($min_date, '+1 Sunday');
   date_modify($min_date, '+1 Monday');
 
   // Jump ahead to the desired week for the beginning of the week range.

+ 2 - 2
sites/all/modules/contrib/fields/date/date_api/date_api_elements.inc

@@ -111,7 +111,7 @@ function date_default_date($element) {
   $format = DATE_FORMAT_DATETIME;
 
   // The text and popup widgets might return less than a full datetime string.
-  if (strlen($element['#default_value']) < 19) {
+  if (is_string($element['#default_value']) && strlen($element['#default_value']) < 19) {
     switch (strlen($element['#default_value'])) {
       case 16:
         $format = 'Y-m-d H:i';
@@ -319,7 +319,7 @@ function date_text_element_process($element, &$form_state, $form) {
 
   $element['#tree'] = TRUE;
   $element['#theme_wrappers'] = array('date_text');
-  $element['date']['#value'] = $element['#value']['date'];
+  $element['date']['#value'] = isset($element['#value']['date']) ? $element['#value']['date'] : '';
   $element['date']['#type'] = 'textfield';
   $element['date']['#weight'] = !empty($element['date']['#weight']) ? $element['date']['#weight'] : $element['#weight'];
   $element['date']['#attributes'] = array('class' => isset($element['#attributes']['class']) ? $element['#attributes']['class'] += array('date-date') : array('date-date'));

+ 11 - 2
sites/all/modules/contrib/fields/date/date_api/theme/theme.inc

@@ -194,6 +194,7 @@ function theme_date_calendar_day($variables) {
 function theme_date_time_ago($variables) {
   $start_date = $variables['start_date'];
   $end_date = $variables['end_date'];
+  $use_end_date = isset($variables['use_end_date']) ? $variables['use_end_date'] : false;
   $interval = !empty($variables['interval']) ? $variables['interval'] : 2;
   $display = isset($variables['interval_display']) ? $variables['interval_display'] : 'time ago';
 
@@ -202,12 +203,20 @@ function theme_date_time_ago($variables) {
     return;
   }
 
+  // We use the end date only when the option is checked.
+  if ($use_end_date){
+    $date = date_format($end_date, DATE_FORMAT_UNIX);
+  }
+  else {
+    $date = date_format($start_date, DATE_FORMAT_UNIX);
+  }
+
   // Time to compare dates to.
+
   $now = date_format(date_now(), DATE_FORMAT_UNIX);
-  $start = date_format($start_date, DATE_FORMAT_UNIX);
 
   // Will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence).
-  $time_diff = $now - $start;
+  $time_diff = $now - $date;
 
   // Uses the same options used by Views format_interval.
   switch ($display) {

+ 3 - 3
sites/all/modules/contrib/fields/date/date_context/date_context.info

@@ -8,9 +8,9 @@ dependencies[] = context
 
 files[] = date_context.module
 files[] = plugins/date_context_date_condition.inc
-; Information added by Drupal.org packaging script on 2015-09-08
-version = "7.x-2.9"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
 core = "7.x"
 project = "date"
-datestamp = "1441727353"
+datestamp = "1491562090"
 

+ 18 - 14
sites/all/modules/contrib/fields/date/date_elements.inc

@@ -74,7 +74,7 @@ function date_field_widget_form(&$form, &$form_state, $field, $instance, $langco
   // The repeating values will be re-generated when the repeat widget form is validated.
   // At this point we can't tell if this form element is going to be hidden by #access, and we're going to
   // lose all but the first value by doing this, so store the original values in case we need to replace them later.
-  if (!empty($field['settings']['repeat'])) {
+  if (!empty($field['settings']['repeat']) && module_exists('date_repeat_field')) {
     if ($delta == 0) {
       $form['#after_build'][] = 'date_repeat_after_build';
       $form_state['storage']['repeat_fields'][$field_name] = array_merge($form['#parents'], array($field_name));
@@ -337,8 +337,11 @@ function date_combo_element_process($element, &$form_state, $form) {
     '#date_label_position' => $instance['widget']['settings']['label_position'],
   );
 
-  $description = !empty($element['#description']) ? t($element['#description']) : '';
-  unset($element['#description']);
+  // Date repeat is a multiple value field. So the description is removed from
+  // the single element earlier. Let's get it back.
+  if (isset($element['show_repeat_settings']) && !empty($element['value']['#instance']['description'])) {
+    $element['#description'] = $element['value']['#instance']['description'];
+  }
 
   // Give this element the right type, using a Date API
   // or a Date Popup element type.
@@ -383,8 +386,7 @@ function date_combo_element_process($element, &$form_state, $form) {
     $element[$to_field]['#prefix'] = '';
     // Users with JS enabled will never see initially blank values for the end
     // date (see Drupal.date.EndDateHandler()), so hide the message for them.
-    $description .= '<span class="js-hide"> ' . t("Empty 'End date' values will use the 'Start date' values.") . '</span>';
-    $element['#fieldset_description'] = $description;
+    $element['#description'] .= '<span class="js-hide"> ' . t("Empty 'End date' values will use the 'Start date' values.") . '</span>';
     if ($field['settings']['todate'] == 'optional') {
       $element[$to_field]['#states'] = array(
         'visible' => array(
@@ -395,9 +397,6 @@ function date_combo_element_process($element, &$form_state, $form) {
       );
     }
   }
-  else {
-    $element[$from_field]['#description'] = $description;
-  }
 
   // Create label for error messages that make sense in multiple values
   // and when the title field is left blank.
@@ -474,6 +473,12 @@ function date_combo_validate($element, &$form_state) {
   $form_values = drupal_array_get_nested_value($form_state['values'], $element['#field_parents']);
   $form_input = drupal_array_get_nested_value($form_state['input'], $element['#field_parents']);
 
+  // Programmatically calling drupal_submit_form() does not always add the date
+  // combo to $form_state['input'].
+  if (empty($form_input[$field_name]) && !empty($form_values[$field_name])) {
+    form_set_value($element, $element['#date_items'], $form_state);
+    return;
+  }
   // If the whole field is empty and that's OK, stop now.
   if (empty($form_input[$field_name]) && !$element['#required']) {
     return;
@@ -546,11 +551,7 @@ function date_combo_validate($element, &$form_state) {
       return;
     }
   }
-  // Don't look for further errors if errors are already flagged
-  // because otherwise we'll show errors on the nested elements
-  // more than once.
-  elseif (!form_get_errors()) {
-
+  else {
     $timezone = !empty($item[$tz_field]) ? $item[$tz_field] : $element['#date_timezone'];
     $timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
     $element[$from_field]['#date_timezone'] = $timezone;
@@ -625,7 +626,10 @@ function date_combo_validate($element, &$form_state) {
       }
     }
   }
-  if (!empty($errors)) {
+  // Don't show further errors if errors are already flagged
+  // because otherwise we'll show errors on the nested elements
+  // more than once.
+  if (!form_get_errors() && !empty($errors)) {
     if ($field['cardinality']) {
       form_error($element, t('There are errors in @field_name value #@delta:', array('@field_name' => $instance['label'], '@delta' => $delta + 1)) . theme('item_list', array('items' => $errors)));
     }

+ 3 - 3
sites/all/modules/contrib/fields/date/date_migrate/date_migrate.info

@@ -4,9 +4,9 @@ core = 7.x
 package = Date/Time
 hidden = TRUE
 
-; Information added by Drupal.org packaging script on 2015-09-08
-version = "7.x-2.9"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
 core = "7.x"
 project = "date"
-datestamp = "1441727353"
+datestamp = "1491562090"
 

+ 3 - 3
sites/all/modules/contrib/fields/date/date_migrate/date_migrate_example/date_migrate_example.info

@@ -20,9 +20,9 @@ package = "Features"
 project = "date_migrate_example"
 version = "7.x-2.0"
 
-; Information added by Drupal.org packaging script on 2015-09-08
-version = "7.x-2.9"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
 core = "7.x"
 project = "date"
-datestamp = "1441727353"
+datestamp = "1491562090"
 

+ 3 - 3
sites/all/modules/contrib/fields/date/date_popup/date_popup.info

@@ -7,9 +7,9 @@ configure = admin/config/date/date_popup
 
 stylesheets[all][] = themes/datepicker.1.7.css
 
-; Information added by Drupal.org packaging script on 2015-09-08
-version = "7.x-2.9"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
 core = "7.x"
 project = "date"
-datestamp = "1441727353"
+datestamp = "1491562090"
 

+ 8 - 0
sites/all/modules/contrib/fields/date/date_popup/date_popup.js

@@ -14,6 +14,14 @@
           $(this).click(function(){
             $(this).focus();
           });
+          if (datePopup.settings.syncEndDate) {
+            $('.start-date-wrapper').each(function(){
+              var start_date_wrapper = this;
+              $(this).find('input:eq(0)').change(function(){
+                $(start_date_wrapper).next('.end-date-wrapper').find('input:eq(0)').val($(this).val());
+              });
+            });
+          }
           break;
 
         case 'timeEntry':

+ 24 - 4
sites/all/modules/contrib/fields/date/date_popup/date_popup.module

@@ -394,6 +394,10 @@ function date_popup_process_date_part(&$element) {
     'fromTo' => isset($fromto),
   );
 
+  if (!empty($element['#instance'])) {
+    $settings['syncEndDate'] = $element['#instance']['settings']['default_value2'] == 'sync';
+  }
+
   // Create a unique id for each set of custom settings.
   $id = date_popup_js_settings_id($element['#id'], 'datepicker', $settings);
 
@@ -474,10 +478,11 @@ function date_popup_process_time_part(&$element) {
       $grans = array('hour', 'minute', 'second');
       $time_granularity = array_intersect($granularity, $grans);
       $format = date_popup_format_to_popup_time(date_limit_format($element['#date_format'], $time_granularity), 'wvega');
+      $default_value = isset($element['#default_value']) ? $element['#default_value'] : '';
       // The first value in the dropdown list should be the same as the element
       // default_value, but it needs to be in JS format (i.e. milliseconds since
       // the epoch).
-      $start_time = new DateObject($element['#default_value'], $element['#date_timezone'], DATE_FORMAT_DATETIME);
+      $start_time = new DateObject($default_value, $element['#date_timezone'], DATE_FORMAT_DATETIME);
       date_increment_round($start_time, $element['#date_increment']);
       $start_time = $start_time->format(DATE_FORMAT_UNIX) * 1000;
       $settings = array(
@@ -580,7 +585,7 @@ function date_popup_validate($element, &$form_state) {
   // If something was input but there is no date, the date is invalid.
   // If the field is empty and required, set error message and return.
   $error_field = implode('][', $element['#parents']);
-  if (empty($date) || !empty($date->errors)) {
+  if ((empty($element['#value']['date']) && empty($element['#value']['time']))  || !empty($date->errors)) {
     if (is_object($date) && !empty($date->errors)) {
       $message = t('The value input for field %field is invalid:', array('%field' => $label));
       $message .= '<br />' . implode('<br />', $date->errors);
@@ -613,7 +618,9 @@ function date_popup_validate($element, &$form_state) {
  */
 function date_popup_input_date($element, $input, $auto_complete = FALSE) {
   if (empty($input) || !is_array($input) || !array_key_exists('date', $input) || empty($input['date'])) {
-    return NULL;
+    //check if there is no time associated in the input variable. This is the exception scenario where the user has entered only time and not date.
+    if(empty($input['time']))
+      return NULL;
   }
   date_popup_add();
   $granularity = date_format_order($element['#date_format']);
@@ -622,9 +629,14 @@ function date_popup_input_date($element, $input, $auto_complete = FALSE) {
 
   $format = date_popup_date_format($element);
   $format .= $has_time ? ' ' . date_popup_time_format($element) : '';
-  $datetime = trim($input['date']);
+  //check if date is empty, if yes, then leave it blank.
+  $datetime = !empty($input['date']) ? trim($input['date']) : '';
   $datetime .= $has_time ? ' ' . trim($input['time']) : '';
   $date = new DateObject($datetime, $element['#date_timezone'], $format);
+  //if the variable is time only then set TimeOnly to TRUE
+  if(empty($input['date']) && !empty($input['time']) ){
+    $date->timeOnly = 'TRUE';
+  }
   if (is_object($date)) {
     $date->limitGranularity($granularity);
     if ($date->validGranularity($granularity, $flexible)) {
@@ -800,6 +812,14 @@ function theme_date_popup($vars) {
   return '<div ' . drupal_attributes($attributes) . '>' . theme('form_element', $element) . '</div>';
 }
 
+/**
+ * Implements hook_date_field_instance_settings_form_alter().
+ */
+function date_popup_date_field_instance_settings_form_alter(&$form, $context) {
+  // Add an extra option to sync the end date with the start date.
+  $form['default_value2']['#options']['sync'] = t('Sync with start date');
+}
+
 /**
  * Implements hook_menu().
  */

+ 3 - 3
sites/all/modules/contrib/fields/date/date_repeat/date_repeat.info

@@ -7,9 +7,9 @@ php = 5.2
 files[] = tests/date_repeat.test
 files[] = tests/date_repeat_form.test
 
-; Information added by Drupal.org packaging script on 2015-09-08
-version = "7.x-2.9"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
 core = "7.x"
 project = "date"
-datestamp = "1441727353"
+datestamp = "1491562090"
 

+ 1 - 1
sites/all/modules/contrib/fields/date/date_repeat/tests/date_repeat_form.test

@@ -25,7 +25,7 @@ class DateRepeatFormTestCase extends DrupalWebTestCase {
 
     // Create and log in our privileged user.
     $this->privileged_user = $this->drupalCreateUser(array(
-      'administer content types', 'administer nodes', 'bypass node access', 'view date repeats'
+      'administer content types', 'administer nodes', 'bypass node access', 'view date repeats', 'administer fields'
     ));
     $this->drupalLogin($this->privileged_user);
 

+ 3 - 3
sites/all/modules/contrib/fields/date/date_repeat_field/date_repeat_field.info

@@ -7,9 +7,9 @@ stylesheets[all][] = date_repeat_field.css
 package = Date/Time
 core = 7.x
 
-; Information added by Drupal.org packaging script on 2015-09-08
-version = "7.x-2.9"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
 core = "7.x"
 project = "date"
-datestamp = "1441727353"
+datestamp = "1491562090"
 

+ 3 - 3
sites/all/modules/contrib/fields/date/date_tools/date_tools.info

@@ -6,9 +6,9 @@ core = 7.x
 configure = admin/config/date/tools
 files[] = tests/date_tools.test
 
-; Information added by Drupal.org packaging script on 2015-09-08
-version = "7.x-2.9"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
 core = "7.x"
 project = "date"
-datestamp = "1441727353"
+datestamp = "1491562090"
 

+ 1 - 1
sites/all/modules/contrib/fields/date/date_tools/tests/date_tools.test

@@ -28,7 +28,7 @@ class DateToolsTestCase extends DrupalWebTestCase {
 
     // Create and log in our privileged user.
     $this->privileged_user = $this->drupalCreateUser(
-      array('administer content types', 'administer nodes', 'bypass node access', 'administer date tools')
+      array('administer content types', 'administer nodes', 'bypass node access', 'administer date tools', 'administer fields')
     );
     $this->drupalLogin($this->privileged_user);
 

+ 3 - 3
sites/all/modules/contrib/fields/date/date_views/date_views.info

@@ -12,9 +12,9 @@ files[] = includes/date_views_filter_handler_simple.inc
 files[] = includes/date_views.views.inc
 files[] = includes/date_views_plugin_pager.inc
 
-; Information added by Drupal.org packaging script on 2015-09-08
-version = "7.x-2.9"
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
 core = "7.x"
 project = "date"
-datestamp = "1441727353"
+datestamp = "1491562090"
 

+ 27 - 1
sites/all/modules/contrib/fields/date/date_views/includes/date_views_filter_handler.inc

@@ -42,6 +42,32 @@ class date_views_filter_handler extends date_views_filter_handler_simple {
     $this->date_combine_conditions('op_contains');
   }
 
+  function op_empty($field) {
+    $this->get_query_fields();
+    if (empty($this->query_fields)) {
+      return;
+    }
+
+    // Add each condition to the custom filter group.
+    foreach ((array) $this->query_fields as $query_field) {
+      $field = $query_field['field'];
+      $this->date_handler = $query_field['date_handler'];
+
+      // Respect relationships when determining the table alias.
+      if ($field['table_name'] != $this->table || !empty($this->relationship)) {
+        $this->related_table_alias = $this->query->ensure_table($field['table_name'], $this->relationship);
+      }
+      else {
+        $this->related_table_alias = NULL;
+      }
+
+      $table_alias = !empty($this->related_table_alias) ? $this->related_table_alias : $field['table_name'];
+      $field_name = $table_alias . '.' . $field['field_name'];
+
+      parent::op_empty($field_name);
+    }
+  }
+
   /**
    * Combines multiple date WHERE expressions into a single WHERE expression.
    *
@@ -67,7 +93,7 @@ class date_views_filter_handler extends date_views_filter_handler_simple {
         $this->related_table_alias = $this->query->ensure_table($field['table_name'], $this->relationship);
       }
       else {
-        $this->related_table_alias = null;
+        $this->related_table_alias = NULL;
       }
       $table_alias = !empty($this->related_table_alias) ? $this->related_table_alias : $field['table_name'];
       $field_name = $table_alias . '.' . $field['field_name'];

+ 1 - 1
sites/all/modules/contrib/fields/date/date_views/includes/date_views_plugin_pager.inc

@@ -281,7 +281,7 @@ class date_views_plugin_pager extends views_plugin_pager {
         else {
           $this->view->date_info->prev_date = clone($argument->min_date);
           date_modify($this->view->date_info->prev_date, '-1 ' . $argument->date_handler->granularity);
-          $this->view->date_info->next_date = clone($argument->max_date);
+          $this->view->date_info->next_date = clone($argument->min_date);
           date_modify($this->view->date_info->next_date, '+1 ' . $argument->date_handler->granularity);
         }
         // Write the date_info properties that depend on the current value.

+ 2 - 2
sites/all/modules/contrib/fields/date/date_views/theme/theme.inc

@@ -77,7 +77,7 @@ function template_preprocess_date_views_pager(&$vars) {
       switch ($granularity) {
         case 'week':
           $prev_week = date_week(date_format($prev_date, 'Y-m-d'));
-          $prev_arg = date_format($prev_date, 'Y-\W') . date_pad($prev_week);
+          $prev_arg = date_format($prev_date, 'o-\W') . date_pad($prev_week);
           break;
         default:
           $prev_arg = date_format($prev_date, $format[$granularity]);
@@ -90,7 +90,7 @@ function template_preprocess_date_views_pager(&$vars) {
       switch ($granularity) {
         case 'week':
           $next_week = date_week(date_format($next_date, 'Y-m-d'));
-          $next_arg = date_format($next_date, 'Y-\W') . date_pad($next_week);
+          $next_arg = date_format($next_date, 'o-\W') . date_pad($next_week);
           break;
         default:
           $next_arg = date_format($next_date, $format[$granularity]);

+ 1 - 1
sites/all/modules/contrib/fields/date/tests/date_api.test

@@ -393,7 +393,7 @@ class DateAPITestCase extends DrupalWebTestCase {
     $input = '23 abc 2012';
     $timezone = NULL;
     $format = 'd M Y';
-    $date = new dateObject($input, $timezone, $format);
+    $date = @new dateObject($input, $timezone, $format);
     $this->assertNotEqual(count($date->errors), 0, '23 abc 2012 should be an invalid date');
 
     // Test Granularity.

+ 1 - 1
sites/all/modules/contrib/fields/date/tests/date_field.test

@@ -16,7 +16,7 @@ abstract class DateFieldBasic extends DrupalWebTestCase {
 
     // Create and log in our privileged user.
     $this->privileged_user = $this->drupalCreateUser(
-      array('administer content types', 'administer nodes', 'bypass node access', 'administer date tools')
+      array('administer content types', 'administer nodes', 'bypass node access', 'administer date tools', 'administer fields')
     );
     $this->drupalLogin($this->privileged_user);
 

+ 30 - 0
sites/all/modules/contrib/fields/date/tests/date_form.test

@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains form specific date element test cases.
+ */
+
+class DateFormTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => t('Date Form test'),
+      'description' => t('Test Date form functions.') ,
+      'group' => t('Date'),
+    );
+  }
+
+  public function setUp() {
+    // Load the date_api module.
+    parent::setUp('date_test');
+  }
+
+  /**
+   * Tests rendering of a date element in a form.
+   */
+  public function testDateForm() {
+    $this->drupalGet('date-test/form');
+  }
+
+}

+ 1 - 0
sites/all/modules/contrib/fields/date/tests/date_migrate.test

@@ -18,6 +18,7 @@ class DateMigrateExampleUnitTest extends DrupalWebTestCase {
       'name' => 'Date Migration',
       'description' => 'Test migration into date fields',
       'group' => 'Date',
+      'dependencies' => array('migrate', 'features'),
     );
   }
 

+ 14 - 0
sites/all/modules/contrib/fields/date/tests/date_test/date_test.info

@@ -0,0 +1,14 @@
+name = "Date module tests"
+description = "Support module for date related testing."
+package = Date/Time
+version = VERSION
+core = 7.x
+hidden = TRUE
+dependencies[] = date
+
+; Information added by Drupal.org packaging script on 2017-04-07
+version = "7.x-2.10"
+core = "7.x"
+project = "date"
+datestamp = "1491562090"
+

+ 40 - 0
sites/all/modules/contrib/fields/date/tests/date_test/date_test.module

@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * @file
+ * Contains date test implementations.
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function date_test_menu() {
+  $items['date-test/form'] = array(
+    'title' => 'Test form with date element',
+    'description' => "Form with date element to make form related tests",
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('date_test_sample_form'),
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+  return $items;
+}
+
+/**
+ * Form callback. Generates a test form with date elements.
+ */
+function date_test_sample_form($form, &$form_state) {
+  $form['date_test_select'] = array(
+    '#type' => 'date_select',
+    '#title' => t('Sample from'),
+    '#date_format' => 'H:i:s a',
+    '#default_value' => array(
+      'hour' => 7,
+      'minute' => 0,
+      'second' => 0,
+      'ampm' => 'am'
+    ),
+  );
+
+  return $form;
+}

+ 29 - 4
sites/all/modules/contrib/fields/date/tests/date_timezone.test

@@ -16,6 +16,16 @@ class DateTimezoneTestCase extends DateFieldBasic {
     );
   }
 
+  public function setUp() {
+    parent::setUp();
+    // Set the timezone explicitly. Otherwise the site's default timezone is
+    // used, which defaults to the server timezone when installing Drupal. This
+    // depends on the environment and is therefore uncertain.
+    // The Australia/Sydney timezone is chosen so all tests are run using an
+    // edge case scenario (UTC+10 and DST).
+    variable_set('date_default_timezone', 'Australia/Sydney');
+  }
+
   /**
    * @todo.
    */
@@ -23,7 +33,7 @@ class DateTimezoneTestCase extends DateFieldBasic {
     // Create a date fields with combinations of various timezone handling and
     // granularity.
     foreach (array('date', 'datestamp', 'datetime') as $field_type) {
-      foreach (array('site', 'none', 'date', 'user', 'utc') as $tz_handling) {
+      foreach (array('site', 'none', 'date', 'user', 'utc', 'Europe/Dublin') as $tz_handling) {
         foreach (array('year', 'month', 'day', 'hour', 'minute', 'second') as $max_granularity) {
           // Skip invalid combinations.
           if (in_array($max_granularity, array('year', 'month', 'day')) && $tz_handling != 'none') {
@@ -182,17 +192,32 @@ class DateTimezoneTestCase extends DateFieldBasic {
       case 'hour':
         $edit[$field_name . '[und][0][value][date]'] = '10/07/2010 - 10';
         $edit[$field_name . '[und][0][value2][date]'] = '10/07/2010 - 11';
-        $should_be = 'Thu, 10/07/2010 - 10 to Thu, 10/07/2010 - 11';
+        if ($tz_handling == 'utc') {
+          $should_be = 'Thu, 10/07/2010 - 21 to Thu, 10/07/2010 - 22';
+        }
+        else {
+          $should_be = 'Thu, 10/07/2010 - 10 to Thu, 10/07/2010 - 11';
+        }
         break;
       case 'minute':
         $edit[$field_name . '[und][0][value][date]'] = '10/07/2010 - 10:30';
         $edit[$field_name . '[und][0][value2][date]'] = '10/07/2010 - 11:30';
-        $should_be = 'Thu, 10/07/2010 - 10:30 to 11:30';
+        if ($tz_handling == 'utc') {
+          $should_be = 'Thu, 10/07/2010 - 21:30 to 22:30';
+        }
+        else {
+          $should_be = 'Thu, 10/07/2010 - 10:30 to 11:30';
+        }
         break;
       case 'second':
         $edit[$field_name . '[und][0][value][date]'] = '10/07/2010 - 10:30:30';
         $edit[$field_name . '[und][0][value2][date]'] = '10/07/2010 - 11:30:30';
-        $should_be = 'Thu, 10/07/2010 - 10:30:30 to 11:30:30';
+        if ($tz_handling == 'utc') {
+          $should_be = 'Thu, 10/07/2010 - 21:30:30 to 22:30:30';
+        }
+        else {
+          $should_be = 'Thu, 10/07/2010 - 10:30:30 to 11:30:30';
+        }
         break;
     }
     $this->drupalPost('node/add/story', $edit, t('Save'));

+ 1 - 1
sites/all/modules/contrib/panels/panels/KNOWN_ISSUES.txt

@@ -88,4 +88,4 @@ Known Issue http://drupal.org/node/207859
     secure pages doesn't know about. When trying to make non-secure ajax calls
     from a secure page, the browser denies the call.
   Solution:
-    The solution is to simply add panels/* to your Secure Pages configuration.
+    The solution is to simply add panels/* to your Secure Pages configuration.

+ 1 - 1
sites/all/modules/contrib/panels/panels/README.txt

@@ -1,3 +1,3 @@
 Welcome to Panels 3
 
-Documentation is available at https://www.drupal.org/node/496278
+Documentation is available at https://www.drupal.org/node/496278

+ 0 - 1
sites/all/modules/contrib/panels/panels/css/panels-dashboard.css

@@ -1,4 +1,3 @@
-
 .dashboard-entry .dashboard-link {
   font-size: 120%;
   font-weight: bold;

+ 0 - 1
sites/all/modules/contrib/panels/panels/css/panels.css

@@ -1,4 +1,3 @@
-
 div.panel-pane div.admin-links {
   font-size: xx-small;
   margin-right: 1em;

+ 2 - 3
sites/all/modules/contrib/panels/panels/css/panels_admin.css

@@ -1,4 +1,3 @@
-
 .layout-link {
   float: left;
   padding: 1em;
@@ -141,12 +140,12 @@ table .argument-operation input {
 }
 
 tr.changed td {
-  background-color: #FFFFDD !important;
+  background-color: #ffffdd !important;
 }
 
 tr.changed td span.star {
   font-weight: bold;
-  color: #E09010;
+  color: #e09010;
 }
 
 td select {

+ 14 - 17
sites/all/modules/contrib/panels/panels/css/panels_dnd.css

@@ -1,4 +1,3 @@
-
 #panels-dnd-main {
   margin: 0.5em 0;
 }
@@ -42,7 +41,7 @@ div.panels-set-title-hide .panels-set-title {
 }
 
 /* Add Icon */
-#panels-dnd-main div.panel-region .pane-add-link  {
+#panels-dnd-main div.panel-region .pane-add-link {
 }
 #panels-dnd-main div.panel-region .pane-add-link img {
   display: none;
@@ -127,24 +126,24 @@ div.panels-set-title-hide .panel-pane-is-title {
 }
 
 .panel-portlet .changed div.grab-title {
-  background-color: #FFFFDD !important;
-  border-bottom: 1px solid #3D9CD7 !important;
+  background-color: #ffffdd !important;
+  border-bottom: 1px solid #3d9cd7 !important;
   color: black !important;
 }
 
 .panel-portlet .changed.hidden-pane div.grab-title {
-  background-color: #B4B488 !important;
-  border-bottom: 1px solid #3D9CD7 !important;
+  background-color: #b4b488 !important;
+  border-bottom: 1px solid #3d9cd7 !important;
 }
 
 .panel-portlet .changed div.grab-title span.star {
   font-weight: bold;
-  color: #E09010;
+  color: #e09010;
 }
 
 .panel-portlet .grabber:hover {
   color: #fff;
-  background-color: #2F78A5;
+  background-color: #2f78a5;
 }
 
 .panel-portlet.hidden-pane .grab-title:hover {
@@ -175,7 +174,8 @@ div.panels-set-title-hide .panel-pane-is-title {
   margin: 0;
 }
 
-.panel-portlet .buttons input, .panel-portlet .buttons button {
+.panel-portlet .buttons input,
+.panel-portlet .buttons button {
   margin: 0;
   padding: 0;
   display: inline;
@@ -186,7 +186,7 @@ div.panels-set-title-hide .panel-pane-is-title {
 }
 
 .panel-portlet .pane-title {
-  font-size:110%;
+  font-size: 110%;
   cursor: pointer;
 }
 
@@ -315,7 +315,7 @@ a.close img {
   padding-left: 1em;
   padding-bottom: 1em;
   margin-bottom: 1em;
-  background-color: #EEEEEE;
+  background-color: #eeeeee;
 }
 
 .panels-section-columns {
@@ -354,7 +354,7 @@ a.close img {
 
 .panels-section-column-categories .inside {
   padding: 0;
- }
+}
 
 .panels-section-column-categories .content-type-button {
   padding-left: 10px;
@@ -431,7 +431,7 @@ a.close img {
   float: none;
 }
 
-.panels-modal-content .modal-form .no-float label  {
+.panels-modal-content .modal-form .no-float label {
   width: auto;
 }
 
@@ -502,7 +502,6 @@ html.js div.panels-display-links div.ctools-dropdown-container ul li a {
 /* @group CTools Dropdown */
 #panels-dnd-main .ctools-dropdown a.ctools-dropdown-text-link,
 html.js div.panels-display-links a.ctools-dropdown-text-link {
-
   background: url('../images/arrow-down-light.png') 0 3px no-repeat!important;
   padding-left: 12px;
 }
@@ -522,7 +521,6 @@ html.js div.panels-display-links div.ctools-dropdown-container {
 
 html.js #panels-dnd-main div.ctools-dropdown div.ctools-dropdown-container ul li,
 html.js div.panels-display-links div.ctools-dropdown-container ul li {
-
   text-decoration: none;
   padding: 0;
   margin: 0;
@@ -565,7 +563,7 @@ html.js #panels-dnd-main div.ctools-dropdown div.ctools-dropdown-container ul li
 html.js div.panels-display-links div.ctools-dropdown-container ul li .panels-sub-menu ul li a,
 html.js #panels-dnd-main div.ctools-dropdown div.ctools-dropdown-container ul li .panels-sub-menu span.panels-text,
 html.js div.panels-display-links div.ctools-dropdown-container ul li .panels-sub-menu span.panels-text {
-  width:auto;
+  width: auto;
   padding: 0 20px;
 }
 
@@ -682,4 +680,3 @@ div.ctools-modal-content {
   top: -2em;
   margin-bottom: -2em;
 }
-

+ 0 - 1
sites/all/modules/contrib/panels/panels/css/panels_page.css

@@ -1,4 +1,3 @@
-
 div.panels-page-type-container {
   clear: left;
 }

+ 1 - 1
sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.i18n.inc

@@ -1,7 +1,7 @@
 <?php
 /**
  * @file
- * Internationalization (i18n) hooks
+ * Internationalization (i18n) hooks.
  */
 
 /**

+ 3 - 3
sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.info

@@ -7,9 +7,9 @@ dependencies[] = i18n_translation
 package = Multilingual - Internationalization
 core = 7.x
 
-; Information added by Drupal.org packaging script on 2016-10-16
-version = "7.x-3.8"
+; Information added by Drupal.org packaging script on 2017-02-06
+version = "7.x-3.9"
 core = "7.x"
 project = "panels"
-datestamp = "1476582295"
+datestamp = "1486394388"
 

+ 4 - 3
sites/all/modules/contrib/panels/panels/i18n_panels/i18n_panels.module

@@ -206,6 +206,7 @@ function i18n_panels_panels_delete_display($did) {
  *
  * This function must not rely on the passed $renderer parameter. The parameter
  * could be empty because this function is reused in i18n_ctools_render_alter().
+ *
  * @todo Check if a drupal_alter() in panels_display::get_title() is applicable.
  *
  * @see i18n_ctools_render_alter()
@@ -234,6 +235,7 @@ function i18n_panels_panels_pre_render(&$display, $renderer) {
  *
  * Under some circumstances the title of the panel page is set before
  * hook_panels_pre_render() is fired. Such cases can be handled with this hook.
+ *
  * @todo Check if a drupal_alter() in panels_display::get_title() is applicable.
  */
 function i18n_ctools_render_alter(&$info, $page, $context) {
@@ -250,7 +252,6 @@ function i18n_ctools_render_alter(&$info, $page, $context) {
  * Implements hook_ctools_plugin_post_alter().
  *
  * Register some translatable configuration settings for plugins.
- *
  */
 function i18n_panels_ctools_plugin_post_alter(&$plugin, $plugin_type_info) {
   if ($plugin_type_info['type'] == 'content_types') {
@@ -322,7 +323,7 @@ function i18n_panels_i18n_string_list($group) {
         if (empty($pane->uuid)) {
           // Fetch exported uuid and validate it.
           $uuid = str_replace('new-', '', $pane->pid);
-          if (!panels_uuid_is_valid($uuid)) {
+          if (!ctools_uuid_is_valid($uuid)) {
             drupal_set_message(t('The pane %pane has no uuid, please resave or re-export it.', array('%pane' => $pane->pid)), 'warning');
             continue;
           }
@@ -366,7 +367,7 @@ function _18n_panels_is_exported_panels_display($display) {
  *
  * @todo I bet there are better ways to solve this mess.
  *
- * @param boolean $reset
+ * @param bool $reset
  *   Reset the static cache.
  *
  * @return array

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