From a5c2931085e7cd87459cc4d8486dc5e145d346c9 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Thu, 22 Aug 2024 14:45:25 -0500 Subject: [PATCH] feat: add "copy link" button for sharing a grid view --- .../templates/grids/vue_template.mako | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/wuttaweb/templates/grids/vue_template.mako b/src/wuttaweb/templates/grids/vue_template.mako index 58721a2..84dcb58 100644 --- a/src/wuttaweb/templates/grids/vue_template.mako +++ b/src/wuttaweb/templates/grids/vue_template.mako @@ -16,6 +16,13 @@ ref="gridFilters" />
+ + + + + + + ## dummy input field needed for sharing links on *insecure* sites + % if getattr(request, 'scheme', None) == 'http': + + % endif +
@@ -223,6 +236,11 @@ ## nb. this tracks whether grid.fetchFirstData() happened fetchedFirstData: false, + ## dummy input value needed for sharing links on *insecure* sites + % if getattr(request, 'scheme', None) == 'http': + shareLink: null, + % endif + ## filtering % if grid.filterable: filters: ${json.dumps(grid.get_vue_filters())|n}, @@ -268,6 +286,11 @@ template: '#${grid.vue_tagname}-template', computed: { + directLink() { + const params = new URLSearchParams(this.getAllParams()) + return `${request.path_url}?${'$'}{params}` + }, + % if grid.filterable: addFilterChoices() { @@ -346,12 +369,50 @@ methods: { + copyDirectLink() { + + if (navigator.clipboard) { + // this is the way forward, but requires HTTPS + navigator.clipboard.writeText(this.directLink) + + } else { + // use deprecated 'copy' command, but this just + // tells the browser to copy currently-selected + // text..which means we first must "add" some text + // to screen, and auto-select that, before copying + // to clipboard + this.shareLink = this.directLink + this.$nextTick(() => { + let input = this.$refs.shareLink.$el.firstChild + input.select() + document.execCommand('copy') + // re-hide the dummy input + this.shareLink = null + }) + } + + this.$buefy.toast.open({ + message: "Link was copied to clipboard", + type: 'is-info', + duration: 2000, // 2 seconds + }) + }, + renderNumber(value) { if (value != undefined) { return value.toLocaleString('en') } }, + getAllParams() { + return { + ...this.getBasicParams(), + % if grid.filterable: + ...this.getFilterParams(), + % endif + } + }, + getBasicParams() { const params = { % if grid.paginated and grid.paginate_on_backend: