Browse Source

updated linkit contrib module to last beta version

Bachir Soussi Chiadmi 7 years ago
parent
commit
76ff40f8bb
100 changed files with 2486 additions and 3587 deletions
  1. 35 14
      sites/all/modules/contrib/fields/linkit/README.md
  2. 19 0
      sites/all/modules/contrib/fields/linkit/config/optional/linkit.linkit_profile.default.yml
  3. 23 42
      sites/all/modules/contrib/fields/linkit/config/schema/linkit.schema.yml
  4. 1 2
      sites/all/modules/contrib/fields/linkit/css/linkit.admin.theme.css
  5. 23 15
      sites/all/modules/contrib/fields/linkit/css/linkit.autocomplete.css
  6. BIN
      sites/all/modules/contrib/fields/linkit/images/throbber-active.gif
  7. BIN
      sites/all/modules/contrib/fields/linkit/images/throbber-inactive.png
  8. 0 21
      sites/all/modules/contrib/fields/linkit/js/attribute/title.js
  9. 82 34
      sites/all/modules/contrib/fields/linkit/js/autocomplete.js
  10. 51 0
      sites/all/modules/contrib/fields/linkit/js/linkit.filter_html.admin.js
  11. 0 52
      sites/all/modules/contrib/fields/linkit/js/linkit.imce.js
  12. BIN
      sites/all/modules/contrib/fields/linkit/js/plugins/linkit/linkit.png
  13. 0 223
      sites/all/modules/contrib/fields/linkit/js/plugins/linkit/plugin.js
  14. 7 5
      sites/all/modules/contrib/fields/linkit/linkit.info.yml
  15. 190 1
      sites/all/modules/contrib/fields/linkit/linkit.install
  16. 2 13
      sites/all/modules/contrib/fields/linkit/linkit.libraries.yml
  17. 0 7
      sites/all/modules/contrib/fields/linkit/linkit.links.action.yml
  18. 0 5
      sites/all/modules/contrib/fields/linkit/linkit.links.task.yml
  19. 123 79
      sites/all/modules/contrib/fields/linkit/linkit.module
  20. 1 1
      sites/all/modules/contrib/fields/linkit/linkit.permissions.yml
  21. 1 41
      sites/all/modules/contrib/fields/linkit/linkit.routing.yml
  22. 6 7
      sites/all/modules/contrib/fields/linkit/linkit.services.yml
  23. 0 69
      sites/all/modules/contrib/fields/linkit/src/Annotation/Attribute.php
  24. 1 13
      sites/all/modules/contrib/fields/linkit/src/Annotation/Matcher.php
  25. 28 0
      sites/all/modules/contrib/fields/linkit/src/Annotation/Substitution.php
  26. 0 112
      sites/all/modules/contrib/fields/linkit/src/AttributeBase.php
  27. 0 46
      sites/all/modules/contrib/fields/linkit/src/AttributeCollection.php
  28. 0 78
      sites/all/modules/contrib/fields/linkit/src/AttributeInterface.php
  29. 0 29
      sites/all/modules/contrib/fields/linkit/src/AttributeManager.php
  30. 0 16
      sites/all/modules/contrib/fields/linkit/src/ConfigurableAttributeBase.php
  31. 0 23
      sites/all/modules/contrib/fields/linkit/src/ConfigurableAttributeInterface.php
  32. 0 5
      sites/all/modules/contrib/fields/linkit/src/ConfigurableMatcherBase.php
  33. 0 6
      sites/all/modules/contrib/fields/linkit/src/ConfigurableMatcherInterface.php
  34. 28 22
      sites/all/modules/contrib/fields/linkit/src/Controller/AutocompleteController.php
  35. 2 24
      sites/all/modules/contrib/fields/linkit/src/Controller/LinkitController.php
  36. 14 31
      sites/all/modules/contrib/fields/linkit/src/Element/Linkit.php
  37. 3 97
      sites/all/modules/contrib/fields/linkit/src/Entity/Profile.php
  38. 0 166
      sites/all/modules/contrib/fields/linkit/src/Form/Attribute/AddForm.php
  39. 0 92
      sites/all/modules/contrib/fields/linkit/src/Form/Attribute/DeleteForm.php
  40. 0 96
      sites/all/modules/contrib/fields/linkit/src/Form/Attribute/EditForm.php
  41. 0 156
      sites/all/modules/contrib/fields/linkit/src/Form/Attribute/OverviewForm.php
  42. 0 207
      sites/all/modules/contrib/fields/linkit/src/Form/LinkitEditorDialog.php
  43. 0 10
      sites/all/modules/contrib/fields/linkit/src/Form/Matcher/AddForm.php
  44. 0 5
      sites/all/modules/contrib/fields/linkit/src/Form/Matcher/DeleteForm.php
  45. 9 13
      sites/all/modules/contrib/fields/linkit/src/Form/Matcher/EditForm.php
  46. 7 12
      sites/all/modules/contrib/fields/linkit/src/Form/Matcher/OverviewForm.php
  47. 0 5
      sites/all/modules/contrib/fields/linkit/src/Form/Profile/AddForm.php
  48. 1 6
      sites/all/modules/contrib/fields/linkit/src/Form/Profile/EditForm.php
  49. 5 10
      sites/all/modules/contrib/fields/linkit/src/Form/Profile/FormBase.php
  50. 13 6
      sites/all/modules/contrib/fields/linkit/src/MatcherBase.php
  51. 0 14
      sites/all/modules/contrib/fields/linkit/src/MatcherCollection.php
  52. 5 18
      sites/all/modules/contrib/fields/linkit/src/MatcherInterface.php
  53. 0 5
      sites/all/modules/contrib/fields/linkit/src/MatcherManager.php
  54. 13 17
      sites/all/modules/contrib/fields/linkit/src/MatcherTokensTrait.php
  55. 0 123
      sites/all/modules/contrib/fields/linkit/src/Plugin/CKEditorPlugin/Linkit.php
  56. 111 0
      sites/all/modules/contrib/fields/linkit/src/Plugin/CKEditorPlugin/LinkitDrupalLink.php
  57. 17 18
      sites/all/modules/contrib/fields/linkit/src/Plugin/Derivative/EntityMatcherDeriver.php
  58. 156 0
      sites/all/modules/contrib/fields/linkit/src/Plugin/Filter/LinkitFilter.php
  59. 0 38
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Attribute/Accesskey.php
  60. 0 41
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Attribute/Clazz.php
  61. 0 38
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Attribute/Id.php
  62. 0 38
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Attribute/Relationship.php
  63. 0 96
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Attribute/Target.php
  64. 0 82
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Attribute/Title.php
  65. 38 0
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Matcher/ContactFormMatcher.php
  66. 40 0
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Matcher/EmailMatcher.php
  67. 221 81
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Matcher/EntityMatcher.php
  68. 69 34
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Matcher/FileMatcher.php
  69. 40 0
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Matcher/FrontPageMatcher.php
  70. 16 13
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Matcher/NodeMatcher.php
  71. 6 8
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Matcher/TermMatcher.php
  72. 31 21
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Matcher/UserMatcher.php
  73. 34 0
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Substitution/Canonical.php
  74. 39 0
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Substitution/File.php
  75. 100 0
      sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Substitution/Media.php
  76. 1 58
      sites/all/modules/contrib/fields/linkit/src/ProfileInterface.php
  77. 6 19
      sites/all/modules/contrib/fields/linkit/src/ProfileListBuilder.php
  78. 0 74
      sites/all/modules/contrib/fields/linkit/src/ResultManager.php
  79. 36 0
      sites/all/modules/contrib/fields/linkit/src/SubstitutionInterface.php
  80. 77 0
      sites/all/modules/contrib/fields/linkit/src/SubstitutionManager.php
  81. 28 0
      sites/all/modules/contrib/fields/linkit/src/SubstitutionManagerInterface.php
  82. 44 0
      sites/all/modules/contrib/fields/linkit/src/Suggestion/DescriptionSuggestion.php
  83. 81 0
      sites/all/modules/contrib/fields/linkit/src/Suggestion/EntitySuggestion.php
  84. 87 0
      sites/all/modules/contrib/fields/linkit/src/Suggestion/SimpleSuggestion.php
  85. 56 0
      sites/all/modules/contrib/fields/linkit/src/Suggestion/SuggestionCollection.php
  86. 28 0
      sites/all/modules/contrib/fields/linkit/src/Suggestion/SuggestionDescriptionInterface.php
  87. 64 0
      sites/all/modules/contrib/fields/linkit/src/Suggestion/SuggestionInterface.php
  88. 63 0
      sites/all/modules/contrib/fields/linkit/src/SuggestionManager.php
  89. 0 160
      sites/all/modules/contrib/fields/linkit/src/Tests/AttributeCrudTest.php
  90. 0 83
      sites/all/modules/contrib/fields/linkit/src/Tests/Controllers/LinkitControllerTest.php
  91. 0 83
      sites/all/modules/contrib/fields/linkit/src/Tests/LinkitTestBase.php
  92. 0 158
      sites/all/modules/contrib/fields/linkit/src/Tests/MatcherCrudTest.php
  93. 0 105
      sites/all/modules/contrib/fields/linkit/src/Tests/Matchers/NodeMatcherTest.php
  94. 0 114
      sites/all/modules/contrib/fields/linkit/src/Tests/Matchers/UserMatcherTest.php
  95. 44 0
      sites/all/modules/contrib/fields/linkit/src/Tests/ProfileCreationTrait.php
  96. 0 125
      sites/all/modules/contrib/fields/linkit/src/Tests/ProfileCrudTest.php
  97. 152 0
      sites/all/modules/contrib/fields/linkit/src/Tests/Update/LinkitUpdateTest.php
  98. 1 6
      sites/all/modules/contrib/fields/linkit/src/Utility/LinkitXss.php
  99. 54 0
      sites/all/modules/contrib/fields/linkit/tests/fixtures/update/editor.editor.format_1.yml
  100. 53 0
      sites/all/modules/contrib/fields/linkit/tests/fixtures/update/editor.editor.format_2.yml

+ 35 - 14
sites/all/modules/contrib/fields/linkit/README.md

@@ -1,33 +1,54 @@
 Linkit
 ===========
-Linkit provides an **enriched linking experience for internal and external
-linking** with editors by using an autocomplete field. Linkit has by default
-support for nodes, users, taxonomy terms, files, comments and
-**basic support for all types of entities** that defines a canonical link
-template.
+Linkit provides an **enriched linking experience for internal and 
+external linking** with editors by using an autocomplete field. Linkit 
+has by default support for nodes, users, taxonomy terms, files, 
+comments and **basic support for all types of entities** that defines a 
+canonical link template.
 
 
 Installation
 ------------
 
 * Normal module installation procedure. See
-  https://www.drupal.org/documentation/install/modules-themes/modules-8
+https://www.drupal.org/documentation/install/modules-themes/modules-8
+
+* **Enable Linkit**
+To enable Linkit, go to `/admin/config/content/formats` and edit the 
+desired text format you want to enable Linkit for. Linkit will alter 
+the default link plugin, so make sure that it is enabled. When the 
+default link plugin is enabled, you will have to select a Linkit 
+profile to use in the "Drupal link" tab under the toolbar configuration.
+
+* **Enable Linkit filter**
+Linkit will insert URLs in a format like "entity:node/1". The Linkit 
+filter will then transform that URL into a "real" URL when rendering 
+the text. **Note: The Linkit filter must run before "Limit allowed HTML 
+tags and correct faulty HTML"**.
+
+* If the **Limit allowed HTML tags and correct faulty HTML** filter is
+enabled, add *data-entity-type* and *data-entity-uuid* to the `<a>` tag
+in the *Allowed HTML* tags (i.e. `<a href data-entity-type data-entity-uuid>`).
+
+* (optional) **Use automatic titles with the Linkit filter**
+If automatic titles is enabled in the Linkit filter settings, and
+**Limit allowed HTML tags and correct faulty HTML** is enabled, add
+*title*  to the `<a>` tag in the *Allowed HTML* tags (i.e.
+`<a href data-entity-type data-entity-uuid title>`).
 
 
 Configuration
 ------------
 
-After the installation, you have to create a Linkit profile. The profile will
-contain information about which plugins to use.
-Profiles can be created at `/admin/config/content/linkit`
+A default Linkit profile will have been installed as a step in the 
+module installation process. The profile will contain information about 
+which plugins to use.
 
-When you have created a profile, you need to enable the Linkit plugin on the
-text format you want to use. Formats are found at
-`admin/config/content/formats`.
+You can create additional profiles at `/admin/config/content/linkit`.
 
 
 Plugins examples
 ------------
 
-There are plugin implementation examples in the linkit_test module bundled with
-Linkit core.
+There are plugin implementation examples in the linkit_test module 
+bundled with Linkit core.

+ 19 - 0
sites/all/modules/contrib/fields/linkit/config/optional/linkit.linkit_profile.default.yml

@@ -0,0 +1,19 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - node
+id: default
+label: Default
+description: 'A default Linkit profile'
+matchers:
+  556010a3-e317-48b3-b4ed-854c10f4b950:
+    uuid: 556010a3-e317-48b3-b4ed-854c10f4b950
+    id: 'entity:node'
+    weight: 0
+    settings:
+      metadata: 'by [node:author] | [node:created:medium]'
+      bundles: {  }
+      group_by_bundle: false
+      include_unpublished: false
+      substitution_type: canonical

+ 23 - 42
sites/all/modules/contrib/fields/linkit/config/schema/linkit.schema.yml

@@ -10,43 +10,11 @@ linkit.linkit_profile.*:
       type: string
     description:
       type: string
-    attributes:
-      type: sequence
-      sequence:
-        type: linkit.attribute
     matchers:
       type: sequence
       sequence:
         type: linkit.matcher
 
-linkit.attribute:
-  type: mapping
-  mapping:
-    id:
-      type: string
-    settings:
-      type: linkit.attribute.[%parent.id]
-    weight:
-      type: integer
-
-linkit.attribute.*:
-  type: mapping
-  label: 'Attribute settings'
-
-# Plugin \Drupal\linkit\Plugin\Linkit\Attribute\Target
-linkit.attribute.target:
-  type: linkit.attribute
-  mapping:
-    widget_type:
-      type: string
-
-# Plugin \Drupal\linkit\Plugin\Linkit\Attribute\Title
-linkit.attribute.title:
-  type: linkit.attribute
-  mapping:
-    automatic_title:
-      type: boolean
-
 linkit.matcher:
   type: mapping
   mapping:
@@ -66,7 +34,7 @@ linkit.matcher.*:
 linkit.matcher.entity:
   type: mapping
   mapping:
-    result_description:
+    metadata:
       type: string
     bundles:
       type: sequence
@@ -75,6 +43,8 @@ linkit.matcher.entity:
       nullable: true
     group_by_bundle:
       type: boolean
+    substitution_type:
+      type: string
 
 linkit.matcher.entity:*:
   type: linkit.matcher.entity
@@ -83,6 +53,11 @@ linkit.matcher.entity:*:
 linkit.matcher.entity:file:
   type: linkit.matcher.entity
   mapping:
+    file_extensions:
+      type: string
+    file_status:
+      type: integer
+      default: 1
     images:
       type: mapping
       mapping:
@@ -113,19 +88,25 @@ linkit.matcher.entity:user:
     include_blocked:
       type: boolean
 
-# Third party settings on behalf of the imce module.
-linkit.linkit_profile.*.third_party.imce:
-  type: mapping
+# Plugin \Drupal\linkit\Plugin\Filter\LinkitFilter
+filter_settings.linkit:
+  type: filter
+  label: 'Linkit'
   mapping:
-    use:
+    title:
       type: boolean
-    scheme:
-      type: string
+      label: 'Automatically set the "title" attribute'
 
-ckeditor.plugin.linkit:
+# Plugin \Drupal\ckeditor\Plugin\CKEditorPlugin\DrupalLink
+# Linkit alters the plugin to save Linkit specific information used by the
+# altered plugin.
+ckeditor.plugin.drupallink:
   type: mapping
-  label: 'Profile dropdown'
+  label: 'Drupal link'
   mapping:
+    linkit_enabled:
+      type: boolean
+      label: 'Use Linkit'
     linkit_profile:
       type: string
-      label: 'List of profiles'
+      label: 'Linkit profile'

+ 1 - 2
sites/all/modules/contrib/fields/linkit/css/linkit.admin.theme.css

@@ -9,7 +9,6 @@
   line-height: 1.2em;
 }
 
-.linkit-matcher-add-form tbody td:first-child,
-.linkit-attribute-add-form tbody td:first-child {
+.linkit-matcher-add-form tbody td:first-child {
   width: 1%;
 }

+ 23 - 15
sites/all/modules/contrib/fields/linkit/css/linkit.autocomplete.css

@@ -3,48 +3,55 @@
  * Stylesheet for the Linkit module.
  */
 .js input.form-linkit-autocomplete {
-  background-image: url(/core/misc/throbber-inactive.png);
+  background-image: url(../images/throbber-inactive.png);
   background-position: 100% center; /* LTR */
   background-repeat: no-repeat;
 }
+
 .js[dir="rtl"] input.form-linkit-autocomplete {
-  background-position: 0% center;
+  background-position: 0 center;
 }
+
 .js input.form-linkit-autocomplete.ui-autocomplete-loading {
-  background-image: url(/core/misc/throbber-active.gif);
+  background-image: url(../images/throbber-active.gif);
   background-position: 100% center; /* LTR */
 }
+
 .js[dir="rtl"] input.form-linkit-autocomplete.ui-autocomplete-loading {
-  background-position: 0% center;
+  background-position: 0 center;
 }
 
 /* Override the default jQuery UI theme */
 .linkit-ui-autocomplete {
-  max-height: 330px;
+  max-height: calc((100vh - 80px)/2);
   overflow: auto;
 }
-.linkit-ui-autocomplete.ui-widget  {
+
+.linkit-ui-autocomplete.ui-widget {
   font-size: .9em;
 }
 
-.linkit-ui-autocomplete.ui-menu .ui-menu-item {
-  list-style: none;
+.linkit-ui-autocomplete.ui-menu .linkit-result-line-wrapper {
+  margin: 0;
   padding: 5px 7px;
 }
 
-.linkit-ui-autocomplete .ui-menu-item.ui-state-focus {
-  margin: 0;
+.linkit-ui-autocomplete.ui-menu .linkit-result-line-wrapper.ui-state-focus,
+.linkit-ui-autocomplete.ui-menu .linkit-result-line-wrapper.ui-state-active {
   border: 0;
   border-bottom: 1px solid #bfbfbf;
   background: #0075ba;
   color: #fff;
 }
 
-.linkit-result:not(:last-of-type) {
+.linkit-result-line:not(:last-of-type) {
   border-bottom: 1px solid #bfbfbf;
 }
 
-.linkit-result--group {
+.ui-menu .linkit-result-line--group.ui-menu-divider {
+  margin: 0;
+  height: auto;
+  line-height: inherit;
   padding: 3px;
   background-color: #e7e7e7;
   border-bottom: 1px solid #bfbfbf;
@@ -54,16 +61,17 @@
   color: #555;
 }
 
-.linkit-result--title {
+.linkit-result-line--title {
+  display: block;
   font-weight: 600;
 }
 
-.linkit-result--description {
+.linkit-result-line--description {
   display: block;
   font-size: 0.9em;
   line-height: 1.3;
 }
 
-.linkit-result--description img {
+.linkit-result-line--description img {
   display: block;
 }

BIN
sites/all/modules/contrib/fields/linkit/images/throbber-active.gif


BIN
sites/all/modules/contrib/fields/linkit/images/throbber-inactive.png


+ 0 - 21
sites/all/modules/contrib/fields/linkit/js/attribute/title.js

@@ -1,21 +0,0 @@
-/**
- * @file
- * Title attribute functions.
- */
-
-(function ($, Drupal, document) {
-
-  'use strict';
-
-  var fieldName = '[name="attributes[title]"]';
-
-  /**
-   * Automatically populate the title attribute.
-   */
-  $(document).bind('linkit.autocomplete.select', function (triggerEvent, event, ui) {
-    if (ui.item.hasOwnProperty('title')) {
-      $('form.linkit-editor-dialog-form').find(fieldName).val(ui.item.title);
-    }
-  });
-
-})(jQuery, Drupal, document);

+ 82 - 34
sites/all/modules/contrib/fields/linkit/js/autocomplete.js

@@ -3,7 +3,7 @@
  * Linkit Autocomplete based on jQuery UI.
  */
 
-(function ($, Drupal, _, document) {
+(function ($, Drupal, _) {
 
   'use strict';
 
@@ -13,7 +13,9 @@
    * JQuery UI autocomplete source callback.
    *
    * @param {object} request
+   *   The request object.
    * @param {function} response
+   *   The function to call with the response.
    */
   function sourceData(request, response) {
     var elementId = this.element.attr('id');
@@ -22,21 +24,15 @@
       autocomplete.cache[elementId] = {};
     }
 
-    /**
-     * @param {object} suggestions
-     */
-    function showSuggestions(suggestions) {
-      response(suggestions.matches);
-    }
-
     /**
      * Transforms the data object into an array and update autocomplete results.
      *
      * @param {object} data
+     *   The data sent back from the server.
      */
     function sourceCallbackHandler(data) {
-      autocomplete.cache[elementId][term] = data;
-      showSuggestions(data);
+      autocomplete.cache[elementId][term] = data.suggestions;
+      response(data.suggestions);
     }
 
     // Get the desired term and construct the autocomplete URL for it.
@@ -44,27 +40,48 @@
 
     // Check if the term is already cached.
     if (autocomplete.cache[elementId].hasOwnProperty(term)) {
-      showSuggestions(autocomplete.cache[elementId][term]);
+      response(autocomplete.cache[elementId][term]);
     }
     else {
-      var options = $.extend({success: sourceCallbackHandler, data: {q: term}}, autocomplete.ajax);
+      var options = $.extend({
+        success: sourceCallbackHandler,
+        data: {q: term}
+      }, autocomplete.ajax);
       $.ajax(this.element.attr('data-autocomplete-path'), options);
     }
   }
 
   /**
-    * Handles an autocomplete select event.
-    *
-    * @param {jQuery.Event} event
-    * @param {object} ui
-    *
-    * @return {boolean}
-    */
+   * Handles an autocomplete select event.
+   *
+   * @param {jQuery.Event} event
+   *   The event triggered.
+   * @param {object} ui
+   *   The jQuery UI settings object.
+   *
+   * @return {boolean}
+   *   False to prevent further handlers.
+   */
   function selectHandler(event, ui) {
-    if (ui.item.hasOwnProperty('path')) {
-      event.target.value = ui.item.path;
+    var $form = $(event.target).closest('form');
+    if (!ui.item.path) {
+      throw 'Missing path param.' + JSON.stringify(ui.item);
     }
-    $(document).trigger('linkit.autocomplete.select', [event, ui]);
+
+    $('input[name="href_dirty_check"]', $form).val(ui.item.path);
+
+    if (ui.item.entity_type_id || ui.item.entity_uuid || ui.item.substitution_id) {
+      if (!ui.item.entity_type_id || !ui.item.entity_uuid || !ui.item.substitution_id) {
+        throw 'Missing path param.' + JSON.stringify(ui.item);
+      }
+
+      $('input[name="attributes[data-entity-type]"]', $form).val(ui.item.entity_type_id);
+      $('input[name="attributes[data-entity-uuid]"]', $form).val(ui.item.entity_uuid);
+      $('input[name="attributes[data-entity-substitution]"]', $form).val(ui.item.substitution_id);
+    }
+
+    event.target.value = ui.item.path;
+
     return false;
   }
 
@@ -74,18 +91,20 @@
    * @param {object} ul
    *   The <ul> element that the newly created <li> element must be appended to.
    * @param {object} item
+   *  The list item to append.
    *
    * @return {object}
+   *   jQuery collection of the ul element.
    */
   function renderItem(ul, item) {
-    var $line = $('<li>').addClass('linkit-result');
-    $line.append($('<span>').html(item.title).addClass('linkit-result--title'));
+    var $line = $('<li>').addClass('linkit-result-line');
+    var $wrapper = $('<div>').addClass('linkit-result-line-wrapper');
+    $wrapper.append($('<span>').html(item.label).addClass('linkit-result-line--title'));
 
-    if (item.description !== null) {
-      $line.append($('<span>').html(item.description).addClass('linkit-result--description'));
+    if (item.hasOwnProperty('description')) {
+      $wrapper.append($('<span>').html(item.description).addClass('linkit-result-line--description'));
     }
-
-    return $line.appendTo(ul);
+    return $line.append($wrapper).appendTo(ul);
   }
 
   /**
@@ -105,7 +124,7 @@
 
     $.each(grouped_items, function (group, items) {
       if (group.length) {
-        ul.append('<li class="linkit-result--group">' + group + '</li>');
+        ul.append('<li class="linkit-result-line--group ui-menu-divider">' + group + '</li>');
       }
 
       $.each(items, function (index, item) {
@@ -114,20 +133,35 @@
     });
   }
 
+  function focusHandler() {
+    return false;
+  }
+
+  function searchHandler(event) {
+    var options = autocomplete.options;
+
+    return !options.isComposing;
+  }
+
   /**
    * Attaches the autocomplete behavior to all required fields.
    *
    * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the autocomplete behaviors.
+   * @prop {Drupal~behaviorDetach} detach
+   *   Detaches the autocomplete behaviors.
    */
   Drupal.behaviors.linkit_autocomplete = {
     attach: function (context) {
-      // Act on textfields with the "form-autocomplete" class.
+      // Act on textfields with the "form-linkit-autocomplete" class.
       var $autocomplete = $(context).find('input.form-linkit-autocomplete').once('linkit-autocomplete');
       if ($autocomplete.length) {
         $.widget('custom.autocomplete', $.ui.autocomplete, {
           _create: function () {
             this._super();
-            this.widget().menu('option', 'items', '> :not(.linkit-result--group)');
+            this.widget().menu('option', 'items', '> :not(.linkit-result-line--group)');
           },
           _renderMenu: autocomplete.options.renderMenu,
           _renderItem: autocomplete.options.renderItem
@@ -136,6 +170,17 @@
         // Use jQuery UI Autocomplete on the textfield.
         $autocomplete.autocomplete(autocomplete.options);
         $autocomplete.autocomplete('widget').addClass('linkit-ui-autocomplete');
+
+        $autocomplete.click(function () {
+          $autocomplete.autocomplete('search', $autocomplete.val());
+        });
+
+        $autocomplete.on('compositionstart.autocomplete', function () {
+          autocomplete.options.isComposing = true;
+        });
+        $autocomplete.on('compositionend.autocomplete', function () {
+          autocomplete.options.isComposing = false;
+        });
       }
     },
     detach: function (context, settings, trigger) {
@@ -154,14 +199,17 @@
     cache: {},
     options: {
       source: sourceData,
+      focus: focusHandler,
+      search: searchHandler,
+      select: selectHandler,
       renderItem: renderItem,
       renderMenu: renderMenu,
-      select: selectHandler,
-      minLength: 1
+      minLength: 1,
+      isComposing: false
     },
     ajax: {
       dataType: 'json'
     }
   };
 
-})(jQuery, Drupal, _, document);
+})(jQuery, Drupal, _);

+ 51 - 0
sites/all/modules/contrib/fields/linkit/js/linkit.filter_html.admin.js

@@ -0,0 +1,51 @@
+/**
+ * @file
+ * Send events to add or remove a tags to the filter_html allowed tags.
+ */
+
+(function ($, Drupal, document) {
+
+  'use strict';
+
+  /**
+   * When enabling the linkit filter, also add linkit rules to filter_html.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches linkitFilterHtml behavior.
+   */
+  Drupal.behaviors.linkitFilterHtml = {
+    attach: function (context) {
+      var selector = '[data-drupal-selector="edit-filters-linkit-status"]';
+      var feature = editorFeature();
+      $(context).find(selector).once('filters-linkit-status').each(function () {
+        $(this).on('click', function () {
+          var eventName = $(this).is(':checked') ? 'drupalEditorFeatureAdded' : 'drupalEditorFeatureRemoved';
+          $(document).trigger(eventName, feature);
+        });
+      });
+    }
+  };
+
+  /**
+   * Returns a editor feature.
+   *
+   * @return {Drupal.EditorFeature}
+   *   A editor feature with linkit specific tags and attributes.
+   */
+  function editorFeature() {
+    var linkitFeature = new Drupal.EditorFeature('linkit');
+    var rule = new Drupal.EditorFeatureHTMLRule();
+    // Tags.
+    rule.required.tags = ['a'];
+    rule.allowed.tags = ['a'];
+    // Attributes.
+    rule.required.attributes = ['data-entity-substitution', 'data-entity-type', 'data-entity-uuid', 'title'];
+    rule.allowed.attributes = ['data-entity-substitution', 'data-entity-type', 'data-entity-uuid', 'title'];
+
+    linkitFeature.addHTMLRule(rule);
+    return linkitFeature;
+  }
+
+})(jQuery, Drupal, document);

+ 0 - 52
sites/all/modules/contrib/fields/linkit/js/linkit.imce.js

@@ -1,52 +0,0 @@
-/**
- * @file
- * IMCE integration for Linkit.
- */
-
-(function ($, Drupal, drupalSettings) {
-
-  'use strict';
-
-  /**
-   * @namespace
-   *
-   * Need to be in the global namespace, otherwise the IMCE window will not show
-   * the 'select' button in the toolbar.
-   */
-  var linkitImce = window.linkitImce = {};
-
-  /**
-   * Drupal behavior to handle imce linkit integration.
-   */
-  Drupal.behaviors.linkitImce = {
-    attach: function (context, settings) {
-      var $link = $(context).find('.linkit-imce-open').once('linkit-imce-open');
-      if ($link.length) {
-        $link.bind('click', function (event) {
-          event.preventDefault();
-          window.open($(this).attr('href'), '', 'width=760,height=560,resizable=1');
-        });
-      }
-    }
-  };
-
-  /**
-   * Handler for imce sendto operation.
-   */
-  linkitImce.sendto = function (file, win) {
-    var imce = win.imce;
-    var items = imce.getSelection();
-
-    if (imce.countSelection() > 1) {
-      imce.setMessage(Drupal.t('You can only select one file.'));
-      return;
-    }
-    var path = imce.getConf('root_url') + '/' + imce.getItemPath(items[0]);
-    $('[data-drupal-selector="edit-attributes-href"]').val(path);
-    win.close();
-  };
-
-
-})(jQuery, Drupal, drupalSettings);
-
-

BIN
sites/all/modules/contrib/fields/linkit/js/plugins/linkit/linkit.png


+ 0 - 223
sites/all/modules/contrib/fields/linkit/js/plugins/linkit/plugin.js

@@ -1,223 +0,0 @@
-/**
- * @file
- * Linkit plugin.
- *
- * @ignore
- */
-
-(function ($, Drupal, drupalSettings, CKEDITOR) {
-
-  'use strict';
-
-  // Alter the dialog settings to make a bigger dialog.
-  // $(window).on('dialog:beforecreate', function (event, dialog, $element, settings) {
-  //  settings.dialogClass = settings.dialogClass.replace('ui-dialog--narrow', '');
-  //  settings.width = 700;
-  // });
-
-  CKEDITOR.plugins.add('linkit', {
-    init: function (editor) {
-      // Add the commands for link and unlink.
-      editor.addCommand('linkit', {
-        allowedContent: new CKEDITOR.style({
-          element: 'a',
-          attributes: {
-            '!href': '',
-            // @TODO: Read these dynamically from the profile.
-            'accesskey': '',
-            'id': '',
-            'rel': '',
-            'target': '',
-            'title': ''
-          }
-        }),
-        requiredContent: new CKEDITOR.style({
-          element: 'a',
-          attributes: {
-            href: ''
-          }
-        }),
-        modes: {wysiwyg: 1},
-        canUndo: true,
-        exec: function (editor) {
-          var linkElement = getSelectedLink(editor);
-          var linkDOMElement = null;
-
-          // Set existing values based on selected element.
-          var existingValues = {};
-          if (linkElement && linkElement.$) {
-            linkDOMElement = linkElement.$;
-
-            // Populate an array with the link's current attributes.
-            var attribute = null;
-            var attributeName;
-            for (var attrIndex = 0; attrIndex < linkDOMElement.attributes.length; attrIndex++) {
-              attribute = linkDOMElement.attributes.item(attrIndex);
-              attributeName = attribute.nodeName.toLowerCase();
-              // Don't consider data-cke-saved- attributes; they're just there
-              // to work around browser quirks.
-              if (attributeName.substring(0, 15) === 'data-cke-saved-') {
-                continue;
-              }
-              // Store the value for this attribute, unless there's a
-              // data-cke-saved- alternative for it, which will contain the
-              // quirk-free, original value.
-              existingValues[attributeName] = linkElement.data('cke-saved-' + attributeName) || attribute.nodeValue;
-            }
-          }
-
-          // Prepare a save callback to be used upon saving the dialog.
-          var saveCallback = function (returnValues) {
-            editor.fire('saveSnapshot');
-
-            // Create a new link element if needed.
-            if (!linkElement && returnValues.attributes.href) {
-              var selection = editor.getSelection();
-              var range = selection.getRanges(1)[0];
-
-              // Use link URL as text with a collapsed cursor.
-              if (range.collapsed) {
-                // Shorten mailto URLs to just the email address.
-                var text = new CKEDITOR.dom.text(returnValues.attributes.href.replace(/^mailto:/, ''), editor.document);
-                range.insertNode(text);
-                range.selectNodeContents(text);
-              }
-
-              // Create the new link by applying a style to the new text.
-              var style = new CKEDITOR.style({element: 'a', attributes: returnValues.attributes});
-              style.type = CKEDITOR.STYLE_INLINE;
-              style.applyToRange(range);
-              range.select();
-
-              // Set the link so individual properties may be set below.
-              linkElement = getSelectedLink(editor);
-            }
-            // Update the link properties.
-            else if (linkElement) {
-              for (var attrName in returnValues.attributes) {
-                if (returnValues.attributes.hasOwnProperty(attrName)) {
-                  // Update the property if a value is specified.
-                  if (returnValues.attributes[attrName].length > 0) {
-                    var value = returnValues.attributes[attrName];
-                    linkElement.data('cke-saved-' + attrName, value);
-                    linkElement.setAttribute(attrName, value);
-                  }
-                  // Delete the property if set to an empty string.
-                  else {
-                    linkElement.removeAttribute(attrName);
-                  }
-                }
-              }
-            }
-
-            // Save snapshot for undo support.
-            editor.fire('saveSnapshot');
-          };
-          // Drupal.t() will not work inside CKEditor plugins because CKEditor
-          // loads the JavaScript file instead of Drupal. Pull translated
-          // strings from the plugin settings that are translated server-side.
-          var dialogSettings = {
-            title: linkElement ? editor.config.linkit_dialogTitleAdd : editor.config.linkit_dialogTitleEdit,
-            dialogClass: 'editor-linkit-dialog'
-          };
-
-          // Open the dialog for the edit form.
-          Drupal.ckeditor.openDialog(editor, Drupal.url('linkit/dialog/linkit/' + editor.config.drupal.format), existingValues, saveCallback, dialogSettings);
-        }
-      });
-
-      // CTRL + L.
-      editor.setKeystroke(CKEDITOR.CTRL + 76, 'linkit');
-
-      // Add buttons.
-      if (editor.ui.addButton) {
-        editor.ui.addButton('Linkit', {
-          label: Drupal.t('Link'),
-          command: 'linkit',
-          icon: this.path + '/linkit.png'
-        });
-      }
-
-      editor.on('doubleclick', function (evt) {
-        var element = getSelectedLink(editor) || evt.data.element;
-
-        if (!element.isReadOnly()) {
-          if (element.is('a')) {
-            editor.getSelection().selectElement(element);
-            editor.getCommand('linkit').exec();
-          }
-        }
-      });
-
-      // If the "menu" plugin is loaded, register the menu items.
-      if (editor.addMenuItems) {
-        editor.addMenuItems({
-          linkit: {
-            label: Drupal.t('Edit Link'),
-            command: 'linkit',
-            group: 'link',
-            order: 1
-          }
-        });
-      }
-
-      // If the "contextmenu" plugin is loaded, register the listeners.
-      if (editor.contextMenu) {
-        editor.contextMenu.addListener(function (element, selection) {
-          if (!element || element.isReadOnly()) {
-            return null;
-          }
-          var anchor = getSelectedLink(editor);
-          if (!anchor) {
-            return null;
-          }
-
-          var menu = {};
-          if (anchor.getAttribute('href') && anchor.getChildCount()) {
-            menu = {
-              linkit: CKEDITOR.TRISTATE_OFF
-            };
-          }
-          return menu;
-        });
-      }
-    }
-  });
-
-  /**
-   * Get the surrounding link element of current selection.
-   *
-   * The following selection will all return the link element.
-   *
-   * @example
-   *  <a href="#">li^nk</a>
-   *  <a href="#">[link]</a>
-   *  text[<a href="#">link]</a>
-   *  <a href="#">li[nk</a>]
-   *  [<b><a href="#">li]nk</a></b>]
-   *  [<a href="#"><b>li]nk</b></a>
-   *
-   * @param {CKEDITOR.editor} editor
-   *   The CKEditor editor object
-   *
-   * @return {?HTMLElement}
-   *   The selected link element, or null.
-   *
-   */
-  function getSelectedLink(editor) {
-    var selection = editor.getSelection();
-    var selectedElement = selection.getSelectedElement();
-    if (selectedElement && selectedElement.is('a')) {
-      return selectedElement;
-    }
-
-    var range = selection.getRanges(true)[0];
-
-    if (range) {
-      range.shrink(CKEDITOR.SHRINK_TEXT);
-      return editor.elementPath(range.getCommonAncestor()).contains('a', 1);
-    }
-    return null;
-  }
-
-})(jQuery, Drupal, drupalSettings, CKEDITOR);

+ 7 - 5
sites/all/modules/contrib/fields/linkit/linkit.info.yml

@@ -1,12 +1,14 @@
 name: Linkit
-description: Linkit
-package: Custom
 type: module
+description: 'Provides an easy interface for internal and external linking with wysiwyg editors.'
+package: User interface
 # core: 8.x
 configure: entity.linkit_profile.collection
+test_dependencies:
+  - imce
 
-# Information added by Drupal.org packaging script on 2017-03-21
-version: '8.x-4.3'
+# Information added by Drupal.org packaging script on 2018-03-08
+version: '8.x-5.0-beta7'
 core: '8.x'
 project: 'linkit'
-datestamp: 1490127367
+datestamp: 1520552594

+ 190 - 1
sites/all/modules/contrib/fields/linkit/linkit.install

@@ -2,5 +2,194 @@
 
 /**
  * @file
- * Installation functions for Linkit module.
+ * Contains install and update functions for Linkit.
  */
+
+/**
+ * Implements hook_uninstall().
+ */
+function linkit_uninstall() {
+  $config_factory = \Drupal::configFactory();
+
+  // Remove the image styles that Linkit has installed.
+  $config_factory->getEditable('image.style.linkit_result_thumbnail')->delete();
+}
+
+/**
+ * Updates Linkit from 4 to 5.
+ *
+ * Removes linkit profile attributes.
+ * Replaces the linkit ckeditor plugin with drupallink.
+ * Enables the linkit filter on text formats where linkit is used.
+ * Adds 'data-entity-type' and 'data-entity-uuid' attributes to the <a> tag
+ * if filter_html is activated.
+ */
+function linkit_update_8500() {
+  $config_factory = \Drupal::configFactory();
+
+  // Iterate on all profile configuration entities.
+  foreach ($config_factory->listAll('linkit.linkit_profile.') as $id) {
+    $profile = $config_factory->getEditable($id);
+    // Remove all attributes.
+    $profile->clear('attributes')->save(TRUE);
+  }
+
+  // An array that will be filled with text format ids that we should enable the
+  // new linkit_filter for.
+  $linkit_enabled_formats = [];
+
+  // Iterate on all editor configuration entities.
+  foreach ($config_factory->listAll('editor.editor.') as $id) {
+    $editor_config = $config_factory->getEditable($id);
+
+    // Save the old settings.
+    $old_linkit_settings = $editor_config->get('settings.plugins.linkit');
+
+    $drupal_link_in_use = FALSE;
+    $old_linkit_button_path = NULL;
+
+    // If the editor has old linkit settings, perform update tasks.
+    if (!is_null($old_linkit_settings)) {
+      // Remove the old linkit settings.
+      $editor_config->clear('settings.plugins.linkit');
+      $editor_config->save(TRUE);
+
+      // Add the format id that the editor is using.
+      $linkit_enabled_formats[] = $editor_config->get('format');
+
+      // Remove the old linkit plugin from the toolbar, and check if DrupalLink
+      // is present in the toolbar as linkit now extends this plugin.
+      $toolbar_rows = $editor_config->get('settings.toolbar.rows');
+      foreach ($toolbar_rows as $row_index => $row) {
+        foreach ($row as $button_group_index => $button_group) {
+          foreach ($button_group['items'] as $item__name) {
+            if ($item__name === 'Linkit') {
+              $old_linkit_button_path = 'settings.toolbar.rows.' . $row_index . '.' . $button_group_index . '.items';
+            }
+
+            if ($item__name === 'DrupalLink') {
+              $drupal_link_in_use = TRUE;
+            }
+          }
+        }
+      }
+
+      if ($old_linkit_button_path) {
+        $buttons = $editor_config->get($old_linkit_button_path);
+        $index = array_search('Linkit', $buttons);
+        // If the DrupalLink plugin is not present in the toolbar, lets add it
+        // in the same button group as the old linkit plugin was in.
+        if (!$drupal_link_in_use) {
+          $buttons[$index] = 'DrupalLink';
+        }
+        else {
+          unset($buttons[$index]);
+        }
+        $editor_config->set($old_linkit_button_path, array_values($buttons));
+        $editor_config->save(TRUE);
+      }
+
+      // Set the linkit settings to the DrupalLink.
+      $drupal_link_settings = [
+        'linkit_enabled' => TRUE,
+        'linkit_profile' => $old_linkit_settings['linkit_profile'],
+      ];
+      $editor_config->set('settings.plugins.drupallink', $drupal_link_settings);
+      $editor_config->save(TRUE);
+    }
+  }
+
+  // Enable the linkit_filter for all formats that is used with linkit.
+  foreach ($linkit_enabled_formats as $filter_id) {
+    $config = $config_factory->getEditable('filter.format.' . $filter_id);
+    $filter_html_weight = $config->get('filters.filter_html.weight');
+
+    $linkit_filter = [
+      'id' => 'linkit',
+      'provider' => 'linkit',
+      'status' => TRUE,
+      'weight' => $filter_html_weight ? ($filter_html_weight - 1) : -15,
+      'settings' => [
+        'title' => FALSE,
+      ],
+    ];
+    $config->set('filters.linkit', $linkit_filter);
+
+    $allowed_html = $config->get('filters.filter_html.settings.allowed_html');
+    if (!empty($allowed_html)) {
+      preg_match_all('/<([\w]+)[^>]*>/', $allowed_html, $out);
+      $current_mapping = array_combine($out[1], $out[0]);
+
+      if (isset($current_mapping['a'])) {
+        $allowed_html = str_replace($current_mapping['a'], str_replace('>', ' data-entity-type data-entity-uuid>', $current_mapping['a']), $allowed_html);
+      }
+      else {
+        $allowed_html .= ' <a href hreflang data-entity-type data-entity-uuid>';
+      }
+      $config->set('filters.filter_html.settings.allowed_html', $allowed_html);
+    }
+
+    $config->save(TRUE);
+  }
+}
+
+/**
+ * Prepare anchor attributes for substitution plugins.
+ */
+function linkit_update_8501() {
+  $config_factory = \Drupal::configFactory();
+
+  // Update all filter formats that allow the data-entity-uuid attribute to also
+  // allow the data-entity-substitution attribute.
+  foreach ($config_factory->listAll('filter.format.') as $id) {
+    $filter = $config_factory->getEditable($id);
+    if ($allowed_html = $filter->get('filters.filter_html.settings.allowed_html')) {
+      $allowed_html = str_replace('data-entity-uuid', 'data-entity-uuid data-entity-substitution', $allowed_html);
+      $filter->set('filters.filter_html.settings.allowed_html', $allowed_html);
+      $filter->save(TRUE);
+    }
+  }
+
+  // Update all "file" matchers to the "file" substitution plugin, to maintain
+  // existing behavior out of the box.
+  $config_factory = \Drupal::configFactory();
+  foreach ($config_factory->listAll('linkit.linkit_profile.') as $id) {
+    $profile = $config_factory->getEditable($id);
+    foreach ($profile->get('matchers') as $key => $matcher) {
+      $settings = $profile->get('matchers.' . $key . '.settings');
+      $settings['substitution_type'] = $matcher['id'] === 'entity:file' ? 'file' : 'canonical';
+      $profile->set('matchers.' . $key . '.settings', $settings);
+    }
+    $profile->save(TRUE);
+  }
+}
+
+/**
+ * Rename profile property 'result_description' to 'metadata'.
+ */
+function linkit_update_8502() {
+  $config_factory = \Drupal::configFactory();
+  foreach ($config_factory->listAll('linkit.linkit_profile.') as $id) {
+    $profile = $config_factory->getEditable($id);
+
+    foreach ($profile->get('matchers') as $key => $matcher) {
+      $old_value = $profile->get('matchers.' . $key . '.settings.result_description');
+      $profile->set('matchers.' . $key . '.settings.metadata', $old_value);
+      $profile->clear('matchers.' . $key . '.settings.result_description');
+    }
+
+    $profile->save(TRUE);
+  }
+}
+
+/**
+ * Remove imce integration settings.
+ */
+function linkit_update_8503() {
+  $config_factory = \Drupal::configFactory();
+  foreach ($config_factory->listAll('linkit.linkit_profile.') as $id) {
+    $profile = $config_factory->getEditable($id);
+    $profile->clear('third_party_settings.imce');
+    $profile->save(TRUE);
+  }
+}

+ 2 - 13
sites/all/modules/contrib/fields/linkit/linkit.libraries.yml

@@ -26,18 +26,7 @@ linkit.autocomplete:
     - core/jquery.ui.autocomplete
     - core/underscore
 
-linkit.attribute.title:
+linkit.filter_html.admin:
   version: VERSION
   js:
-    js/attribute/title.js: {}
-  dependencies:
-    - linkit/linkit.base
-    - linkit/linkit.autocomplete
-
-linkit.imce:
-  version: VERSION
-  js:
-    js/linkit.imce.js: {}
-  dependencies:
-    - core/jquery.once
-    - linkit/linkit.base
+    js/linkit.filter_html.admin.js: {}

+ 0 - 7
sites/all/modules/contrib/fields/linkit/linkit.links.action.yml

@@ -9,10 +9,3 @@ linkit.matcher.add:
   title: 'Add matcher'
   appears_on:
     - linkit.matchers
-
-linkit.attribute.add:
-  route_name: linkit.attribute.add
-  title: 'Add attribute'
-  appears_on:
-    - linkit.attributes
-

+ 0 - 5
sites/all/modules/contrib/fields/linkit/linkit.links.task.yml

@@ -8,8 +8,3 @@ linkit.matchers:
   title: 'Manage matchers'
   base_route: entity.linkit_profile.edit_form
   weight: 5
-linkit.attributes:
-  route_name: linkit.attributes
-  title: 'Manage attributes'
-  base_route: entity.linkit_profile.edit_form
-  weight: 10

+ 123 - 79
sites/all/modules/contrib/fields/linkit/linkit.module

@@ -2,108 +2,152 @@
 
 /**
  * @file
- *
+ * Linkit hook implementations.
  */
 
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
-use Drupal\Core\StreamWrapper\StreamWrapperInterface;
 use Drupal\Core\Url;
-use Drupal\linkit\ProfileInterface;
 
 /**
  * Implements hook_help().
  */
 function linkit_help($route_name, RouteMatchInterface $route_match) {
   switch ($route_name) {
-    case 'entity.linkit_profile.attributes':
-      return '<p>' . t('Attributes are HTML attributes that will be attached to the insert plugin.') . '</p>';
-      break;
+    case 'help.page.linkit':
+      $output = '';
+      $output .= '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t('The Linkit module provides an easy interface for internal and external linking with wysiwyg editors by using an autocomplete field.') . '</p>';
+      $output .= '<h3>' . t('Uses') . '</h3>';
+      $output .= '<dl>';
+      $output .= '<dt>' . t('Managing Linkit profiles') . '</dt>';
+      $output .= '<dd>' . t('You can create and edit Linkit profiles on the <a href=":profiles">Linkit profile page</a>. You can create a Linkit profile by clicking "<a href=":add_profile">Add profile</a>".', [':profiles' => Url::fromRoute('entity.linkit_profile.collection')->toString(), ':add_profile' => Url::fromRoute('entity.linkit_profile.add_form')->toString()]) . '</dd>';
+      $output .= '</dl>';
+      return $output;
+
+    case 'entity.linkit_profile.collection':
+      $output = '<p>' . t('Linkit profiles define how Linkit will operate on fields that have Linkit attached.') . '</p>';
+      $output .= '<p>' . t('The most common way to use Linkit is to enable Linkit on the Drupal Link plugin and associate a Linkit profile to it on a Text format.') . '</p>';
+      return $output;
+
+    case 'linkit.matchers':
+      $output = '<p>' . t('Matchers defines how different data can be queried and displayed in the autocomplete suggestion list. Multiple matchers of the same type can be used at the same time to granulate the suggestions. The order of the added matchers defines in which order the suggestions will be presented.') . '</p>';
+      return $output;
   }
 }
 
-
 /**
- * Implements hook_form_BASE_FORM_ID_alter() for linkit_profile_form on behalf
- * of the 'imce' module.
- *
- * Adds IMCE settings to the form.
- *
- * @see imce_form_linkit_profile_form_builder()
+ * Implements hook_ckeditor_plugin_info_alter().
  */
-function imce_form_linkit_profile_form_alter(&$form, FormStateInterface $form_state) {
-  /** @var \Drupal\Linkit\ProfileInterface $linkit_profile */
-  $linkit_profile = $form_state->getFormObject()->getEntity();
-
-  $form['imce'] = array(
-    '#type' => 'details',
-    '#title' => t('IMCE integration'),
-    '#group' => 'additional_settings',
-  );
-
-  $form['imce']['imce_use'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Enable IMCE File Browser in the editor dialog.'),
-    '#default_value' => $linkit_profile->getThirdPartySetting('imce', 'use', FALSE),
-  );
-
-  $scheme_options = \Drupal::service('stream_wrapper_manager')->getNames(StreamWrapperInterface::READ_VISIBLE);
-  $form['imce']['imce_scheme'] = array(
-    '#type' => 'radios',
-    '#title' => t('Scheme'),
-    '#options' => $scheme_options,
-    '#default_value' => $linkit_profile->getThirdPartySetting('imce', 'scheme', 'public'),
-    '#states' => [
-      'visible' => [
-        ':input[name="imce_use"]' => ['checked' => TRUE],
-      ],
-    ],
-  );
-
-  $form['#entity_builders'][] = 'imce_form_linkit_profile_form_builder';
+function linkit_ckeditor_plugin_info_alter(array &$plugins) {
+  if (isset($plugins['drupallink'])) {
+    $plugins['drupallink']['class'] = "Drupal\\linkit\\Plugin\\CKEditorPlugin\\LinkitDrupalLink";
+  }
 }
 
 /**
- * Entity builder for the linkit profile form with imce options.
- *
- * @see imce_form_linkit_profile_form_alter().
+ * Implements hook_form_FORM_ID_alter().
  */
-function imce_form_linkit_profile_form_builder($entity_type, ProfileInterface $linkit_profile, &$form, FormStateInterface $form_state) {
-  $linkit_profile->setThirdPartySetting('imce', 'use', $form_state->getValue('imce_use'));
-  $linkit_profile->setThirdPartySetting('imce', 'scheme', $form_state->getValue('imce_scheme'));
+function linkit_form_editor_link_dialog_alter(&$form, FormStateInterface $form_state, $form_id) {
+  // Alter only the form with ID 'editor_link_dialog'.
+  if ($form_id !== 'editor_link_dialog') {
+    return;
+  }
+
+  /** @var Drupal\filter\Entity\FilterFormat $filter_format */
+  $filter_format = $form_state->getBuildInfo()['args'][0];
+
+  /** @var \Drupal\Core\Entity\EntityStorageInterface $editorStorage */
+  $editorStorage = Drupal::service('entity.manager')->getStorage('editor');
+
+  /** @var \Drupal\editor\EditorInterface $editor */
+  $editor = $editorStorage->load($filter_format->id());
+  $plugin_settings = $editor->getSettings()['plugins']['drupallink'];
+
+  // Do not alter the form if Linkit is not enabled for this text format.
+  if (!isset($plugin_settings['linkit_enabled']) || (isset($plugin_settings['linkit_enabled']) && !$plugin_settings['linkit_enabled'])) {
+    return;
+  }
+
+  $linkit_profile_id = $editor->getSettings()['plugins']['drupallink']['linkit_profile'];
+
+  if (isset($form_state->getUserInput()['editor_object'])) {
+    $input = $form_state->getUserInput()['editor_object'];
+    $form_state->set('link_element', $input);
+    $form_state->setCached(TRUE);
+  }
+  else {
+    // Retrieve the link element's attributes from form state.
+    $input = $form_state->get('link_element') ?: [];
+  }
+
+  $form['href_dirty_check'] = [
+    '#type' => 'hidden',
+    '#default_value' => isset($input['href']) ? $input['href'] : '',
+  ];
+
+  $form['attributes']['href'] = array_merge($form['attributes']['href'], [
+    '#type' => 'linkit',
+    '#description' => t('Start typing to find content.'),
+    '#autocomplete_route_name' => 'linkit.autocomplete',
+    '#autocomplete_route_parameters' => [
+      'linkit_profile_id' => $linkit_profile_id,
+    ],
+    "#weight" => -10,
+    '#default_value' => isset($input['href']) ? $input['href'] : '',
+  ]);
+
+  $fields = [
+    'data-entity-type',
+    'data-entity-uuid',
+    'data-entity-substitution',
+  ];
+
+  $form['attributes']["#weight"] = -100;
+
+  foreach ($fields as $field_name) {
+    $form['attributes'][$field_name] = [
+      '#title' => $field_name,
+      '#type' => 'hidden',
+      '#default_value' => isset($input[$field_name]) ? $input[$field_name] : '',
+    ];
+  }
+
+  // Add #submit callback that handles the data-* attributes.
+  array_unshift($form['#submit'], 'linkit_form_editor_link_dialog_submit');
 }
 
 /**
- * Implements hook_form_BASE_FORM_ID_alter() for linkit_editor_dialog_form on
- * behalf of the 'imce' module.
- *
- * Adds a button to open the imce file browser if it is enabled.
+ * Handles the data-* attributes and href replacement when appropriate.
  */
-function imce_form_linkit_editor_dialog_form_alter(&$form, FormStateInterface $form_state) {
-  /** @var \Drupal\Linkit\ProfileInterface $linkit_profile */
-  $linkit_profile = $form_state->getFormObject()->getLinkitProfile();
-
-  if($linkit_profile->getThirdPartySetting('imce', 'use', FALSE)) {
-    $form['imce-link'] = [
-      '#type' => 'link',
-      '#title' => t('Open IMCE file browser'),
-      '#url' => Url::fromRoute('imce.page', [
-        'scheme' => $linkit_profile->getThirdPartySetting('imce', 'scheme', 'public'),
-      ]),
-      '#options' => array(
-        'query' => array(
-          'sendto' => 'linkitImce.sendto',
-        ),
-      ),
-      '#attributes' => [
-        'class' => ['linkit-imce-open'],
-      ],
-      '#attached' => [
-        'library' => [
-          'linkit/linkit.imce'
-        ],
-      ],
-      '#weight' => 1,
-    ];
+function linkit_form_editor_link_dialog_submit(array &$form, FormStateInterface $form_state) {
+  $link_element = $form_state->get('link_element');
+
+  $href = $form_state->getValue(['attributes', 'href']);
+  $href_dirty_check = $form_state->getValue(['href_dirty_check']);
+
+  if ($href !== $href_dirty_check) {
+    $form_state->unsetValue(['attributes', 'data-entity-type']);
+    $form_state->unsetValue(['attributes', 'data-entity-uuid']);
+    $form_state->unsetValue(['attributes', 'data-entity-substitution']);
+  }
+
+  $fields = [
+    'href',
+    'data-entity-type',
+    'data-entity-uuid',
+    'data-entity-substitution',
+  ];
+
+  foreach ($fields as $field_name) {
+    $value = $form_state->getValue(['attributes', $field_name]);
+    if (empty($value)) {
+      if (!empty($link_element)) {
+        $form_state->setValue(['attributes', $field_name], '');
+      }
+      else {
+        $form_state->unsetValue(['attributes', $field_name]);
+      }
+    }
   }
 }

+ 1 - 1
sites/all/modules/contrib/fields/linkit/linkit.permissions.yml

@@ -1,2 +1,2 @@
 administer linkit profiles:
-  title: 'Administer linkit profiles'
+  title: 'Administer linkit profiles'

+ 1 - 41
sites/all/modules/contrib/fields/linkit/linkit.routing.yml

@@ -29,37 +29,6 @@ entity.linkit_profile.delete_form:
   requirements:
     _permission: 'administer linkit profiles'
 
-linkit.attributes:
-  path: '/admin/config/content/linkit/manage/{linkit_profile}/attributes'
-  defaults:
-    _form: '\Drupal\linkit\Form\Attribute\OverviewForm'
-    _title: 'Manage attributes'
-  requirements:
-    _permission: 'administer linkit profiles'
-
-linkit.attribute.add:
-  path: '/admin/config/content/linkit/manage/{linkit_profile}/attributes/add'
-  defaults:
-    _form: '\Drupal\linkit\Form\Attribute\AddForm'
-    _title: 'Add attribute'
-  requirements:
-    _permission: 'administer linkit profiles'
-
-linkit.attribute.delete:
-  path: '/admin/config/content/linkit/manage/{linkit_profile}/attributes/{plugin_instance_id}/delete'
-  defaults:
-    _form: '\Drupal\linkit\Form\Attribute\DeleteForm'
-  requirements:
-    _permission: 'administer linkit profiles'
-
-linkit.attribute.edit:
-  path: '/admin/config/content/linkit/manage/{linkit_profile}/attributes/{plugin_instance_id}'
-  defaults:
-    _form: '\Drupal\linkit\Form\Attribute\EditForm'
-    _title_callback: 'Drupal\linkit\Controller\LinkitController::attributeTitle'
-  requirements:
-    _permission: 'administer linkit profiles'
-
 linkit.matchers:
   path: '/admin/config/content/linkit/manage/{linkit_profile}/matchers'
   defaults:
@@ -91,21 +60,12 @@ linkit.matcher.edit:
   requirements:
     _permission: 'administer linkit profiles'
 
-linkit.linkit_dialog:
-  path: '/linkit/dialog/linkit/{filter_format}'
-  defaults:
-    _form: '\Drupal\linkit\Form\LinkitEditorDialog'
-    _title: 'Add link'
-  requirements:
-    _entity_access: 'filter_format.use'
-  options:
-    _theme: ajax_base_page
-
 linkit.autocomplete:
   path: '/linkit/autocomplete/{linkit_profile_id}'
   defaults:
     _controller: '\Drupal\linkit\Controller\AutocompleteController::autocomplete'
   requirements:
+    # Access is handled by the matchers.
     _access: 'TRUE'
   options:
     _theme: ajax_base_page

+ 6 - 7
sites/all/modules/contrib/fields/linkit/linkit.services.yml

@@ -1,11 +1,10 @@
 services:
-  plugin.manager.linkit.attribute:
-    class: Drupal\linkit\AttributeManager
-    parent: default_plugin_manager
-
   plugin.manager.linkit.matcher:
     class: Drupal\linkit\MatcherManager
     parent: default_plugin_manager
-
-  linkit.result_manager:
-    class: Drupal\linkit\ResultManager
+  plugin.manager.linkit.substitution:
+    class: Drupal\linkit\SubstitutionManager
+    arguments: ['@entity_type.manager']
+    parent: default_plugin_manager
+  linkit.suggestion_manager:
+    class: Drupal\linkit\SuggestionManager

+ 0 - 69
sites/all/modules/contrib/fields/linkit/src/Annotation/Attribute.php

@@ -1,69 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Annotation\Attribute.
- */
-
-namespace Drupal\linkit\Annotation;
-
-use Drupal\Component\Annotation\Plugin;
-
-/**
- * Defines an attribute annotation object.
- *
- * Plugin Namespace: Plugin\Linkit\Attribute
- *
- * For a working example, see \Drupal\linkit\Plugin\Linkit\Attribute\Title
- *
- * @see \Drupal\linkit\AttributeInterface
- * @see \Drupal\linkit\AttributeBase
- * @see \Drupal\linkit\AttributeManager
- * @see plugin_api
- *
- * @Annotation
- */
-class Attribute extends Plugin {
-
-  /**
-   * The plugin ID.
-   *
-   * @var string
-   */
-  public $id;
-
-  /**
-   * The human-readable name of the attribute.
-   *
-   * The string should be wrapped in a @Translation().
-   *
-   * @var \Drupal\Core\Annotation\Translation
-   */
-  public $label;
-
-  /**
-   * The real HTML attribute name for this attribute.
-   *
-   * @var string
-   */
-  public $html_name;
-
-  /**
-   * A brief description of the attribute.
-   *
-   * This will be shown when adding or configuring a profile.
-   *
-   * @ingroup plugin_translatable
-   *
-   * @var \Drupal\Core\Annotation\Translation (optional)
-   */
-  public $description = '';
-
-  /**
-   * A default weight for the attribute.
-   *
-   * @var int (optional)
-   */
-  public $weight = 0;
-
-}

+ 1 - 13
sites/all/modules/contrib/fields/linkit/src/Annotation/Matcher.php

@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Annotation\Matcher.
- */
-
 namespace Drupal\linkit\Annotation;
 
 use Drupal\Component\Annotation\Plugin;
@@ -12,7 +7,7 @@ use Drupal\Component\Annotation\Plugin;
 /**
  * Defines a matcher annotation object.
  *
- * Plugin Namespace: Plugin\Linkit\Matcher
+ * Plugin Namespace: Plugin\Linkit\Matcher.
  *
  * @see \Drupal\linkit\MatcherInterface
  * @see \Drupal\linkit\MatcherBase
@@ -39,11 +34,4 @@ class Matcher extends Plugin {
    */
   public $label;
 
-  /**
-   * The entity type that is managed by this matcher.
-   *
-   * @var string
-   */
-  public $entity_type;
-
 }

+ 28 - 0
sites/all/modules/contrib/fields/linkit/src/Annotation/Substitution.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace Drupal\linkit\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Defines a substitution annotation object.
+ *
+ * @Annotation
+ */
+class Substitution extends Plugin {
+
+  /**
+   * The plugin ID.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The human-readable name of the substitution.
+   *
+   * @var \Drupal\Core\Annotation\Translation
+   */
+  public $label;
+
+}

+ 0 - 112
sites/all/modules/contrib/fields/linkit/src/AttributeBase.php

@@ -1,112 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\AttributeBase.
- */
-
-namespace Drupal\linkit;
-
-use Drupal\Core\Plugin\PluginBase;
-
-/**
- * Provides a base class for attribute plugins.
- *
- * @see \Drupal\linkit\Annotation\Attribute
- * @see \Drupal\linkit\AttributeBase
- * @see \Drupal\linkit\AttributeManager
- * @see plugin_api
- */
-abstract class AttributeBase extends PluginBase implements AttributeInterface {
-
-  /**
-   * The weight of the attribute compared to others in an attribute collection.
-   *
-   * @var int
-   */
-  protected $weight = 0;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition);
-
-    $this->setConfiguration($configuration);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getConfiguration() {
-    return [
-      'id' => $this->getPluginId(),
-      'weight' => $this->weight,
-      'settings' => $this->configuration,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setConfiguration(array $configuration) {
-    $configuration += [
-      'weight' => '0',
-      'settings' => [],
-    ];
-    $this->configuration = $configuration['settings'] + $this->defaultConfiguration();
-    $this->weight = $configuration['weight'];
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function defaultConfiguration() {
-    return [];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function calculateDependencies() {
-    return [];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getLabel() {
-    return $this->pluginDefinition['label'];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getHtmlName() {
-    return $this->pluginDefinition['html_name'];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getDescription() {
-    return $this->pluginDefinition['description'];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getWeight() {
-    return $this->weight;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setWeight($weight) {
-    $this->weight = $weight;
-    return $this;
-  }
-
-}

+ 0 - 46
sites/all/modules/contrib/fields/linkit/src/AttributeCollection.php

@@ -1,46 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\AttributeCollection.
- */
-
-namespace Drupal\linkit;
-
-use Drupal\Core\Plugin\DefaultLazyPluginCollection;
-
-/**
- * A collection of attribute plugins.
- */
-class AttributeCollection extends DefaultLazyPluginCollection {
-
-  /**
-   * All possible attribute IDs.
-   *
-   * @var array
-   */
-  protected $definitions;
-
-  /**
-   * {@inheritdoc}
-   *
-   * @return \Drupal\linkit\AttributeInterface
-   */
-  public function &get($instance_id) {
-    return parent::get($instance_id);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function sortHelper($aID, $bID) {
-    $a_weight = $this->get($aID)->getWeight();
-    $b_weight = $this->get($bID)->getWeight();
-    if ($a_weight == $b_weight) {
-      return strnatcasecmp($this->get($aID)->getLabel(), $this->get($bID)->getLabel());
-    }
-
-    return ($a_weight < $b_weight) ? -1 : 1;
-  }
-
-}

+ 0 - 78
sites/all/modules/contrib/fields/linkit/src/AttributeInterface.php

@@ -1,78 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\AttributeInterface.
- */
-
-namespace Drupal\linkit;
-
-use Drupal\Component\Plugin\ConfigurablePluginInterface;
-use Drupal\Component\Plugin\PluginInspectionInterface;
-
-/**
- * Defines the interface for attributes plugins.
- *
- * @see \Drupal\linkit\Annotation\Attribute
- * @see \Drupal\linkit\AttributeBase
- * @see \Drupal\linkit\AttributeManager
- * @see plugin_api
- */
-interface AttributeInterface extends PluginInspectionInterface, ConfigurablePluginInterface {
-
-  /**
-   * Returns the attribute label.
-   *
-   * @return string
-   *   The attribute label.
-   */
-  public function getLabel();
-
-  /**
-   * Returns the attribute description.
-   *
-   * @return string
-   *   The attribute description.
-   */
-  public function getDescription();
-
-  /**
-   * Returns the attribute html name. This is the name of the attribute
-   * that will be inserted in the <code>&lt;a&gt;</code> tag.
-   *
-   * @return string
-   *   The attribute html name.
-   */
-  public function getHtmlName();
-
-  /**
-   * Returns the weight of the attribute.
-   *
-   * @return int|string
-   *   Either the integer weight of the attribute or an empty string.
-   */
-  public function getWeight();
-
-  /**
-   * Sets the weight for this attribute.
-   *
-   * @param int $weight
-   *   The weight for this attribute.
-   *
-   * @return $this
-   */
-  public function setWeight($weight);
-
-  /**
-   * The form element structure for this attribute to be used in the dialog.
-   *
-   * @param mixed $default_value
-   *   The default value for the element. Used when editing an attribute in the
-   *   dialog.
-   *
-   * @return array
-   *   The form element.
-   */
-  public function buildFormElement($default_value);
-
-}

+ 0 - 29
sites/all/modules/contrib/fields/linkit/src/AttributeManager.php

@@ -1,29 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\AttributeManager.
- */
-
-namespace Drupal\linkit;
-
-use Drupal\Core\Cache\CacheBackendInterface;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\Core\Plugin\DefaultPluginManager;
-
-/**
- * Manages attributes.
- */
-class AttributeManager extends DefaultPluginManager {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/Linkit/Attribute', $namespaces, $module_handler, 'Drupal\linkit\AttributeInterface', 'Drupal\linkit\Annotation\Attribute');
-
-    $this->alterInfo('linkit_attribute');
-    $this->setCacheBackend($cache_backend, 'linkit_attributes');
-  }
-
-}

+ 0 - 16
sites/all/modules/contrib/fields/linkit/src/ConfigurableAttributeBase.php

@@ -1,16 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\ConfigurableAttributeBase.
- */
-
-namespace Drupal\linkit;
-
-/**
- * Provides a base class for configurable attributes.
- *
- * @see plugin_api
- */
-abstract class ConfigurableAttributeBase extends AttributeBase implements ConfigurableAttributeInterface {
-}

+ 0 - 23
sites/all/modules/contrib/fields/linkit/src/ConfigurableAttributeInterface.php

@@ -1,23 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\ConfigurableAttributeInterface.
- */
-
-namespace Drupal\linkit;
-
-use Drupal\Core\Plugin\PluginFormInterface;
-
-/**
- * Defines the interface for configurable attributes.
- *
- * @see \Drupal\linkit\Annotation\Attribute
- * @see \Drupal\linkit\ConfigurableAttributeBase
- * @see \Drupal\linkit\AttributeInterface
- * @see \Drupal\linkit\AttributeBase
- * @see \Drupal\linkit\AttributeManager
- * @see plugin_api
- */
-interface ConfigurableAttributeInterface extends AttributeInterface, PluginFormInterface {
-}

+ 0 - 5
sites/all/modules/contrib/fields/linkit/src/ConfigurableMatcherBase.php

@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\ConfigurableMatcherBase.
- */
-
 namespace Drupal\linkit;
 
 /**

+ 0 - 6
sites/all/modules/contrib/fields/linkit/src/ConfigurableMatcherInterface.php

@@ -1,11 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\ConfigurableMatcherInterface.
- */
-
-
 namespace Drupal\linkit;
 
 use Drupal\Core\Plugin\PluginFormInterface;

+ 28 - 22
sites/all/modules/contrib/fields/linkit/src/Controller/AutocompleteController.php

@@ -1,20 +1,18 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Controller\AutocompleteController.
- */
-
 namespace Drupal\linkit\Controller;
 
 use Drupal\Component\Utility\Unicode;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
-use Drupal\linkit\ResultManager;
+use Drupal\linkit\SuggestionManager;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Request;
 
+/**
+ * Returns responses for linkit autocomplete routes.
+ */
 class AutocompleteController implements ContainerInjectionInterface {
 
   /**
@@ -25,11 +23,11 @@ class AutocompleteController implements ContainerInjectionInterface {
   protected $linkitProfileStorage;
 
   /**
-   * The result manager.
+   * The suggestion manager.
    *
-   * @var \Drupal\linkit\ResultManager
+   * @var \Drupal\linkit\SuggestionManager
    */
-  protected $resultManager;
+  protected $suggestionManager;
 
   /**
    * The linkit profile.
@@ -41,14 +39,14 @@ class AutocompleteController implements ContainerInjectionInterface {
   /**
    * Constructs a EntityAutocompleteController object.
    *
-   * @param ResultManager $resultManager
-   *   The result service.
    * @param \Drupal\Core\Entity\EntityStorageInterface $linkit_profile_storage
    *   The linkit profile storage service.
+   * @param \Drupal\linkit\SuggestionManager $suggestionManager
+   *   The suggestion service.
    */
-  public function __construct(EntityStorageInterface $linkit_profile_storage, ResultManager $resultManager) {
+  public function __construct(EntityStorageInterface $linkit_profile_storage, SuggestionManager $suggestionManager) {
     $this->linkitProfileStorage = $linkit_profile_storage;
-    $this->resultManager = $resultManager;
+    $this->suggestionManager = $suggestionManager;
   }
 
   /**
@@ -57,7 +55,7 @@ class AutocompleteController implements ContainerInjectionInterface {
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('entity.manager')->getStorage('linkit_profile'),
-      $container->get('linkit.result_manager')
+      $container->get('linkit.suggestion_manager')
     );
   }
 
@@ -67,23 +65,31 @@ class AutocompleteController implements ContainerInjectionInterface {
    * Like other autocomplete functions, this function inspects the 'q' query
    * parameter for the string to use to search for suggestions.
    *
-   * @param Request $request
+   * @param \Symfony\Component\HttpFoundation\Request $request
    *   The request.
-   * @param $linkit_profile_id
+   * @param string $linkit_profile_id
    *   The linkit profile id.
-   * @return JsonResponse
+   *
+   * @return \Symfony\Component\HttpFoundation\JsonResponse
    *   A JSON response containing the autocomplete suggestions.
    */
   public function autocomplete(Request $request, $linkit_profile_id) {
     $this->linkitProfile = $this->linkitProfileStorage->load($linkit_profile_id);
-    $string = Unicode::strtolower($request->query->get('q'));
+    $string = $request->query->get('q');
 
-    $matches = $this->resultManager->getResults($this->linkitProfile, $string);
+    $suggestionCollection = $this->suggestionManager->getSuggestions($this->linkitProfile, Unicode::strtolower($string));
 
-    $json_object = new \stdClass();
-    $json_object->matches = $matches;
+    /*
+     * If there are no suggestions from the matcher plugins, we have to add a
+     * special suggestion that have the same path as the given string so users
+     * can select it and use it anyway. This is a common use case with external
+     * links.
+     */
+    if (!count($suggestionCollection->getSuggestions()) && !empty($string)) {
+      $suggestionCollection = $this->suggestionManager->addUnscathedSuggestion($suggestionCollection, $string);
+    }
 
-    return new JsonResponse($json_object);
+    return new JsonResponse($suggestionCollection);
   }
 
 }

+ 2 - 24
sites/all/modules/contrib/fields/linkit/src/Controller/LinkitController.php

@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Controller\LinkitController.
- */
-
 namespace Drupal\linkit\Controller;
 
 use Drupal\Core\Controller\ControllerBase;
@@ -25,7 +20,7 @@ class LinkitController extends ControllerBase {
    *   The profile label as a render array.
    */
   public function profileTitle(ProfileInterface $linkit_profile) {
-    return $this->t('Edit %label profile', array('%label' => $linkit_profile->label()));
+    return $this->t('Edit %label profile', ['%label' => $linkit_profile->label()]);
   }
 
   /**
@@ -42,24 +37,7 @@ class LinkitController extends ControllerBase {
   public function matcherTitle(ProfileInterface $linkit_profile, $plugin_instance_id) {
     /** @var \Drupal\linkit\MatcherInterface $matcher */
     $matcher = $linkit_profile->getMatcher($plugin_instance_id);
-    return $this->t('Edit %label matcher', array('%label' => $matcher->getLabel()));
-  }
-
-  /**
-   * Route title callback.
-   *
-   * @param \Drupal\linkit\ProfileInterface $linkit_profile
-   *   The profile.
-   * @param string $plugin_instance_id
-   *   The plugin instance id.
-   *
-   * @return string
-   *   The title for the attribute edit form.
-   */
-  public function attributeTitle(ProfileInterface $linkit_profile, $plugin_instance_id) {
-    /** @var \Drupal\linkit\AttributeInterface $attribute */
-    $attribute = $linkit_profile->getAttribute($plugin_instance_id);
-    return $this->t('Edit %label attribute', array('%label' => $attribute->getLabel()));
+    return $this->t('Edit %label matcher', ['%label' => $matcher->getLabel()]);
   }
 
 }

+ 14 - 31
sites/all/modules/contrib/fields/linkit/src/Element/Linkit.php

@@ -1,15 +1,9 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Element\Linkit.
- */
-
 namespace Drupal\linkit\Element;
 
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\BubbleableMetadata;
-use Drupal\Core\Render\Element;
 use Drupal\Core\Render\Element\FormElement;
 use Drupal\Core\Render\Element\Textfield;
 use Drupal\Core\Url;
@@ -26,20 +20,20 @@ class Linkit extends FormElement {
    */
   public function getInfo() {
     $class = get_class($this);
-    return array(
+    return [
       '#input' => TRUE,
       '#size' => 60,
-      '#process' => array(
-        array($class, 'processLinkitAutocomplete'),
-        array($class, 'processGroup'),
-      ),
-      '#pre_render' => array(
-        array($class, 'preRenderLinkitElement'),
-        array($class, 'preRenderGroup'),
-      ),
+      '#process' => [
+        [$class, 'processLinkitAutocomplete'],
+        [$class, 'processGroup'],
+      ],
+      '#pre_render' => [
+        [$class, 'preRenderLinkitElement'],
+        [$class, 'preRenderGroup'],
+      ],
       '#theme' => 'input__textfield',
-      '#theme_wrappers' => array('form_element'),
-    );
+      '#theme_wrappers' => ['form_element'],
+    ];
   }
 
   /**
@@ -63,7 +57,7 @@ class Linkit extends FormElement {
     $access = FALSE;
 
     if (!empty($element['#autocomplete_route_name'])) {
-      $parameters = isset($element['#autocomplete_route_parameters']) ? $element['#autocomplete_route_parameters'] : array();
+      $parameters = isset($element['#autocomplete_route_parameters']) ? $element['#autocomplete_route_parameters'] : [];
       $url = Url::fromRoute($element['#autocomplete_route_name'], $parameters)->toString(TRUE);
       /** @var \Drupal\Core\Access\AccessManagerInterface $access_manager */
       $access_manager = \Drupal::service('access_manager');
@@ -88,21 +82,10 @@ class Linkit extends FormElement {
   }
 
   /**
-   * Prepares a #type 'linkit' render element for input.html.twig.
-   *
-   * @param array $element
-   *   An associative array containing the properties of the element.
-   *   Properties used: #title, #value, #description, #size, #attributes.
-   *
-   * @return array
-   *   The $element with prepared variables ready for input.html.twig.
+   * {@inheritdoc}
    */
   public static function preRenderLinkitElement($element) {
-    $element['#attributes']['type'] = 'text';
-    Element::setAttributes($element, array('id', 'name', 'value', 'size'));
-    static::setAttributes($element, array('form-text'));
-
-    return $element;
+    return Textfield::preRenderTextfield($element);
   }
 
 }

+ 3 - 97
sites/all/modules/contrib/fields/linkit/src/Entity/Profile.php

@@ -1,15 +1,9 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Entity\Profile.
- */
-
 namespace Drupal\linkit\Entity;
 
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
-use Drupal\linkit\AttributeCollection;
 use Drupal\linkit\MatcherCollection;
 use Drupal\linkit\MatcherInterface;
 use Drupal\linkit\ProfileInterface;
@@ -43,7 +37,6 @@ use Drupal\linkit\ProfileInterface;
  *     "id",
  *     "label",
  *     "description",
- *     "attributes",
  *     "matchers"
  *   }
  * )
@@ -71,28 +64,6 @@ class Profile extends ConfigEntityBase implements ProfileInterface, EntityWithPl
    */
   protected $description;
 
-  /**
-   * Configured attribute for this profile.
-   *
-   * An associative array of attribute assigned to the profile, keyed by the
-   * attribute id of each attribute and using the properties:
-   * - id: The plugin ID of the attribute instance.
-   * - status: (optional) A Boolean indicating whether the attribute is enabled
-   *   in the profile. Defaults to FALSE.
-   * - weight: (optional) The weight of the attribute in the profile.
-   *   Defaults to 0.
-   *
-   * @var array
-   */
-  protected $attributes = [];
-
-  /**
-   * Holds the collection of attributes that are attached to this profile.
-   *
-   * @var \Drupal\linkit\AttributeCollection
-   */
-  protected $attributeCollection;
-
   /**
    * Configured matchers for this profile.
    *
@@ -130,50 +101,6 @@ class Profile extends ConfigEntityBase implements ProfileInterface, EntityWithPl
     return $this;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getAttribute($attribute_id) {
-    return $this->getAttributes()->get($attribute_id);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getAttributes() {
-    if (!$this->attributeCollection) {
-      $this->attributeCollection = new AttributeCollection($this->getAttributeManager(), $this->attributes);
-      $this->attributeCollection->sort();
-    }
-    return $this->attributeCollection;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function addAttribute(array $configuration) {
-    $this->getAttributes()->addInstanceId($configuration['id'], $configuration);
-    return $configuration['id'];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function removeAttribute($attribute_id) {
-    unset($this->attributes[$attribute_id]);
-    $this->getAttributes()->removeInstanceId($attribute_id);
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setAttributeConfig($attribute_id, array $configuration) {
-    $this->attributes[$attribute_id] = $configuration;
-    $this->getAttributes()->setInstanceConfiguration($attribute_id, $configuration);
-    return $this;
-  }
-
   /**
    * {@inheritdoc}
    */
@@ -186,7 +113,7 @@ class Profile extends ConfigEntityBase implements ProfileInterface, EntityWithPl
    */
   public function getMatchers() {
     if (!$this->matcherCollection) {
-      $this->matcherCollection = new MatcherCollection($this->getMatcherManager(), $this->matchers);
+      $this->matcherCollection = new MatcherCollection(\Drupal::service('plugin.manager.linkit.matcher'), $this->matchers);
       $this->matcherCollection->sort();
     }
     return $this->matcherCollection;
@@ -223,30 +150,9 @@ class Profile extends ConfigEntityBase implements ProfileInterface, EntityWithPl
    * {@inheritdoc}
    */
   public function getPluginCollections() {
-    return array(
-      'attributes' => $this->getAttributes(),
+    return [
       'matchers' => $this->getMatchers(),
-    );
-  }
-
-  /**
-   * Returns the attribute manager.
-   *
-   * @return \Drupal\Component\Plugin\PluginManagerInterface
-   *   The attribute manager.
-   */
-  protected function getAttributeManager() {
-    return \Drupal::service('plugin.manager.linkit.attribute');
-  }
-
-  /**
-   * Returns the matcher manager.
-   *
-   * @return \Drupal\Component\Plugin\PluginManagerInterface
-   *   The matcher manager.
-   */
-  protected function getMatcherManager() {
-    return \Drupal::service('plugin.manager.linkit.matcher');
+    ];
   }
 
 }

+ 0 - 166
sites/all/modules/contrib/fields/linkit/src/Form/Attribute/AddForm.php

@@ -1,166 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Form\Attribute\AddForm.
- */
-
-namespace Drupal\linkit\Form\Attribute;
-
-use Drupal\Core\Form\FormBase;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\linkit\AttributeManager;
-use Drupal\linkit\ConfigurableAttributeInterface;
-use Drupal\linkit\ProfileInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Provides a form to apply attributes to a profile.
- */
-class AddForm extends FormBase {
-
-  /**
-   * The profiles to which the attributes will be applied.
-   *
-   * @var \Drupal\linkit\ProfileInterface
-   */
-  protected $linkitProfile;
-
-  /**
-   * The attribute manager.
-   *
-   * @var \Drupal\linkit\AttributeManager
-   */
-  protected $manager;
-
-  /**
-   * Constructs a new AddForm.
-   *
-   * @param \Drupal\linkit\AttributeManager $manager
-   *   The attribute manager.
-   */
-  public function __construct(AttributeManager $manager) {
-    $this->manager = $manager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('plugin.manager.linkit.attribute')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFormId() {
-    return "linkit_attribute_add_form";
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, FormStateInterface $form_state, ProfileInterface $linkit_profile = NULL) {
-    $this->linkitProfile = $linkit_profile;
-
-    $form['#attached']['library'][] = 'linkit/linkit.admin';
-    $header = [
-      'label' => $this->t('Attributes'),
-      'description' => $this->t('Description'),
-    ];
-
-    $form['plugin'] = [
-      '#type' => 'tableselect',
-      '#header' => $header,
-      '#options' => $this->buildRows(),
-      '#empty' => $this->t('No attributes available.'),
-      '#multiple' => FALSE,
-    ];
-
-    $form['actions'] = ['#type' => 'actions'];
-    $form['actions']['submit'] = [
-      '#type' => 'submit',
-      '#value' => $this->t('Save and continue'),
-      '#submit' => ['::submitForm'],
-      '#tableselect' => TRUE,
-      '#button_type' => 'primary',
-    ];
-
-    return $form;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validateForm(array &$form, FormStateInterface $form_state) {
-    if (empty($form_state->getValue('plugin'))) {
-      $form_state->setErrorByName('plugin', $this->t('No attribute selected.'));
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
-    $form_state->cleanValues();
-
-    /** @var \Drupal\linkit\AttributeInterface $plugin */
-    $plugin = $this->manager->createInstance($form_state->getValue('plugin'));
-    $plugin_id = $this->linkitProfile->addAttribute($plugin->getConfiguration());
-    $this->linkitProfile->save();
-
-    $this->logger('linkit')->notice('Added %label attribute to the @profile profile.', [
-      '%label' => $this->linkitProfile->getAttribute($plugin_id)->getLabel(),
-      '@profile' => $this->linkitProfile->label(),
-    ]);
-
-    $is_configurable = $plugin instanceof ConfigurableAttributeInterface;
-    if ($is_configurable) {
-      $form_state->setRedirect('linkit.attribute.edit', [
-        'linkit_profile' => $this->linkitProfile->id(),
-        'plugin_instance_id' => $plugin_id,
-      ]);
-    }
-    else {
-      drupal_set_message($this->t('Added %label attribute.', ['%label' => $plugin->getLabel()]));
-
-      $form_state->setRedirect('linkit.attributes', [
-        'linkit_profile' => $this->linkitProfile->id(),
-      ]);
-    }
-  }
-
-  /**
-   * Builds the table rows.
-   *
-   * Only attributes that is not already applied to the profile are shown.
-   *
-   * @return array
-   *   An array of table rows.
-   */
-  private function buildRows() {
-    $rows = [];
-
-    $applied_plugins = $this->linkitProfile->getAttributes()->getConfiguration();
-    $all_plugins = $this->manager->getDefinitions();
-    uasort($all_plugins, function ($a, $b) {
-      return strnatcasecmp($a['label'], $b['label']);
-    });
-    foreach (array_diff_key($all_plugins, $applied_plugins) as $definition) {
-      /** @var \Drupal\linkit\AttributeInterface $plugin */
-      $plugin = $this->manager->createInstance($definition['id']);
-
-      $row = [
-        'label' => (string) $plugin->getLabel(),
-        'description' => (string) $plugin->getDescription(),
-      ];
-
-      $rows[$plugin->getPluginId()] = $row;
-    }
-
-    return $rows;
-  }
-
-}

+ 0 - 92
sites/all/modules/contrib/fields/linkit/src/Form/Attribute/DeleteForm.php

@@ -1,92 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Form\Attribute\DeleteForm.
- */
-
-namespace Drupal\linkit\Form\Attribute;
-
-use Drupal\Core\Form\ConfirmFormBase;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Url;
-use Drupal\linkit\ProfileInterface;
-use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
-
-/**
- * Provides a form to remove an attribute from a profile.
- */
-class DeleteForm extends ConfirmFormBase {
-
-  /**
-   * The profiles that the attribute is applied to.
-   *
-   * @var \Drupal\linkit\ProfileInterface
-   */
-  protected $linkitProfile;
-
-  /**
-   * The attribute to be removed from the profile.
-   *
-   * @var \Drupal\linkit\AttributeInterface
-   */
-  protected $linkitAttribute;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getQuestion() {
-    return $this->t('Are you sure you want to delete the @plugin attribute from the %profile profile?', ['%profile' => $this->linkitProfile->label(), '@plugin' => $this->linkitAttribute->getLabel()]);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCancelUrl() {
-    return Url::fromRoute('linkit.attributes', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ]);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFormId() {
-    return 'linkit_attribute_delete_form';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, FormStateInterface $form_state, ProfileInterface $linkit_profile = NULL, $plugin_instance_id = NULL) {
-    $this->linkitProfile = $linkit_profile;
-
-    if (!$this->linkitProfile->getAttributes()->has($plugin_instance_id)) {
-      throw new NotFoundHttpException();
-    }
-
-    $this->linkitAttribute = $this->linkitProfile->getAttribute($plugin_instance_id);
-    return parent::buildForm($form, $form_state);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
-    if ($this->linkitProfile->getAttributes()->has($this->linkitAttribute->getPluginId())) {
-      $this->linkitProfile->removeAttribute($this->linkitAttribute->getPluginId());
-      $this->linkitProfile->save();
-
-      drupal_set_message($this->t('The attribute %label has been deleted.', ['%label' => $this->linkitAttribute->getLabel()]));
-      $this->logger('linkit')->notice('The attribute %label has been deleted in the @profile profile.', [
-        '%label' => $this->linkitAttribute->getLabel(),
-        '@profile' => $this->linkitProfile->label(),
-      ]);
-    }
-
-    $form_state->setRedirect('linkit.attributes', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ]);
-  }
-
-}

+ 0 - 96
sites/all/modules/contrib/fields/linkit/src/Form/Attribute/EditForm.php

@@ -1,96 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Form\Attribute\EditForm.
- */
-
-namespace Drupal\linkit\Form\Attribute;
-
-use Drupal\Core\Form\FormBase;
-use Drupal\Core\Form\FormState;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Url;
-use Drupal\linkit\ProfileInterface;
-
-/**
- *  Provides an edit form for attributes.
- */
-class EditForm extends FormBase {
-
-  /**
-   * The profiles to which the attributes will be applied.
-   *
-   * @var \Drupal\linkit\ProfileInterface
-   */
-  protected $linkitProfile;
-
-  /**
-   * The attribute to edit.
-   *
-   * @var \Drupal\linkit\ConfigurableAttributeInterface
-   */
-  protected $linkitAttribute;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFormId() {
-    return 'linkit_attribute_edit_form';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, FormStateInterface $form_state, ProfileInterface $linkit_profile = NULL, $plugin_instance_id = NULL) {
-    $this->linkitProfile = $linkit_profile;
-    $this->linkitAttribute = $this->linkitProfile->getAttribute($plugin_instance_id);
-    $form['data'] = [
-      '#tree' => true,
-    ];
-
-    $form['data'] += $this->linkitAttribute->buildConfigurationForm($form, $form_state);
-
-    $form['actions'] = array('#type' => 'actions');
-    $form['actions']['submit'] = array(
-      '#type' => 'submit',
-      '#value' => $this->t('Save changes'),
-      '#submit' => array('::submitForm'),
-      '#button_type' => 'primary',
-    );
-    $form['actions']['delete'] = array(
-      '#type' => 'link',
-      '#title' => $this->t('Delete'),
-      '#url' => Url::fromRoute('linkit.attribute.delete', [
-        'linkit_profile' => $this->linkitProfile->id(),
-        'plugin_instance_id' => $this->linkitAttribute->getPluginId(),
-      ]),
-      '#attributes' => [
-        'class' => ['button', 'button--danger'],
-      ],
-    );
-
-    return $form;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
-    $form_state->cleanValues();
-    $plugin_data = (new FormState())->setValues($form_state->getValue('data'));
-    $this->linkitAttribute->submitConfigurationForm($form, $plugin_data);
-    $this->linkitProfile->save();
-
-    drupal_set_message($this->t('Saved %label configuration.', array('%label' => $this->linkitAttribute->getLabel())));
-    $this->logger('linkit')->notice('The attribute %label has been updated in the @profile profile.', [
-      '%label' => $this->linkitAttribute->getLabel(),
-      '@profile' => $this->linkitProfile->label(),
-    ]);
-
-    $form_state->setRedirect('linkit.attributes', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ]);
-  }
-
-}

+ 0 - 156
sites/all/modules/contrib/fields/linkit/src/Form/Attribute/OverviewForm.php

@@ -1,156 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Form\Attribute\OverviewForm.
- */
-
-namespace Drupal\linkit\Form\Attribute;
-
-use Drupal\Core\Form\FormBase;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Url;
-use Drupal\linkit\AttributeManager;
-use Drupal\linkit\ConfigurableAttributeInterface;
-use Drupal\linkit\ProfileInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Provides an overview form for attribute on a profile.
- */
-class OverviewForm extends FormBase {
-
-  /**
-   * The profiles to which the attributes are applied to.
-   *
-   * @var \Drupal\linkit\ProfileInterface
-   */
-  private $linkitProfile;
-
-  /**
-   * The attribute manager.
-   *
-   * @var \Drupal\linkit\AttributeManager
-   */
-  protected $manager;
-
-  /**
-   * Constructs a new OverviewForm.
-   *
-   * @param \Drupal\linkit\AttributeManager $manager
-   *   The attribute manager.
-   */
-  public function __construct(AttributeManager $manager) {
-    $this->manager = $manager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('plugin.manager.linkit.attribute')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFormId() {
-    return "linkit_attribute_overview_form";
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, FormStateInterface $form_state, ProfileInterface $linkit_profile = NULL) {
-    $this->linkitProfile = $linkit_profile;
-
-    $form['plugins'] = [
-      '#type' => 'table',
-      '#header' => [
-        $this->t('Attribute'),
-        $this->t('Description'),
-        $this->t('Weight'),
-        $this->t('Operations'),
-      ],
-      '#empty' => $this->t('No attributes added.'),
-      '#tabledrag' => [
-        [
-          'action' => 'order',
-          'relationship' => 'sibling',
-          'group' => 'plugin-order-weight',
-        ],
-      ],
-    ];
-
-    foreach ($this->linkitProfile->getAttributes() as $plugin) {
-      $key = $plugin->getPluginId();
-
-      $form['plugins'][$key]['#attributes']['class'][] = 'draggable';
-      $form['plugins'][$key]['#weight'] = $plugin->getWeight();
-
-      $form['plugins'][$key]['label'] = [
-        '#plain_text' => (string) $plugin->getLabel(),
-      ];
-
-      $form['plugins'][$key]['description'] = [
-        '#plain_text' => (string) $plugin->getDescription(),
-      ];
-
-      $form['plugins'][$key]['weight'] = [
-        '#type' => 'weight',
-        '#title' => t('Weight for @title', ['@title' => (string) $plugin->getLabel()]),
-        '#title_display' => 'invisible',
-        '#default_value' => $plugin->getWeight(),
-        '#attributes' => ['class' => ['plugin-order-weight']],
-      ];
-
-      $form['plugins'][$key]['operations'] = [
-        '#type' => 'operations',
-        '#links' => [],
-      ];
-
-      $is_configurable = $plugin instanceof ConfigurableAttributeInterface;
-      if ($is_configurable) {
-        $form['plugins'][$key]['operations']['#links']['edit'] = [
-          'title' => t('Edit'),
-          'url' => Url::fromRoute('linkit.attribute.edit', [
-            'linkit_profile' =>  $this->linkitProfile->id(),
-            'plugin_instance_id' => $key,
-          ]),
-        ];
-      }
-
-      $form['plugins'][$key]['operations']['#links']['delete'] = [
-        'title' => t('Delete'),
-        'url' => Url::fromRoute('linkit.attribute.delete', [
-          'linkit_profile' =>  $this->linkitProfile->id(),
-          'plugin_instance_id' => $key,
-        ]),
-      ];
-    }
-
-    $form['actions'] = ['#type' => 'actions'];
-    $form['actions']['submit'] = [
-      '#type' => 'submit',
-      '#value' => $this->t('Save'),
-      '#button_type' => 'primary',
-    ];
-
-    return $form;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
-    foreach ($form_state->getValue('plugins') as $id => $plugin_data) {
-      if ($this->linkitProfile->getAttributes()->has($id)) {
-        $this->linkitProfile->getAttribute($id)->setWeight($plugin_data['weight']);
-      }
-    }
-    $this->linkitProfile->save();
-  }
-
-}

+ 0 - 207
sites/all/modules/contrib/fields/linkit/src/Form/LinkitEditorDialog.php

@@ -1,207 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Form\LinkitEditorDialog.
- */
-
-namespace Drupal\linkit\Form;
-
-use Drupal\Core\Entity\EntityStorageInterface;
-use Drupal\Core\Form\FormBase;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\filter\Entity\FilterFormat;
-use Drupal\Core\Ajax\AjaxResponse;
-use Drupal\Core\Ajax\HtmlCommand;
-use Drupal\editor\Ajax\EditorDialogSave;
-use Drupal\Core\Ajax\CloseModalDialogCommand;
-use Drupal\linkit\AttributeCollection;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Provides a linkit dialog for text editors.
- */
-class LinkitEditorDialog extends FormBase {
-
-  /**
-   * The editor storage service.
-   *
-   * @var \Drupal\Core\Entity\EntityStorageInterface
-   */
-  protected $editorStorage;
-
-  /**
-   * The linkit profile storage service.
-   *
-   * @var \Drupal\Core\Entity\EntityStorageInterface
-   */
-  protected $linkitProfileStorage;
-
-  /**
-   * The linkit profile.
-   *
-   * @var \Drupal\linkit\ProfileInterface
-   */
-  protected $linkitProfile;
-
-  /**
-   * Constructs a form object for linkit dialog.
-   *
-   * @param \Drupal\Core\Entity\EntityStorageInterface $editor_storage
-   *   The editor storage service.
-   * @param \Drupal\Core\Entity\EntityStorageInterface $linkit_profile_storage
-   *   The linkit profile storage service.
-   */
-  public function __construct(EntityStorageInterface $editor_storage, EntityStorageInterface $linkit_profile_storage) {
-    $this->editorStorage = $editor_storage;
-    $this->linkitProfileStorage = $linkit_profile_storage;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('entity.manager')->getStorage('editor'),
-      $container->get('entity.manager')->getStorage('linkit_profile')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFormId() {
-    return 'linkit_editor_dialog_form';
-  }
-
-  /**
-   * {@inheritdoc}
-   *
-   * @param \Drupal\filter\Entity\FilterFormat $filter_format
-   *   The filter format for which this dialog corresponds.
-   */
-  public function buildForm(array $form, FormStateInterface $form_state, FilterFormat $filter_format = NULL) {
-    // The default values are set directly from \Drupal::request()->request,
-    // provided by the editor plugin opening the dialog.
-    $user_input = $form_state->getUserInput();
-    $input = isset($user_input['editor_object']) ? $user_input['editor_object'] : [];
-
-    /** @var \Drupal\editor\EditorInterface $editor */
-    $editor = $this->editorStorage->load($filter_format->id());
-    $linkit_profile_id = $editor->getSettings()['plugins']['linkit']['linkit_profile'];
-    $this->linkitProfile = $this->linkitProfileStorage->load($linkit_profile_id);
-
-    $form['#tree'] = TRUE;
-    $form['#attached']['library'][] = 'editor/drupal.editor.dialog';
-    $form['#prefix'] = '<div id="linkit-editor-dialog-form">';
-    $form['#suffix'] = '</div>';
-
-    // Everything under the "attributes" key is merged directly into the
-    // generated link tag's attributes.
-    $form['attributes']['href'] = [
-      '#title' => $this->t('Link'),
-      '#type' => 'linkit',
-      '#default_value' => isset($input['href']) ? $input['href'] : '',
-      '#description' => $this->t('Start typing to find content or paste a URL.'),
-      '#autocomplete_route_name' => 'linkit.autocomplete',
-      '#autocomplete_route_parameters' => [
-        'linkit_profile_id' => $linkit_profile_id
-      ],
-      '#weight' => 0,
-    ];
-
-    $this->addAttributes($form, $form_state, $this->linkitProfile->getAttributes(), $input);
-
-    $form['actions'] = [
-      '#type' => 'actions',
-    ];
-
-    $form['actions']['save_modal'] = [
-      '#type' => 'submit',
-      '#value' => $this->t('Save'),
-      '#submit' => [],
-      '#ajax' => [
-        'callback' => '::submitForm',
-        'event' => 'click',
-      ],
-    ];
-
-    return $form;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validateForm(array &$form, FormStateInterface $form_state) {
-    $attributes = array_filter($form_state->getValue('attributes'));
-    $form_state->setValue('attributes', $attributes);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, FormStateInterface $form_state) {
-    $response = new AjaxResponse();
-
-    if ($form_state->getErrors()) {
-      unset($form['#prefix'], $form['#suffix']);
-      $form['status_messages'] = [
-        '#type' => 'status_messages',
-        '#weight' => -10,
-      ];
-      $response->addCommand(new HtmlCommand('#linkit-editor-dialog-form', $form));
-    }
-    else {
-      $response->addCommand(new EditorDialogSave($form_state->getValues()));
-      $response->addCommand(new CloseModalDialogCommand());
-    }
-
-    return $response;
-  }
-
-  /**
-   * Adds the attributes enabled on the current profile.
-   *
-   * @param array $form
-   *   An associative array containing the structure of the form.
-   * @param \Drupal\Core\Form\FormStateInterface $form_state
-   *   The current state of the form.
-   * @param AttributeCollection $attributes
-   *   A collection of attributes for the current profile.
-   * @param array $input
-   *   An array with the attribute values from the editor.
-   */
-  private function addAttributes(array &$form, FormStateInterface &$form_state, AttributeCollection $attributes, array $input) {
-    if ($attributes->count()) {
-      $form['linkit_attributes'] = [
-        '#type' => 'container',
-        '#title' => $this->t('Attributes'),
-        '#weight' => '10',
-      ];
-
-      /** @var \Drupal\linkit\AttributeInterface $plugin */
-      foreach ($attributes as $plugin) {
-        $plugin_name = $plugin->getHtmlName();
-
-        $default_value = isset($input[$plugin_name]) ? $input[$plugin_name] : '';
-        $form['linkit_attributes'][$plugin_name] = $plugin->buildFormElement($default_value);
-        $form['linkit_attributes'][$plugin_name] += [
-          '#parents' => [
-            'attributes', $plugin_name,
-          ],
-        ];
-      }
-    }
-  }
-
-  /**
-   * Gets the linkit profile entity.
-   *
-   * @return \Drupal\linkit\ProfileInterface
-   *   The current linkit profile used by this form.
-   */
-  public function getLinkitProfile() {
-    return $this->linkitProfile;
-  }
-
-}

+ 0 - 10
sites/all/modules/contrib/fields/linkit/src/Form/Matcher/AddForm.php

@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Form\Matcher\AddForm.
- */
-
 namespace Drupal\linkit\Form\Matcher;
 
 use Drupal\Core\Form\FormBase;
@@ -88,11 +83,6 @@ class AddForm extends FormBase {
       '#button_type' => 'primary',
     ];
 
-    $options = [];
-    foreach ($this->manager->getDefinitions() as $id => $plugin) {
-      $options[$id] = $plugin['label'];
-    }
-
     return $form;
   }
 

+ 0 - 5
sites/all/modules/contrib/fields/linkit/src/Form/Matcher/DeleteForm.php

@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Form\Matcher\DeleteForm.
- */
-
 namespace Drupal\linkit\Form\Matcher;
 
 use Drupal\Core\Form\ConfirmFormBase;

+ 9 - 13
sites/all/modules/contrib/fields/linkit/src/Form/Matcher/EditForm.php

@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Form\Matcher\EditForm.
- */
-
 namespace Drupal\linkit\Form\Matcher;
 
 use Drupal\Core\Form\FormBase;
@@ -14,7 +9,7 @@ use Drupal\Core\Url;
 use Drupal\linkit\ProfileInterface;
 
 /**
- *  Provides an edit form for matchers.
+ * Provides an edit form for matchers.
  */
 class EditForm extends FormBase {
 
@@ -48,14 +43,14 @@ class EditForm extends FormBase {
 
     $form += $this->linkitMatcher->buildConfigurationForm($form, $form_state);
 
-    $form['actions'] = array('#type' => 'actions');
-    $form['actions']['submit'] = array(
+    $form['actions'] = ['#type' => 'actions'];
+    $form['actions']['submit'] = [
       '#type' => 'submit',
       '#value' => $this->t('Save changes'),
-      '#submit' => array('::submitForm'),
+      '#submit' => ['::submitForm'],
       '#button_type' => 'primary',
-    );
-    $form['actions']['delete'] = array(
+    ];
+    $form['actions']['delete'] = [
       '#type' => 'link',
       '#title' => $this->t('Delete'),
       '#url' => Url::fromRoute('linkit.matcher.delete', [
@@ -65,7 +60,7 @@ class EditForm extends FormBase {
       '#attributes' => [
         'class' => ['button', 'button--danger'],
       ],
-    );
+    ];
 
     return $form;
   }
@@ -79,7 +74,7 @@ class EditForm extends FormBase {
     $this->linkitMatcher->submitConfigurationForm($form, $plugin_data);
     $this->linkitProfile->save();
 
-    drupal_set_message($this->t('Saved %label configuration.', array('%label' => $this->linkitMatcher->getLabel())));
+    drupal_set_message($this->t('Saved %label configuration.', ['%label' => $this->linkitMatcher->getLabel()]));
     $this->logger('linkit')->notice('The matcher %label has been updated in the @profile profile.', [
       '%label' => $this->linkitMatcher->getLabel(),
       '@profile' => $this->linkitProfile->label(),
@@ -89,4 +84,5 @@ class EditForm extends FormBase {
       'linkit_profile' => $this->linkitProfile->id(),
     ]);
   }
+
 }

+ 7 - 12
sites/all/modules/contrib/fields/linkit/src/Form/Matcher/OverviewForm.php

@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Form\Matcher\OverviewForm.
- */
-
 namespace Drupal\linkit\Form\Matcher;
 
 use Drupal\Core\Form\FormBase;
@@ -70,8 +65,8 @@ class OverviewForm extends FormBase {
       '#type' => 'table',
       '#header' => [
         [
-          'data' => $this->t('Matcher'),
-          'colspan' => 2
+          'data' => $this->t('Matchers'),
+          'colspan' => 2,
         ],
         $this->t('Weight'),
         $this->t('Operations'),
@@ -109,7 +104,7 @@ class OverviewForm extends FormBase {
 
       $form['plugins'][$key]['weight'] = [
         '#type' => 'weight',
-        '#title' => t('Weight for @title', ['@title' => (string) $plugin->getLabel()]),
+        '#title' => $this->t('Weight for @title', ['@title' => (string) $plugin->getLabel()]),
         '#title_display' => 'invisible',
         '#default_value' => $plugin->getWeight(),
         '#attributes' => ['class' => ['plugin-order-weight']],
@@ -123,18 +118,18 @@ class OverviewForm extends FormBase {
       $is_configurable = $plugin instanceof ConfigurableMatcherInterface;
       if ($is_configurable) {
         $form['plugins'][$key]['operations']['#links']['edit'] = [
-          'title' => t('Edit'),
+          'title' => $this->t('Edit'),
           'url' => Url::fromRoute('linkit.matcher.edit', [
-            'linkit_profile' =>  $this->linkitProfile->id(),
+            'linkit_profile' => $this->linkitProfile->id(),
             'plugin_instance_id' => $key,
           ]),
         ];
       }
 
       $form['plugins'][$key]['operations']['#links']['delete'] = [
-        'title' => t('Delete'),
+        'title' => $this->t('Delete'),
         'url' => Url::fromRoute('linkit.matcher.delete', [
-          'linkit_profile' =>  $this->linkitProfile->id(),
+          'linkit_profile' => $this->linkitProfile->id(),
           'plugin_instance_id' => $key,
         ]),
       ];

+ 0 - 5
sites/all/modules/contrib/fields/linkit/src/Form/Profile/AddForm.php

@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Form\Profile\AddForm.
- */
-
 namespace Drupal\linkit\Form\Profile;
 
 use Drupal\Core\Form\FormStateInterface;

+ 1 - 6
sites/all/modules/contrib/fields/linkit/src/Form/Profile/EditForm.php

@@ -1,16 +1,11 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Form\Profile\EditForm.
- */
-
 namespace Drupal\linkit\Form\Profile;
 
 use Drupal\Core\Form\FormStateInterface;
 
 /**
- *  Provides an edit form for profile.
+ * Provides an edit form for profile.
  *
  * @see \Drupal\linkit\Profile\FormBase
  */

+ 5 - 10
sites/all/modules/contrib/fields/linkit/src/Form/Profile/FormBase.php

@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Form\Profile\FormBase.
- */
-
 namespace Drupal\linkit\Form\Profile;
 
 use Drupal\Core\Entity\EntityForm;
@@ -39,7 +34,7 @@ abstract class FormBase extends EntityForm {
       '#type' => 'machine_name',
       '#default_value' => $this->entity->id(),
       '#machine_name' => [
-        'exists' => ['\Drupal\linkit\Entity\Profile', 'load']
+        'exists' => ['\Drupal\linkit\Entity\Profile', 'load'],
       ],
       '#disabled' => !$this->entity->isNew(),
     ];
@@ -51,10 +46,10 @@ abstract class FormBase extends EntityForm {
       '#description' => $this->t('The text will be displayed on the <em>profile collection</em> page.'),
     ];
 
-    $form['additional_settings'] = array(
+    $form['additional_settings'] = [
       '#type' => 'vertical_tabs',
       '#weight' => 99,
-    );
+    ];
 
     return parent::form($form, $form_state);
   }
@@ -69,7 +64,7 @@ abstract class FormBase extends EntityForm {
     $linkit_profile->set('label', trim($linkit_profile->label()));
 
     $status = $linkit_profile->save();
-    $edit_link = $this->entity->link($this->t('Edit'));
+    $edit_link = $this->entity->toLink($this->t('Edit'), 'edit-form')->toString();
     switch ($status) {
       case SAVED_NEW:
         drupal_set_message($this->t('Created new profile %label.', ['%label' => $linkit_profile->label()]));
@@ -82,7 +77,7 @@ abstract class FormBase extends EntityForm {
       case SAVED_UPDATED:
         drupal_set_message($this->t('Updated profile %label.', ['%label' => $linkit_profile->label()]));
         $this->logger('linkit')->notice('Updated profile %label.', ['%label' => $linkit_profile->label(), 'link' => $edit_link]);
-        $form_state->setRedirectUrl($linkit_profile->urlInfo('edit-form'));
+        $form_state->setRedirectUrl($linkit_profile->toUrl('edit-form'));
         break;
     }
   }

+ 13 - 6
sites/all/modules/contrib/fields/linkit/src/MatcherBase.php

@@ -1,14 +1,10 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\MatcherBase.
- */
-
 namespace Drupal\linkit;
 
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Plugin\PluginBase;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Provides a base class for matchers.
@@ -40,6 +36,17 @@ abstract class MatcherBase extends PluginBase implements MatcherInterface, Conta
     $this->setConfiguration($configuration);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition
+    );
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -58,7 +65,7 @@ abstract class MatcherBase extends PluginBase implements MatcherInterface, Conta
    * {@inheritdoc}
    */
   public function getSummary() {
-    return array();
+    return [];
   }
 
   /**

+ 0 - 14
sites/all/modules/contrib/fields/linkit/src/MatcherCollection.php

@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\MatcherCollection.
- */
-
 namespace Drupal\linkit;
 
 use Drupal\Core\Plugin\DefaultLazyPluginCollection;
@@ -21,15 +16,6 @@ class MatcherCollection extends DefaultLazyPluginCollection {
    */
   protected $definitions;
 
-  /**
-   * {@inheritdoc}
-   *
-   * @return \Drupal\linkit\MatcherInterface
-   */
-  public function &get($instance_id) {
-    return parent::get($instance_id);
-  }
-
   /**
    * {@inheritdoc}
    */

+ 5 - 18
sites/all/modules/contrib/fields/linkit/src/MatcherInterface.php

@@ -1,15 +1,9 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\MatcherInterface.
- */
-
 namespace Drupal\linkit;
 
 use Drupal\Component\Plugin\ConfigurablePluginInterface;
 use Drupal\Component\Plugin\PluginInspectionInterface;
-use Drupal\Core\Plugin\PluginFormInterface;
 
 /**
  * Defines the interface for matchers.
@@ -64,21 +58,14 @@ interface MatcherInterface extends PluginInspectionInterface, ConfigurablePlugin
   public function setWeight($weight);
 
   /**
-   * Gets an array with search matches that will be presented in the autocomplete
-   * widget.
+   * Executes the matcher.
    *
-   * @param $string
+   * @param string $string
    *   The string that contains the text to search for.
    *
-   * @return array
-   *   An array whose values are an associative array containing:
-   *   - title: A string to use as the search result label.
-   *   - description: (optional) A string with additional information about the
-   *     result item.
-   *   - path: The URL to the item.
-   *   - group: (optional) A string with the group name for the result item.
-   *     Best practice is to use the plugin name as group name.
+   * @return \Drupal\linkit\Suggestion\SuggestionCollection
+   *   A suggestion collection.
    */
-  public function getMatches($string);
+  public function execute($string);
 
 }

+ 0 - 5
sites/all/modules/contrib/fields/linkit/src/MatcherManager.php

@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\MatcherManager.
- */
-
 namespace Drupal\linkit;
 
 use Drupal\Core\Cache\CacheBackendInterface;

+ 13 - 17
sites/all/modules/contrib/fields/linkit/src/MatcherTokensTrait.php

@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\MatcherTokensTrait.
- */
-
 namespace Drupal\linkit;
 
 /**
@@ -15,23 +10,23 @@ trait MatcherTokensTrait {
   /**
    * Inserts a form element with a list of available tokens.
    *
-   * @param $form
+   * @param array $form
    *   The form array to append the token list to.
    * @param array $types
    *   An array of token types to use.
    */
-  public function insertTokenList(&$form, array $types = array()) {
+  public function insertTokenList(array &$form, array $types = []) {
     if (\Drupal::moduleHandler()->moduleExists('token')) {
       // Add the token tree UI.
-      $form['token_tree'] = array(
+      $form['metadata']['token_tree'] = [
         '#theme' => 'token_tree_link',
         '#token_types' => $types,
         '#dialog' => TRUE,
-        '#weight' => -90,
-      );
+        '#weight' => 10,
+      ];
     }
     else {
-      $token_items = array();
+      $token_items = [];
       foreach ($this->getAvailableTokens($types) as $type => $tokens) {
         foreach ($tokens as $name => $info) {
           $token_description = !empty($info['description']) ? $info['description'] : '';
@@ -40,16 +35,16 @@ trait MatcherTokensTrait {
       }
 
       if (count($token_items)) {
-        $form['tokens'] = array(
+        $form['metadata']['tokens'] = [
           '#type' => 'details',
           '#title' => t('Available tokens'),
-          '#weight' => -90,
-        );
+          '#weight' => 10,
+        ];
 
-        $form['tokens']['list'] = array(
+        $form['metadata']['tokens']['list'] = [
           '#theme' => 'item_list',
           '#items' => $token_items,
-        );
+        ];
       }
     }
   }
@@ -59,10 +54,11 @@ trait MatcherTokensTrait {
    *
    * @param array $types
    *   An array of token types to use.
+   *
    * @return array
    *   An array with available tokens
    */
-  public function getAvailableTokens(array $types = array()) {
+  public function getAvailableTokens(array $types = []) {
     $info = \Drupal::token()->getInfo();
     $available = array_intersect_key($info['tokens'], array_flip($types));
     return $available;

+ 0 - 123
sites/all/modules/contrib/fields/linkit/src/Plugin/CKEditorPlugin/Linkit.php

@@ -1,123 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Plugin\CKEditorPlugin\Linkit.
- */
-
-namespace Drupal\linkit\Plugin\CKEditorPlugin;
-
-use Drupal\ckeditor\CKEditorPluginBase;
-use Drupal\ckeditor\CKEditorPluginConfigurableInterface;
-use Drupal\Core\Entity\EntityStorageInterface;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
-use Drupal\editor\Entity\Editor;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Defines the "linkit" plugin.
- *
- * @CKEditorPlugin(
- *   id = "linkit",
- *   label = @Translation("Linkit"),
- *   module = "linkit"
- * )
- */
-class Linkit extends CKEditorPluginBase implements CKEditorPluginConfigurableInterface, ContainerFactoryPluginInterface {
-
-  /**
-   * The Linkit profile storage.
-   *
-   * @var \Drupal\Core\Entity\EntityStorageInterface
-   */
-  protected $linkitProfileStorage;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $linkit_profile_storage) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition);
-    $this->linkitProfileStorage = $linkit_profile_storage;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
-    return new static(
-      $configuration,
-      $plugin_id,
-      $plugin_definition,
-      $container->get('entity.manager')->getStorage('linkit_profile')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFile() {
-    return drupal_get_path('module', 'linkit') . '/js/plugins/linkit/plugin.js';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getConfig(Editor $editor) {
-    return array(
-      'linkit_dialogTitleAdd' => t('Add link'),
-      'linkit_dialogTitleEdit' => t('Edit link'),
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getButtons() {
-    return array(
-      'Linkit' => array(
-        'label' => t('Linkit'),
-        'image' => drupal_get_path('module', 'linkit') . '/js/plugins/linkit/linkit.png',
-      ),
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function settingsForm(array $form, FormStateInterface $form_state, Editor $editor) {
-    $settings = $editor->getSettings();
-
-    $all_profiles = $this->linkitProfileStorage->loadMultiple();
-
-    $options = array();
-    foreach ($all_profiles as $profile) {
-      $options[$profile->id()] = $profile->label();
-    }
-
-    $form['linkit_profile'] = array(
-      '#type' => 'select',
-      '#title' => t('Select a linkit profile'),
-      '#options' => $options,
-      '#default_value' => isset($settings['plugins']['linkit']) ? $settings['plugins']['linkit'] : '',
-      '#empty_option' => $this->t('- Select profile -'),
-      '#description' => $this->t('Select the linkit profile you wish to use with this text format.'),
-      '#element_validate' => array(
-        array($this, 'validateLinkitProfileSelection'),
-      ),
-    );
-
-    return $form;
-  }
-
-  /**
-   * #element_validate handler for the "linkit_profile" element in settingsForm().
-   */
-  public function validateLinkitProfileSelection(array $element, FormStateInterface $form_state) {
-    $toolbar_buttons = $form_state->getValue(array('editor', 'settings', 'toolbar', 'button_groups'));
-    if (strpos($toolbar_buttons, '"Linkit"') !== FALSE && empty($element['#value'])) {
-      $form_state->setError($element, t('Please select the linkit profile you wish to use.'));
-    }
-  }
-
-}

+ 111 - 0
sites/all/modules/contrib/fields/linkit/src/Plugin/CKEditorPlugin/LinkitDrupalLink.php

@@ -0,0 +1,111 @@
+<?php
+
+namespace Drupal\linkit\Plugin\CKEditorPlugin;
+
+use Drupal\ckeditor\CKEditorPluginConfigurableInterface;
+use Drupal\ckeditor\Plugin\CKEditorPlugin\DrupalLink;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\editor\Entity\Editor;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Adds a settings form to select a Linkit profile on the default link plugin.
+ */
+class LinkitDrupalLink extends DrupalLink implements CKEditorPluginConfigurableInterface, ContainerFactoryPluginInterface {
+
+  /**
+   * The Linkit profile storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $linkitProfileStorage;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $linkit_profile_storage) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->linkitProfileStorage = $linkit_profile_storage;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity.manager')->getStorage('linkit_profile')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, FormStateInterface $form_state, Editor $editor) {
+    $settings = $editor->getSettings();
+
+    $all_profiles = $this->linkitProfileStorage->loadMultiple();
+
+    $options = [];
+    foreach ($all_profiles as $profile) {
+      $options[$profile->id()] = $profile->label();
+    }
+
+    $form['linkit_enabled'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Linkit enabled'),
+      '#default_value' => isset($settings['plugins']['drupallink']['linkit_enabled']) ? $settings['plugins']['drupallink']['linkit_enabled'] : '',
+      '#description' => $this->t('Enable Linkit for this text format.'),
+    ];
+
+    $form['linkit_profile'] = [
+      '#type' => 'select',
+      '#title' => $this->t('Linkit profile'),
+      '#options' => $options,
+      '#default_value' => isset($settings['plugins']['drupallink']['linkit_profile']) ? $settings['plugins']['drupallink']['linkit_profile'] : '',
+      '#empty_option' => $this->t('- Select -'),
+      '#description' => $this->t('Select the Linkit profile you wish to use with this text format.'),
+      '#states' => [
+        'invisible' => [
+          'input[data-drupal-selector="edit-editor-settings-plugins-drupallink-linkit-enabled"]' => ['checked' => FALSE],
+        ],
+      ],
+      '#element_validate' => [
+        [$this, 'validateLinkitProfileSelection'],
+      ],
+    ];
+
+    return $form;
+  }
+
+  /**
+   * Linkit profile select validation.
+   *
+   * #element_validate callback for the "linkit_profile" element.
+   *
+   * @param array $element
+   *   An associative array containing the properties and children of the
+   *   generic form element.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form for the form this element belongs to.
+   *
+   * @see \Drupal\Core\Render\Element\FormElement::processPattern()
+   */
+  public function validateLinkitProfileSelection(array $element, FormStateInterface $form_state) {
+    $values = $form_state->getValue([
+      'editor',
+      'settings',
+      'plugins',
+      'drupallink',
+    ]);
+    $enabled = isset($values['linkit_enabled']) && $values['linkit_enabled'] === 1;
+    if ($enabled && empty(trim($values['linkit_profile']))) {
+      $form_state->setError($element, $this->t('Please select the Linkit profile you wish to use.'));
+    }
+  }
+
+}

+ 17 - 18
sites/all/modules/contrib/fields/linkit/src/Plugin/Derivative/EntityMatcherDeriver.php

@@ -1,39 +1,35 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Plugin\Derivative\EntityMatcherDeriver.
- */
-
 namespace Drupal\linkit\Plugin\Derivative;
 
 use Drupal\Component\Plugin\Derivative\DeriverBase;
-use Drupal\Component\Utility\Unicode;
-use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\ContentEntityTypeInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
+ * Provides matchers based on active entities.
  *
  * @see plugin_api
  */
 class EntityMatcherDeriver extends DeriverBase implements ContainerDeriverInterface {
 
   /**
-   * The entity manager.
+   * The entity type manager.
    *
-   * @var \Drupal\Core\Entity\EntityManagerInterface
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
    */
-  protected $entityManager;
+  protected $entityTypeManager;
 
   /**
    * Creates an EntityMatcherDeriver object.
    *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
    */
-  public function __construct(EntityManagerInterface $entity_manager) {
-    $this->entityManager = $entity_manager;
+  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
+    $this->entityTypeManager = $entity_type_manager;
   }
 
   /**
@@ -41,7 +37,7 @@ class EntityMatcherDeriver extends DeriverBase implements ContainerDeriverInterf
    */
   public static function create(ContainerInterface $container, $base_plugin_id) {
     return new static(
-      $container->get('entity.manager')
+      $container->get('entity_type.manager')
     );
   }
 
@@ -49,10 +45,13 @@ class EntityMatcherDeriver extends DeriverBase implements ContainerDeriverInterf
    * {@inheritdoc}
    */
   public function getDerivativeDefinitions($base_plugin_definition) {
-    foreach ($this->entityManager->getDefinitions() as $entity_type_id => $entity_type) {
-      $has_canonical = $entity_type->hasLinkTemplate('canonical');
+    foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) {
+      $canonical = $entity_type->getLinkTemplate('canonical');
+      $edit_form = $entity_type->getLinkTemplate('edit-form');
 
-      if ($has_canonical) {
+      // Only entities that has a distinct canonical URI that is not the same
+      // as the edit-form URI will be derived.
+      if ($entity_type instanceof ContentEntityTypeInterface && $canonical && ($canonical !== $edit_form)) {
         $this->derivatives[$entity_type_id] = $base_plugin_definition;
         $this->derivatives[$entity_type_id]['id'] = $base_plugin_definition['id'] . ':' . $entity_type_id;
         $this->derivatives[$entity_type_id]['label'] = $entity_type->getLabel();

+ 156 - 0
sites/all/modules/contrib/fields/linkit/src/Plugin/Filter/LinkitFilter.php

@@ -0,0 +1,156 @@
+<?php
+
+namespace Drupal\linkit\Plugin\Filter;
+
+use Drupal\Component\Utility\Html;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\filter\FilterProcessResult;
+use Drupal\filter\Plugin\FilterBase;
+use Drupal\linkit\SubstitutionManagerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Provides a Linkit filter.
+ *
+ * @Filter(
+ *   id = "linkit",
+ *   title = @Translation("Linkit URL converter"),
+ *   description = @Translation("Updates links inserted by Linkit to point to entity URL aliases."),
+ *   settings = {
+ *     "title" = TRUE,
+ *   },
+ *   type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_REVERSIBLE
+ * )
+ */
+class LinkitFilter extends FilterBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The entity repository.
+   *
+   * @var \Drupal\Core\Entity\EntityRepositoryInterface
+   */
+  protected $entityRepository;
+
+  /**
+   * The substitution manager.
+   *
+   * @var \Drupal\linkit\SubstitutionManagerInterface
+   */
+  protected $substitutionManager;
+
+  /**
+   * Constructs a LinkitFilter object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
+   *   The entity repository service.
+   * @param \Drupal\linkit\SubstitutionManagerInterface $substitution_manager
+   *   The substitution manager.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityRepositoryInterface $entity_repository, SubstitutionManagerInterface $substitution_manager) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->entityRepository = $entity_repository;
+    $this->substitutionManager = $substitution_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity.repository'),
+      $container->get('plugin.manager.linkit.substitution')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function process($text, $langcode) {
+    $result = new FilterProcessResult($text);
+
+    if (strpos($text, 'data-entity-type') !== FALSE && strpos($text, 'data-entity-uuid') !== FALSE) {
+      $dom = Html::load($text);
+      $xpath = new \DOMXPath($dom);
+
+      foreach ($xpath->query('//a[@data-entity-type and @data-entity-uuid]') as $element) {
+        /** @var \DOMElement $element */
+        try {
+          // Load the appropriate translation of the linked entity.
+          $entity_type = $element->getAttribute('data-entity-type');
+          $uuid = $element->getAttribute('data-entity-uuid');
+
+          // Make the substitution optional, for backwards compatibility,
+          // maintaining the previous hard-coded direct file link assumptions,
+          // for content created before the substitution feature.
+          if (!$substitution_type = $element->getAttribute('data-entity-substitution')) {
+            $substitution_type = $entity_type === 'file' ? 'file' : SubstitutionManagerInterface::DEFAULT_SUBSTITUTION;
+          }
+
+          $entity = $this->entityRepository->loadEntityByUuid($entity_type, $uuid);
+          if ($entity) {
+
+            $entity = $this->entityRepository->getTranslationFromContext($entity, $langcode);
+
+            /** @var \Drupal\Core\GeneratedUrl $url */
+            $url = $this->substitutionManager
+              ->createInstance($substitution_type)
+              ->getUrl($entity);
+
+            $element->setAttribute('href', $url->getGeneratedUrl());
+            $access = $entity->access('view', NULL, TRUE);
+
+            // Set the appropriate title attribute.
+            if ($this->settings['title'] && !$access->isForbidden() && !$element->getAttribute('title')) {
+              $element->setAttribute('title', $entity->label());
+            }
+
+            // The processed text now depends on:
+            $result
+              // - the linked entity access for the current user.
+              ->addCacheableDependency($access)
+              // - the generated URL (which has undergone path & route
+              // processing)
+              ->addCacheableDependency($url)
+              // - the linked entity (whose URL and title may change)
+              ->addCacheableDependency($entity);
+          }
+        }
+        catch (\Exception $e) {
+          watchdog_exception('linkit_filter', $e);
+        }
+      }
+
+      $result->setProcessedText(Html::serialize($dom));
+    }
+
+    return $result;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, FormStateInterface $form_state) {
+    $form['title'] = [
+      '#type' => 'checkbox',
+      '#title' => $this->t('Automatically set the <code>title</code> attribute to that of the (translated) referenced content'),
+      '#default_value' => $this->settings['title'],
+      '#attached' => [
+        'library' => ['linkit/linkit.filter_html.admin'],
+      ],
+    ];
+    return $form;
+  }
+
+}

+ 0 - 38
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Attribute/Accesskey.php

@@ -1,38 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Plugin\Linkit\Attribute\Accesskey.
- */
-
-namespace Drupal\linkit\Plugin\Linkit\Attribute;
-
-use Drupal\linkit\AttributeBase;
-
-/**
- * Accesskey attribute.
- *
- * @Attribute(
- *   id = "accesskey",
- *   label = @Translation("Accesskey"),
- *   html_name = "accesskey",
- *   description = @Translation("Basic input field for the accesskey attribute.")
- * )
- */
-class Accesskey extends AttributeBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildFormElement($default_value) {
-    return [
-      '#type' => 'textfield',
-      '#title' => t('Accesskey'),
-      '#default_value' => $default_value,
-      '#maxlength' => 255,
-      '#size' => 40,
-      '#placeholder' => t('The "accesskey" attribute value'),
-    ];
-  }
-
-}

+ 0 - 41
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Attribute/Clazz.php

@@ -1,41 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Plugin\Linkit\Attribute\Clazz.
- */
-
-namespace Drupal\linkit\Plugin\Linkit\Attribute;
-
-use Drupal\linkit\AttributeBase;
-
-/**
- * Class attribute.
- *
- * @TODO: For now Drupal filter_html wont support class attributes with
- * wildcards.
- * See: \Drupal\filter\Plugin\Filter\FilterHtml::getHTMLRestrictions
- * See: core/modules/filter/filter.filter_html.admin.js
- *
- * @Attribute(
- *   id = "class",
- *   label = @Translation("Class"),
- *   html_name = "class",
- *   description = @Translation("Basic input field for the class attribute."),
- * )
- */
-//class Clazz extends AttributeBase {
-//
-//  /**
-//   * {@inheritdoc}
-//   */
-//  public function buildFormElement($default_value) {
-//    return [
-//      '#type' => 'textfield',
-//      '#title' => t('Class'),
-//      '#maxlength' => 255,
-//      '#size' => 40,
-//    ];
-//  }
-//
-//}

+ 0 - 38
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Attribute/Id.php

@@ -1,38 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Plugin\Linkit\Attribute\Id.
- */
-
-namespace Drupal\linkit\Plugin\Linkit\Attribute;
-
-use Drupal\linkit\AttributeBase;
-
-/**
- * Id attribute.
- *
- * @Attribute(
- *   id = "id",
- *   label = @Translation("Id"),
- *   html_name = "id",
- *   description = @Translation("Basic input field for the id attribute."),
- * )
- */
-class Id extends AttributeBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildFormElement($default_value) {
-    return [
-      '#type' => 'textfield',
-      '#title' => t('Id'),
-      '#default_value' => $default_value,
-      '#maxlength' => 255,
-      '#size' => 40,
-      '#placeholder' => t('The "id" attribute value'),
-    ];
-  }
-
-}

+ 0 - 38
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Attribute/Relationship.php

@@ -1,38 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Plugin\Linkit\Attribute\Relationship.
- */
-
-namespace Drupal\linkit\Plugin\Linkit\Attribute;
-
-use Drupal\linkit\AttributeBase;
-
-/**
- * Relationship attribute.
- *
- * @Attribute(
- *   id = "relationship",
- *   label = @Translation("Relationship"),
- *   html_name = "rel",
- *   description = @Translation("Basic input field for the relationship attribute."),
- * )
- */
-class Relationship extends AttributeBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildFormElement($default_value) {
-    return [
-      '#type' => 'textfield',
-      '#title' => t('Relationship'),
-      '#default_value' => $default_value,
-      '#maxlength' => 255,
-      '#size' => 40,
-      '#placeholder' => t('The "rel" attribute value'),
-    ];
-  }
-
-}

+ 0 - 96
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Attribute/Target.php

@@ -1,96 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Plugin\Linkit\Attribute\Target.
- */
-
-namespace Drupal\linkit\Plugin\Linkit\Attribute;
-
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\linkit\ConfigurableAttributeBase;
-
-/**
- * Target attribute.
- *
- * @Attribute(
- *   id = "target",
- *   label = @Translation("Target"),
- *   html_name = "target"
- * )
- */
-class Target extends ConfigurableAttributeBase {
-
-  const SELECT_LIST = 'select_list';
-  const SIMPLE_CHECKBOX = 'simple_checkbox';
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildFormElement($default_value) {
-    switch ($this->configuration['widget_type']) {
-      case self::SELECT_LIST:
-        return [
-          '#type' => 'select',
-          '#title' => t('Target'),
-          '#options' => [
-            '' => '',
-            '_blank' => t('New window (_blank)'),
-            '_top' => t('Top window (_top)'),
-            '_self' => t('Same window (_self)'),
-            '_parent' => t('Parent window (_parent)')
-          ],
-          '#default_value' => $default_value,
-        ];
-      case self::SIMPLE_CHECKBOX:
-        return [
-          '#type' => 'checkbox',
-          '#title' => t('Open in new window'),
-          '#default_value' => $default_value,
-          '#return_value' => '_blank',
-        ];
-    }
-
-    return [];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function defaultConfiguration() {
-    return parent::defaultConfiguration() + [
-      'widget_type' => self::SIMPLE_CHECKBOX,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
-    $form['widget_type'] = [
-      '#type' => 'radios',
-      '#title' => $this->t('Widget type'),
-      '#default_value' => $this->configuration['widget_type'],
-      '#options' =>  [
-        self::SELECT_LIST => $this->t('Selectlist with predefined targets.'),
-        self::SIMPLE_CHECKBOX => $this->t('Simple checkbox to allow links to be opened in a new browser window or tab.'),
-      ],
-    ];
-
-    return $form;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
-    $this->configuration['widget_type'] = $form_state->getValue('widget_type');
-  }
-
-}

+ 0 - 82
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Attribute/Title.php

@@ -1,82 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Plugin\Linkit\Attribute\Title.
- */
-
-namespace Drupal\linkit\Plugin\Linkit\Attribute;
-
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\linkit\ConfigurableAttributeBase;
-
-/**
- * Title attribute.
- *
- * @Attribute(
- *   id = "title",
- *   label = @Translation("Title"),
- *   html_name = "title",
- *   description = @Translation("Basic input field for the title attribute.")
- * )
- */
-class Title extends ConfigurableAttributeBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildFormElement($default_value) {
-    $element = [
-      '#type' => 'textfield',
-      '#title' => t('Title'),
-      '#default_value' => $default_value,
-      '#maxlength' => 255,
-      '#size' => 40,
-      '#placeholder' => t('The "title" attribute value'),
-    ];
-
-    if ($this->configuration['automatic_title']) {
-      $element['#attached']['library'][] = 'linkit/linkit.attribute.title';
-      $element['#placeholder'] = t('The "title" attribute value (auto populated)');
-    }
-
-    return $element;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function defaultConfiguration() {
-    return parent::defaultConfiguration() + [
-      'automatic_title' => FALSE,
-    ];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
-    $form['automatic_title'] = [
-      '#type' => 'checkbox',
-      '#title' => $this->t('Automatically populate title'),
-      '#default_value' => $this->configuration['automatic_title'],
-      '#description' => $this->t('Automatically populate the title attribute with the title from the match selection.'),
-    ];
-
-    return $form;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
-    $this->configuration['automatic_title'] = $form_state->getValue('automatic_title');
-  }
-
-}

+ 38 - 0
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Matcher/ContactFormMatcher.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace Drupal\linkit\Plugin\Linkit\Matcher;
+
+/**
+ * Provides specific linkit matchers for contact forms.
+ *
+ * @Matcher(
+ *   id = "entity:contact_form",
+ *   label = @Translation("Contact form"),
+ *   target_entity = "contact_form",
+ *   provider = "contact"
+ * )
+ */
+class ContactFormMatcher extends EntityMatcher {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function calculateDependencies() {
+    return parent::calculateDependencies() + [
+      'module' => ['contact'],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function buildEntityQuery($search_string) {
+    $query = parent::buildEntityQuery($search_string);
+
+    // Remove the personal contact form from the suggestion list.
+    $query->condition('id', 'personal', '<>');
+
+    return $query;
+  }
+
+}

+ 40 - 0
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Matcher/EmailMatcher.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace Drupal\linkit\Plugin\Linkit\Matcher;
+
+use Drupal\Component\Utility\Html;
+use Drupal\linkit\MatcherBase;
+use Drupal\linkit\Suggestion\DescriptionSuggestion;
+use Drupal\linkit\Suggestion\SuggestionCollection;
+
+/**
+ * Provides specific linkit matchers for emails.
+ *
+ * @Matcher(
+ *   id = "email",
+ *   label = @Translation("Email"),
+ * )
+ */
+class EmailMatcher extends MatcherBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function execute($string) {
+    $suggestions = new SuggestionCollection();
+
+    // Check for an e-mail address then return an e-mail match and create a
+    // mail-to link if appropriate.
+    if (filter_var($string, FILTER_VALIDATE_EMAIL)) {
+      $suggestion = new DescriptionSuggestion();
+      $suggestion->setLabel($this->t('E-mail @email', ['@email' => $string]))
+        ->setPath('mailto:' . Html::escape($string))
+        ->setGroup($this->t('E-mail'))
+        ->setDescription($this->t('Opens your mail client ready to e-mail @email', ['@email' => $string]));
+
+      $suggestions->addSuggestion($suggestion);
+    }
+    return $suggestions;
+  }
+
+}

+ 221 - 81
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Matcher/EntityMatcher.php

@@ -1,24 +1,31 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Plugin\Linkit\Matcher\EntityMatcher.
- */
-
 namespace Drupal\linkit\Plugin\Linkit\Matcher;
 
 use Drupal\Component\Utility\Html;
+use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
 use Drupal\Core\Database\Connection;
-use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Entity\Query\QueryInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Url;
 use Drupal\linkit\ConfigurableMatcherBase;
 use Drupal\linkit\MatcherTokensTrait;
+use Drupal\linkit\SubstitutionManagerInterface;
+use Drupal\linkit\Suggestion\EntitySuggestion;
+use Drupal\linkit\Suggestion\SuggestionCollection;
 use Drupal\linkit\Utility\LinkitXss;
+use Exception;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
+ * Provides default linkit matchers for all entity types.
+ *
  * @Matcher(
  *   id = "entity",
  *   label = @Translation("Entity"),
@@ -37,11 +44,25 @@ class EntityMatcher extends ConfigurableMatcherBase {
   protected $database;
 
   /**
-   * The entity manager.
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * The entity type bundle info.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
+   */
+  protected $entityTypeBundleInfo;
+
+  /**
+   * The entity repository.
    *
-   * @var \Drupal\Core\Entity\EntityManagerInterface
+   * @var \Drupal\Core\Entity\EntityRepositoryInterface
    */
-  protected $entityManager;
+  protected $entityRepository;
 
   /**
    * The module handler service.
@@ -58,26 +79,36 @@ class EntityMatcher extends ConfigurableMatcherBase {
   protected $currentUser;
 
   /**
-   * The target entity type id
+   * The target entity type ID.
    *
    * @var string
    */
-  protected $target_type;
+  protected $targetType;
+
+  /**
+   * The substitution manager.
+   *
+   * @var \Drupal\linkit\SubstitutionManagerInterface
+   */
+  protected $substitutionManager;
 
   /**
    * {@inheritdoc}
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, Connection $database, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler,   AccountInterface $current_user) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, Connection $database, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, EntityRepositoryInterface $entity_repository, ModuleHandlerInterface $module_handler, AccountInterface $current_user, SubstitutionManagerInterface $substitution_manager) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
 
     if (empty($plugin_definition['target_entity'])) {
       throw new \InvalidArgumentException("Missing required 'target_entity' property for a matcher.");
     }
     $this->database = $database;
-    $this->entityManager = $entity_manager;
+    $this->entityTypeManager = $entity_type_manager;
+    $this->entityTypeBundleInfo = $entity_type_bundle_info;
+    $this->entityRepository = $entity_repository;
     $this->moduleHandler = $module_handler;
     $this->currentUser = $current_user;
-    $this->target_type = $plugin_definition['target_entity'];
+    $this->targetType = $plugin_definition['target_entity'];
+    $this->substitutionManager = $substitution_manager;
   }
 
   /**
@@ -89,9 +120,12 @@ class EntityMatcher extends ConfigurableMatcherBase {
       $plugin_id,
       $plugin_definition,
       $container->get('database'),
-      $container->get('entity.manager'),
+      $container->get('entity_type.manager'),
+      $container->get('entity_type.bundle.info'),
+      $container->get('entity.repository'),
       $container->get('module_handler'),
-      $container->get('current_user')
+      $container->get('current_user'),
+      $container->get('plugin.manager.linkit.substitution')
     );
   }
 
@@ -100,12 +134,12 @@ class EntityMatcher extends ConfigurableMatcherBase {
    */
   public function getSummary() {
     $summery = parent::getSummary();
-    $entity_type = $this->entityManager->getDefinition($this->target_type);
+    $entity_type = $this->entityTypeManager->getDefinition($this->targetType);
 
-    $result_description = $this->configuration['result_description'];
-    if (!empty($result_description)) {
-      $summery[] = $this->t('Result description: @result_description', [
-        '@result_description' => $result_description
+    $metadata = $this->configuration['metadata'];
+    if (!empty($metadata)) {
+      $summery[] = $this->t('Metadata: @metadata', [
+        '@metadata' => $metadata,
       ]);
     }
 
@@ -114,7 +148,7 @@ class EntityMatcher extends ConfigurableMatcherBase {
       $bundles = [];
 
       if ($has_bundle_filter) {
-        $bundles_info = $this->entityManager->getBundleInfo($this->target_type);
+        $bundles_info = $this->entityTypeBundleInfo->getBundleInfo($this->targetType);
         foreach ($this->configuration['bundles'] as $bundle) {
           $bundles[] = $bundles_info[$bundle]['label'];
         }
@@ -136,55 +170,93 @@ class EntityMatcher extends ConfigurableMatcherBase {
    * {@inheritdoc}
    */
   public function defaultConfiguration() {
-    return parent::defaultConfiguration() + [
-      'result_description' => '',
+    return [
+      'metadata' => '',
       'bundles' => [],
       'group_by_bundle' => FALSE,
-    ];
+      'substitution_type' => SubstitutionManagerInterface::DEFAULT_SUBSTITUTION,
+    ] + parent::defaultConfiguration();
   }
 
   /**
    * {@inheritdoc}
    */
   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
-    $entity_type = $this->entityManager->getDefinition($this->target_type);
-    $form['result_description'] = [
-      '#title' => $this->t('Result description'),
+    $entity_type = $this->entityTypeManager->getDefinition($this->targetType);
+
+    $form['metadata'] = [
+      '#type' => 'details',
+      '#title' => $this->t('Suggestion metadata'),
+      '#open' => TRUE,
+      '#weight' => -100,
+    ];
+
+    $form['metadata']['metadata'] = [
+      '#title' => $this->t('Metadata'),
       '#type' => 'textfield',
-      '#default_value' => $this->configuration['result_description'],
+      '#default_value' => $this->configuration['metadata'],
+      '#description' => $this->t('Metadata is shown together with each suggestion in the suggestion list.'),
       '#size' => 120,
       '#maxlength' => 255,
-      '#weight' => -100,
+      '#weight' => 0,
     ];
 
-    $this->insertTokenList($form, [$this->target_type]);
+    $this->insertTokenList($form, [$this->targetType]);
 
     // Filter the possible bundles to use if the entity has bundles.
     if ($entity_type->hasKey('bundle')) {
       $bundle_options = [];
-      foreach ($this->entityManager->getBundleInfo($this->target_type) as $bundle_name => $bundle_info) {
+      foreach ($this->entityTypeBundleInfo->getBundleInfo($this->targetType) as $bundle_name => $bundle_info) {
         $bundle_options[$bundle_name] = $bundle_info['label'];
       }
 
-      $form['bundles'] = [
+      $form['bundle_restrictions'] = [
+        '#type' => 'details',
+        '#title' => $this->t('Bundle restrictions'),
+        '#open' => TRUE,
+        '#weight' => -90,
+      ];
+
+      $form['bundle_restrictions']['bundles'] = [
         '#type' => 'checkboxes',
-        '#title' => $this->t('Restrict to the selected bundles'),
+        '#title' => $this->t('Restrict suggestions to the selected bundles'),
         '#options' => $bundle_options,
         '#default_value' => $this->configuration['bundles'],
-        '#description' => $this->t('If none of the checkboxes is checked, allow all bundles.'),
+        '#description' => $this->t('If none of the checkboxes is checked, all bundles are allowed.'),
         '#element_validate' => [[get_class($this), 'elementValidateFilter']],
-        '#weight' => -50,
       ];
 
-      // Group the results by bundle.
-      $form['group_by_bundle'] = [
+      $form['bundle_grouping'] = [
+        '#type' => 'details',
+        '#title' => $this->t('Bundle grouping'),
+        '#open' => TRUE,
+      ];
+
+      // Group the suggestions by bundle.
+      $form['bundle_grouping']['group_by_bundle'] = [
         '#type' => 'checkbox',
         '#title' => $this->t('Group by bundle'),
         '#default_value' => $this->configuration['group_by_bundle'],
-        '#weight' => -50,
+        '#description' => $this->t('Group suggestions by their bundle.'),
       ];
     }
 
+    $substitution_options = $this->substitutionManager->getApplicablePluginsOptionList($this->targetType);
+    $form['substitution'] = [
+      '#type' => 'details',
+      '#title' => $this->t('URL substitution'),
+      '#open' => TRUE,
+      '#weight' => 100,
+      '#access' => count($substitution_options) !== 1,
+    ];
+    $form['substitution']['substitution_type'] = [
+      '#title' => $this->t('Substitution Type'),
+      '#type' => 'select',
+      '#default_value' => $this->configuration['substitution_type'],
+      '#options' => $substitution_options,
+      '#description' => $this->t('Configure how the selected entity should be transformed into a URL for insertion.'),
+    ];
+
     return $form;
   }
 
@@ -198,9 +270,10 @@ class EntityMatcher extends ConfigurableMatcherBase {
    * {@inheritdoc}
    */
   public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
-    $this->configuration['result_description'] = $form_state->getValue('result_description');
+    $this->configuration['metadata'] = $form_state->getValue('metadata');
     $this->configuration['bundles'] = $form_state->getValue('bundles');
     $this->configuration['group_by_bundle'] = $form_state->getValue('group_by_bundle');
+    $this->configuration['substitution_type'] = $form_state->getValue('substitution_type');
   }
 
   /**
@@ -214,55 +287,64 @@ class EntityMatcher extends ConfigurableMatcherBase {
   /**
    * {@inheritdoc}
    */
-  public function getMatches($string) {
+  public function execute($string) {
+    $suggestions = new SuggestionCollection();
     $query = $this->buildEntityQuery($string);
-    $result = $query->execute();
+    $query_result = $query->execute();
+    $url_results = $this->findEntityIdByUrl($string);
+    $result = array_merge($query_result, $url_results);
 
+    // If no results, return an empty suggestion collection.
     if (empty($result)) {
-      return [];
+      return $suggestions;
     }
 
-    $matches = [];
-    $entities = $this->entityManager->getStorage($this->target_type)->loadMultiple($result);
+    $entities = $this->entityTypeManager->getStorage($this->targetType)->loadMultiple($result);
 
-    foreach ($entities as $entity_id => $entity) {
+    foreach ($entities as $entity) {
       // Check the access against the defined entity access handler.
       /** @var \Drupal\Core\Access\AccessResultInterface $access */
       $access = $entity->access('view', $this->currentUser, TRUE);
+
       if (!$access->isAllowed()) {
         continue;
       }
 
-      $matches[] = [
-        'title' => $this->buildLabel($entity),
-        'description' => $this->buildDescription($entity),
-        'path' => $this->buildPath($entity),
-        'group' => $this->buildGroup($entity),
-      ];
+      $entity = $this->entityRepository->getTranslationFromContext($entity);
+      $suggestion = $this->createSuggestion($entity);
+      $suggestions->addSuggestion($suggestion);
     }
 
-    return $matches;
+    return $suggestions;
   }
 
   /**
    * Builds an EntityQuery to get entities.
    *
-   * @param $match
+   * @param string $search_string
    *   Text to match the label against.
    *
    * @return \Drupal\Core\Entity\Query\QueryInterface
    *   The EntityQuery object with the basic conditions and sorting applied to
    *   it.
    */
-  protected function buildEntityQuery($match) {
-    $match = $this->database->escapeLike($match);
+  protected function buildEntityQuery($search_string) {
+    $search_string = $this->database->escapeLike($search_string);
 
-    $entity_type = $this->entityManager->getDefinition($this->target_type);
-    $query = $this->entityManager->getStorage($this->target_type)->getQuery();
+    $entity_type = $this->entityTypeManager->getDefinition($this->targetType);
+    $query = $this->entityTypeManager->getStorage($this->targetType)->getQuery();
     $label_key = $entity_type->getKey('label');
 
     if ($label_key) {
-      $query->condition($label_key, '%' . $match . '%', 'LIKE');
+      // For configuration entities, the condition needs to be CONTAINS as
+      // the matcher does not support LIKE.
+      if ($entity_type instanceof ConfigEntityTypeInterface) {
+        $query->condition($label_key, $search_string, 'CONTAINS');
+      }
+      else {
+        $query->condition($label_key, '%' . $search_string . '%', 'LIKE');
+      }
+
       $query->sort($label_key, 'ASC');
     }
 
@@ -271,59 +353,78 @@ class EntityMatcher extends ConfigurableMatcherBase {
       $query->condition($bundle_key, $this->configuration['bundles'], 'IN');
     }
 
+    $this->addQueryTags($query);
+
+    return $query;
+  }
+
+  /**
+   * Adds query tags to the query.
+   *
+   * @param \Drupal\Core\Entity\Query\QueryInterface $query
+   *   A query to add tags to.
+   */
+  protected function addQueryTags(QueryInterface $query) {
     // Add tags to let other modules alter the query.
     $query->addTag('linkit_entity_autocomplete');
-    $query->addTag('linkit_entity_' . $this->target_type . '_autocomplete');
+    $query->addTag('linkit_entity_' . $this->targetType . '_autocomplete');
 
     // Add access tag for the query.
     $query->addTag('entity_access');
-    $query->addTag($this->target_type . '_access');
-
-    return $query;
+    $query->addTag($this->targetType . '_access');
   }
 
   /**
-   * Builds the label string used in the match array.
+   * Creates a suggestion.
    *
    * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The matched entity.
    *
-   * @return string
-   *   The label for this entity.
+   * @return \Drupal\linkit\Suggestion\EntitySuggestion
+   *   A suggestion object with populated entity data.
    */
-  protected function buildLabel($entity) {
-    return Html::escape($entity->label());
+  protected function createSuggestion(EntityInterface $entity) {
+    $suggestion = new EntitySuggestion();
+    $suggestion->setLabel($this->buildLabel($entity))
+      ->setGroup($this->buildGroup($entity))
+      ->setDescription($this->buildDescription($entity))
+      ->setEntityUuid($entity->uuid())
+      ->setEntityTypeId($entity->getEntityTypeId())
+      ->setSubstitutionId($this->configuration['substitution_type'])
+      ->setPath($this->buildPath($entity));
+
+    return $suggestion;
   }
 
   /**
-   * Builds the description string used in the match array.
+   * Builds the label string used in the suggestion.
    *
    * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The matched entity.
    *
    * @return string
-   *    The description for this entity.
+   *   The label for this entity.
    */
-  protected function buildDescription($entity) {
-    $description = \Drupal::token()->replace($this->configuration['result_description'], [$this->target_type => $entity], []);
-    return LinkitXss::descriptionFilter($description);
+  protected function buildLabel(EntityInterface $entity) {
+    return Html::escape($entity->label());
   }
 
   /**
-   * Builds the path string used in the match array.
+   * Builds the metadata string used in the suggestion.
    *
    * @param \Drupal\Core\Entity\EntityInterface $entity
-   *    The matched entity.
+   *   The matched entity.
    *
    * @return string
-   *   The URL for this entity.
+   *   The metadata for this entity.
    */
-  protected function buildPath($entity) {
-    return $entity->toUrl()->toString();
+  protected function buildDescription(EntityInterface $entity) {
+    $description = \Drupal::token()->replace($this->configuration['metadata'], [$this->targetType => $entity], ['clear' => TRUE]);
+    return LinkitXss::descriptionFilter($description);
   }
 
   /**
-   * Builds the group string used in the match array.
+   * Builds the group string used in the suggestion.
    *
    * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The matched entity.
@@ -331,13 +432,13 @@ class EntityMatcher extends ConfigurableMatcherBase {
    * @return string
    *   The match group for this entity.
    */
-  protected function buildGroup($entity) {
+  protected function buildGroup(EntityInterface $entity) {
     $group = $entity->getEntityType()->getLabel();
 
     // If the entities by this entity should be grouped by bundle, get the
     // name and append it to the group.
     if ($this->configuration['group_by_bundle']) {
-      $bundles = $this->entityManager->getBundleInfo($entity->getEntityTypeId());
+      $bundles = $this->entityTypeBundleInfo->getBundleInfo($entity->getEntityTypeId());
       $bundle_label = $bundles[$entity->bundle()]['label'];
       $group .= ' - ' . $bundle_label;
     }
@@ -345,4 +446,43 @@ class EntityMatcher extends ConfigurableMatcherBase {
     return $group;
   }
 
+  /**
+   * Builds the path string used in the suggestion.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The matched entity.
+   *
+   * @return string
+   *   The path for this entity.
+   */
+  protected function buildPath(EntityInterface $entity) {
+    return $entity->toUrl('canonical', ['path_processing' => FALSE])->toString();
+  }
+
+  /**
+   * Finds entity id from the given input.
+   *
+   * @param string $user_input
+   *   The string to url parse.
+   *
+   * @return array
+   *   An array with an entity id if the input can be parsed as an internal url
+   *   and a match is found, otherwise an empty array.
+   */
+  protected function findEntityIdByUrl($user_input) {
+    $result = [];
+
+    try {
+      $params = Url::fromUserInput($user_input)->getRouteParameters();
+      if (key($params) === $this->targetType) {
+        $result = [end($params)];
+      }
+    }
+    catch (Exception $e) {
+      // Do nothing.
+    }
+
+    return $result;
+  }
+
 }

+ 69 - 34
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Matcher/FileMatcher.php

@@ -1,21 +1,19 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Plugin\Linkit\Matcher\FileMatcher.
- */
-
 namespace Drupal\linkit\Plugin\Linkit\Matcher;
 
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\image\Entity\ImageStyle;
 use Drupal\linkit\Utility\LinkitXss;
 
 /**
+ * Provides specific linkit matchers for the file entity type.
+ *
  * @Matcher(
  *   id = "entity:file",
- *   target_entity = "file",
  *   label = @Translation("File"),
+ *   target_entity = "file",
  *   provider = "file"
  * )
  */
@@ -25,39 +23,48 @@ class FileMatcher extends EntityMatcher {
    * {@inheritdoc}
    */
   public function getSummary() {
-    $summery = parent::getSummary();
+    $summary = parent::getSummary();
 
-    $summery[] = $this->t('Show image dimensions: @show_image_dimensions', [
+    if (!empty($this->configuration['file_extensions'])) {
+      $summary[] = $this->t('Limit matches to the following file extensions: @file_extensions', [
+        '@file_extensions' => str_replace(' ', ', ', $this->configuration['file_extensions']),
+      ]);
+    }
+
+    $summary[] = $this->t('Show image dimensions: @show_image_dimensions', [
       '@show_image_dimensions' => $this->configuration['images']['show_dimensions'] ? $this->t('Yes') : $this->t('No'),
     ]);
 
-    $summery[] = $this->t('Show image thumbnail: @show_image_thumbnail', [
+    $summary[] = $this->t('Show image thumbnail: @show_image_thumbnail', [
       '@show_image_thumbnail' => $this->configuration['images']['show_thumbnail'] ? $this->t('Yes') : $this->t('No'),
     ]);
 
     if ($this->moduleHandler->moduleExists('image') && $this->configuration['images']['show_thumbnail']) {
       $image_style = ImageStyle::load($this->configuration['images']['thumbnail_image_style']);
-        if (!is_null($image_style)) {
-          $summery[] = $this->t('Thumbnail style: @thumbnail_style', [
-          '@thumbnail_style' =>  $image_style->label(),
+      if (!is_null($image_style)) {
+        $summary[] = $this->t('Thumbnail style: @thumbnail_style', [
+          '@thumbnail_style' => $image_style->label(),
         ]);
       }
     }
 
-    return $summery;
+    return $summary;
   }
 
   /**
    * {@inheritdoc}
    */
   public function defaultConfiguration() {
-    return parent::defaultConfiguration() + [
+    return [
+      'file_extensions' => '',
+      'file_status' => FILE_STATUS_PERMANENT,
       'images' => [
         'show_dimensions' => FALSE,
         'show_thumbnail' => FALSE,
         'thumbnail_image_style' => 'linkit_result_thumbnail',
       ],
-    ];
+      'substitution_type' => 'file',
+    ] + parent::defaultConfiguration();
   }
 
   /**
@@ -82,28 +89,46 @@ class FileMatcher extends EntityMatcher {
   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildConfigurationForm($form, $form_state);
 
-    $form['images'] = array(
+    $form['extensions'] = [
+      '#type' => 'details',
+      '#title' => $this->t('File extensions'),
+      '#open' => TRUE,
+      '#weight' => -100,
+    ];
+
+    $file_extensions = str_replace(' ', ', ', $this->configuration['file_extensions']);
+    $form['extensions']['file_extensions'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Allowed file extensions'),
+      '#default_value' => $file_extensions,
+      '#description' => $this->t('Separate extensions with a space or comma and do not include the leading dot.'),
+      '#element_validate' => [['\Drupal\file\Plugin\Field\FieldType\FileItem', 'validateExtensions']],
+      '#maxlength' => 256,
+    ];
+
+    $form['images'] = [
       '#type' => 'details',
-      '#title' => t('Image file settings'),
-      '#description' => t('Extra settings for image files in the result.'),
+      '#title' => $this->t('Image file settings'),
+      '#description' => $this->t('Extra settings for image files in the result.'),
+      '#open' => TRUE,
       '#tree' => TRUE,
-    );
+    ];
 
     $form['images']['show_dimensions'] = [
-      '#title' => t('Show pixel dimensions'),
+      '#title' => $this->t('Show pixel dimensions'),
       '#type' => 'checkbox',
       '#default_value' => $this->configuration['images']['show_dimensions'],
     ];
 
     if ($this->moduleHandler->moduleExists('image')) {
       $form['images']['show_thumbnail'] = [
-        '#title' => t('Show thumbnail'),
+        '#title' => $this->t('Show thumbnail'),
         '#type' => 'checkbox',
         '#default_value' => $this->configuration['images']['show_thumbnail'],
       ];
 
       $form['images']['thumbnail_image_style'] = [
-        '#title' => t('Thumbnail image style'),
+        '#title' => $this->t('Thumbnail image style'),
         '#type' => 'select',
         '#default_value' => $this->configuration['images']['thumbnail_image_style'],
         '#options' => image_style_options(FALSE),
@@ -124,6 +149,8 @@ class FileMatcher extends EntityMatcher {
   public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     parent::submitConfigurationForm($form, $form_state);
 
+    $this->configuration['file_extensions'] = $form_state->getValue('file_extensions');
+
     $values = $form_state->getValue('images');
     if (!$values['show_thumbnail']) {
       $values['thumbnail_image_style'] = NULL;
@@ -135,9 +162,19 @@ class FileMatcher extends EntityMatcher {
   /**
    * {@inheritdoc}
    */
-  protected function buildEntityQuery($match) {
-    $query = parent::buildEntityQuery($match);
-    $query->condition('status', FILE_STATUS_PERMANENT);
+  protected function buildEntityQuery($search_string) {
+    $query = parent::buildEntityQuery($search_string);
+
+    $query->condition('status', $this->configuration['file_status']);
+
+    if (!empty($this->configuration['file_extensions'])) {
+      $file_extensions = explode(' ', $this->configuration['file_extensions']);
+      $group = $query->orConditionGroup();
+      foreach ($file_extensions as $file_extension) {
+        $group->condition('filename', '%\.' . $this->database->escapeLike($file_extension), 'LIKE');
+      }
+      $query->condition($group);
+    }
 
     return $query;
   }
@@ -145,8 +182,8 @@ class FileMatcher extends EntityMatcher {
   /**
    * {@inheritdoc}
    */
-  protected function buildDescription($entity) {
-    $description_array = array();
+  protected function buildDescription(EntityInterface $entity) {
+    $description_array = [];
 
     $description_array[] = parent::buildDescription($entity);
 
@@ -161,29 +198,27 @@ class FileMatcher extends EntityMatcher {
       }
 
       if ($this->configuration['images']['show_thumbnail'] && $this->moduleHandler->moduleExists('image')) {
-        $image_element = array(
+        $image_element = [
           '#weight' => -10,
           '#theme' => 'image_style',
           '#style_name' => $this->configuration['images']['thumbnail_image_style'],
           '#uri' => $entity->getFileUri(),
-        );
+        ];
 
         $description_array[] = (string) \Drupal::service('renderer')->render($image_element);
       }
     }
 
-    $description = implode('<br />' , $description_array);
+    $description = implode('<br />', $description_array);
     return LinkitXss::descriptionFilter($description);
   }
 
   /**
    * {@inheritdoc}
-   *
-   * The file entity still uses url() even though it's deprecated in the
-   * entity interface.
    */
-  protected function buildPath($entity) {
+  protected function buildPath(EntityInterface $entity) {
     /** @var \Drupal\file\FileInterface $entity */
     return file_url_transform_relative(file_create_url($entity->getFileUri()));
   }
+
 }

+ 40 - 0
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Matcher/FrontPageMatcher.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace Drupal\linkit\Plugin\Linkit\Matcher;
+
+use Drupal\Core\Url;
+use Drupal\linkit\MatcherBase;
+use Drupal\linkit\Suggestion\DescriptionSuggestion;
+use Drupal\linkit\Suggestion\SuggestionCollection;
+
+/**
+ * Provides specific linkit matchers for the front page.
+ *
+ * @Matcher(
+ *   id = "front_page",
+ *   label = @Translation("Front page"),
+ * )
+ */
+class FrontPageMatcher extends MatcherBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function execute($string) {
+    $suggestions = new SuggestionCollection();
+
+    // Special for link to front page.
+    if (strpos($string, 'front') !== FALSE) {
+      $suggestion = new DescriptionSuggestion();
+      $suggestion->setLabel($this->t('Front page'))
+        ->setPath(Url::fromRoute('<front>')->toString())
+        ->setGroup($this->t('System'))
+        ->setDescription($this->t('The front page for this site.'));
+
+      $suggestions->addSuggestion($suggestion);
+    }
+
+    return $suggestions;
+  }
+
+}

+ 16 - 13
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Matcher/NodeMatcher.php

@@ -1,19 +1,16 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Plugin\Linkit\Matcher\NodeMatcher.
- */
-
 namespace Drupal\linkit\Plugin\Linkit\Matcher;
 
 use Drupal\Core\Form\FormStateInterface;
 
 /**
+ * Provides specific linkit matchers for the node entity type.
+ *
  * @Matcher(
  *   id = "entity:node",
- *   target_entity = "node",
  *   label = @Translation("Content"),
+ *   target_entity = "node",
  *   provider = "node"
  * )
  */
@@ -36,9 +33,9 @@ class NodeMatcher extends EntityMatcher {
    * {@inheritdoc}
    */
   public function defaultConfiguration() {
-    return parent::defaultConfiguration() + [
+    return [
       'include_unpublished' => FALSE,
-    ];
+    ] + parent::defaultConfiguration();
   }
 
   /**
@@ -56,11 +53,17 @@ class NodeMatcher extends EntityMatcher {
   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildConfigurationForm($form, $form_state);
 
-    $form['include_unpublished'] = [
-      '#title' => t('Include unpublished nodes'),
+    $form['unpublished_nodes'] = [
+      '#type' => 'details',
+      '#title' => $this->t('Unpublished nodes'),
+      '#open' => TRUE,
+    ];
+
+    $form['unpublished_nodes']['include_unpublished'] = [
+      '#title' => $this->t('Include unpublished nodes'),
       '#type' => 'checkbox',
       '#default_value' => $this->configuration['include_unpublished'],
-      '#description' => t('In order to see unpublished nodes, the requesting user must also have permissions to do so.'),
+      '#description' => $this->t('In order to see unpublished nodes, users must also have permissions to do so.'),
     ];
 
     return $form;
@@ -78,8 +81,8 @@ class NodeMatcher extends EntityMatcher {
   /**
    * {@inheritdoc}
    */
-  protected function buildEntityQuery($match) {
-    $query = parent::buildEntityQuery($match);
+  protected function buildEntityQuery($search_string) {
+    $query = parent::buildEntityQuery($search_string);
 
     $no_access = !$this->currentUser->hasPermission('bypass node access') && !count($this->moduleHandler->getImplementations('node_grants'));
     if ($this->configuration['include_unpublished'] !== TRUE || $no_access) {

+ 6 - 8
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Matcher/TermMatcher.php

@@ -1,20 +1,18 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Plugin\Linkit\Matcher\TermMatcher.
- */
-
 namespace Drupal\linkit\Plugin\Linkit\Matcher;
 
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\linkit\Utility\LinkitXss;
 
 /**
+ * Provides specific linkit matchers for the taxonomy_term entity type.
+ *
  * @Matcher(
  *   id = "entity:taxonomy_term",
- *   target_entity = "taxonomy_term",
  *   label = @Translation("Taxonomy term"),
+ *   target_entity = "taxonomy_term",
  *   provider = "taxonomy"
  * )
  */
@@ -41,8 +39,8 @@ class TermMatcher extends EntityMatcher {
   /**
    * {@inheritdoc}
    */
-  protected function buildDescription($entity) {
-    $description = \Drupal::token()->replace($this->configuration['result_description'], ['term' => $entity], []);
+  protected function buildDescription(EntityInterface $entity) {
+    $description = \Drupal::token()->replace($this->configuration['metadata'], ['term' => $entity], []);
     return LinkitXss::descriptionFilter($description);
   }
 

+ 31 - 21
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Matcher/UserMatcher.php

@@ -1,19 +1,17 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Plugin\Linkit\Matcher\UserMatcher.
- */
-
 namespace Drupal\linkit\Plugin\Linkit\Matcher;
+
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\user\RoleInterface;
 
 /**
+ * Provides specific linkit matchers for the user entity type.
+ *
  * @Matcher(
  *   id = "entity:user",
- *   target_entity = "user",
  *   label = @Translation("User"),
+ *   target_entity = "user",
  *   provider = "user"
  * )
  */
@@ -41,13 +39,12 @@ class UserMatcher extends EntityMatcher {
    * {@inheritdoc}
    */
   public function defaultConfiguration() {
-    return parent::defaultConfiguration() + [
+    return [
       'roles' => [],
       'include_blocked' => FALSE,
-    ];
+    ] + parent::defaultConfiguration();
   }
 
-
   /**
    * {@inheritdoc}
    */
@@ -63,20 +60,33 @@ class UserMatcher extends EntityMatcher {
   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildConfigurationForm($form, $form_state);
 
-    $form['roles'] = array(
+    $form['role_restrictions'] = [
+      '#type' => 'details',
+      '#title' => $this->t('Role restrictions'),
+      '#open' => TRUE,
+      '#weight' => -90,
+    ];
+
+    $form['role_restrictions']['roles'] = [
       '#type' => 'checkboxes',
       '#title' => $this->t('Restrict to the selected roles'),
-      '#options' => array_diff_key(user_role_names(TRUE), array(RoleInterface::AUTHENTICATED_ID => RoleInterface::AUTHENTICATED_ID)),
-      '#default_value' =>  $this->configuration['roles'],
-      '#description' => $this->t('If none of the checkboxes is checked, allow all roles.'),
+      '#options' => array_diff_key(user_role_names(TRUE), [RoleInterface::AUTHENTICATED_ID => RoleInterface::AUTHENTICATED_ID]),
+      '#default_value' => $this->configuration['roles'],
+      '#description' => $this->t('If none of the checkboxes is checked, all roles are allowed.'),
       '#element_validate' => [[get_class($this), 'elementValidateFilter']],
-    );
+    ];
+
+    $form['blocked_users'] = [
+      '#type' => 'details',
+      '#title' => $this->t('Blocked users'),
+      '#open' => TRUE,
+    ];
 
-    $form['include_blocked'] = [
-      '#title' => t('Include blocked user'),
+    $form['blocked_users']['include_blocked'] = [
+      '#title' => $this->t('Include blocked user'),
       '#type' => 'checkbox',
       '#default_value' => $this->configuration['include_blocked'],
-      '#description' => t('In order to see blocked users, the requesting user must also have permissions to do so.'),
+      '#description' => $this->t('In order to see blocked users, users must have permissions to do so.'),
     ];
 
     return $form;
@@ -95,12 +105,12 @@ class UserMatcher extends EntityMatcher {
   /**
    * {@inheritdoc}
    */
-  protected function buildEntityQuery($match) {
-    $query = parent::buildEntityQuery($match);
+  protected function buildEntityQuery($search_string) {
+    $query = parent::buildEntityQuery($search_string);
 
-    $match = $this->database->escapeLike($match);
+    $search_string = $this->database->escapeLike($search_string);
     // The user entity don't specify a label key so we have to do it instead.
-    $query->condition('name', '%' . $match . '%', 'LIKE');
+    $query->condition('name', '%' . $search_string . '%', 'LIKE');
 
     // Filter by role.
     if (!empty($this->configuration['roles'])) {

+ 34 - 0
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Substitution/Canonical.php

@@ -0,0 +1,34 @@
+<?php
+
+namespace Drupal\linkit\Plugin\Linkit\Substitution;
+
+use Drupal\Component\Plugin\PluginBase;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\linkit\SubstitutionInterface;
+
+/**
+ * A substitution plugin for the canonical URL of an entity.
+ *
+ * @Substitution(
+ *   id = "canonical",
+ *   label = @Translation("Canonical URL"),
+ * )
+ */
+class Canonical extends PluginBase implements SubstitutionInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getUrl(EntityInterface $entity) {
+    return $entity->toUrl('canonical')->toString(TRUE);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function isApplicable(EntityTypeInterface $entity_type) {
+    return $entity_type->hasLinkTemplate('canonical');
+  }
+
+}

+ 39 - 0
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Substitution/File.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace Drupal\linkit\Plugin\Linkit\Substitution;
+
+use Drupal\Component\Plugin\PluginBase;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\GeneratedUrl;
+use Drupal\linkit\SubstitutionInterface;
+
+/**
+ * A substitution plugin for the URL to a file.
+ *
+ * @Substitution(
+ *   id = "file",
+ *   label = @Translation("Direct File URL"),
+ * )
+ */
+class File extends PluginBase implements SubstitutionInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getUrl(EntityInterface $entity) {
+    $url = new GeneratedUrl();
+    /** @var \Drupal\file\FileInterface $entity */
+    $url->setGeneratedUrl(file_create_url($entity->getFileUri()));
+    $url->addCacheableDependency($entity);
+    return $url;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function isApplicable(EntityTypeInterface $entity_type) {
+    return $entity_type->isSubclassOf('Drupal\file\FileInterface');
+  }
+
+}

+ 100 - 0
sites/all/modules/contrib/fields/linkit/src/Plugin/Linkit/Substitution/Media.php

@@ -0,0 +1,100 @@
+<?php
+
+namespace Drupal\linkit\Plugin\Linkit\Substitution;
+
+use Drupal\Component\Plugin\PluginBase;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Entity\EntityTypeManager;
+use Drupal\Core\GeneratedUrl;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\linkit\SubstitutionInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * A substitution plugin for the URL to a file.
+ *
+ * @Substitution(
+ *   id = "media",
+ *   label = @Translation("Direct URL to media file entity"),
+ * )
+ */
+class Media extends PluginBase implements SubstitutionInterface, ContainerFactoryPluginInterface {
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManager
+   */
+  protected $entityTypeManager;
+
+  /**
+   * Constructs a Media object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Entity\EntityTypeManager $entity_type_manager
+   *   The entity type manager.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManager $entity_type_manager) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->entityTypeManager = $entity_type_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity_type.manager')
+    );
+  }
+
+  /**
+   * Get the URL associated with a given entity.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity to get a URL for.
+   *
+   * @return \Drupal\Core\GeneratedUrl
+   *   A url to replace.
+   */
+  public function getUrl(EntityInterface $entity) {
+    $url = new GeneratedUrl();
+
+    /** @var \Drupal\media\MediaTypeInterface $media_type */
+    $media_type = $entity->get('bundle')->entity;
+    // Default to the canonical URL if the bundle doesn't have a source field.
+    if (empty($media_type->getSource()->getConfiguration()['source_field'])) {
+      return $entity->toUrl('canonical')->toString(TRUE);
+    }
+
+    $source_field = $media_type->getSource()->getConfiguration()['source_field'];
+    /** @var \Drupal\file\FileInterface $file */
+    $file = $entity->{$source_field}->entity;
+    $url->setGeneratedUrl(file_create_url($file->getFileUri()));
+    $url->addCacheableDependency($entity);
+    return $url;
+  }
+
+  /**
+   * Checks if this substitution plugin is applicable for the given entity type.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   An entity type object.
+   *
+   * @return bool
+   *   If the plugin is applicable.
+   */
+  public static function isApplicable(EntityTypeInterface $entity_type) {
+    return $entity_type->entityClassImplements('Drupal\media\MediaInterface');
+  }
+
+}

+ 1 - 58
sites/all/modules/contrib/fields/linkit/src/ProfileInterface.php

@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\ProfileInterface.
- */
-
 namespace Drupal\linkit;
 
 use Drupal\Core\Config\Entity\ConfigEntityInterface;
@@ -32,58 +27,6 @@ interface ProfileInterface extends ConfigEntityInterface {
    */
   public function setDescription($description);
 
-  /**
-   * Returns a specific attribute.
-   *
-   * @param string $attribute_id
-   *   The attribute ID.
-   *
-   * @return \Drupal\linkit\AttributeInterface
-   *   The attribute object.
-   */
-  public function getAttribute($attribute_id);
-
-  /**
-   * Returns the attributes for this profile.
-   *
-   * @return \Drupal\linkit\AttributeCollection|\Drupal\linkit\AttributeInterface[]
-   *   The attribute collection.
-   */
-  public function getAttributes();
-
-  /**
-   * Adds an attribute to this profile.
-   *
-   * @param array $configuration
-   *   An array of attribute configuration.
-   *
-   * @return String
-   *   The ID of the attribute.
-   */
-  public function addAttribute(array $configuration);
-
-  /**
-   * Removes an attribute from this profile.
-   *
-   * @param string $attribute_id
-   *  The attribute ID.
-   *
-   * @return $this
-   */
-  public function removeAttribute($attribute_id);
-
-  /**
-   * Sets the configuration for an attribute instance.
-   *
-   * @param string $attribute_id
-   *   The ID of the attribute to set the configuration for.
-   * @param array $configuration
-   *   The attribute configuration to set.
-   *
-   * @return $this
-   */
-  public function setAttributeConfig($attribute_id, array $configuration);
-
   /**
    * Returns a specific matcher.
    *
@@ -118,7 +61,7 @@ interface ProfileInterface extends ConfigEntityInterface {
    * Removes a matcher from this profile.
    *
    * @param \Drupal\linkit\MatcherInterface $matcher
-   *  The matcher object.
+   *   The matcher object.
    *
    * @return $this
    */

+ 6 - 19
sites/all/modules/contrib/fields/linkit/src/ProfileListBuilder.php

@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\ProfileListBuilder.
- */
-
 namespace Drupal\linkit;
 
 use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
@@ -22,11 +17,11 @@ class ProfileListBuilder extends ConfigEntityListBuilder {
    * {@inheritdoc}
    */
   public function buildHeader() {
-      $header['title'] = t('Profile');
-      $header['description'] = [
-          'data' => t('Description'),
-          'class' => [RESPONSIVE_PRIORITY_MEDIUM],
-      ];
+    $header['title'] = t('Profile');
+    $header['description'] = [
+      'data' => t('Description'),
+      'class' => [RESPONSIVE_PRIORITY_MEDIUM],
+    ];
     return $header + parent::buildHeader();
   }
 
@@ -55,15 +50,7 @@ class ProfileListBuilder extends ConfigEntityListBuilder {
       'title' => t('Manage matchers'),
       'weight' => 10,
       'url' => Url::fromRoute('linkit.matchers', [
-        'linkit_profile' => $entity->id()
-      ]),
-    ];
-
-    $operations['attributes'] = [
-      'title' => t('Manage attributes'),
-      'weight' => 20,
-      'url' => Url::fromRoute('linkit.attributes', [
-        'linkit_profile' => $entity->id()
+        'linkit_profile' => $entity->id(),
       ]),
     ];
 

+ 0 - 74
sites/all/modules/contrib/fields/linkit/src/ResultManager.php

@@ -1,74 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\ResultManager.
- */
-
-namespace Drupal\linkit;
-
-
-use Drupal\Component\Utility\Html;
-use Drupal\Core\Url;
-
-/**
- * Result service to handle autocomplete matcher results.
- */
-class ResultManager {
-
-  /**
-   * Gets the results.
-   *
-   * @param ProfileInterface $linkitProfile
-   *   The linkit profile.
-   * @param $search_string
-   *   The string ro use in the matchers.
-   *
-   * @return array
-   *   An array of matches.
-   */
-  public function getResults(ProfileInterface $linkitProfile, $search_string) {
-    $matches = array();
-
-    if (empty(trim($search_string))) {
-      return [[
-        'title' => t('No results'),
-      ]];
-    }
-
-    // Special for link to front page.
-    if (strpos($search_string, 'front') !== FALSE) {
-      $matches[] = [
-        'title' => t('Front page'),
-        'description' => 'The front page for this site.',
-        'path' => Url::fromRoute('<front>')->toString(),
-        'group' => t('System'),
-      ];
-    }
-
-    foreach ($linkitProfile->getMatchers() as $plugin) {
-      $matches = array_merge($matches, $plugin->getMatches($search_string));
-    }
-
-    // Check for an e-mail address then return an e-mail match and create a
-    // mail-to link if appropriate.
-    if (filter_var($search_string, FILTER_VALIDATE_EMAIL)) {
-      $matches[] = [
-        'title' => t('E-mail @email', ['@email' => $search_string]),
-        'description' => t('Opens your mail client ready to e-mail @email', ['@email' => $search_string]),
-        'path' => 'mailto:' . Html::escape($search_string),
-        'group' => t('E-mail'),
-      ];
-    }
-
-    // If there is still no matches, return a "no results" array.
-    if (empty($matches)) {
-      return [[
-        'title' => t('No results'),
-      ]];
-    }
-
-    return $matches;
-  }
-
-}

+ 36 - 0
sites/all/modules/contrib/fields/linkit/src/SubstitutionInterface.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace Drupal\linkit;
+
+use Drupal\Component\Plugin\PluginInspectionInterface;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+
+/**
+ * Interface for substitution plugins.
+ */
+interface SubstitutionInterface extends PluginInspectionInterface {
+
+  /**
+   * Get the URL associated with a given entity.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity to get a URL for.
+   *
+   * @return \Drupal\Core\GeneratedUrl
+   *   A url to replace.
+   */
+  public function getUrl(EntityInterface $entity);
+
+  /**
+   * Checks if this substitution plugin is applicable for the given entity type.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   An entity type object.
+   *
+   * @return bool
+   *   If the plugin is applicable.
+   */
+  public static function isApplicable(EntityTypeInterface $entity_type);
+
+}

+ 77 - 0
sites/all/modules/contrib/fields/linkit/src/SubstitutionManager.php

@@ -0,0 +1,77 @@
+<?php
+
+namespace Drupal\linkit;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\DefaultPluginManager;
+
+/**
+ * A plugin manager for the substitution plugins.
+ */
+class SubstitutionManager extends DefaultPluginManager implements SubstitutionManagerInterface {
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * Constructs the SubstitutionManager object.
+   *
+   * @param \Traversable $namespaces
+   *   An object that implements \Traversable which contains the root paths
+   *   keyed by the corresponding namespace to look for plugin implementations.
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+   *   Cache backend instance to use.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to invoke the alter hook with.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   */
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, EntityTypeManagerInterface $entity_type_manager) {
+    parent::__construct('Plugin/Linkit/Substitution', $namespaces, $module_handler, 'Drupal\linkit\SubstitutionInterface', 'Drupal\linkit\Annotation\Substitution');
+    $this->alterInfo('linkit_substitution');
+    $this->setCacheBackend($cache_backend, 'linkit_substitution');
+
+    $this->entityTypeManager = $entity_type_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getApplicablePluginsOptionList($entity_type_id) {
+    $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
+    $options = [];
+    foreach ($this->filterPlugins($this->getDefinitions(), $entity_type) as $id => $definition) {
+      $options[$id] = $definition['label'];
+    }
+    return $options;
+  }
+
+  /**
+   * Filter the list of plugins by their applicability.
+   *
+   * @param array $definitions
+   *   An array of plugin definitions.
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   The entity type to get applicable plugins for.
+   *
+   * @return array
+   *   The definitions appropriate for the given entity type.
+   *
+   * @see SubstitutionInterface::isApplicable()
+   */
+  protected function filterPlugins(array $definitions, EntityTypeInterface $entity_type) {
+    return array_filter($definitions, function ($definition) use ($entity_type) {
+      /** @var \Drupal\linkit\SubstitutionInterface $class */
+      $class = $definition['class'];
+      return $class::isApplicable($entity_type);
+    });
+  }
+
+}

+ 28 - 0
sites/all/modules/contrib/fields/linkit/src/SubstitutionManagerInterface.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace Drupal\linkit;
+
+use Drupal\Component\Plugin\PluginManagerInterface;
+
+/**
+ * An interface for the substitution manager.
+ */
+interface SubstitutionManagerInterface extends PluginManagerInterface {
+
+  /**
+   * Get the default substitution.
+   */
+  const DEFAULT_SUBSTITUTION = 'canonical';
+
+  /**
+   * Get a form API options list for the entity ID.
+   *
+   * @param string $entity_type_id
+   *   The entity type ID.
+   *
+   * @return array
+   *   An options list.
+   */
+  public function getApplicablePluginsOptionList($entity_type_id);
+
+}

+ 44 - 0
sites/all/modules/contrib/fields/linkit/src/Suggestion/DescriptionSuggestion.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace Drupal\linkit\Suggestion;
+
+/**
+ * Defines a linkit suggestion with description.
+ */
+class DescriptionSuggestion extends SimpleSuggestion implements SuggestionDescriptionInterface {
+
+  /**
+   * The suggestion description.
+   *
+   * A string with additional information about the suggestion.
+   *
+   * @var string
+   */
+  protected $description;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    return $this->description;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setDescription($description) {
+    $this->description = $description;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function jsonSerialize() {
+
+    return parent::jsonSerialize() + [
+      'description' => $this->getDescription(),
+    ];
+  }
+
+}

+ 81 - 0
sites/all/modules/contrib/fields/linkit/src/Suggestion/EntitySuggestion.php

@@ -0,0 +1,81 @@
+<?php
+
+namespace Drupal\linkit\Suggestion;
+
+/**
+ * Defines a entity suggestion.
+ */
+class EntitySuggestion extends DescriptionSuggestion {
+
+  /**
+   * The entity uuid.
+   *
+   * @var string
+   */
+  protected $entityUuid;
+
+  /**
+   * The entity type id.
+   *
+   * @var string
+   */
+  protected $entityTypeId;
+
+  /**
+   * The substitution id.
+   *
+   * @var string
+   */
+  protected $substitutionId;
+
+  /**
+   * Sets the entity uuid.
+   *
+   * @param string $entity_uuid
+   *   The entity uuid.
+   *
+   * @return $this
+   */
+  public function setEntityUuid($entity_uuid) {
+    $this->entityUuid = $entity_uuid;
+    return $this;
+  }
+
+  /**
+   * Sets the entity type id.
+   *
+   * @param string $entity_type_id
+   *   The entity type id.
+   *
+   * @return $this
+   */
+  public function setEntityTypeId($entity_type_id) {
+    $this->entityTypeId = $entity_type_id;
+    return $this;
+  }
+
+  /**
+   * Sets the substitution id.
+   *
+   * @param string $substitution_id
+   *   The substitution id.
+   *
+   * @return $this
+   */
+  public function setSubstitutionId($substitution_id) {
+    $this->substitutionId = $substitution_id;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function jsonSerialize() {
+    return parent::jsonSerialize() + [
+      'entity_uuid' => $this->entityUuid,
+      'entity_type_id' => $this->entityTypeId,
+      'substitution_id' => $this->substitutionId,
+    ];
+  }
+
+}

+ 87 - 0
sites/all/modules/contrib/fields/linkit/src/Suggestion/SimpleSuggestion.php

@@ -0,0 +1,87 @@
+<?php
+
+namespace Drupal\linkit\Suggestion;
+
+/**
+ * Defines a simple suggestion.
+ */
+class SimpleSuggestion implements SuggestionInterface {
+
+  /**
+   * The suggestion label.
+   *
+   * @var string
+   */
+  protected $label;
+
+  /**
+   * The suggestion path.
+   *
+   * @var string
+   */
+  protected $path;
+
+  /**
+   * The suggestion group.
+   *
+   * @var string
+   */
+  protected $group;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLabel() {
+    return $this->label;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setLabel($label) {
+    $this->label = $label;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getPath() {
+    return $this->path;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setPath($path) {
+    $this->path = $path;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGroup() {
+    return $this->group;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setGroup($group) {
+    $this->group = $group;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function jsonSerialize() {
+    return [
+      'label' => $this->getLabel(),
+      'path' => $this->getPath(),
+      'group' => $this->getGroup(),
+    ];
+  }
+
+}

+ 56 - 0
sites/all/modules/contrib/fields/linkit/src/Suggestion/SuggestionCollection.php

@@ -0,0 +1,56 @@
+<?php
+
+namespace Drupal\linkit\Suggestion;
+
+/**
+ * Defines a suggestion collection used to avoid JSON Hijacking.
+ */
+class SuggestionCollection implements \JsonSerializable {
+
+  /**
+   * An array of suggestions.
+   *
+   * @var array
+   */
+  protected $suggestions = [];
+
+  /**
+   * Returns all suggestions in the collection.
+   *
+   * @return \Drupal\linkit\Suggestion\SuggestionInterface[]
+   *   All suggestions in the collection.
+   */
+  public function getSuggestions() {
+    return $this->suggestions;
+  }
+
+  /**
+   * Adds a suggestion to this collection.
+   *
+   * @param \Drupal\linkit\Suggestion\SuggestionInterface $suggestion
+   *   The suggestion to add to the collection.
+   */
+  public function addSuggestion(SuggestionInterface $suggestion) {
+    $this->suggestions[] = $suggestion;
+  }
+
+  /**
+   * Adds a collection of suggestions to the this collection.
+   *
+   * @param \Drupal\linkit\Suggestion\SuggestionCollection $suggestionCollection
+   *   A collection of suggestions.
+   */
+  public function addSuggestions(SuggestionCollection $suggestionCollection) {
+    $this->suggestions = array_merge($this->suggestions, $suggestionCollection->getSuggestions());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function jsonSerialize() {
+    return [
+      'suggestions' => $this->suggestions,
+    ];
+  }
+
+}

+ 28 - 0
sites/all/modules/contrib/fields/linkit/src/Suggestion/SuggestionDescriptionInterface.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace Drupal\linkit\Suggestion;
+
+/**
+ * Defines the interface for suggestions that have a description.
+ */
+interface SuggestionDescriptionInterface {
+
+  /**
+   * Gets the suggestion description.
+   *
+   * @return string
+   *   The suggestion description.
+   */
+  public function getDescription();
+
+  /**
+   * Sets the suggestion description.
+   *
+   * @param string $description
+   *   The suggestion description.
+   *
+   * @return $this
+   */
+  public function setDescription($description);
+
+}

+ 64 - 0
sites/all/modules/contrib/fields/linkit/src/Suggestion/SuggestionInterface.php

@@ -0,0 +1,64 @@
+<?php
+
+namespace Drupal\linkit\Suggestion;
+
+/**
+ * Defines the interface for suggestions.
+ */
+interface SuggestionInterface extends \JsonSerializable {
+
+  /**
+   * Gets the suggestion label.
+   *
+   * @return string
+   *   The suggestion label.
+   */
+  public function getLabel();
+
+  /**
+   * Sets the suggestion label.
+   *
+   * @param string $label
+   *   The suggestion label to set.
+   *
+   * @return $this
+   */
+  public function setLabel($label);
+
+  /**
+   * Gets the suggestion path.
+   *
+   * @return string
+   *   The suggestion path.
+   */
+  public function getPath();
+
+  /**
+   * Sets the suggestion path.
+   *
+   * @param string $path
+   *   The suggestion path to set.
+   *
+   * @return $this
+   */
+  public function setPath($path);
+
+  /**
+   * Gets the suggestion group.
+   *
+   * @return string
+   *   The suggestion group.
+   */
+  public function getGroup();
+
+  /**
+   * Sets the suggestion group.
+   *
+   * @param string $group
+   *   The suggestion group to set.
+   *
+   * @return $this
+   */
+  public function setGroup($group);
+
+}

+ 63 - 0
sites/all/modules/contrib/fields/linkit/src/SuggestionManager.php

@@ -0,0 +1,63 @@
+<?php
+
+namespace Drupal\linkit;
+
+use Drupal\Component\Utility\Html;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\linkit\Suggestion\DescriptionSuggestion;
+use Drupal\linkit\Suggestion\SuggestionCollection;
+
+/**
+ * Suggestion service to handle autocomplete suggestions.
+ */
+class SuggestionManager {
+
+  use StringTranslationTrait;
+
+  /**
+   * Gets the suggestions.
+   *
+   * @param ProfileInterface $linkitProfile
+   *   The linkit profile.
+   * @param string $search_string
+   *   The string ro use in the matchers.
+   *
+   * @return \Drupal\linkit\Suggestion\SuggestionCollection
+   *   A suggestion collection.
+   */
+  public function getSuggestions(ProfileInterface $linkitProfile, $search_string) {
+    $suggestions = new SuggestionCollection();
+
+    if (empty(trim($search_string))) {
+      return $suggestions;
+    }
+
+    foreach ($linkitProfile->getMatchers() as $plugin) {
+      $suggestions->addSuggestions($plugin->execute($search_string));
+    }
+
+    return $suggestions;
+  }
+
+  /**
+   * Adds an unscathed suggestion to the given suggestion collection.
+   *
+   * @param \Drupal\linkit\Suggestion\SuggestionCollection $suggestionCollection
+   *   A suggestion collection to add the unscathed suggestion to.
+   * @param string $search_string
+   *   The string ro use in the matchers.
+   *
+   * @return \Drupal\linkit\Suggestion\SuggestionCollection
+   *   A suggestion collection.
+   */
+  public function addUnscathedSuggestion(SuggestionCollection $suggestionCollection, $search_string) {
+    $suggestion = new DescriptionSuggestion();
+    $suggestion->setLabel(Html::escape($search_string))
+      ->setGroup($this->t('No results'))
+      ->setDescription($this->t('Linkit could not find any suggestions. This URL will be used as is.'))
+      ->setPath($search_string);
+    $suggestionCollection->addSuggestion($suggestion);
+    return $suggestionCollection;
+  }
+
+}

+ 0 - 160
sites/all/modules/contrib/fields/linkit/src/Tests/AttributeCrudTest.php

@@ -1,160 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Tests\AttributeCrudTest.
- */
-
-namespace Drupal\linkit\Tests;
-
-use Drupal\Core\Url;
-use Drupal\linkit\Entity\Profile;
-
-/**
- * Tests adding, listing and deleting attributes on a profile.
- *
- * @group linkit
- */
-class AttributeCrudTest extends LinkitTestBase {
-
-  /**
-   * The attribute manager.
-   *
-   * @var \Drupal\linkit\AttributeManager
-   */
-  protected $manager;
-
-  /**
-   * The linkit profile.
-   *
-   * @var \Drupal\linkit\ProfileInterface
-   */
-  protected $linkitProfile;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->manager = $this->container->get('plugin.manager.linkit.attribute');
-
-    $this->linkitProfile = $this->createProfile();
-    $this->drupalLogin($this->adminUser);
-  }
-
-  /**
-   * Test the overview page.
-   */
-  function testOverview() {
-    $this->drupalGet(Url::fromRoute('linkit.attributes', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ]));
-    $this->assertText(t('No attributes added.'));
-
-    $this->assertLinkByHref(Url::fromRoute('linkit.attribute.add', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ])->toString());
-  }
-
-  /**
-   * Test adding an attribute to a profile.
-   */
-  function testAdd() {
-    $this->drupalGet(Url::fromRoute('linkit.attribute.add', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ]));
-
-    $this->assertEqual(count($this->manager->getDefinitions()), count($this->xpath('//input[@type="radio"]')), 'All attributes are available.');
-
-    $edit = array();
-    $edit['plugin'] = 'dummy_attribute';
-    $this->drupalPostForm(NULL, $edit, t('Save and continue'));
-
-    $this->assertUrl(Url::fromRoute('linkit.attributes', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ]));
-
-    $this->assertEqual(1, count($this->xpath('//table/tbody/tr')), 'Attribute added.');
-    $this->assertNoText(t('No attributes added.'));
-  }
-
-  /**
-   * Test adding a configurable attribute to a profile.
-   */
-  function testAddConfigurable() {
-    $this->drupalGet(Url::fromRoute('linkit.attribute.add', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ]));
-
-    $this->assertEqual(count($this->manager->getDefinitions()), count($this->xpath('//input[@type="radio"]')), 'All attributes are available.');
-
-    $edit = array();
-    $edit['plugin'] = 'configurable_dummy_attribute';
-    $this->drupalPostForm(NULL, $edit, t('Save and continue'));
-
-    $this->assertUrl(Url::fromRoute('linkit.attribute.edit', [
-      'linkit_profile' => $this->linkitProfile->id(),
-      'plugin_instance_id' => 'configurable_dummy_attribute',
-    ]));
-
-    $this->drupalGet(Url::fromRoute('linkit.attributes', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ]));
-
-    $this->assertEqual(1, count($this->xpath('//table/tbody/tr')), 'Attribute added.');
-    $this->assertNoText(t('No attributes added.'));
-
-    $plugin_url = Url::fromRoute('linkit.attribute.edit', [
-      'linkit_profile' => $this->linkitProfile->id(),
-      'plugin_instance_id' => 'configurable_dummy_attribute',
-    ]);
-
-    $this->assertLinkByHref($plugin_url->toString());
-  }
-
-  /**
-   * Test delete an attribute from a profile.
-   */
-  function testDelete() {
-    /** @var \Drupal\linkit\AttributeInterface $plugin */
-    $plugin = $this->manager->createInstance('dummy_attribute');
-
-    $this->linkitProfile->addAttribute($plugin->getConfiguration());
-    $this->linkitProfile->save();
-
-    // Try delete an attribute that is not attached to the profile.
-    $this->drupalGet(Url::fromRoute('linkit.attribute.delete', [
-      'linkit_profile' => $this->linkitProfile->id(),
-      'plugin_instance_id' => 'doesntexists'
-    ]));
-    $this->assertResponse('404');
-
-    // Go to the delete page, but press cancel.
-    $this->drupalGet(Url::fromRoute('linkit.attribute.delete', [
-      'linkit_profile' => $this->linkitProfile->id(),
-      'plugin_instance_id' => $plugin->getPluginId(),
-    ]));
-    $this->clickLink(t('Cancel'));
-    $this->assertUrl(Url::fromRoute('linkit.attributes', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ]));
-
-    // Delete the attribute from the profile.
-    $this->drupalGet(Url::fromRoute('linkit.attribute.delete', [
-      'linkit_profile' => $this->linkitProfile->id(),
-      'plugin_instance_id' => 'dummy_attribute',
-    ]));
-
-    $this->drupalPostForm(NULL, [], t('Confirm'));
-    $this->assertRaw(t('The attribute %plugin has been deleted.', ['%plugin' => $plugin->getLabel()]));
-    $this->assertUrl(Url::fromRoute('linkit.attributes', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ]));
-    $this->assertText(t('No attributes added.'));
-
-    /** @var \Drupal\linkit\Entity\Profile $updated_profile */
-    $updated_profile = Profile::load($this->linkitProfile->id());
-    $this->assertFalse($updated_profile->getAttributes()->has($plugin->getPluginId()), 'The attribute is deleted from the profile');
-  }
-
-}

+ 0 - 83
sites/all/modules/contrib/fields/linkit/src/Tests/Controllers/LinkitControllerTest.php

@@ -1,83 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Tests\Controllers\LinkitControllerTest.
- */
-
-namespace Drupal\linkit\Tests\Controllers;
-
-use Drupal\Core\Url;
-use Drupal\linkit\Tests\LinkitTestBase;
-
-
-/**
- * Tests Linkit controller.
- *
- * @group linkit
- */
-class LinkitControllerTest extends LinkitTestBase {
-
-  /**
-   * The linkit profile.
-   *
-   * @var \Drupal\linkit\ProfileInterface
-   */
-  protected $linkitProfile;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    $this->linkitProfile = $this->createProfile();
-
-    $this->drupalLogin($this->adminUser);
-  }
-
-  /**
-   * Tests the profile route title callback.
-   */
-  function testProfileTitle() {
-    $this->drupalGet(Url::fromRoute('entity.linkit_profile.edit_form', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ]));
-
-    $this->assertText('Edit ' . $this->linkitProfile->label() . ' profile');
-  }
-
-  /**
-   * Tests the matcher route title callback.
-   */
-  function testMatcherTitle() {
-    /** @var \Drupal\linkit\MatcherInterface $plugin */
-    $plugin = $this->container->get('plugin.manager.linkit.matcher')->createInstance('configurable_dummy_matcher');
-    $matcher_uuid = $this->linkitProfile->addMatcher($plugin->getConfiguration());
-    $this->linkitProfile->save();
-
-    $this->drupalGet(Url::fromRoute('linkit.matcher.edit', [
-      'linkit_profile' => $this->linkitProfile->id(),
-      'plugin_instance_id' => $matcher_uuid,
-    ]));
-
-    $this->assertText('Edit ' . $plugin->getLabel() . ' matcher');
-  }
-
-  /**
-   * Tests the attribute route title callback.
-   */
-  function testAttributeTitle() {
-    /** @var \Drupal\linkit\AttributeInterface $plugin */
-    $plugin = $this->container->get('plugin.manager.linkit.attribute')->createInstance('configurable_dummy_attribute');
-    $this->linkitProfile->addAttribute($plugin->getConfiguration());
-    $this->linkitProfile->save();
-
-    $this->drupalGet(Url::fromRoute('linkit.attribute.edit', [
-      'linkit_profile' => $this->linkitProfile->id(),
-      'plugin_instance_id' => $plugin->getPluginId(),
-    ]));
-    $this->assertText('Edit ' . $plugin->getLabel() . ' attribute');
-  }
-
-}

+ 0 - 83
sites/all/modules/contrib/fields/linkit/src/Tests/LinkitTestBase.php

@@ -1,83 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Tests\LinkitTestBase.
- */
-
-namespace Drupal\linkit\Tests;
-
-use Drupal\Component\Utility\Unicode;
-use Drupal\linkit\Entity\Profile;
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Sets up page and article content types.
- */
-abstract class LinkitTestBase extends WebTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * Enable block module to get the local_actions_block to work.
-   *
-   * @var array
-   */
-  public static $modules = ['linkit', 'linkit_test', 'block'];
-
-  /**
-   * A user with the 'administer linkit profiles' permission.
-   *
-   * @var \Drupal\user\UserInterface
-   */
-  protected $adminUser;
-
-  /**
-   * A user without the 'administer linkit profiles' permission.
-   *
-   * @var \Drupal\user\UserInterface
-   */
-  protected $baseUser;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->adminUser = $this->drupalCreateUser(['administer linkit profiles']);
-    $this->baseUser = $this->drupalCreateUser();
-
-    $this->drupalPlaceBlock('page_title_block', ['region' => 'content']);
-    $this->drupalPlaceBlock('local_tasks_block', ['region' => 'content']);
-    $this->drupalPlaceBlock('local_actions_block', ['region' => 'content']);
-    $this->drupalPlaceBlock('system_messages_block', ['region' => 'highlighted']);
-  }
-
-  /**
-   * Creates a profile based on default settings.
-   *
-   * @param array $settings
-   *   (optional) An associative array of settings for the profile, as used in
-   *   entity_create(). Override the defaults by specifying the key and value
-   *   in the array
-   *
-   *   The following defaults are provided:
-   *   - label: Random string.
-   *
-   * @return \Drupal\linkit\ProfileInterface
-   *   The created profile entity.
-   */
-  protected function createProfile(array $settings = []) {
-    // Populate defaults array.
-    $settings += [
-      'id' => Unicode::strtolower($this->randomMachineName()),
-      'label' => $this->randomMachineName(),
-    ];
-
-    $profile = Profile::create($settings);
-    $profile->save();
-
-    return $profile;
-  }
-
-}

+ 0 - 158
sites/all/modules/contrib/fields/linkit/src/Tests/MatcherCrudTest.php

@@ -1,158 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Tests\MatcherCrudTest.
- */
-
-namespace Drupal\linkit\Tests;
-use Drupal\Core\Url;
-use Drupal\linkit\Entity\Profile;
-
-/**
- * Tests adding, listing, updating and deleting matchers on a profile.
- *
- * @group linkit
- */
-class MatcherCrudTest extends LinkitTestBase {
-
-  /**
-   * The attribute manager.
-   *
-   * @var \Drupal\linkit\MatcherManager
-   */
-  protected $manager;
-
-  /**
-   * The linkit profile.
-   *
-   * @var \Drupal\linkit\ProfileInterface
-   */
-  protected $linkitProfile;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->manager = $this->container->get('plugin.manager.linkit.matcher');
-
-    $this->linkitProfile = $this->createProfile();
-    $this->drupalLogin($this->adminUser);
-  }
-
-  /**
-   * Test the overview page.
-   */
-  function testOverview() {
-    $this->drupalGet(Url::fromRoute('linkit.matchers', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ]));
-    $this->assertText(t('No matchers added.'));
-
-    $this->assertLinkByHref(Url::fromRoute('linkit.matcher.add', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ])->toString());
-  }
-
-  /**
-   * Test adding a matcher to a profile.
-   */
-  function testAdd() {
-    $this->drupalGet(Url::fromRoute('linkit.matcher.add', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ]));
-
-    $edit = array();
-    $edit['plugin'] = 'dummy_matcher';
-    $this->drupalPostForm(NULL, $edit, t('Save and continue'));
-
-    // Load the saved profile.
-    $this->linkitProfile = Profile::load($this->linkitProfile->id());
-
-    $matcher_ids = $this->linkitProfile->getMatchers()->getInstanceIds();
-    /** @var \Drupal\linkit\MatcherInterface $plugin */
-    $plugin = $this->linkitProfile->getMatcher(current($matcher_ids));
-
-    $this->assertRaw(t('Added %label matcher.', ['%label' => $plugin->getLabel()]));
-    $this->assertNoText(t('No matchers added.'));
-  }
-
-  /**
-   * Test adding a configurable attribute to a profile.
-   */
-  function testAddConfigurable() {
-    $this->drupalGet(Url::fromRoute('linkit.matcher.add', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ]));
-
-    $edit = array();
-    $edit['plugin'] = 'configurable_dummy_matcher';
-    $this->drupalPostForm(NULL, $edit, t('Save and continue'));
-
-    // Load the saved profile.
-    $this->linkitProfile = Profile::load($this->linkitProfile->id());
-
-    $matcher_ids = $this->linkitProfile->getMatchers()->getInstanceIds();
-    /** @var \Drupal\linkit\MatcherInterface $plugin */
-    $plugin = $this->linkitProfile->getMatcher(current($matcher_ids));
-
-    $this->assertUrl(Url::fromRoute('linkit.matcher.edit', [
-      'linkit_profile' => $this->linkitProfile->id(),
-      'plugin_instance_id' => $plugin->getUuid(),
-    ]));
-
-    $this->drupalGet(Url::fromRoute('linkit.matchers', [
-      'linkit_profile' => $this->linkitProfile->id(),
-    ]));
-
-    $this->assertNoText(t('No matchers added.'));
-  }
-
-  /**
-   * Test delete a matcher from a profile.
-   */
-  function testDelete() {
-    /** @var \Drupal\linkit\AttributeInterface $plugin */
-    $plugin = $this->manager->createInstance('dummy_matcher');
-
-    $profile = $this->createProfile();
-    $plugin_uuid = $profile->addMatcher($plugin->getConfiguration());
-    $profile->save();
-
-    // Try delete a matcher that is not attached to the profile.
-    $this->drupalGet(Url::fromRoute('linkit.matcher.delete', [
-      'linkit_profile' => $profile->id(),
-      'plugin_instance_id' => 'doesntexists'
-    ]));
-    $this->assertResponse('404');
-
-    // Go to the delete page, but press cancel.
-    $this->drupalGet(Url::fromRoute('linkit.matcher.delete', [
-      'linkit_profile' => $profile->id(),
-      'plugin_instance_id' => $plugin_uuid,
-    ]));
-    $this->clickLink(t('Cancel'));
-    $this->assertUrl(Url::fromRoute('linkit.matchers', [
-      'linkit_profile' => $profile->id(),
-    ]));
-
-    // Delete the matcher from the profile.
-    $this->drupalGet(Url::fromRoute('linkit.matcher.delete', [
-      'linkit_profile' => $profile->id(),
-      'plugin_instance_id' => $plugin_uuid,
-    ]));
-
-    $this->drupalPostForm(NULL, [], t('Confirm'));
-    $this->assertRaw(t('The matcher %plugin has been deleted.', ['%plugin' => $plugin->getLabel()]));
-    $this->assertUrl(Url::fromRoute('linkit.matchers', [
-      'linkit_profile' => $profile->id(),
-    ]));
-    $this->assertText(t('No matchers added.'));
-
-    /** @var \Drupal\linkit\Entity\Profile $updated_profile */
-    $updated_profile = Profile::load($profile->id());
-    $this->assertFalse($updated_profile->getMatchers()->has($plugin_uuid), 'The user matcher is deleted from the profile');
-  }
-
-}

+ 0 - 105
sites/all/modules/contrib/fields/linkit/src/Tests/Matchers/NodeMatcherTest.php

@@ -1,105 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Tests\Matchers\NodeMatcherTest.
- */
-
-namespace Drupal\linkit\Tests\Matchers;
-
-use Drupal\linkit\Tests\LinkitTestBase;
-
-/**
- * Tests node matcher.
- *
- * @group linkit
- */
-class NodeMatcherTest extends LinkitTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['node'];
-
-  /**
-   * The matcher manager.
-   *
-   * @var \Drupal\linkit\MatcherManager
-   */
-  protected $manager;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->drupalLogin($this->adminUser);
-    $this->manager = $this->container->get('plugin.manager.linkit.matcher');
-
-    $type1 = $this->drupalCreateContentType(['type' => 'test1', 'name' => 'Test1']);
-    $type2 = $this->drupalCreateContentType(['type' => 'test2', 'name' => 'Test2']);
-
-    // Nodes with type 1.
-    $this->drupalCreateNode(['title' => 'Lorem Ipsum 1', 'type' => $type1->id()]);
-    $this->drupalCreateNode(['title' => 'Lorem Ipsum 2', 'type' => $type1->id()]);
-
-    // Nodes with type 1.
-    $this->drupalCreateNode(['title' => 'Lorem Ipsum 3', 'type' => $type2->id()]);
-
-    // Unpublished node.
-    $this->drupalCreateNode(['title' => 'Lorem unpublishd', 'type' => $type1->id(), 'status' => FALSE]);
-  }
-
-  /**
-   * Tests node matcher.
-   */
-  function testNodeMatcherWidthDefaultConfiguration() {
-    /** @var \Drupal\linkit\MatcherInterface $plugin */
-    $plugin = $this->manager->createInstance('entity:node', []);
-    $matches = $plugin->getMatches('Lorem');
-    $this->assertEqual(3, count($matches), 'Correct number of matches');
-  }
-
-  /**
-   * Tests node matcher with bundle filer.
-   */
-  function testNodeMatcherWidthBundleFiler() {
-    /** @var \Drupal\linkit\MatcherInterface $plugin */
-    $plugin = $this->manager->createInstance('entity:node', [
-      'settings' => [
-        'bundles' => [
-          'test1' => 'test1'
-        ],
-      ],
-    ]);
-
-    $matches = $plugin->getMatches('Lorem');
-    $this->assertEqual(2, count($matches), 'Correct number of matches');
-  }
-
-  /**
-   * Tests node matcher with include unpublished setting activated.
-   */
-  function testNodeMatcherWidthIncludeUnpublished() {
-    /** @var \Drupal\linkit\MatcherInterface $plugin */
-    $plugin = $this->manager->createInstance('entity:node', [
-      'settings' => [
-        'include_unpublished' => TRUE,
-      ],
-    ]);
-
-    // Test without permissions to see unpublished nodes.
-    $matches = $plugin->getMatches('Lorem');
-    $this->assertEqual(3, count($matches), 'Correct number of matches');
-
-    $account = $this->drupalCreateUser(['bypass node access']);
-    $this->drupalLogin($account);
-
-    // Test with permissions to see unpublished nodes.
-    $matches = $plugin->getMatches('Lorem');
-    $this->assertEqual(4, count($matches), 'Correct number of matches');
-  }
-
-}

+ 0 - 114
sites/all/modules/contrib/fields/linkit/src/Tests/Matchers/UserMatcherTest.php

@@ -1,114 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Tests\Matchers\UserMatcherTest.
- */
-
-namespace Drupal\linkit\Tests\Matchers;
-
-use Drupal\linkit\Tests\LinkitTestBase;
-
-/**
- * Tests user matcher.
- *
- * @group linkit
- */
-class UserMatcherTest extends LinkitTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['user'];
-
-  /**
-   * The matcher manager.
-   *
-   * @var \Drupal\linkit\MatcherManager
-   */
-  protected $manager;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-    $this->drupalLogin($this->drupalCreateUser(['access user profiles']));
-    $this->manager = $this->container->get('plugin.manager.linkit.matcher');
-
-    $custom_role = $this->drupalCreateRole(array(), 'custom_role', 'custom_role');
-    $custom_role_admin = $this->drupalCreateRole(array(), 'custom_role_admin', 'custom_role_admin');
-
-    $this->drupalCreateUser([], 'lorem');
-    $this->drupalCreateUser([], 'foo');
-
-    $account = $this->drupalCreateUser([], 'ipsumlorem');
-    $account->addRole($custom_role);
-    $account->save();
-
-    $account = $this->drupalCreateUser([], 'lorem_custom_role');
-    $account->addRole($custom_role);
-    $account->save();
-
-    $account = $this->drupalCreateUser([], 'lorem_custom_role_admin');
-    $account->addRole($custom_role_admin);
-    $account->save();
-
-    $account = $this->drupalCreateUser([], 'blocked_lorem');
-    $account->block();
-    $account->save();
-  }
-
-  /**
-   * Tests user matcher.
-   */
-  function testUserMatcherWidthDefaultConfiguration() {
-    /** @var \Drupal\linkit\MatcherInterface $plugin */
-    $plugin = $this->manager->createInstance('entity:user', []);
-    $matches = $plugin->getMatches('Lorem');
-    $this->assertEqual(4, count($matches), 'Correct number of matches');
-  }
-
-  /**
-   * Tests user matcher with role filer.
-   */
-  function testUserMatcherWidthRoleFiler() {
-    /** @var \Drupal\linkit\MatcherInterface $plugin */
-    $plugin = $this->manager->createInstance('entity:user', [
-      'settings' => [
-        'roles' => [
-          'custom_role' => 'custom_role'
-        ],
-      ],
-    ]);
-
-    $matches = $plugin->getMatches('Lorem');
-    $this->assertEqual(2, count($matches), 'Correct number of matches');
-  }
-
-  /**
-   * Tests user matcher with include blocked setting activated.
-   */
-  function testUserMatcherWidthIncludeBlocked() {
-    /** @var \Drupal\linkit\MatcherInterface $plugin */
-    $plugin = $this->manager->createInstance('entity:user', [
-      'settings' => [
-        'include_blocked' => TRUE,
-      ],
-    ]);
-
-    // Test without permissions to see blocked users.
-    $matches = $plugin->getMatches('blocked');
-    $this->assertEqual(0, count($matches), 'Correct number of matches');
-
-    $account = $this->drupalCreateUser(['administer users']);
-    $this->drupalLogin($account);
-
-    // Test with permissions to see blocked users.
-    $matches = $plugin->getMatches('blocked');
-    $this->assertEqual(1, count($matches), 'Correct number of matches');
-  }
-
-}

+ 44 - 0
sites/all/modules/contrib/fields/linkit/src/Tests/ProfileCreationTrait.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace Drupal\linkit\Tests;
+
+use Drupal\Component\Utility\Unicode;
+use Drupal\linkit\Entity\Profile;
+
+/**
+ * Provides methods to create profiles based on default settings.
+ *
+ * This trait is meant to be used only by test classes.
+ */
+trait ProfileCreationTrait {
+
+  /**
+   * Creates a profile based on default settings.
+   *
+   * @param array $settings
+   *   (optional) An associative array of settings for the profile, as used in
+   *   entity_create(). Override the defaults by specifying the key and value
+   *   in the array.
+   *   The following defaults are provided:
+   *   - id: Random string.
+   *   - label: Random string.
+   *
+   * @return \Drupal\linkit\ProfileInterface
+   *   The created profile entity.
+   */
+  protected function createProfile(array $settings = []) {
+    // Populate defaults array.
+    $settings += [
+      'id' => Unicode::strtolower($this->randomMachineName()),
+      'label' => $this->randomMachineName(),
+    ];
+
+    $profile = Profile::create($settings);
+    $profile->save();
+
+    $profile = Profile::load($profile->id());
+
+    return $profile;
+  }
+
+}

+ 0 - 125
sites/all/modules/contrib/fields/linkit/src/Tests/ProfileCrudTest.php

@@ -1,125 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\linkit\Tests\ProfileCreationTest.
- */
-
-namespace Drupal\linkit\Tests;
-use Drupal\Component\Utility\Unicode;
-use Drupal\Core\Url;
-
-/**
- * Tests creating, loading and deleting profiles.
- *
- * @group linkit
- */
-class ProfileCrudTest extends LinkitTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    $this->drupalLogin($this->adminUser);
-  }
-
-  /**
-   * Test the overview page.
-   */
-  function testOverview() {
-    // Verify that the profile collection page is not accessible for regular
-    // users.
-    $this->drupalLogin($this->baseUser);
-    $this->drupalGet(Url::fromRoute('entity.linkit_profile.collection'));
-    $this->assertResponse(403);
-    $this->drupalLogout();
-
-    // Verify that the profile collection page is accessible for regular users.
-    $this->drupalLogin($this->adminUser);
-
-    $profiles = [];
-    $profiles[] = $this->createProfile();
-    $profiles[] = $this->createProfile();
-
-    $this->drupalGet(Url::fromRoute('entity.linkit_profile.collection'));
-    $this->assertResponse(200);
-
-    // Assert that the 'Add profile' action exists.
-    $this->assertLinkByHref(Url::fromRoute('entity.linkit_profile.add_form')->toString());
-
-    /** @var \Drupal\linkit\ProfileInterface $profile */
-    foreach ($profiles as $profile) {
-      $this->assertLinkByHref('admin/config/content/linkit/manage/' . $profile->id());
-      $this->assertLinkByHref('admin/config/content/linkit/manage/' . $profile->id() . '/delete');
-    }
-  }
-
-  /**
-   * Creates profile.
-   */
-  function testProfileCreation() {
-    $this->drupalGet(Url::fromRoute('entity.linkit_profile.add_form'));
-    $this->drupalGet('admin/config/content/linkit/add');
-    $this->assertResponse(200);
-
-    // Create a profile.
-    $edit = [];
-    $edit['label'] = Unicode::strtolower($this->randomMachineName());
-    $edit['id'] = Unicode::strtolower($this->randomMachineName());
-    $edit['description'] = $this->randomMachineName(16);
-    $this->drupalPostForm(NULL, $edit, t('Save and manage matchers'));
-
-    $this->assertRaw(t('Created new profile %label.', ['%label' => $edit['label']]));
-
-    $this->drupalGet(Url::fromRoute('entity.linkit_profile.collection'));
-    $this->assertText($edit['label'], 'Profile exists in the profile collection.');
-  }
-
-  /**
-   * Updates a profile.
-   */
-  function testProfileUpdate() {
-    $profile = $this->createProfile();
-    $this->drupalGet(Url::fromRoute('entity.linkit_profile.edit_form', [
-      'linkit_profile' => $profile->id(),
-    ]));
-    $this->assertResponse(200);
-
-    $id_field = $this->xpath('.//input[not(@disabled) and @name="id"]');
-
-    $this->assertTrue(empty($id_field), 'Machine name field is disabled.');
-    $this->assertLinkByHref(Url::fromRoute('entity.linkit_profile.edit_form', [
-      'linkit_profile' => $profile->id(),
-    ])->toString());
-    $this->assertLinkByHref('admin/config/content/linkit/manage/' . $profile->id() . '/delete');
-
-    $edit = [];
-    $edit['label'] = $this->randomMachineName();
-    $edit['description'] = $this->randomMachineName(16);
-    $this->drupalPostForm(NULL, $edit, t('Update profile'));
-
-    $this->assertRaw(t('Updated profile %label.', ['%label' => $edit['label']]));
-
-    $this->drupalGet(Url::fromRoute('entity.linkit_profile.collection'));
-    $this->assertText($edit['label'], 'Updated profile exists in the profile collection.');
-  }
-
-  /**
-   * Delete a profile.
-   */
-  function testProfileDelete() {
-    /** @var \Drupal\linkit\ProfileInterface $profile */
-    $profile = $this->createProfile();
-    $this->drupalGet(Url::fromRoute('entity.linkit_profile.delete_form', [
-      'linkit_profile' => $profile->id(),
-    ]));
-    $this->drupalPostForm(NULL, [], t('Delete'));
-
-    $this->assertRaw(t('The linkit profile %label has been deleted.', ['%label' => $profile->label()]));
-    $this->drupalGet(Url::fromRoute('entity.linkit_profile.collection'));
-    $this->assertNoText($profile->label(), 'Deleted profile does not exists in the profile collection.');
-  }
-
-}

+ 152 - 0
sites/all/modules/contrib/fields/linkit/src/Tests/Update/LinkitUpdateTest.php

@@ -0,0 +1,152 @@
+<?php
+
+namespace Drupal\linkit\Tests\Update;
+
+use Drupal\filter\Entity\FilterFormat;
+use Drupal\system\Tests\Update\UpdatePathTestBase;
+
+/**
+ * Tests Linkit upgrade paths.
+ *
+ * @group Update
+ */
+class LinkitUpdateTest extends UpdatePathTestBase {
+
+  /**
+   * The config factory service.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->configFactory = $this->container->get('config.factory');
+  }
+
+  /**
+   * Set database dump files to be used.
+   */
+  protected function setDatabaseDumpFiles() {
+    $this->databaseDumpFiles = [
+      __DIR__ . '/../../../tests/fixtures/update/drupal-8.linkit-enabled.standard.php.gz',
+      __DIR__ . '/../../../tests/fixtures/update/linkit-additions.php',
+    ];
+  }
+
+  /**
+   * Tests linkit_update_8500().
+   *
+   * @see linkit_update_8500()
+   */
+  public function testLinkitUpdate8500() {
+    $editor = $this->configFactory->get('editor.editor.format_1');
+    $this->assertTrue($editor->get('settings.plugins.linkit'), 'We got old linkit settings in the editor configuration.');
+    $format_1_linkit_profile = $editor->get('settings.plugins.linkit.linkit_profile');
+
+    $editor = $this->configFactory->get('editor.editor.format_2');
+    $this->assertTrue($editor->get('settings.plugins.linkit'), 'We got old linkit settings in the editor configuration.');
+    $format_2_linkit_profile = $editor->get('settings.plugins.linkit.linkit_profile');
+
+    $editor = $this->configFactory->get('editor.editor.format_3');
+    $this->assertTrue($editor->get('settings.plugins.linkit'), 'We got old linkit settings in the editor configuration.');
+    $format_3_linkit_profile = $editor->get('settings.plugins.linkit.linkit_profile');
+
+    $this->runUpdates();
+
+    $test_profile = $this->configFactory->get('linkit.linkit_profile.test_profile');
+    $this->assertEqual(NULL, $test_profile->get('attributes'), 'Attributes are deleted from the profile.');
+
+    $editor = $this->configFactory->get('editor.editor.format_1');
+    $this->assertNull($editor->get('settings.plugins.linkit'), 'Old linkit settings in the editor configuration is removed.');
+    $this->assertEqual($editor->get('settings.toolbar.rows.0.1.items.0'), 'DrupalLink', 'Drupal link plugin is in the toolbar.');
+    $this->assertNotEqual($editor->get('settings.toolbar.rows.0.1.items.1'), 'Linkit', 'Linkit plugin is removed from the toolbar.');
+    $this->assertTrue($editor->get('settings.plugins.drupallink.linkit_enabled'), 'Drupal link plugin has linkit enabled.');
+    $this->assertEqual($editor->get('settings.plugins.drupallink.linkit_profile'), $format_1_linkit_profile, 'Drupal link plugin uses the same profile as the old linkit plugin.');
+
+    $editor = $this->configFactory->get('editor.editor.format_2');
+    $this->assertNull($editor->get('settings.plugins.linkit'), 'Old linkit settings in the editor configuration is removed.');
+    $this->assertEqual($editor->get('settings.toolbar.rows.0.1.items.0'), 'DrupalLink', 'Drupal link plugin is in the toolbar.');
+    $this->assertTrue($editor->get('settings.plugins.drupallink.linkit_enabled'), 'Drupal link plugin has linkit enabled.');
+    $this->assertEqual($editor->get('settings.plugins.drupallink.linkit_profile'), $format_2_linkit_profile, 'Drupal link plugin uses the same profile as the old linkit plugin.');
+
+    $editor = $this->configFactory->get('editor.editor.format_3');
+    $this->assertNull($editor->get('settings.plugins.linkit'), 'Old linkit settings in the editor configuration is removed.');
+    $this->assertEqual($editor->get('settings.toolbar.rows.0.0.items.0'), 'DrupalLink', 'Drupal link plugin is in the toolbar.');
+    $this->assertTrue($editor->get('settings.plugins.drupallink.linkit_enabled'), 'Drupal link plugin has linkit enabled.');
+    $this->assertEqual($editor->get('settings.plugins.drupallink.linkit_profile'), $format_3_linkit_profile, 'Drupal link plugin uses the same profile as the old linkit plugin.');
+
+    $format = $this->configFactory->get('filter.format.format_1');
+    $this->assertNotNull($format->get('filters.linkit'), 'Linkit filter is enabled.');
+    $this->assertTrue($format->get('filters.linkit.weight') < $format->get('filters.filter_html.weight'), 'Linkit filter is running before filter_html.');
+
+    $format = $this->configFactory->get('filter.format.format_2');
+    $this->assertNotNull($format->get('filters.linkit'), 'Linkit filter is enabled.');
+
+    $format = $this->configFactory->get('filter.format.format_3');
+    $this->assertNotNull($format->get('filters.linkit'), 'Linkit filter is enabled.');
+
+    $htmlRestrictions = FilterFormat::load('format_1')->getHtmlRestrictions();
+    $this->assertTrue(array_key_exists("data-entity-type", $htmlRestrictions['allowed']['a']));
+    $this->assertTrue(array_key_exists("data-entity-uuid", $htmlRestrictions['allowed']['a']));
+
+    $htmlRestrictions = FilterFormat::load('format_3')->getHtmlRestrictions();
+    $this->assertTrue(array_key_exists("data-entity-type", $htmlRestrictions['allowed']['a']));
+    $this->assertTrue(array_key_exists("data-entity-uuid", $htmlRestrictions['allowed']['a']));
+  }
+
+  /**
+   * Tests linkit_update_8501().
+   *
+   * @see linkit_update_8501()
+   */
+  public function testLinkitUpdate8501() {
+    $this->runUpdates();
+
+    $test_profile = $this->configFactory->get('linkit.linkit_profile.test_profile');
+    $this->assertEqual('canonical', $test_profile->get('matchers.fc48c807-2a9c-44eb-b86b-7e134c1aa252.settings.substitution_type'), 'Content matcher has a substitution type of canonical.');
+    $this->assertEqual('file', $test_profile->get('matchers.b8d6d672-6377-493f-b492-3cc69511cf17.settings.substitution_type'), 'File matcher has a substitution type of file.');
+
+    $htmlRestrictions = FilterFormat::load('format_1')->getHtmlRestrictions();
+    $this->assertTrue(array_key_exists("data-entity-type", $htmlRestrictions['allowed']['a']));
+    $this->assertTrue(array_key_exists("data-entity-uuid", $htmlRestrictions['allowed']['a']));
+    $this->assertTrue(array_key_exists("data-entity-substitution", $htmlRestrictions['allowed']['a']));
+  }
+
+  /**
+   * Tests linkit_update_8502().
+   *
+   * @see linkit_update_8502()
+   */
+  public function testLinkitUpdate8502() {
+    $test_profile = $this->configFactory->get('linkit.linkit_profile.test_profile');
+    $this->assertNotNull($test_profile->get('matchers.fc48c807-2a9c-44eb-b86b-7e134c1aa252.settings.result_description'), 'Profile have result_description');
+
+    $this->runUpdates();
+
+    $test_profile = $this->configFactory->get('linkit.linkit_profile.test_profile');
+    $this->assertNull($test_profile->get('matchers.fc48c807-2a9c-44eb-b86b-7e134c1aa252.settings.result_description'), 'Profile does not have result_description');
+    $this->assertNotNull($test_profile->get('matchers.fc48c807-2a9c-44eb-b86b-7e134c1aa252.settings.metadata'), 'Profile have metadata');
+  }
+
+  /**
+   * Tests linkit_update_8503().
+   *
+   * @see linkit_update_8503()
+   */
+  public function testLinkitUpdate8503() {
+    $test_profile = $this->configFactory->get('linkit.linkit_profile.test_profile_imce');
+    $this->assertNotNull($test_profile->get('third_party_settings.imce.use'), 'Profile have imce use');
+    $this->assertNotNull($test_profile->get('third_party_settings.imce.scheme'), 'Profile have imce scheme');
+
+    $this->runUpdates();
+
+    $test_profile = $this->configFactory->get('linkit.linkit_profile.test_profile_imce');
+    $this->assertNull($test_profile->get('third_party_settings.imce.use'), 'Profile does not have imce use');
+    $this->assertNull($test_profile->get('third_party_settings.imce.scheme'), 'Profile does not have imce scheme');
+  }
+
+}

+ 1 - 6
sites/all/modules/contrib/fields/linkit/src/Utility/LinkitXss.php

@@ -1,10 +1,5 @@
 <?php
 
-/**
- * @file
- * Contains \Drupal\linkit\Utility\LinkitXss.
- */
-
 namespace Drupal\linkit\Utility;
 
 use Drupal\Component\Utility\Xss;
@@ -17,7 +12,7 @@ class LinkitXss extends Xss {
   /**
    * Description filter helper.
    *
-   * @param $string
+   * @param string $string
    *   The string with raw HTML in it. It will be stripped of everything that
    *   can cause an XSS attack.
    *

+ 54 - 0
sites/all/modules/contrib/fields/linkit/tests/fixtures/update/editor.editor.format_1.yml

@@ -0,0 +1,54 @@
+uuid: 4947dfdc-fca3-41fd-97a8-b9dcdb4d510c
+langcode: en
+status: true
+dependencies:
+  config:
+    - filter.format.format_1
+  module:
+    - ckeditor
+format: format_1
+editor: ckeditor
+settings:
+  toolbar:
+    rows:
+      -
+        -
+          name: Formatting
+          items:
+            - Bold
+            - Italic
+        -
+          name: Links
+          items:
+            - DrupalLink
+            - Linkit
+            - DrupalUnlink
+        -
+          name: Lists
+          items:
+            - BulletedList
+            - NumberedList
+        -
+          name: Media
+          items:
+            - Blockquote
+            - DrupalImage
+        -
+          name: Tools
+          items:
+            - Source
+  plugins:
+    stylescombo:
+      styles: ''
+    language:
+      language_list: un
+    linkit:
+      linkit_profile: test_profile
+image_upload:
+  status: false
+  scheme: public
+  directory: inline-images
+  max_size: ''
+  max_dimensions:
+    width: null
+    height: null

+ 53 - 0
sites/all/modules/contrib/fields/linkit/tests/fixtures/update/editor.editor.format_2.yml

@@ -0,0 +1,53 @@
+uuid: fcc983a2-6cfd-44c4-a592-e6573180c2ac
+langcode: en
+status: true
+dependencies:
+  config:
+    - filter.format.format_2
+  module:
+    - ckeditor
+format: format_2
+editor: ckeditor
+settings:
+  toolbar:
+    rows:
+      -
+        -
+          name: Formatting
+          items:
+            - Bold
+            - Italic
+        -
+          name: Links
+          items:
+            - Linkit
+            - DrupalUnlink
+        -
+          name: Lists
+          items:
+            - BulletedList
+            - NumberedList
+        -
+          name: Media
+          items:
+            - Blockquote
+            - DrupalImage
+        -
+          name: Tools
+          items:
+            - Source
+  plugins:
+    stylescombo:
+      styles: ''
+    language:
+      language_list: un
+    linkit:
+      linkit_profile: test_profile
+image_upload:
+  status: false
+  scheme: public
+  directory: inline-images
+  max_size: ''
+  max_dimensions:
+    width: null
+    height: null

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