[FEATURE] Add a telephone (tel:) link handler 74/58674/5
authorRune Piper <kontakt@runepiper.de>
Tue, 23 Oct 2018 13:41:01 +0000 (15:41 +0200)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Fri, 11 Jan 2019 09:53:36 +0000 (10:53 +0100)
The new link handler allows you to set links
in a new tab in the link browser to
phone numbers using the tel: protocol.

Resolves: #86629
Releases: master
Change-Id: I1a69fefbe16db9aaae51abfd80f154fa6aa8791a
Reviewed-on: https://review.typo3.org/58674
Reviewed-by: Jan Helke <typo3@helke.de>
Tested-by: Jan Helke <typo3@helke.de>
Tested-by: TYPO3com <noreply@typo3.com>
Reviewed-by: Jörg Bösche <typo3@joergboesche.de>
Tested-by: Mona Muzaffar <mona.muzaffar@gmx.de>
Reviewed-by: Mona Muzaffar <mona.muzaffar@gmx.de>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
12 files changed:
typo3/sysext/core/Classes/LinkHandling/LegacyLinkNotationConverter.php
typo3/sysext/core/Classes/LinkHandling/LinkService.php
typo3/sysext/core/Classes/LinkHandling/TelephoneLinkHandler.php [new file with mode: 0644]
typo3/sysext/core/Configuration/DefaultConfiguration.php
typo3/sysext/core/Documentation/Changelog/master/Feature-86629-ImplementLinkHandlerForTelephoneNumbers.rst [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/LinkHandling/TelephoneLinkHandlerTest.php [new file with mode: 0644]
typo3/sysext/frontend/Classes/Typolink/TelephoneLinkBuilder.php [new file with mode: 0644]
typo3/sysext/recordlist/Classes/LinkHandler/TelephoneLinkHandler.php [new file with mode: 0644]
typo3/sysext/recordlist/Resources/Private/Language/locallang_browse_links.xlf
typo3/sysext/recordlist/Resources/Private/Templates/LinkBrowser/Telephone.html [new file with mode: 0644]
typo3/sysext/recordlist/Resources/Public/JavaScript/TelephoneLinkHandler.js [new file with mode: 0644]
typo3/sysext/recordlist/ext_localconf.php

index 265f2c7..abc0d90 100644 (file)
@@ -73,6 +73,9 @@ class LegacyLinkNotationConverter
         } elseif (GeneralUtility::validEmail(parse_url($linkParameter, PHP_URL_PATH))) {
             $result['type'] = LinkService::TYPE_EMAIL;
             $result['email'] = $linkParameter;
+        } elseif (strpos($linkParameter, 'tel:') === 0) {
+            $result['type'] = LinkService::TYPE_TELEPHONE;
+            $result['telephone'] = $linkParameter;
         } elseif (strpos($linkParameter, ':') !== false) {
             // Check for link-handler keyword
             list($linkHandlerKeyword, $linkHandlerValue) = explode(':', $linkParameter, 2);
index f23f66d..e0aa9dd 100644 (file)
@@ -29,6 +29,7 @@ class LinkService implements SingletonInterface
     const TYPE_PAGE = 'page';
     const TYPE_URL = 'url';
     const TYPE_EMAIL = 'email';
+    const TYPE_TELEPHONE = 'telephone';
     const TYPE_FILE = 'file';
     const TYPE_FOLDER = 'folder';
     const TYPE_RECORD = 'record';
@@ -120,6 +121,9 @@ class LinkService implements SingletonInterface
         } elseif (stripos($urn, 'mailto:') === 0 && $this->handlers[self::TYPE_EMAIL]) {
             $result = $this->handlers[self::TYPE_EMAIL]->resolveHandlerData(['email' => $urn]);
             $result['type'] = self::TYPE_EMAIL;
+        } elseif (stripos($urn, 'tel:') === 0 && $this->handlers[self::TYPE_TELEPHONE]) {
+            $result = $this->handlers[self::TYPE_TELEPHONE]->resolveHandlerData(['telephone' => $urn]);
+            $result['type'] = self::TYPE_TELEPHONE;
         } else {
             $result = [];
             if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['Link']['resolveByStringRepresentation'] ?? null)) {
diff --git a/typo3/sysext/core/Classes/LinkHandling/TelephoneLinkHandler.php b/typo3/sysext/core/Classes/LinkHandling/TelephoneLinkHandler.php
new file mode 100644 (file)
index 0000000..c02f30d
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Core\LinkHandling;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Resolves telephone numbers
+ */
+class TelephoneLinkHandler implements LinkHandlingInterface
+{
+
+    /**
+     * Returns the link to a telephone number as a string
+     *
+     * @param array $parameters
+     * @return mixed
+     */
+    public function asString(array $parameters): string
+    {
+        $telephoneNumber = preg_replace('/(?:[^\d\+]+)/', '', $parameters['telephone']);
+
+        return 'tel:' . $telephoneNumber;
+    }
+
+    /**
+     * Returns the telephone number without the "tel:" prefix
+     * in the 'telephone' property of the array.
+     *
+     * @param array $data
+     * @return array
+     */
+    public function resolveHandlerData(array $data): array
+    {
+        return ['telephone' => substr($data['telephone'], 4)];
+    }
+}
index ca62c4d..886eb5c 100644 (file)
@@ -323,6 +323,7 @@ return [
             'url'    => \TYPO3\CMS\Core\LinkHandling\UrlLinkHandler::class,
             'email'  => \TYPO3\CMS\Core\LinkHandling\EmailLinkHandler::class,
             'record' => \TYPO3\CMS\Core\LinkHandling\RecordLinkHandler::class,
+            'telephone' => \TYPO3\CMS\Core\LinkHandling\TelephoneLinkHandler::class,
         ],
         'livesearch' => [],  // Array: keywords used for commands to search for specific tables
         'formEngine' => [
@@ -1314,6 +1315,7 @@ return [
             'url' => \TYPO3\CMS\Frontend\Typolink\ExternalUrlLinkBuilder::class,
             'email' => \TYPO3\CMS\Frontend\Typolink\EmailLinkBuilder::class,
             'record' => \TYPO3\CMS\Frontend\Typolink\DatabaseRecordLinkBuilder::class,
+            'telephone' => \TYPO3\CMS\Frontend\Typolink\TelephoneLinkBuilder::class,
             'unknown' => \TYPO3\CMS\Frontend\Typolink\LegacyLinkBuilder::class,
         ],
         'passwordHashing' => [
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-86629-ImplementLinkHandlerForTelephoneNumbers.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-86629-ImplementLinkHandlerForTelephoneNumbers.rst
new file mode 100644 (file)
index 0000000..3654727
--- /dev/null
@@ -0,0 +1,18 @@
+.. include:: ../../Includes.txt
+
+=============================================================
+Feature: #86629 - Implement LinkHandler for telephone numbers
+=============================================================
+
+See :issue:`86629`
+
+Description
+===========
+
+A new phone number link handler has been added.
+
+With this new link handler you can set links in a new tab in the link browser to phone numbers using the `tel:` protocol.
+
+A valid phone number consists of only numbers and the + character.
+
+.. index:: Backend, Frontend
diff --git a/typo3/sysext/core/Tests/Unit/LinkHandling/TelephoneLinkHandlerTest.php b/typo3/sysext/core/Tests/Unit/LinkHandling/TelephoneLinkHandlerTest.php
new file mode 100644 (file)
index 0000000..9e036ba
--- /dev/null
@@ -0,0 +1,102 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Core\Tests\Unit\LinkHandling;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\LinkHandling\TelephoneLinkHandler;
+use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
+
+/**
+ * Class TelephoneLinkHandlerTest
+ */
+class TelephoneLinkHandlerTest extends UnitTestCase
+{
+
+    /**
+     * Data to resolve strings to arrays and vice versa, external, mail, page
+     *
+     * @return array
+     */
+    public function resolveParametersForNonFilesDataProvider(): array
+    {
+        return [
+            'telephone number with protocol' => [
+                [
+                    'telephone' => 'tel:012345678'
+                ],
+                [
+                    'telephone' => '012345678'
+                ],
+                'tel:012345678'
+            ],
+            'telephone number with protocol and spaces' => [
+                [
+                    'telephone' => 'tel:+49 123 45 56 78'
+                ],
+                [
+                    'telephone' => '+49 123 45 56 78'
+                ],
+                'tel:+49123455678'
+            ],
+            'invalid telephone number' => [
+                [
+                    'telephone' => 'tel:+43-hello-world'
+                ],
+                [
+                    'telephone' => '+43-hello-world'
+                ],
+                'tel:+43'
+            ],
+            'telephone number with weird characters' => [
+                [
+                    'telephone' => 'tel:+43/123!45&56%78'
+                ],
+                [
+                    'telephone' => '+43/123!45&56%78'
+                ],
+                'tel:+43123455678'
+            ],
+        ];
+    }
+
+    /**
+     * @test
+     *
+     * @param array $input
+     * @param array  $expected
+     *
+     * @dataProvider resolveParametersForNonFilesDataProvider
+     */
+    public function resolveReturnsSplitParameters($input, $expected): void
+    {
+        $subject = new TelephoneLinkHandler();
+        $this->assertEquals($expected, $subject->resolveHandlerData($input));
+    }
+
+    /**
+     * @test
+     *
+     * @param string $input
+     * @param array  $parameters
+     * @param string $expected
+     *
+     * @dataProvider resolveParametersForNonFilesDataProvider
+     */
+    public function splitParametersToUnifiedIdentifier($input, $parameters, $expected)
+    {
+        $subject = new TelephoneLinkHandler();
+        $this->assertEquals($expected, $subject->asString($parameters));
+    }
+}
diff --git a/typo3/sysext/frontend/Classes/Typolink/TelephoneLinkBuilder.php b/typo3/sysext/frontend/Classes/Typolink/TelephoneLinkBuilder.php
new file mode 100644 (file)
index 0000000..27e88e3
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Frontend\Typolink;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Builds a TypoLink to a telephone number
+ */
+class TelephoneLinkBuilder extends AbstractTypolinkBuilder
+{
+    /**
+     * @inheritdoc
+     */
+    public function build(array &$linkDetails, string $linkText, string $target, array $conf): array
+    {
+        return [$linkDetails['typoLinkParameter'], $linkText];
+    }
+}
diff --git a/typo3/sysext/recordlist/Classes/LinkHandler/TelephoneLinkHandler.php b/typo3/sysext/recordlist/Classes/LinkHandler/TelephoneLinkHandler.php
new file mode 100644 (file)
index 0000000..9e7a29d
--- /dev/null
@@ -0,0 +1,107 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Recordlist\LinkHandler;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Core\Page\PageRenderer;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Link handler for telephone links
+ * @internal This class is a specific LinkHandler implementation and is not part of the TYPO3's Core API.
+ */
+class TelephoneLinkHandler extends AbstractLinkHandler implements LinkHandlerInterface
+{
+    /**
+     * Parts of the current link
+     *
+     * @var array
+     */
+    protected $linkParts = [];
+
+    /**
+     * We don't support updates since there is no difference to simply set the link again.
+     *
+     * @var bool
+     */
+    protected $updateSupported = false;
+
+    /**
+     * Constructor
+     */
+    public function __construct()
+    {
+        parent::__construct();
+        // remove unsupported link attributes
+        foreach (['target', 'rel'] as $attribute) {
+            $position = array_search($attribute, $this->linkAttributes, true);
+            if ($position !== false) {
+                unset($this->linkAttributes[$position]);
+            }
+        }
+    }
+
+    /**
+     * Checks if this is the handler for the given link
+     *
+     * The handler may store this information locally for later usage.
+     *
+     * @param array $linkParts Link parts as returned from TypoLinkCodecService
+     *
+     * @return bool
+     */
+    public function canHandleLink(array $linkParts): bool
+    {
+        if (isset($linkParts['url']['telephone'])) {
+            $this->linkParts = $linkParts;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Format the current link for HTML output
+     *
+     * @return string
+     */
+    public function formatCurrentUrl(): string
+    {
+        return $this->linkParts['url']['telephone'];
+    }
+
+    /**
+     * Render the link handler
+     *
+     * @param ServerRequestInterface $request
+     *
+     * @return string
+     */
+    public function render(ServerRequestInterface $request): string
+    {
+        GeneralUtility::makeInstance(PageRenderer::class)->loadRequireJsModule('TYPO3/CMS/Recordlist/TelephoneLinkHandler');
+
+        $this->view->assign('telephone', !empty($this->linkParts) ? $this->linkParts['url']['telephone'] : '');
+        return $this->view->render('Telephone');
+    }
+
+    /**
+     * @return string[] Array of body-tag attributes
+     */
+    public function getBodyTagAttributes(): array
+    {
+        return [];
+    }
+}
index f0fc4be..41e859a 100644 (file)
@@ -30,6 +30,9 @@
                        <trans-unit id="email">
                                <source>Email</source>
                        </trans-unit>
+                       <trans-unit id="telephone">
+                               <source>Telephone</source>
+                       </trans-unit>
                        <trans-unit id="special">
                                <source>Special</source>
                        </trans-unit>
@@ -84,6 +87,9 @@
                        <trans-unit id="emailAddress">
                                <source>Email address</source>
                        </trans-unit>
+                       <trans-unit id="telephoneNumber">
+                               <source>Telephone number</source>
+                       </trans-unit>
                        <trans-unit id="setLink">
                                <source>Set Link</source>
                        </trans-unit>
diff --git a/typo3/sysext/recordlist/Resources/Private/Templates/LinkBrowser/Telephone.html b/typo3/sysext/recordlist/Resources/Private/Templates/LinkBrowser/Telephone.html
new file mode 100644 (file)
index 0000000..fe38bb2
--- /dev/null
@@ -0,0 +1,19 @@
+<div class="element-browser-panel element-browser-main">
+       <div class="element-browser-main-content">
+               <div class="element-browser-body">
+                       <form action="" id="ltelephoneform" class="form-horizontal">
+                               <div class="form-group form-group-sm">
+                                       <label class="col-xs-4 control-label"><f:translate key="LLL:EXT:recordlist/Resources/Private/Language/locallang_browse_links.xlf:telephoneNumber" /></label>
+                                       <div class="col-xs-8">
+                                               <div class="input-group">
+                                                       <input type="tel" name="ltelephone" size="20" class="form-control" value="{telephone}" />
+                                                       <div class="input-group-btn">
+                                                               <input class="btn btn-sm btn-default" type="submit" value="{f:translate(key: 'LLL:EXT:recordlist/Resources/Private/Language/locallang_browse_links.xlf:setLink')}" />
+                                                       </div>
+                                               </div>
+                                       </div>
+                               </div>
+                       </form>
+               </div>
+       </div>
+</div>
diff --git a/typo3/sysext/recordlist/Resources/Public/JavaScript/TelephoneLinkHandler.js b/typo3/sysext/recordlist/Resources/Public/JavaScript/TelephoneLinkHandler.js
new file mode 100644 (file)
index 0000000..461363e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Module: TYPO3/CMS/Recordlist/TelephoneLinkHandler
+ * Telephone link interaction
+ */
+define(['jquery', 'TYPO3/CMS/Recordlist/LinkBrowser'], function($, LinkBrowser) {
+  'use strict';
+
+  /**
+   *
+   * @type {{}}
+   * @exports TYPO3/CMS/Recordlist/TelephoneLinkHandler
+   */
+  var TelephoneLinkHandler = {};
+
+  $(function() {
+    $('#ltelephoneform').on('submit', function(event) {
+      event.preventDefault();
+
+      var value = $(this).find('[name="ltelephone"]').val();
+      if (value === 'tel:') {
+        return;
+      }
+      if (value.indexOf('tel:') === 0) {
+        value = value.substr(4);
+      }
+
+      LinkBrowser.finalizeFunction('tel:' + value);
+    });
+  });
+
+  return TelephoneLinkHandler;
+});
index 0d77305..4c0692a 100644 (file)
@@ -30,12 +30,19 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ElementBrowsers']['folder'] = \TYPO3\
             handler = TYPO3\\CMS\\Recordlist\\LinkHandler\\UrlLinkHandler
             label = LLL:EXT:recordlist/Resources/Private/Language/locallang_browse_links.xlf:extUrl
             displayAfter = folder
-            scanAfter = mail
+            scanAfter = telephone
         }
         mail {
             handler = TYPO3\\CMS\\Recordlist\\LinkHandler\\MailLinkHandler
             label = LLL:EXT:recordlist/Resources/Private/Language/locallang_browse_links.xlf:email
             displayAfter = url
+            scanBefore = url
+        }
+        telephone {
+            handler = TYPO3\\CMS\\Recordlist\\LinkHandler\\TelephoneLinkHandler
+            label = LLL:EXT:recordlist/Resources/Private/Language/locallang_browse_links.xlf:telephone
+            displayAfter = mail
+            scanBefore = url
         }
     }
 ');