mirror of
https://github.com/Hopiu/wagtail.git
synced 2026-05-13 09:43:10 +00:00
Add support for phone links in rich text
Add support for phone links in rich text
This commit is contained in:
commit
7b2e499af0
14 changed files with 165 additions and 2 deletions
|
|
@ -12,6 +12,7 @@ const BROKEN_LINK_ICON = <Icon name="warning" />;
|
|||
const MAIL_ICON = <Icon name="mail" />;
|
||||
|
||||
const getEmailAddress = mailto => mailto.replace('mailto:', '').split('?')[0];
|
||||
const getPhoneNumber = tel => tel.replace('tel:', '').split('?')[0];
|
||||
const getDomainName = url => url.replace(/(^\w+:|^)\/\//, '').split('/')[0];
|
||||
|
||||
// Determines how to display the link based on its type: page, mail, anchor or external.
|
||||
|
|
@ -29,6 +30,9 @@ export const getLinkAttributes = (data) => {
|
|||
} else if (url.startsWith('mailto:')) {
|
||||
icon = MAIL_ICON;
|
||||
label = getEmailAddress(url);
|
||||
} else if (url.startsWith('tel:')) {
|
||||
icon = LINK_ICON;
|
||||
label = getPhoneNumber(url);
|
||||
} else if (url.startsWith('#')) {
|
||||
icon = LINK_ICON;
|
||||
label = url;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,13 @@ describe('Link', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('phone', () => {
|
||||
expect(getLinkAttributes({ url: 'tel:+46700000000' })).toMatchObject({
|
||||
url: 'tel:+46700000000',
|
||||
label: '+46700000000',
|
||||
});
|
||||
});
|
||||
|
||||
it('anchor', () => {
|
||||
expect(getLinkAttributes({ url: '#testanchor' })).toMatchObject({
|
||||
url: '#testanchor',
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ export const getChooserConfig = (entityType, entity, selectedText) => {
|
|||
page_type: 'wagtailcore.page',
|
||||
allow_external_link: true,
|
||||
allow_email_link: true,
|
||||
allow_phone_link: true,
|
||||
allow_anchor_link: true,
|
||||
link_text: selectedText,
|
||||
};
|
||||
|
|
@ -58,6 +59,9 @@ export const getChooserConfig = (entityType, entity, selectedText) => {
|
|||
} else if (data.url.startsWith('mailto:')) {
|
||||
url = global.chooserUrls.emailLinkChooser;
|
||||
urlParams.link_url = data.url.replace('mailto:', '');
|
||||
} else if (data.url.startsWith('tel:')) {
|
||||
url = global.chooserUrls.phoneLinkChooser;
|
||||
urlParams.link_url = data.url.replace('tel:', '');
|
||||
} else if (data.url.startsWith('#')) {
|
||||
url = global.chooserUrls.anchorLinkChooser;
|
||||
urlParams.link_url = data.url.replace('#', '');
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ Object {
|
|||
"allow_anchor_link": true,
|
||||
"allow_email_link": true,
|
||||
"allow_external_link": true,
|
||||
"allow_phone_link": true,
|
||||
"link_text": "",
|
||||
"link_url": "https://www.example.com/",
|
||||
"page_type": "wagtailcore.page",
|
||||
|
|
@ -81,6 +82,7 @@ Object {
|
|||
"allow_anchor_link": true,
|
||||
"allow_email_link": true,
|
||||
"allow_external_link": true,
|
||||
"allow_phone_link": true,
|
||||
"link_text": "",
|
||||
"link_url": "test@example.com",
|
||||
"page_type": "wagtailcore.page",
|
||||
|
|
@ -98,6 +100,7 @@ Object {
|
|||
"allow_anchor_link": true,
|
||||
"allow_email_link": true,
|
||||
"allow_external_link": true,
|
||||
"allow_phone_link": true,
|
||||
"link_text": "",
|
||||
"page_type": "wagtailcore.page",
|
||||
},
|
||||
|
|
@ -114,6 +117,7 @@ Object {
|
|||
"allow_anchor_link": true,
|
||||
"allow_email_link": true,
|
||||
"allow_external_link": true,
|
||||
"allow_phone_link": true,
|
||||
"link_text": "",
|
||||
"page_type": "wagtailcore.page",
|
||||
},
|
||||
|
|
@ -130,6 +134,7 @@ Object {
|
|||
"allow_anchor_link": true,
|
||||
"allow_email_link": true,
|
||||
"allow_external_link": true,
|
||||
"allow_phone_link": true,
|
||||
"link_text": "",
|
||||
"page_type": "wagtailcore.page",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ Whichever way you insert a link, you will be presented with the form displayed b
|
|||
* Internal link: A link to an existing page within your website.
|
||||
* External link: A link to a page on another website.
|
||||
* Email link: A link that will open the user's default email client with the email address prepopulated.
|
||||
* Phone link: A link that will open the user's default client for initiating audio calls, with the phone number prepopulated.
|
||||
|
||||
* You can also navigate through the website to find an internal link via the explorer.
|
||||
|
||||
|
|
|
|||
|
|
@ -39,3 +39,8 @@ class AnchorLinkChooserForm(forms.Form):
|
|||
class EmailLinkChooserForm(forms.Form):
|
||||
email_address = forms.EmailField(required=True)
|
||||
link_text = forms.CharField(required=False)
|
||||
|
||||
|
||||
class PhoneLinkChooserForm(forms.Form):
|
||||
phone_number = forms.CharField(required=True)
|
||||
link_text = forms.CharField(required=False)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
urlParams = {
|
||||
'allow_external_link': true,
|
||||
'allow_email_link': true,
|
||||
'allow_phone_link': true,
|
||||
'allow_anchor_link': true,
|
||||
};
|
||||
|
||||
|
|
@ -57,6 +58,10 @@
|
|||
url = window.chooserUrls.emailLinkChooser;
|
||||
href = href.replace('mailto:', '');
|
||||
urlParams['link_url'] = href;
|
||||
} else if (href.startsWith('tel:')) {
|
||||
url = window.chooserUrls.phoneLinkChooser;
|
||||
href = href.replace('tel:', '');
|
||||
urlParams['link_url'] = href;
|
||||
} else if (href.startsWith('#')) {
|
||||
url = window.chooserUrls.anchorLinkChooser;
|
||||
href = href.replace('#', '');
|
||||
|
|
|
|||
|
|
@ -133,6 +133,17 @@ PAGE_CHOOSER_MODAL_ONLOAD_HANDLERS = {
|
|||
return false;
|
||||
});
|
||||
},
|
||||
'phone_link': function(modal, jsonData) {
|
||||
$('p.link-types a', modal.body).on('click', function() {
|
||||
modal.loadUrl(this.href);
|
||||
return false;
|
||||
});
|
||||
|
||||
$('form', modal.body).on('submit', function() {
|
||||
modal.postForm(this.action, $(this).serialize());
|
||||
return false;
|
||||
});
|
||||
},
|
||||
'external_link': function(modal, jsonData) {
|
||||
$('p.link-types a', modal.body).on('click', function() {
|
||||
modal.loadUrl(this.href);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{% load i18n wagtailadmin_tags %}
|
||||
{% if allow_external_link or allow_email_link or allow_anchor_link or current == 'external' or current == 'email' or current == 'anchor' %}
|
||||
{% if allow_external_link or allow_email_link or allow_phone_link or allow_anchor_link or current == 'external' or current == 'email' or current == 'phone' or current == 'anchor' %}
|
||||
<p class="link-types">
|
||||
{% if current == 'internal' %}
|
||||
<b>{% trans "Internal link" %}</b>
|
||||
|
|
@ -23,6 +23,12 @@
|
|||
| <a href="{% url 'wagtailadmin_choose_page_email_link' %}{% querystring p=None parent_page_id=parent_page_id %}">{% trans "Email link" %}</a>
|
||||
{% endif %}
|
||||
|
||||
{% if current == 'phone' %}
|
||||
| <b>{% trans "Phone link" %}</b>
|
||||
{% elif allow_phone_link %}
|
||||
| <a href="{% url 'wagtailadmin_choose_page_phone_link' %}{% querystring p=None parent_page_id=parent_page_id %}">{% trans "Phone link" %}</a>
|
||||
{% endif %}
|
||||
|
||||
{% if current == 'anchor' %}
|
||||
| <b>{% trans "Anchor link" %}</b>
|
||||
{% elif allow_anchor_link %}
|
||||
|
|
|
|||
17
wagtail/admin/templates/wagtailadmin/chooser/phone_link.html
Normal file
17
wagtail/admin/templates/wagtailadmin/chooser/phone_link.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{% load i18n wagtailadmin_tags %}
|
||||
{% trans "Add a phone link" as phone_str %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=phone_str %}
|
||||
|
||||
<div class="nice-padding">
|
||||
{% include 'wagtailadmin/chooser/_link_types.html' with current='phone' %}
|
||||
|
||||
<form action="{% url 'wagtailadmin_choose_page_phone_link' %}{% querystring %}" method="post" novalidate>
|
||||
{% csrf_token %}
|
||||
<ul class="fields">
|
||||
{% for field in form %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" %}
|
||||
{% endfor %}
|
||||
<li><input type="submit" value="{% trans 'Insert link' %}" class="button" /></li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
'pageChooser': '{% url "wagtailadmin_choose_page" %}',
|
||||
'externalLinkChooser': '{% url "wagtailadmin_choose_page_external_link" %}',
|
||||
'emailLinkChooser': '{% url "wagtailadmin_choose_page_email_link" %}',
|
||||
'phoneLinkChooser': '{% url "wagtailadmin_choose_page_phone_link" %}',
|
||||
'anchorLinkChooser': '{% url "wagtailadmin_choose_page_anchor_link" %}',
|
||||
};
|
||||
window.unicodeSlugsEnabled = {% if unicode_slugs_enabled %}true{% else %}false{% endif %};
|
||||
|
|
|
|||
|
|
@ -692,6 +692,66 @@ class TestChooserEmailLink(TestCase, WagtailTestUtils):
|
|||
self.assertEqual(result['prefer_this_title_as_link_text'], True)
|
||||
|
||||
|
||||
class TestChooserPhoneLink(TestCase, WagtailTestUtils):
|
||||
def setUp(self):
|
||||
self.login()
|
||||
|
||||
def get(self, params={}):
|
||||
return self.client.get(reverse('wagtailadmin_choose_page_phone_link'), params)
|
||||
|
||||
def post(self, post_data={}, url_params={}):
|
||||
url = reverse('wagtailadmin_choose_page_phone_link')
|
||||
if url_params:
|
||||
url += '?' + urlencode(url_params)
|
||||
return self.client.post(url, post_data)
|
||||
|
||||
def test_simple(self):
|
||||
response = self.get()
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, 'wagtailadmin/chooser/phone_link.html')
|
||||
|
||||
def test_prepopulated_form(self):
|
||||
response = self.get({'link_text': 'Example', 'link_url': '+123456789'})
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, 'Example')
|
||||
self.assertContains(response, '+123456789')
|
||||
|
||||
def test_create_link(self):
|
||||
response = self.post({'phone-link-chooser-phone_number': '+123456789', 'phone-link-chooser-link_text': 'call'})
|
||||
result = json.loads(response.content.decode())['result']
|
||||
self.assertEqual(result['url'], "tel:+123456789")
|
||||
self.assertEqual(result['title'], "call")
|
||||
self.assertEqual(result['prefer_this_title_as_link_text'], True)
|
||||
|
||||
def test_create_link_without_text(self):
|
||||
response = self.post({'phone-link-chooser-phone_number': '+123456789'})
|
||||
result = json.loads(response.content.decode())['result']
|
||||
self.assertEqual(result['url'], "tel:+123456789")
|
||||
self.assertEqual(result['title'], "+123456789") # When no link text is given, it uses the phone number
|
||||
self.assertEqual(result['prefer_this_title_as_link_text'], False)
|
||||
|
||||
def test_notice_changes_to_link_text(self):
|
||||
response = self.post(
|
||||
{'phone-link-chooser-phone_number': '+222222222', 'phone-link-chooser-link_text': 'example'}, # POST data
|
||||
{'link_url': '+111111111', 'link_text': 'example'} # GET params - initial data
|
||||
)
|
||||
result = json.loads(response.content.decode())['result']
|
||||
self.assertEqual(result['url'], "tel:+222222222")
|
||||
self.assertEqual(result['title'], "example")
|
||||
# no change to link text, so prefer the existing link/selection content where available
|
||||
self.assertEqual(result['prefer_this_title_as_link_text'], False)
|
||||
|
||||
response = self.post(
|
||||
{'phone-link-chooser-phone_number': '+222222222', 'phone-link-chooser-link_text': 'new example'}, # POST data
|
||||
{'link_url': '+111111111', 'link_text': 'example'} # GET params - initial data
|
||||
)
|
||||
result = json.loads(response.content.decode())['result']
|
||||
self.assertEqual(result['url'], "tel:+222222222")
|
||||
self.assertEqual(result['title'], "new example")
|
||||
# link text has changed, so tell the caller to use it
|
||||
self.assertEqual(result['prefer_this_title_as_link_text'], True)
|
||||
|
||||
|
||||
class TestCanChoosePage(TestCase, WagtailTestUtils):
|
||||
fixtures = ['test.json']
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ urlpatterns = [
|
|||
url(r'^choose-page/search/$', chooser.search, name='wagtailadmin_choose_page_search'),
|
||||
url(r'^choose-external-link/$', chooser.external_link, name='wagtailadmin_choose_page_external_link'),
|
||||
url(r'^choose-email-link/$', chooser.email_link, name='wagtailadmin_choose_page_email_link'),
|
||||
url(r'^choose-phone-link/$', chooser.phone_link, name='wagtailadmin_choose_page_phone_link'),
|
||||
url(r'^choose-anchor-link/$', chooser.anchor_link, name='wagtailadmin_choose_page_anchor_link'),
|
||||
|
||||
url(r'^tag-autocomplete/$', tags.autocomplete, name='wagtailadmin_tag_autocomplete'),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ from django.http import Http404
|
|||
from django.shortcuts import get_object_or_404, render
|
||||
|
||||
from wagtail.admin.forms.choosers import (
|
||||
AnchorLinkChooserForm, EmailLinkChooserForm, ExternalLinkChooserForm)
|
||||
AnchorLinkChooserForm, EmailLinkChooserForm, ExternalLinkChooserForm, PhoneLinkChooserForm)
|
||||
|
||||
from wagtail.admin.forms.search import SearchForm
|
||||
from wagtail.admin.modal_workflow import render_modal_workflow
|
||||
from wagtail.core import hooks
|
||||
|
|
@ -20,6 +21,7 @@ def shared_context(request, extra_context=None):
|
|||
'parent_page_id': request.GET.get('parent_page_id'),
|
||||
'allow_external_link': request.GET.get('allow_external_link'),
|
||||
'allow_email_link': request.GET.get('allow_email_link'),
|
||||
'allow_phone_link': request.GET.get('allow_phone_link'),
|
||||
'allow_anchor_link': request.GET.get('allow_anchor_link'),
|
||||
}
|
||||
if extra_context:
|
||||
|
|
@ -287,3 +289,37 @@ def email_link(request):
|
|||
'form': form,
|
||||
}), json_data={'step': 'email_link'}
|
||||
)
|
||||
|
||||
|
||||
def phone_link(request):
|
||||
initial_data = {
|
||||
'link_text': request.GET.get('link_text', ''),
|
||||
'phone_number': request.GET.get('link_url', ''),
|
||||
}
|
||||
|
||||
if request.method == 'POST':
|
||||
form = PhoneLinkChooserForm(request.POST, initial=initial_data, prefix='phone-link-chooser')
|
||||
|
||||
if form.is_valid():
|
||||
result = {
|
||||
'url': 'tel:' + form.cleaned_data['phone_number'],
|
||||
'title': form.cleaned_data['link_text'].strip() or form.cleaned_data['phone_number'],
|
||||
# If the user has explicitly entered / edited something in the link_text field,
|
||||
# always use that text. If not, we should favour keeping the existing link/selection
|
||||
# text, where applicable.
|
||||
'prefer_this_title_as_link_text': ('link_text' in form.changed_data),
|
||||
}
|
||||
return render_modal_workflow(
|
||||
request, None, None,
|
||||
None, json_data={'step': 'external_link_chosen', 'result': result}
|
||||
)
|
||||
else:
|
||||
form = PhoneLinkChooserForm(initial=initial_data, prefix='phone-link-chooser')
|
||||
|
||||
return render_modal_workflow(
|
||||
request,
|
||||
'wagtailadmin/chooser/phone_link.html', None,
|
||||
shared_context(request, {
|
||||
'form': form,
|
||||
}), json_data={'step': 'phone_link'}
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue