Commit 9632e2f5 authored by anon's avatar anon Committed by anon

Issue #2844466 by anon, ckaotik: Insert external link on form submit

parent f6a24536
......@@ -43,7 +43,10 @@
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);
}
}
......@@ -62,28 +65,23 @@
function selectHandler(event, ui) {
var $form = $(event.target).closest('form');
if (ui.item.path != null) {
$('input[name="attributes[href]"]', $form).val(ui.item.path);
$('input[name="attributes[data-entity-type]"]', $form).val('');
$('input[name="attributes[data-entity-uuid]"]', $form).val('');
$('input[name="attributes[data-entity-substitution]"]', $form).val('');
event.target.value = ui.item.path;
if (!ui.item.path) {
throw 'Missing path param.' + JSON.stringify(ui.item);
}
else {
$('input[name="attributes[href]"]', $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 data params.' + JSON.stringify(ui.item);
throw 'Missing path param.' + JSON.stringify(ui.item);
}
// The href needs to be set in order for the drupallink saveCallback to
// insert new anchor elements.
$('input[name="attributes[href]"]', $form).val('#');
$('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.label;
}
$('.linkit-link-information > span', $form).text(ui.item.label);
event.target.value = ui.item.path;
return false;
}
......@@ -163,6 +161,10 @@
// 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());
});
}
},
detach: function (context, settings, trigger) {
......
......@@ -84,48 +84,16 @@ function linkit_form_editor_link_dialog_alter(&$form, FormStateInterface $form_s
}
$form['linkit'] = [
'#title' => t('Link'),
'#title' => t('URL'),
'#type' => 'linkit',
'#description' => t('Start typing to find content or paste a URL.'),
'#description' => t('Start typing to find content.'),
'#maxlength' => 2048,
'#autocomplete_route_name' => 'linkit.autocomplete',
'#autocomplete_route_parameters' => [
'linkit_profile_id' => $linkit_profile_id,
],
"#weight" => -10,
];
// Determine what the default value of the linkit autocomplete field.
try {
if (!empty($input['data-entity-type']) && !empty($input['data-entity-uuid'])) {
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = \Drupal::service('entity.repository')
->loadEntityByUuid($input['data-entity-type'], $input['data-entity-uuid']);
$entity = \Drupal::service('entity.repository')
->getTranslationFromContext($entity);
$access = !$entity->access('view', NULL, TRUE)->isForbidden();
$autocomplete_default_value = !empty($access) && $access ? $entity->label() : '';
}
}
catch (Exception $exception) {
// Do nothing, this is handled in the finally block.
}
finally {
// If the href is not set, the data- attributes might not exists, or the
// href is external. In that case, use the given href.
if (!isset($autocomplete_default_value)) {
$autocomplete_default_value = isset($input['href']) ? $input['href'] : '';
}
}
$form['linkit']['#default_value'] = $autocomplete_default_value;
$form['link-information'] = [
'#type' => 'inline_template',
'#template' => '<div class="form-item linkit-link-information"><strong>{% trans %}Selected link:{% endtrans %}</strong> <span>{{ link_target }}</span></div>',
'#context' => [
'link_target' => !empty($entity) && !empty($access) && $access ? $entity->label() : $autocomplete_default_value,
],
"#weight" => -10,
'#default_value' => isset($input['href']) ? $input['href'] : '',
];
$fields = [
......@@ -139,6 +107,7 @@ function linkit_form_editor_link_dialog_alter(&$form, FormStateInterface $form_s
foreach ($fields as $field_name) {
$form['attributes'][$field_name] = [
'#title' => $field_name,
'#type' => 'hidden',
'#default_value' => isset($input[$field_name]) ? $input[$field_name] : '',
];
......@@ -178,19 +147,32 @@ function linkit_form_editor_link_dialog_alter(&$form, FormStateInterface $form_s
function linkit_form_editor_link_dialog_submit(array &$form, FormStateInterface $form_state) {
$link_element = $form_state->get('link_element');
$data_entity_type = $form_state->getValue(['attributes', 'data-entity-type']);
$data_entity_uuid = $form_state->getValue(['attributes', 'data-entity-uuid']);
$href = $form_state->getValue(['attributes', 'href']);
$linkit_field = $form_state->getValue(['linkit']);
if (empty($data_entity_type) || empty($data_entity_uuid)) {
if (!empty($link_element)) {
$form_state->setValue(['attributes', 'data-entity-type'], '');
$form_state->setValue(['attributes', 'data-entity-uuid'], '');
$form_state->setValue(['attributes', 'data-entity-substitution'], '');
}
else {
$form_state->unsetValue(['attributes', 'data-entity-type']);
$form_state->unsetValue(['attributes', 'data-entity-uuid']);
$form_state->unsetValue(['attributes', 'data-entity-substitution']);
if ($href !== $linkit_field) {
$form_state->setValue(['attributes', 'href'], $linkit_field);
$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]);
}
}
}
}
......@@ -12,12 +12,14 @@ use Drupal\Core\Entity\EntityTypeManagerInterface;
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;
/**
......@@ -287,7 +289,9 @@ class EntityMatcher extends ConfigurableMatcherBase {
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 (empty($result)) {
return $suggestions;
......@@ -299,7 +303,7 @@ class EntityMatcher extends ConfigurableMatcherBase {
// Check the access against the defined entity access handler.
/** @var \Drupal\Core\Access\AccessResultInterface $access */
$access = $entity->access('view', $this->currentUser, TRUE);
if ($access->isForbidden()) {
if (!$access->isAllowed()) {
continue;
}
......@@ -311,7 +315,8 @@ class EntityMatcher extends ConfigurableMatcherBase {
->setDescription($this->buildDescription($entity))
->setEntityUuid($entity->uuid())
->setEntityTypeId($entity->getEntityTypeId())
->setSubstitutionId($this->configuration['substitution_type']);
->setSubstitutionId($this->configuration['substitution_type'])
->setPath($this->buildPath($entity));
$suggestions->addSuggestion($suggestion);
}
......@@ -415,4 +420,43 @@ class EntityMatcher extends ConfigurableMatcherBase {
return $group;
}
/**
* Builds the path used in the match array.
*
* @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;
}
}
......@@ -213,4 +213,12 @@ class FileMatcher extends EntityMatcher {
return LinkitXss::descriptionFilter($description);
}
/**
* {@inheritdoc}
*/
protected function buildPath(EntityInterface $entity) {
/** @var \Drupal\file\FileInterface $entity */
return file_url_transform_relative(file_create_url($entity->getFileUri()));
}
}
......@@ -54,6 +54,11 @@ class LinkitAutocompleteTest extends LinkitKernelTestBase {
protected function setUp() {
parent::setUp();
// Create user 1 who has special permissions.
$this->createUser();
\Drupal::currentUser()->setAccount($this->createUser([], ['view test entity']));
\Drupal::service('router.builder')->rebuild();
$this->installEntitySchema('user');
$this->installEntitySchema('entity_test');
......
......@@ -148,9 +148,11 @@ class LinkitEditorLinkDialogTest extends LinkitKernelTestBase {
*/
public function testEditWithDataAttributes() {
$entity_label = $this->randomString();
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = EntityTest::create(['name' => $entity_label]);
$entity->save();
/** @var \Drupal\Core\Entity\EntityInterface $entity_no_access */
$entity_no_access = EntityTest::create(['name' => 'forbid_access']);
$entity_no_access->save();
......@@ -158,7 +160,7 @@ class LinkitEditorLinkDialogTest extends LinkitKernelTestBase {
$input = [
'editor_object' => [
'href' => '#',
'href' => $entity->toUrl()->toString(),
'data-entity-type' => $entity->getEntityTypeId(),
'data-entity-uuid' => $entity->uuid(),
'data-entity-substitution' => SubstitutionManagerInterface::DEFAULT_SUBSTITUTION,
......@@ -188,46 +190,10 @@ class LinkitEditorLinkDialogTest extends LinkitKernelTestBase {
$form_builder->processForm($form_id, $form, $form_state);
$this->assertEquals('linkit.autocomplete', $form['linkit']['#autocomplete_route_name'], 'Linkit is enabled on the linkit field.');
$this->assertEquals($entity->label(), $form['linkit']['#default_value'], 'The linkit field has the label as default value.');
$this->assertEquals($entity->toUrl()->toString(), $form['linkit']['#default_value'], 'The linkit field has the url as default value.');
$this->assertEquals($entity->getEntityTypeId(), $form_state->getValue(['attributes', 'data-entity-type']), 'Attribute "data-entity-type" exists and has the correct value.');
$this->assertEquals($entity->uuid(), $form_state->getValue(['attributes', 'data-entity-uuid']), 'Attribute "data-entity-uuid" exists and has the correct value.');
$this->assertEquals(SubstitutionManagerInterface::DEFAULT_SUBSTITUTION, $form_state->getValue(['attributes', 'data-entity-substitution']), 'Attribute "data-entity-substitution" exists and has the correct value.');
// Make sure the dialog don't display entity labels for inaccessible
// entities.
$input = [
'editor_object' => [
'href' => '#',
'data-entity-type' => $entity_no_access->getEntityTypeId(),
'data-entity-uuid' => $entity_no_access->uuid(),
'data-entity-substitution' => SubstitutionManagerInterface::DEFAULT_SUBSTITUTION,
],
'dialogOptions' => [
'title' => 'Edit Link',
'dialogClass' => 'editor-link-dialog',
'autoResize' => 'true',
],
'_drupal_ajax' => '1',
'ajax_page_state' => [
'theme' => 'bartik',
'theme_token' => 'some-token',
'libraries' => '',
],
];
$form_state = (new FormState())
->setRequestMethod('POST')
->setUserInput($input)
->addBuildInfo('args', [$this->editor]);
/** @var \Drupal\Core\Form\FormBuilderInterface $form_builder */
$form_builder = $this->container->get('form_builder');
$form_id = $form_builder->getFormId($form_object, $form_state);
$form = $form_builder->retrieveForm($form_id, $form_state);
$form_builder->prepareForm($form_id, $form, $form_state);
$form_builder->processForm($form_id, $form, $form_state);
$this->assertEquals('linkit.autocomplete', $form['linkit']['#autocomplete_route_name'], 'Linkit is enabled on the linkit field.');
$this->assertEmpty($form['linkit']['#default_value']);
}
/**
......
......@@ -32,6 +32,11 @@ class ContactFormMatcherTest extends LinkitKernelTestBase {
protected function setUp() {
parent::setUp();
// Create user 1 who has special permissions.
$this->createUser();
\Drupal::currentUser()->setAccount($this->createUser([], ['access site-wide contact form', 'view test entity translations']));
$this->manager = $this->container->get('plugin.manager.linkit.matcher');
ContactForm::create([
......
......@@ -36,6 +36,11 @@ class TermMatcherTest extends LinkitKernelTestBase {
protected function setUp() {
parent::setUp();
// Create user 1 who has special permissions.
$this->createUser();
\Drupal::currentUser()->setAccount($this->createUser([], ['access content']));
$this->installEntitySchema('taxonomy_term');
$this->manager = $this->container->get('plugin.manager.linkit.matcher');
......
......@@ -25,6 +25,11 @@ class UserMatcherTest extends LinkitKernelTestBase {
protected function setUp() {
parent::setUp();
// Create user 1 who has special permissions.
$this->createUser();
\Drupal::currentUser()->setAccount($this->createUser([], ['access user profiles']));
$this->manager = $this->container->get('plugin.manager.linkit.matcher');
$custom_role = Role::create([
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment