Skip to content
Snippets Groups Projects
Unverified Commit e4681668 authored by briancanini's avatar briancanini Committed by GitHub
Browse files

Merge pull request #612 from ASCWebServices/lee5151

Drupal 10 Contrib Module Update
parents bcc1a39e ef2f7a2d
No related branches found
No related tags found
No related merge requests found
Showing
with 778 additions and 185 deletions
......@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "b811d44ed2412e7c33e294cc83b69afe",
"content-hash": "b39b06475672c73571f48c4dd7300d76",
"packages": [
{
"name": "alchemy/zippy",
......@@ -2398,10 +2398,6 @@
"name": "RobLoach",
"homepage": "https://www.drupal.org/user/61114"
},
{
"name": "soxofaan",
"homepage": "https://www.drupal.org/user/41478"
},
{
"name": "thomas.frobieter",
"homepage": "https://www.drupal.org/user/409335"
......@@ -3473,26 +3469,30 @@
},
{
"name": "drupal/editor_advanced_link",
"version": "1.9.0",
"version": "2.2.4",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/editor_advanced_link.git",
"reference": "8.x-1.9"
"reference": "2.2.4"
},
"dist": {
"type": "zip",
"url": "https://ftp.drupal.org/files/projects/editor_advanced_link-8.x-1.9.zip",
"reference": "8.x-1.9",
"shasum": "ee40ec8c8c7b14c69de3de6a5275959dc32455c4"
"url": "https://ftp.drupal.org/files/projects/editor_advanced_link-2.2.4.zip",
"reference": "2.2.4",
"shasum": "cd0db397827f2e21ec8a68211e8a153463a6c89b"
},
"require": {
"drupal/core": "^8 || ^9"
"drupal/core": "^9.2 || ^10"
},
"require-dev": {
"drupal/ckeditor": "*",
"phpro/grumphp": "^2.0"
},
"type": "drupal-module",
"extra": {
"drupal": {
"version": "8.x-1.9",
"datestamp": "1624032562",
"version": "2.2.4",
"datestamp": "1688040059",
"security-coverage": {
"status": "covered",
"message": "Covered by Drupal's security advisory policy"
......@@ -3509,7 +3509,7 @@
"homepage": "https://www.drupal.org/user/931394"
}
],
"description": "Add title, target etc. attributes to Text Editor's link dialog if the text format allows them.",
"description": "Editor Advanced link",
"homepage": "https://www.drupal.org/project/editor_advanced_link",
"support": {
"source": "https://git.drupalcode.org/project/editor_advanced_link"
......@@ -4177,21 +4177,23 @@
},
{
"name": "drupal/focal_point",
"version": "1.5.0",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/focal_point.git",
"reference": "8.x-1.5"
"reference": "2.0.1"
},
"dist": {
"type": "zip",
"url": "https://ftp.drupal.org/files/projects/focal_point-8.x-1.5.zip",
"reference": "8.x-1.5",
"shasum": "41198e9220788c3b7d3146b10e5dfd6c73cd4784"
"url": "https://ftp.drupal.org/files/projects/focal_point-2.0.1.zip",
"reference": "2.0.1",
"shasum": "2af4bb7f305735adbc216de742f0fa02bba6457b"
},
"require": {
"drupal/core": "^8.8 || ^9",
"drupal/crop": "^1.0 || ^2.0"
"drupal/core": "^9.3 || ^10",
"drupal/crop": "^2.3",
"drupal/jquery_ui": "^1.6",
"drupal/jquery_ui_draggable": "^2.0"
},
"require-dev": {
"drupal/crop": "*"
......@@ -4199,8 +4201,8 @@
"type": "drupal-module",
"extra": {
"drupal": {
"version": "8.x-1.5",
"datestamp": "1598663903",
"version": "2.0.1",
"datestamp": "1689093654",
"security-coverage": {
"status": "covered",
"message": "Covered by Drupal's security advisory policy"
......@@ -4303,26 +4305,26 @@
},
{
"name": "drupal/google_tag",
"version": "1.5.0",
"version": "1.6.0",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/google_tag.git",
"reference": "8.x-1.5"
"reference": "8.x-1.6"
},
"dist": {
"type": "zip",
"url": "https://ftp.drupal.org/files/projects/google_tag-8.x-1.5.zip",
"reference": "8.x-1.5",
"shasum": "b2929a517cc86bb3e54dded127556f18236a8628"
"url": "https://ftp.drupal.org/files/projects/google_tag-8.x-1.6.zip",
"reference": "8.x-1.6",
"shasum": "d084315e54c2e561b8b64eef86081c2634d054cd"
},
"require": {
"drupal/core": "^8.8 || ^9"
"drupal/core": "^8.8 || ^9 || ^10"
},
"type": "drupal-module",
"extra": {
"drupal": {
"version": "8.x-1.5",
"datestamp": "1648569365",
"version": "8.x-1.6",
"datestamp": "1671145853",
"security-coverage": {
"status": "covered",
"message": "Covered by Drupal's security advisory policy"
......@@ -4753,6 +4755,59 @@
"source": "https://git.drupalcode.org/project/jquery_ui_datepicker"
}
},
{
"name": "drupal/jquery_ui_draggable",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/jquery_ui_draggable.git",
"reference": "2.0.0"
},
"dist": {
"type": "zip",
"url": "https://ftp.drupal.org/files/projects/jquery_ui_draggable-2.0.0.zip",
"reference": "2.0.0",
"shasum": "13a8f4bf037449cd176ddb967fc9cba9a466a705"
},
"require": {
"drupal/core": "^9.2 || ^10",
"drupal/jquery_ui": "^1.6"
},
"type": "drupal-module",
"extra": {
"drupal": {
"version": "2.0.0",
"datestamp": "1670871516",
"security-coverage": {
"status": "covered",
"message": "Covered by Drupal's security advisory policy"
}
}
},
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
"GPL-2.0-or-later"
],
"authors": [
{
"name": "bnjmnm",
"homepage": "https://www.drupal.org/user/2369194"
},
{
"name": "lauriii",
"homepage": "https://www.drupal.org/user/1078742"
},
{
"name": "zrpnr",
"homepage": "https://www.drupal.org/user/1448368"
}
],
"description": "Provides jQuery UI Draggable library.",
"homepage": "https://www.drupal.org/project/jquery_ui_draggable",
"support": {
"source": "https://git.drupalcode.org/project/jquery_ui_draggable"
}
},
{
"name": "drupal/jquery_ui_menu",
"version": "2.0.0",
......@@ -7619,26 +7674,26 @@
},
{
"name": "drupal/views_autocomplete_filters",
"version": "1.3.0",
"version": "1.4.0",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/views_autocomplete_filters.git",
"reference": "8.x-1.3"
"reference": "8.x-1.4"
},
"dist": {
"type": "zip",
"url": "https://ftp.drupal.org/files/projects/views_autocomplete_filters-8.x-1.3.zip",
"reference": "8.x-1.3",
"shasum": "55762182e55c70f117d5edb8692049e0881ec4ce"
"url": "https://ftp.drupal.org/files/projects/views_autocomplete_filters-8.x-1.4.zip",
"reference": "8.x-1.4",
"shasum": "f65d5c6d25df802968c514836ea8edd22ba063a1"
},
"require": {
"drupal/core": "^8 || ^9"
"drupal/core": "^8 || ^9 || ^10"
},
"type": "drupal-module",
"extra": {
"drupal": {
"version": "8.x-1.3",
"datestamp": "1587146330",
"version": "8.x-1.4",
"datestamp": "1677771862",
"security-coverage": {
"status": "covered",
"message": "Covered by Drupal's security advisory policy"
......
......@@ -15,11 +15,11 @@
'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php',
'667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
'23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
'23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php',
'3e41e0554275033aae3e9e7e056c2d14' => $vendorDir . '/longwave/laminas-diactoros/src/functions/create_uploaded_file.php',
'f4ee20bfdee1006b0970e8d951bea11e' => $vendorDir . '/longwave/laminas-diactoros/src/functions/marshal_headers_from_sapi.php',
'039b4ca04402a921dc2af19c2e8c1f6e' => $vendorDir . '/longwave/laminas-diactoros/src/functions/marshal_method_from_sapi.php',
......
......@@ -16,11 +16,11 @@ class ComposerStaticInit5c689ffcd54b9e495ed983fdce09b530
'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php',
'0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php',
'667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php',
'23c18046f52bef3eea034657bafda50f' => __DIR__ . '/..' . '/symfony/polyfill-php81/bootstrap.php',
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php',
'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php',
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
'23c18046f52bef3eea034657bafda50f' => __DIR__ . '/..' . '/symfony/polyfill-php81/bootstrap.php',
'3e41e0554275033aae3e9e7e056c2d14' => __DIR__ . '/..' . '/longwave/laminas-diactoros/src/functions/create_uploaded_file.php',
'f4ee20bfdee1006b0970e8d951bea11e' => __DIR__ . '/..' . '/longwave/laminas-diactoros/src/functions/marshal_headers_from_sapi.php',
'039b4ca04402a921dc2af19c2e8c1f6e' => __DIR__ . '/..' . '/longwave/laminas-diactoros/src/functions/marshal_method_from_sapi.php',
......
......@@ -3586,27 +3586,31 @@
},
{
"name": "drupal/editor_advanced_link",
"version": "1.9.0",
"version_normalized": "1.9.0.0",
"version": "2.2.4",
"version_normalized": "2.2.4.0",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/editor_advanced_link.git",
"reference": "8.x-1.9"
"reference": "2.2.4"
},
"dist": {
"type": "zip",
"url": "https://ftp.drupal.org/files/projects/editor_advanced_link-8.x-1.9.zip",
"reference": "8.x-1.9",
"shasum": "ee40ec8c8c7b14c69de3de6a5275959dc32455c4"
"url": "https://ftp.drupal.org/files/projects/editor_advanced_link-2.2.4.zip",
"reference": "2.2.4",
"shasum": "cd0db397827f2e21ec8a68211e8a153463a6c89b"
},
"require": {
"drupal/core": "^8 || ^9"
"drupal/core": "^9.2 || ^10"
},
"require-dev": {
"drupal/ckeditor": "*",
"phpro/grumphp": "^2.0"
},
"type": "drupal-module",
"extra": {
"drupal": {
"version": "8.x-1.9",
"datestamp": "1624032562",
"version": "2.2.4",
"datestamp": "1688040059",
"security-coverage": {
"status": "covered",
"message": "Covered by Drupal's security advisory policy"
......@@ -3624,7 +3628,7 @@
"homepage": "https://www.drupal.org/user/931394"
}
],
"description": "Add title, target etc. attributes to Text Editor's link dialog if the text format allows them.",
"description": "Editor Advanced link",
"homepage": "https://www.drupal.org/project/editor_advanced_link",
"support": {
"source": "https://git.drupalcode.org/project/editor_advanced_link"
......@@ -4321,22 +4325,24 @@
},
{
"name": "drupal/focal_point",
"version": "1.5.0",
"version_normalized": "1.5.0.0",
"version": "2.0.1",
"version_normalized": "2.0.1.0",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/focal_point.git",
"reference": "8.x-1.5"
"reference": "2.0.1"
},
"dist": {
"type": "zip",
"url": "https://ftp.drupal.org/files/projects/focal_point-8.x-1.5.zip",
"reference": "8.x-1.5",
"shasum": "41198e9220788c3b7d3146b10e5dfd6c73cd4784"
"url": "https://ftp.drupal.org/files/projects/focal_point-2.0.1.zip",
"reference": "2.0.1",
"shasum": "2af4bb7f305735adbc216de742f0fa02bba6457b"
},
"require": {
"drupal/core": "^8.8 || ^9",
"drupal/crop": "^1.0 || ^2.0"
"drupal/core": "^9.3 || ^10",
"drupal/crop": "^2.3",
"drupal/jquery_ui": "^1.6",
"drupal/jquery_ui_draggable": "^2.0"
},
"require-dev": {
"drupal/crop": "*"
......@@ -4344,8 +4350,8 @@
"type": "drupal-module",
"extra": {
"drupal": {
"version": "8.x-1.5",
"datestamp": "1598663903",
"version": "2.0.1",
"datestamp": "1689093654",
"security-coverage": {
"status": "covered",
"message": "Covered by Drupal's security advisory policy"
......@@ -4362,6 +4368,10 @@
"name": "Alexander Ross (bleen)",
"homepage": "https://www.drupal.org/u/bleen",
"role": "Maintainer"
},
{
"name": "Rajeshreeputra",
"homepage": "https://www.drupal.org/user/3418561"
}
],
"description": "Focal Point allows content creators to mark the most important part of an image for easier cropping.",
......@@ -4449,27 +4459,27 @@
},
{
"name": "drupal/google_tag",
"version": "1.5.0",
"version_normalized": "1.5.0.0",
"version": "1.6.0",
"version_normalized": "1.6.0.0",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/google_tag.git",
"reference": "8.x-1.5"
"reference": "8.x-1.6"
},
"dist": {
"type": "zip",
"url": "https://ftp.drupal.org/files/projects/google_tag-8.x-1.5.zip",
"reference": "8.x-1.5",
"shasum": "b2929a517cc86bb3e54dded127556f18236a8628"
"url": "https://ftp.drupal.org/files/projects/google_tag-8.x-1.6.zip",
"reference": "8.x-1.6",
"shasum": "d084315e54c2e561b8b64eef86081c2634d054cd"
},
"require": {
"drupal/core": "^8.8 || ^9"
"drupal/core": "^8.8 || ^9 || ^10"
},
"type": "drupal-module",
"extra": {
"drupal": {
"version": "8.x-1.5",
"datestamp": "1648569365",
"version": "8.x-1.6",
"datestamp": "1671145853",
"security-coverage": {
"status": "covered",
"message": "Covered by Drupal's security advisory policy"
......@@ -4482,6 +4492,22 @@
"GPL-2.0-or-later"
],
"authors": [
{
"name": "acquia",
"homepage": "https://www.drupal.org/user/1231722"
},
{
"name": "japerry",
"homepage": "https://www.drupal.org/user/45640"
},
{
"name": "kaynen",
"homepage": "https://www.drupal.org/user/733308"
},
{
"name": "mglaman",
"homepage": "https://www.drupal.org/user/2416470"
},
{
"name": "solotandem",
"homepage": "https://www.drupal.org/user/240748"
......@@ -4904,6 +4930,62 @@
},
"install-path": "../../web/modules/jquery_ui_datepicker"
},
{
"name": "drupal/jquery_ui_draggable",
"version": "2.0.0",
"version_normalized": "2.0.0.0",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/jquery_ui_draggable.git",
"reference": "2.0.0"
},
"dist": {
"type": "zip",
"url": "https://ftp.drupal.org/files/projects/jquery_ui_draggable-2.0.0.zip",
"reference": "2.0.0",
"shasum": "13a8f4bf037449cd176ddb967fc9cba9a466a705"
},
"require": {
"drupal/core": "^9.2 || ^10",
"drupal/jquery_ui": "^1.6"
},
"type": "drupal-module",
"extra": {
"drupal": {
"version": "2.0.0",
"datestamp": "1670871516",
"security-coverage": {
"status": "covered",
"message": "Covered by Drupal's security advisory policy"
}
}
},
"installation-source": "dist",
"notification-url": "https://packages.drupal.org/8/downloads",
"license": [
"GPL-2.0-or-later"
],
"authors": [
{
"name": "bnjmnm",
"homepage": "https://www.drupal.org/user/2369194"
},
{
"name": "lauriii",
"homepage": "https://www.drupal.org/user/1078742"
},
{
"name": "zrpnr",
"homepage": "https://www.drupal.org/user/1448368"
}
],
"description": "Provides jQuery UI Draggable library.",
"homepage": "https://www.drupal.org/project/jquery_ui_draggable",
"support": {
"source": "https://git.drupalcode.org/project/jquery_ui_draggable"
},
"install-path": "../../web/modules/jquery_ui_draggable"
},
{
"name": "drupal/jquery_ui_menu",
"version": "2.0.0",
......@@ -7905,27 +7987,27 @@
},
{
"name": "drupal/views_autocomplete_filters",
"version": "1.3.0",
"version_normalized": "1.3.0.0",
"version": "1.4.0",
"version_normalized": "1.4.0.0",
"source": {
"type": "git",
"url": "https://git.drupalcode.org/project/views_autocomplete_filters.git",
"reference": "8.x-1.3"
"reference": "8.x-1.4"
},
"dist": {
"type": "zip",
"url": "https://ftp.drupal.org/files/projects/views_autocomplete_filters-8.x-1.3.zip",
"reference": "8.x-1.3",
"shasum": "55762182e55c70f117d5edb8692049e0881ec4ce"
"url": "https://ftp.drupal.org/files/projects/views_autocomplete_filters-8.x-1.4.zip",
"reference": "8.x-1.4",
"shasum": "f65d5c6d25df802968c514836ea8edd22ba063a1"
},
"require": {
"drupal/core": "^8 || ^9"
"drupal/core": "^8 || ^9 || ^10"
},
"type": "drupal-module",
"extra": {
"drupal": {
"version": "8.x-1.3",
"datestamp": "1587146330",
"version": "8.x-1.4",
"datestamp": "1677771862",
"security-coverage": {
"status": "covered",
"message": "Covered by Drupal's security advisory policy"
......@@ -7938,14 +8020,18 @@
"GPL-2.0-or-later"
],
"authors": [
{
"name": "RobLoach",
"homepage": "https://www.drupal.org/user/61114"
},
{
"name": "colan",
"homepage": "https://www.drupal.org/user/58704"
},
{
"name": "heddn",
"homepage": "https://www.drupal.org/user/1463982"
},
{
"name": "RobLoach",
"homepage": "https://www.drupal.org/user/61114"
},
{
"name": "vasike",
"homepage": "https://www.drupal.org/user/156237"
......
......@@ -3,7 +3,7 @@
'name' => 'osu-asc-webservices/d8-upstream',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '44d8d50fd541fad1e6de4cfd98b65e451d9cde2e',
'reference' => '7040eff8f4c1d42cdbbaddb9a22f24952ff2d9d1',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
......@@ -662,9 +662,9 @@
'dev_requirement' => false,
),
'drupal/editor_advanced_link' => array(
'pretty_version' => '1.9.0',
'version' => '1.9.0.0',
'reference' => '8.x-1.9',
'pretty_version' => '2.2.4',
'version' => '2.2.4.0',
'reference' => '2.2.4',
'type' => 'drupal-module',
'install_path' => __DIR__ . '/../../web/modules/editor_advanced_link',
'aliases' => array(),
......@@ -761,9 +761,9 @@
'dev_requirement' => false,
),
'drupal/focal_point' => array(
'pretty_version' => '1.5.0',
'version' => '1.5.0.0',
'reference' => '8.x-1.5',
'pretty_version' => '2.0.1',
'version' => '2.0.1.0',
'reference' => '2.0.1',
'type' => 'drupal-module',
'install_path' => __DIR__ . '/../../web/modules/focal_point',
'aliases' => array(),
......@@ -779,9 +779,9 @@
'dev_requirement' => false,
),
'drupal/google_tag' => array(
'pretty_version' => '1.5.0',
'version' => '1.5.0.0',
'reference' => '8.x-1.5',
'pretty_version' => '1.6.0',
'version' => '1.6.0.0',
'reference' => '8.x-1.6',
'type' => 'drupal-module',
'install_path' => __DIR__ . '/../../web/modules/google_tag',
'aliases' => array(),
......@@ -832,6 +832,15 @@
'aliases' => array(),
'dev_requirement' => false,
),
'drupal/jquery_ui_draggable' => array(
'pretty_version' => '2.0.0',
'version' => '2.0.0.0',
'reference' => '2.0.0',
'type' => 'drupal-module',
'install_path' => __DIR__ . '/../../web/modules/jquery_ui_draggable',
'aliases' => array(),
'dev_requirement' => false,
),
'drupal/jquery_ui_menu' => array(
'pretty_version' => '2.0.0',
'version' => '2.0.0.0',
......@@ -1256,9 +1265,9 @@
'dev_requirement' => false,
),
'drupal/views_autocomplete_filters' => array(
'pretty_version' => '1.3.0',
'version' => '1.3.0.0',
'reference' => '8.x-1.3',
'pretty_version' => '1.4.0',
'version' => '1.4.0.0',
'reference' => '8.x-1.4',
'type' => 'drupal-module',
'install_path' => __DIR__ . '/../../web/modules/views_autocomplete_filters',
'aliases' => array(),
......@@ -1558,7 +1567,7 @@
'osu-asc-webservices/d8-upstream' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '44d8d50fd541fad1e6de4cfd98b65e451d9cde2e',
'reference' => '7040eff8f4c1d42cdbbaddb9a22f24952ff2d9d1',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
......
node_modules
vendor
composer.lock
# Editor Advanced link
## Table of contents
- Introduction
- Requirements
- Installation
- Configuration
- Recommended modules
- Maintainers
## Introduction
Enhances the link Dialog in CKEditor. Allows to define the following
attributes:
- `title`
- `class`
- `id`
- `target`
- `rel`
For a full description of the module, visit the project page:\
<https://www.drupal.org/project/editor_advanced_link>
To submit bug reports and feature suggestions, or track changes:\
<https://www.drupal.org/project/issues/editor_advanced_link>
## Requirements
This module requires no modules outside of Drupal Core.
## Installation
Install the module as you would normally install a contributed Drupal
module. Visit [the documentation](https://www.drupal.org/docs/extending-drupal/installing-modules)
for further information.
## Configuration
- Install and enable the module.
- Go to the "Text formats and editor" admin page
(admin/config/content/formats).
- If you are using CKEditor 5, click the "Advanced links" tab. There you will
see a list of attributes provided by this module that you can enable. For
example, "ARIA label", "ID", and "Open in new window."
- If you are using CKEditor 4, configure your text format.
- If the "Limit allowed HTML tags and correct faulty HTML" filter is disabled
you don't have anything to do with this text format
- else, add the `title`, `class`, `id`, `target` and/or the `rel` attributes
to the "allowed HTML tags" field (only those whitelisted will show up in
the dialog)
## Recommended modules
- [Editor File upload](https://www.drupal.org/project/editor_file):\
Allows to create link to uploaded files in the text editor easily.
- [Linkit](https://www.drupal.org/project/linkit):\
Provides an easy interface for internal and external linking with WYSIWYG
editors by using an autocomplete field.
- [CKEditor Entity Link](https://www.drupal.org/project/ckeditor_entity_link):\
It is an alternative to Linkit that also provides an easy interface for
internal linking within the editor.
## Maintainers
Current maintainers:
- [Edouard Cunibil (DuaelFr)](https://www.drupal.org/u/duaelfr)
This project has been sponsored by:
- [Happyculture](https://happyculture.coop) (paid contribution time)
CONTENTS OF THIS FILE
---------------------
* Introduction
* Requirements
* Recommended modules
* Installation
* Configuration
* Maintainers
INTRODUCTION
------------
Enhances the link Dialog in CKEditor.
Allows to define the following attributes:
- title
- class
- id
- target
- rel
* For a full description of the module, visit the project page:
https://www.drupal.org/project/editor_advanced_link
* To submit bug reports and feature suggestions, or track changes:
https://www.drupal.org/project/issues/editor_advanced_link
REQUIREMENTS
------------
This module requires no modules outside of Drupal core.
RECOMMENDED MODULES
-------------------
* Editor File upload (https://www.drupal.org/project/editor_file):
Allows to create link to uploaded files in the text editor easily.
* Linkit (https://www.drupal.org/project/linkit):
Provides an easy interface for internal and external linking with WYSIWYG
editors by using an autocomplete field.
* CKEditor Entity Link (https://www.drupal.org/project/ckeditor_entity_link):
It is an alternative to Linkit that also provides an easy interface for
internal linking within the editor.
INSTALLATION
------------
Install the module as you would normally install a contributed Drupal module.
Visit https://www.drupal.org/node/1897420 for further information.
CONFIGURATION
-------------
Install as usual then:
- go to the "Text formats and editor" admin page (admin/config/content/formats)
- configure your text format
- if the "Limit allowed HTML tags and correct faulty HTML" filter is disabled
you dont have anything to do with this text format
- else, add the "title", "class", "id", "target" and/or the "rel" attributes to
the "allowed HTML tags" field (only those whitelisted will show up in the dialog)
MAINTAINERS
-----------
Current maintainers:
* Edouard Cunibil (DuaelFr) - https://www.drupal.org/u/duaelfr
This project has been sponsored by:
* Happyculture (paid contribution time) - https://happyculture.coop
{
"name": "drupal/editor_advanced_link",
"description": "Editor Advanced link",
"type": "drupal-module",
"require-dev": {
"phpro/grumphp": "^2.0"
},
"config": {
"allow-plugins": {
"phpro/grumphp": true
}
}
}
# Plugin \Drupal\editor_advanced_link\Plugin\CKEditor5Plugin\AdvancedLink
ckeditor5.plugin.editor_advanced_link_link:
type: mapping
label: 'Advanced Link'
mapping:
enabled_attributes:
type: sequence
orderby: value
label: 'Enabled attributes'
sequence:
type: string
label: 'Enabled attribute'
constraints:
Choice:
callback: \Drupal\editor_advanced_link\Plugin\CKEditor5Plugin\AdvancedLink::validChoices
editor_advanced_link_link:
ckeditor5:
plugins:
- editorAdvancedLink.EditorAdvancedLink
config:
editorAdvancedLink:
# These are all options; this will be filtered based on configuration.
# @see \Drupal\editor_advanced_link\Plugin\CKEditor5Plugin\AdvancedLink::getDynamicPluginConfig
options:
- aria-label
- title
- class
- id
- target
- rel
drupal:
label: Advanced links
class: Drupal\editor_advanced_link\Plugin\CKEditor5Plugin\AdvancedLink
library: editor_advanced_link/ckeditor5
elements:
- <a aria-label title class id target="_blank" rel>
conditions:
plugins:
- ckeditor5_link
name: 'Advanced Link'
name: 'Editor Advanced Link'
description: 'Add title, target etc. attributes to Text Editor''s link dialog if the text format allows them.'
type: module
core: 8.x
core_version_requirement: ^8 || ^9
core_version_requirement: ^9.2 || ^10
dependencies:
- drupal:editor
test_dependencies:
- drupal:ckeditor
# Information added by Drupal.org packaging script on 2021-06-18
version: '8.x-1.9'
# Information added by Drupal.org packaging script on 2023-06-29
version: '2.2.4'
project: 'editor_advanced_link'
datestamp: 1624032564
datestamp: 1688040061
......@@ -4,5 +4,15 @@ editor_advanced_link:
js/editor_advanced_link.js: {}
dependencies:
- core/drupal
- core/drupal.announce
- core/jquery
- core/jquery.once
- core/once
ckeditor5:
version: VERSION
js:
js/build/editorAdvancedLink.js: { preprocess: false, minified: true }
dependencies:
- core/drupal
- ckeditor5/ckeditor5
- ckeditor5/ckeditor5.link
grumphp:
tasks:
git_blacklist:
keywords:
- "eval("
triggered_by:
- js
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CKEditor5=t():(e.CKEditor5=e.CKEditor5||{},e.CKEditor5.editorAdvancedLink=t())}(self,(()=>(()=>{var e={"./node_modules/css-loader/dist/cjs.js!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[0].use[2]!./js/ckeditor5_plugins/editorAdvancedLink/src/details/details.css":(e,t,r)=>{"use strict";r.d(t,{Z:()=>a});var i=r("./node_modules/css-loader/dist/runtime/noSourceMaps.js"),s=r.n(i),n=r("./node_modules/css-loader/dist/runtime/api.js"),o=r.n(n)()(s());o.push([e.id,".ck.ck-form__details>summary{cursor:pointer}.ck.ck-form__details>summary:focus-visible{border:var(--ck-focus-ring);box-shadow:var(--ck-focus-outer-shadow),0 0}",""]);const a=o},"./node_modules/css-loader/dist/runtime/api.js":e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var r="",i=void 0!==t[5];return t[4]&&(r+="@supports (".concat(t[4],") {")),t[2]&&(r+="@media ".concat(t[2]," {")),i&&(r+="@layer".concat(t[5].length>0?" ".concat(t[5]):""," {")),r+=e(t),i&&(r+="}"),t[2]&&(r+="}"),t[4]&&(r+="}"),r})).join("")},t.i=function(e,r,i,s,n){"string"==typeof e&&(e=[[null,e,void 0]]);var o={};if(i)for(var a=0;a<this.length;a++){var l=this[a][0];null!=l&&(o[l]=!0)}for(var c=0;c<e.length;c++){var d=[].concat(e[c]);i&&o[d[0]]||(void 0!==n&&(void 0===d[5]||(d[1]="@layer".concat(d[5].length>0?" ".concat(d[5]):""," {").concat(d[1],"}")),d[5]=n),r&&(d[2]?(d[1]="@media ".concat(d[2]," {").concat(d[1],"}"),d[2]=r):d[2]=r),s&&(d[4]?(d[1]="@supports (".concat(d[4],") {").concat(d[1],"}"),d[4]=s):d[4]="".concat(s)),t.push(d))}},t}},"./node_modules/css-loader/dist/runtime/noSourceMaps.js":e=>{"use strict";e.exports=function(e){return e[1]}},"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js":(e,t,r)=>{"use strict";var i,s=function(){return void 0===i&&(i=Boolean(window&&document&&document.all&&!window.atob)),i},n=function(){var e={};return function(t){if(void 0===e[t]){var r=document.querySelector(t);if(window.HTMLIFrameElement&&r instanceof window.HTMLIFrameElement)try{r=r.contentDocument.head}catch(e){r=null}e[t]=r}return e[t]}}(),o=[];function a(e){for(var t=-1,r=0;r<o.length;r++)if(o[r].identifier===e){t=r;break}return t}function l(e,t){for(var r={},i=[],s=0;s<e.length;s++){var n=e[s],l=t.base?n[0]+t.base:n[0],c=r[l]||0,d="".concat(l," ").concat(c);r[l]=c+1;var u=a(d),m={css:n[1],media:n[2],sourceMap:n[3]};-1!==u?(o[u].references++,o[u].updater(m)):o.push({identifier:d,updater:g(m,t),references:1}),i.push(d)}return i}function c(e){var t=document.createElement("style"),i=e.attributes||{};if(void 0===i.nonce){var s=r.nc;s&&(i.nonce=s)}if(Object.keys(i).forEach((function(e){t.setAttribute(e,i[e])})),"function"==typeof e.insert)e.insert(t);else{var o=n(e.insert||"head");if(!o)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");o.appendChild(t)}return t}var d,u=(d=[],function(e,t){return d[e]=t,d.filter(Boolean).join("\n")});function m(e,t,r,i){var s=r?"":i.media?"@media ".concat(i.media," {").concat(i.css,"}"):i.css;if(e.styleSheet)e.styleSheet.cssText=u(t,s);else{var n=document.createTextNode(s),o=e.childNodes;o[t]&&e.removeChild(o[t]),o.length?e.insertBefore(n,o[t]):e.appendChild(n)}}function h(e,t,r){var i=r.css,s=r.media,n=r.sourceMap;if(s?e.setAttribute("media",s):e.removeAttribute("media"),n&&"undefined"!=typeof btoa&&(i+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(n))))," */")),e.styleSheet)e.styleSheet.cssText=i;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(i))}}var f=null,p=0;function g(e,t){var r,i,s;if(t.singleton){var n=p++;r=f||(f=c(t)),i=m.bind(null,r,n,!1),s=m.bind(null,r,n,!0)}else r=c(t),i=h.bind(null,r,t),s=function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(r)};return i(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;i(e=t)}else s()}}e.exports=function(e,t){(t=t||{}).singleton||"boolean"==typeof t.singleton||(t.singleton=s());var r=l(e=e||[],t);return function(e){if(e=e||[],"[object Array]"===Object.prototype.toString.call(e)){for(var i=0;i<r.length;i++){var s=a(r[i]);o[s].references--}for(var n=l(e,t),c=0;c<r.length;c++){var d=a(r[c]);0===o[d].references&&(o[d].updater(),o.splice(d,1))}r=n}}}},"ckeditor5/src/core.js":(e,t,r)=>{e.exports=r("dll-reference CKEditor5.dll")("./src/core.js")},"ckeditor5/src/typing.js":(e,t,r)=>{e.exports=r("dll-reference CKEditor5.dll")("./src/typing.js")},"ckeditor5/src/ui.js":(e,t,r)=>{e.exports=r("dll-reference CKEditor5.dll")("./src/ui.js")},"dll-reference CKEditor5.dll":e=>{"use strict";e.exports=CKEditor5.dll}},t={};function r(i){var s=t[i];if(void 0!==s)return s.exports;var n=t[i]={id:i,exports:{}};return e[i](n,n.exports,r),n.exports}r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},r.d=(e,t)=>{for(var i in t)r.o(t,i)&&!r.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.nc=void 0;var i={};return(()=>{"use strict";r.d(i,{default:()=>p});var e=r("ckeditor5/src/core.js"),t=r("ckeditor5/src/typing.js");const s={linkTitle:{label:Drupal.t("Title"),viewAttribute:"title"},linkAriaLabel:{label:Drupal.t("ARIA label"),viewAttribute:"aria-label",group:"advanced"},linkClass:{label:Drupal.t("CSS classes"),viewAttribute:"class",group:"advanced"},linkId:{label:Drupal.t("ID"),viewAttribute:"id",group:"advanced"},linkRel:{label:Drupal.t("Link relationship"),viewAttribute:"rel",group:"advanced"}},n={advanced:{label:Drupal.t("Advanced")}};class o extends e.Plugin{static get pluginName(){return"EditorAdvancedLinkEditing"}init(){const e=this.editor.config.get("editorAdvancedLink");if(!e.options)return void(this.enabledModelNames=[]);const t=Object.values(e.options);this.enabledModelNames=Object.keys(s).filter((e=>t.includes(s[e].viewAttribute))),this.enabledModelNames.forEach((e=>{this._allowAndConvertExtraAttribute(e,s[e].viewAttribute),this._removeExtraAttributeOnUnlinkCommandExecute(e),this._refreshExtraAttributeValue(e)})),this._addExtraAttributeOnLinkCommandExecute(Object.keys(s))}_allowAndConvertExtraAttribute(e,t){const{editor:r}=this;r.model.schema.extend("$text",{allowAttributes:e}),r.conversion.for("downcast").attributeToElement({model:e,view:(e,{writer:r})=>{const i=r.createAttributeElement("a",{[t]:e},{priority:5});return r.setCustomProperty("link",!0,i),i}}),r.conversion.for("upcast").elementToAttribute({view:{name:"a",attributes:{[t]:!0}},model:{key:e,value:e=>e.getAttribute(t)}})}_addExtraAttributeOnLinkCommandExecute(e){const{editor:t}=this,r=t.commands.get("link");let i=!1;r.on("execute",((r,s)=>{if(s.length<3)return;if(i)return void(i=!1);r.stop(),i=!0;const n=s[s.length-1],{model:o}=this.editor,{selection:a}=o.document;o.change((r=>{t.execute("link",...s);const i=a.getFirstPosition();e.forEach((e=>{if(a.isCollapsed){const t=i.textNode||i.nodeBefore;n[e]?r.setAttribute(e,n[e],r.createRangeOn(t)):r.removeAttribute(e,r.createRangeOn(t)),r.removeSelectionAttribute(e)}else{const t=o.schema.getValidRanges(a.getRanges(),e);for(const i of t)n[e]?r.setAttribute(e,n[e],i):r.removeAttribute(e,i)}}))}))}),{priority:"high"})}_removeExtraAttributeOnUnlinkCommandExecute(e){const{editor:r}=this,i=r.commands.get("unlink"),{model:s}=this.editor,{selection:n}=s.document;let o=!1;i.on("execute",(i=>{o||(i.stop(),s.change((()=>{o=!0,r.execute("unlink"),o=!1,s.change((r=>{let i;i=n.isCollapsed?[(0,t.findAttributeRange)(n.getFirstPosition(),e,n.getAttribute(e),s)]:s.schema.getValidRanges(n.getRanges(),e);for(const t of i)r.removeAttribute(e,t)}))})))}),{priority:"high"})}_refreshExtraAttributeValue(e){const{editor:t}=this,r=t.commands.get("link"),{model:i}=this.editor,{selection:s}=i.document;r.set(e,null),i.document.on("change",(()=>{r[e]=s.getAttribute(e)}))}}var a=r("ckeditor5/src/ui.js"),l=r("./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js"),c=r.n(l),d=r("./node_modules/css-loader/dist/cjs.js!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[0].use[2]!./js/ckeditor5_plugins/editorAdvancedLink/src/details/details.css"),u={injectType:"singletonStyleTag",attributes:{"data-cke":!0},insert:"head",singleton:!0};c()(d.Z,u);d.Z.locals;class m extends a.View{constructor(e,t={}){super(e);const r=this.bindTemplate;this.set("isFocused",!1),this.set("label",t.label||""),this.set("class",t.class||null),this.children=this.createCollection(),this.setTemplate({tag:"details",attributes:{class:["ck","ck-form__details",r.if("isFocused","ck-form__details--focused"),r.to("class")]},children:this.children}),this.summary=new a.View(e),this.summary.setTemplate({tag:"summary",attributes:{class:["ck","ck-form__details__summary"]},children:[{text:r.to("label")}]}),this.children.add(this.summary)}render(){super.render(),this.element.addEventListener("toggle",this.onToggle.bind(this))}focus(){this.summary.element.focus()}onToggle(e){if(e.target.open){const e=this.parent._focusables.getIndex(this);Object.values(this.children._items).slice(1).reverse().forEach((t=>{this.parent._focusables.add(t,e+1),this.parent.focusTracker.add(t.element)}))}else Object.values(this.children._items).slice(1).forEach((e=>{this.parent._focusables.remove(e),this.parent.focusTracker.remove(e.element)}))}}class h extends e.Plugin{init(){this.groups={},this.editor.plugins.get("LinkUI")._createViews&&this.editor.plugins.get("LinkUI")._createViews(),this._changeFormToVertical(),this._addExtraFormFields()}_addExtraFormFields(){const{editor:e}=this;e.plugins.get("ContextualBalloon").on("set:visibleView",((t,r,i,n)=>{const o=e.plugins.get("LinkUI").formView;if(i===n||i!==o)return;const{enabledModelNames:a}=e.plugins.get("EditorAdvancedLinkEditing");a.reverse().forEach((e=>{this._createExtraFormField(e,s[e])})),this._handleExtraFormFieldSubmit(a),this._addGroupsToFormView(),this._moveTargetDecoratorToAdvancedGroup()}))}_changeFormToVertical(){this.editor.plugins.get("LinkUI").formView.extendTemplate({attributes:{class:["ck-vertical-form","ck-link-form_layout-vertical"]}})}_createExtraFormField(e,t){const{editor:r}=this,{locale:i}=r,s=r.plugins.get("LinkUI").formView,n=r.commands.get("link");if(void 0===s[e]){const r=t.group?this._getGroup(t.group):s,o=new a.LabeledFieldView(i,a.createLabeledInputText);o.label=t.label,r.children.add(o,1),t.group||(s._focusables.add(o,1),s.focusTracker.add(o.element)),s[e]=o,s[e].fieldView.bind("value").to(n,e),s[e].fieldView.element.value=n[e]||""}}_addGroupsToFormView(){if(0===Object.entries(this.groups).length)return;const{editor:e}=this,t=e.plugins.get("LinkUI").formView;Object.values(this.groups).reverse().forEach((e=>{e.added||(t.children.add(e,2),e.parent=t,t._focusables.add(e,2),t.focusTracker.add(e.element),e.added=!0)}));[t.children.find((e=>e.template.attributes.class.indexOf("ck-button-save")>-1)),t.children.find((e=>e.template.attributes.class.indexOf("ck-button-cancel")>-1))].forEach(((e,r)=>{t.children.remove(e),t._focusables.remove(e),t.focusTracker.remove(e.element),t.children.add(e,3+r),t._focusables.add(e,3+r),t.focusTracker.add(e.element)}))}_getGroup(e){if(!this.groups[e]){const{editor:t}=this,{locale:r}=t;this.groups[e]=new m(r,{label:n[e].label})}return this.groups[e]}_moveTargetDecoratorToAdvancedGroup(){const{editor:e}=this,t=e.plugins.get("LinkUI").formView;t.targetMoved||(t._manualDecoratorSwitches._items.forEach((e=>{e.label===Drupal.t("Open in new window")&&this._getGroup("advanced").children.add(e)})),t.targetMoved=!0)}_handleExtraFormFieldSubmit(e){const{editor:t}=this,r=t.plugins.get("LinkUI").formView,i=t.commands.get("link");this.listenTo(r,"submit",(()=>{const t=e.reduce(((e,t)=>(e[t]=r[t].fieldView.element.value,e)),{});i.once("execute",((e,r)=>{if(r.length<3)r.push(t);else{if(3!==r.length)throw Error("The link command has more than 3 arguments.");Object.assign(r[2],t)}}),{priority:"highest"})}),{priority:"high"})}}class f extends e.Plugin{static get requires(){return[o,h]}static get pluginName(){return"EditorAdvancedLink"}}const p={EditorAdvancedLink:f}})(),i=i.default})()));
\ No newline at end of file
This plugin is largely based on CKEditor 5's [block plugin widget tutorial](https://ckeditor.com/docs/ckeditor5/latest/framework/guides/tutorials/implementing-a-block-widget.html),
but with added documentation to facilitate better understanding of CKEditor 5
plugin development and other minor changes.
Within `/src` are the multiple files that will be used by the build process to
become a CKEditor 5 plugin in `/build`. Technically, everything in these files
could be in a single `index.js` - the only file the MUST be present is
`/src/index.js`. However, splitting the plugin into concern-specific files has
maintainability benefits.
.ck.ck-form__details {
& > summary {
cursor: pointer;
&:focus-visible {
border: var(--ck-focus-ring);
box-shadow: var(--ck-focus-outer-shadow), 0 0;
}
}
}
/**
* @module ui/details/detailsview
*/
// eslint-disable-next-line import/no-extraneous-dependencies
import { View } from 'ckeditor5/src/ui';
import './details.css';
/**
* The class component representing a details element. It should be used in more
* advanced forms to group fields.
*
* @extends module:ui/view~View
*/
export default class DetailsView extends View {
/**
* Creates an instance of the details class.
*
* @param {module:utils/locale~Locale} locale The locale instance.
* @param {Object} options The options.
* @param {String} options.label The summary label.
* @param {String} [options.class] An additional class.
*/
constructor(locale, options = {}) {
super(locale);
const bind = this.bindTemplate;
/**
* An observable flag set to `true` when {@link #fieldView} is currently
* focused by the user (`false` otherwise).
*
* @readonly
* @observable
* @member {Boolean} #isFocused
* @default false
*/
this.set( 'isFocused', false );
/**
* The label of the details element.
*
* @observable
* @member {String} #label
*/
this.set('label', options.label || '');
/**
* An additional CSS class added to the {@link #element}.
*
* @observable
* @member {String} #class
*/
this.set('class', options.class || null);
/**
* A collection of items.
*
* @readonly
* @member {module:ui/viewcollection~ViewCollection}
*/
this.children = this.createCollection();
this.setTemplate({
tag: 'details',
attributes: {
class: [
'ck',
'ck-form__details',
bind.if( 'isFocused', 'ck-form__details--focused' ),
bind.to('class'),
],
},
children: this.children,
});
this.summary = new View(locale);
this.summary.setTemplate({
tag: 'summary',
attributes: {
class: ['ck', 'ck-form__details__summary'],
},
children: [{ text: bind.to('label') }],
});
this.children.add(this.summary);
}
render() {
super.render();
this.element.addEventListener('toggle', this.onToggle.bind(this));
}
focus() {
this.summary.element.focus();
}
onToggle(evt) {
if (evt.target.open) {
const groupIndex = this.parent._focusables.getIndex(this);
Object.values(this.children._items).slice(1).reverse().forEach((child) => {
this.parent._focusables.add(child, groupIndex+1);
this.parent.focusTracker.add(child.element);
});
}
else {
Object.values(this.children._items).slice(1).forEach((child) => {
this.parent._focusables.remove(child);
this.parent.focusTracker.remove(child.element);
});
}
}
}
// eslint-disable-next-line import/no-extraneous-dependencies
import { Plugin } from 'ckeditor5/src/core';
// eslint-disable-next-line import/no-extraneous-dependencies
import { findAttributeRange } from 'ckeditor5/src/typing';
import { additionalFormElements } from './utils';
export default class EditorAdvancedLinkEditing extends Plugin {
/**
* @inheritdoc
*/
static get pluginName() {
return 'EditorAdvancedLinkEditing';
}
init() {
const editorAdvancedLinkConfig =
this.editor.config.get('editorAdvancedLink');
if (!editorAdvancedLinkConfig.options) {
this.enabledModelNames = [];
return;
}
const enabledViewAttributes = Object.values(
editorAdvancedLinkConfig.options,
);
this.enabledModelNames = Object.keys(additionalFormElements).filter(
(modelName) => {
return enabledViewAttributes.includes(
additionalFormElements[modelName].viewAttribute,
);
},
);
this.enabledModelNames.forEach((modelName) => {
this._allowAndConvertExtraAttribute(
modelName,
additionalFormElements[modelName].viewAttribute,
);
this._removeExtraAttributeOnUnlinkCommandExecute(modelName);
this._refreshExtraAttributeValue(modelName);
});
this._addExtraAttributeOnLinkCommandExecute(
Object.keys(additionalFormElements),
);
}
_allowAndConvertExtraAttribute(modelName, viewName) {
const { editor } = this;
editor.model.schema.extend('$text', { allowAttributes: modelName });
// Model -> View (DOM)
editor.conversion.for('downcast').attributeToElement({
model: modelName,
view: (value, { writer }) => {
const linkViewElement = writer.createAttributeElement(
'a',
{
[viewName]: value,
},
{ priority: 5 },
);
// Without it the isLinkElement() will not recognize the link and the UI will not show up
// when the user clicks a link.
writer.setCustomProperty('link', true, linkViewElement);
return linkViewElement;
},
});
// View (DOM/DATA) -> Model
editor.conversion.for('upcast').elementToAttribute({
view: {
name: 'a',
attributes: {
[viewName]: true,
},
},
model: {
key: modelName,
value: (viewElement) => viewElement.getAttribute(viewName),
},
});
}
_addExtraAttributeOnLinkCommandExecute(modelNames) {
const { editor } = this;
const linkCommand = editor.commands.get('link');
let linkCommandExecuting = false;
linkCommand.on(
'execute',
(evt, args) => {
// Custom handling is only required if an extra attribute was passed into
// editor.execute( 'link', ... ).
if (args.length < 3) {
return;
}
if (linkCommandExecuting) {
linkCommandExecuting = false;
return;
}
// If the additional attribute was passed, we stop the default execution
// of the LinkCommand. We're going to create Model#change() block for undo
// and execute the LinkCommand together with setting the extra attribute.
evt.stop();
// Prevent infinite recursion by keeping records of when link command is
// being executed by this function.
linkCommandExecuting = true;
const extraAttributeValues = args[args.length - 1];
const { model } = this.editor;
const { selection } = model.document;
// Wrapping the original command execution in a model.change() block to make sure there's a single undo step
// when the extra attribute is added.
model.change((writer) => {
editor.execute('link', ...args);
const firstPosition = selection.getFirstPosition();
modelNames.forEach((modelName) => {
if (selection.isCollapsed) {
const node = firstPosition.textNode || firstPosition.nodeBefore;
if (extraAttributeValues[modelName]) {
writer.setAttribute(
modelName,
extraAttributeValues[modelName],
writer.createRangeOn(node),
);
} else {
writer.removeAttribute(modelName, writer.createRangeOn(node));
}
writer.removeSelectionAttribute(modelName);
} else {
const ranges = model.schema.getValidRanges(
selection.getRanges(),
modelName,
);
for (const range of ranges) {
if (extraAttributeValues[modelName]) {
writer.setAttribute(
modelName,
extraAttributeValues[modelName],
range,
);
}
else {
writer.removeAttribute(modelName, range);
}
}
}
});
});
},
{ priority: 'high' },
);
}
_removeExtraAttributeOnUnlinkCommandExecute(modelName) {
const { editor } = this;
const unlinkCommand = editor.commands.get('unlink');
const { model } = this.editor;
const { selection } = model.document;
let isUnlinkingInProgress = false;
// Make sure all changes are in a single undo step so cancel the original unlink first in the high priority.
unlinkCommand.on(
'execute',
(evt) => {
if (isUnlinkingInProgress) {
return;
}
evt.stop();
// This single block wraps all changes that should be in a single undo step.
model.change(() => {
// Now, in this single "undo block" let the unlink command flow naturally.
isUnlinkingInProgress = true;
// Do the unlinking within a single undo step.
editor.execute('unlink');
// Let's make sure the next unlinking will also be handled.
isUnlinkingInProgress = false;
// The actual integration that removes the extra attribute.
model.change((writer) => {
// Get ranges to unlink.
let ranges;
if (selection.isCollapsed) {
ranges = [
findAttributeRange(
selection.getFirstPosition(),
modelName,
selection.getAttribute(modelName),
model,
),
];
} else {
ranges = model.schema.getValidRanges(
selection.getRanges(),
modelName,
);
}
// Remove the extra attribute from specified ranges.
// eslint-disable-next-line max-nested-callbacks
for (const range of ranges) {
writer.removeAttribute(modelName, range);
}
});
});
},
{ priority: 'high' },
);
}
_refreshExtraAttributeValue(modelName) {
const { editor } = this;
const linkCommand = editor.commands.get('link');
const { model } = this.editor;
const { selection } = model.document;
linkCommand.set(modelName, null);
model.document.on('change', () => {
linkCommand[modelName] = selection.getAttribute(modelName);
});
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment