BTHLABS-56: _Copy share link_ button in view association page
Co-authored-by: Tomek Wójcik <labs@tomekwojcik.pl> Co-committed-by: Tomek Wójcik <labs@tomekwojcik.pl>
This commit is contained in:
parent
ab84f685c0
commit
d1e60babf4
|
@ -0,0 +1,58 @@
|
||||||
|
/*!
|
||||||
|
* HotPocket by BTHLabs (https://hotpocket.app/)
|
||||||
|
* Copyright 2025-present BTHLabs <contact@bthlabs.pl> (https://bthlabs.pl/)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
((HotPocket) => {
|
||||||
|
class HotPocketUIPasteboardLinkPlugin {
|
||||||
|
constructor (app) {
|
||||||
|
}
|
||||||
|
onLoad (event) {
|
||||||
|
let canCopy = false;
|
||||||
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||||
|
canCopy = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let pasteboardLink of document.querySelectorAll('.ui-pasteboard-link')) {
|
||||||
|
if (canCopy === false) {
|
||||||
|
pasteboardLink.classList.add('d-none');
|
||||||
|
} else {
|
||||||
|
pasteboardLink.addEventListener('click', this.onClick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onClick = (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const icon = event.target.querySelector('i.bi');
|
||||||
|
icon.classList.replace('bi-clipboard-fill', 'bi-clipboard');
|
||||||
|
|
||||||
|
navigator.clipboard.writeText(event.target.href).
|
||||||
|
then(() => {
|
||||||
|
icon.classList.replace('bi-clipboard', 'bi-clipboard-fill');
|
||||||
|
}).
|
||||||
|
catch((reason) => {
|
||||||
|
console.error('HotPocket.UI.PasteboardLink.onClick()', reason);
|
||||||
|
window.alert('Could not copy the link :(');
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
HotPocket.addPlugin('UI.PasteboardLink', (app) => {
|
||||||
|
return new HotPocketUIPasteboardLinkPlugin(app);
|
||||||
|
});
|
||||||
|
})(window.HotPocket);
|
|
@ -41,7 +41,20 @@
|
||||||
if (navigator.share) {
|
if (navigator.share) {
|
||||||
shareButton.addEventListener('click', this.onShareButtonClick);
|
shareButton.addEventListener('click', this.onShareButtonClick);
|
||||||
} else {
|
} else {
|
||||||
shareButton.addClass('d-none');
|
shareButton.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uiPlugin = this.app.plugin('UI');
|
||||||
|
for (let controlButton of document.querySelectorAll('#ViewAssociationView .ui-controls > a.btn')) {
|
||||||
|
if (uiPlugin.jsEnabled === true) {
|
||||||
|
if (controlButton.classList.contains('ui-noscript-show')) {
|
||||||
|
controlButton.remove();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (controlButton.classList.contains('ui-noscript-hide')) {
|
||||||
|
controlButton.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -59,12 +72,9 @@
|
||||||
onShareButtonClick = (event) => {
|
onShareButtonClick = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const shareUrl = new URL(window.location.href);
|
|
||||||
shareUrl.searchParams.set('share', 'true');
|
|
||||||
|
|
||||||
navigator.share({
|
navigator.share({
|
||||||
title: document.title,
|
title: document.title,
|
||||||
url: shareUrl.toString(),
|
url: event.target.href,
|
||||||
});
|
});
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
class HotPocketUIPlugin {
|
class HotPocketUIPlugin {
|
||||||
constructor (app) {
|
constructor (app) {
|
||||||
document.body.classList.add('ui-js-enabled');
|
document.body.classList.add('ui-js-enabled');
|
||||||
|
this.jsEnabled = document.body.classList.contains('ui-js-enabled');
|
||||||
|
|
||||||
if (window.navigator.standalone === true) {
|
if (window.navigator.standalone === true) {
|
||||||
document.querySelector('body').classList.add('ui-mode-standalone');
|
document.querySelector('body').classList.add('ui-mode-standalone');
|
||||||
|
|
|
@ -25,8 +25,8 @@
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
{% if show_controls %}
|
{% if show_controls %}
|
||||||
<p class="mb-3 text-center">
|
<div class="d-flex justify-content-center mb-3">
|
||||||
{% spaceless %}
|
<div class="btn-group ui-controls" role="group">
|
||||||
<a
|
<a
|
||||||
class="btn btn-primary btn-sm"
|
class="btn btn-primary btn-sm"
|
||||||
href="{% url 'ui.associations.edit' pk=association.pk %}"
|
href="{% url 'ui.associations.edit' pk=association.pk %}"
|
||||||
|
@ -35,14 +35,29 @@
|
||||||
<i class="bi bi-pencil"></i> {% translate 'Edit' %}
|
<i class="bi bi-pencil"></i> {% translate 'Edit' %}
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
class="btn btn-secondary btn-sm ms-2 ui-noscript-hide ui-share-button"
|
class="btn btn-secondary btn-sm ui-noscript-hide ui-share-button"
|
||||||
href="#"
|
href="{{ share_url }}"
|
||||||
role="button"
|
role="button"
|
||||||
>
|
>
|
||||||
<i class="bi bi-box-arrow-up"></i> {% translate 'Share' %}
|
<i class="bi bi-box-arrow-up"></i> {% translate 'Share' %}
|
||||||
</a>
|
</a>
|
||||||
{% endspaceless %}
|
<a
|
||||||
</p>
|
class="btn btn-secondary btn-sm ui-noscript-hide ui-pasteboard-link"
|
||||||
|
href="{{ share_url }}"
|
||||||
|
role="button"
|
||||||
|
>
|
||||||
|
<i class="bi bi-clipboard"></i> {% translate 'Copy share link' %}
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class="btn btn-secondary btn-sm ui-noscript-show"
|
||||||
|
href="{{ share_url }}"
|
||||||
|
rel="noopener noreferer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<i class="bi bi-link-45deg"></i> {% translate 'Share link' %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if association.description %}
|
{% if association.description %}
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
|
|
|
@ -152,6 +152,7 @@
|
||||||
<script src="{% static 'ui/js/hotpocket-backend.ui.ViewAssociationView.js' %}" type="text/javascript"></script>
|
<script src="{% static 'ui/js/hotpocket-backend.ui.ViewAssociationView.js' %}" type="text/javascript"></script>
|
||||||
<script src="{% static 'ui/js/hotpocket-backend.ui.BrowseAccountAppsView.js' %}" type="text/javascript"></script>
|
<script src="{% static 'ui/js/hotpocket-backend.ui.BrowseAccountAppsView.js' %}" type="text/javascript"></script>
|
||||||
<script src="{% static 'ui/js/hotpocket-backend.ui.InlineCreateSaveForm.js' %}" type="text/javascript"></script>
|
<script src="{% static 'ui/js/hotpocket-backend.ui.InlineCreateSaveForm.js' %}" type="text/javascript"></script>
|
||||||
|
<script src="{% static 'ui/js/hotpocket-backend.ui.PasteboardLink.js' %}" type="text/javascript"></script>
|
||||||
{% block page_scripts %}{% endblock %}
|
{% block page_scripts %}{% endblock %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
(() => {
|
(() => {
|
||||||
|
|
|
@ -198,12 +198,21 @@ def view(request: HttpRequest, pk: uuid.UUID) -> HttpResponse:
|
||||||
if is_share is True:
|
if is_share is True:
|
||||||
show_controls = show_controls and False
|
show_controls = show_controls and False
|
||||||
|
|
||||||
|
share_url = reverse(
|
||||||
|
'ui.associations.view',
|
||||||
|
args=(association.pk,),
|
||||||
|
query=[
|
||||||
|
('share', 'true'),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
'ui/associations/view.html',
|
'ui/associations/view.html',
|
||||||
{
|
{
|
||||||
'association': association,
|
'association': association,
|
||||||
'show_controls': show_controls,
|
'show_controls': show_controls,
|
||||||
|
'share_url': share_url,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,14 @@ def test_authenticated_ok(authenticated_client: Client,
|
||||||
assert hasattr(result.context['association'], 'target') is True
|
assert hasattr(result.context['association'], 'target') is True
|
||||||
assert result.context['association'].target.pk == association_out.target.pk
|
assert result.context['association'].target.pk == association_out.target.pk
|
||||||
assert result.context['show_controls'] is True
|
assert result.context['show_controls'] is True
|
||||||
|
assert 'share_url' in result.context
|
||||||
|
|
||||||
|
expected_share_url = reverse(
|
||||||
|
'ui.associations.view',
|
||||||
|
args=(association_out.pk,),
|
||||||
|
query=[('share', 'true')],
|
||||||
|
)
|
||||||
|
assert result.context['share_url'] == expected_share_url
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
|
|
Loading…
Reference in New Issue
Block a user