openvibers/openvibe.wiki Commits

Share: one Share sheet on every article (#219)

OP OpenVibers committed 7 days ago · 765d570f1e · 4 files, +39 −4

* Share: the one Share sheet on every article

Add the network's Share button (data-ov-share-sheet) to the article's page
actions with the canonical address, title and summary (and the first
picture when the article has one).

* Share: the shared kit button, one look everywhere

Render the one Share button with openvibe-shared 4.114.0's kit.share
(or its exact markup where the page is built in the browser), so every
site shows the same quiet button with the share icon. Remove the
site-specific Share styles.

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex 9aa7b12..1fe6b07 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -2,6 +2,7 @@
## Unreleased
++- Share: every article carries the network's one Share button (`data-ov-share-sheet`) in its page actions, with the article's canonical address, title and summary; `openvibe-shared`'s navbar loads the sheet on the first press. `test/share-sheet.test.js`.
- Account export and deletion (ADR-033): `POST /internal/events` (loopback, `WIKI_EVENTS_SECRET`) answers network.account.export_requested and network.account.deleted through `server/wiki/account-data.js` over `openvibe-sdk/account-data` (SDK v0.37.0, was v0.35.0).
- **Deleted:** the person's own user spaces (through `deleteSpace`), roles, watches and drafts.
- **Authorless:** their contributions elsewhere stay without their id.
ddiff --git a/server/http/pages.js b/server/http/pages.js
iindex b68ce81..6b3c342 100644
---- a/server/http/pages.js
++++ b/server/http/pages.js
@@@ -415,8 +415,9 @@ function createPages({ svc, viewers, platform, config, log = console, limits, vi
}),
seo.structuredData.breadcrumbs(crumbsLd),
].filter(Boolean) : null;
-- send(req, res, 200, views.articlePage(v, { html: bodyHtml, discussion, actor: req.actor, mediaUrl: (id) => platform.media.publicUrl(id), resolve: (title) => infoboxLinks.get(title) || { href: null, exists: false }, flash: req.query.saved ? 'Saved.' : null }), {
-- decision, title: v.revision.fields.title, description, ogType: 'article', jsonLd, path: svc.pagePath(space, page), cache: publicCache,
++ const shareMedia = v.attachments.find((a) => a.mediaId && !a.brokenReason);
++ send(req, res, 200, views.articlePage(v, { html: bodyHtml, discussion, actor: req.actor, mediaUrl: (id) => platform.media.publicUrl(id), resolve: (title) => infoboxLinks.get(title) || { href: null, exists: false }, flash: req.query.saved ? 'Saved.' : null, shareUrl: url, shareText: description, shareImage: shareMedia ? platform.media.publicUrl(shareMedia.mediaId) : null }), {
++ decision, title: v.revision.fields.title, description, ogType: 'article', jsonLd, path: svc.pagePath(space, page), cache: publicCache, styles: ['kit.css'],
});
}));
ddiff --git a/server/render/views.js b/server/render/views.js
iindex ca7f187..aecf00e 100644
---- a/server/render/views.js
++++ b/server/render/views.js
@@@ -4,6 +4,7 @@
* unless raw()). Forms are plain HTML posts; nothing here needs JavaScript.
*/
const ssr = require('openvibe-publishing/ssr');
++const kit = require('openvibe-shared/kit');
const showcase = require('openvibe-shared/showcase');
const { figureHtml } = require('openvibe-publishing/media');
const { infoboxToText, mediaRefs } = require('../wiki/content');
@@@ -408,8 +409,9 @@ function pageFacts(v, base) {
return html`<p class="wk-facts">${facts.map((f, i) => html`${i ? html`<span aria-hidden="true"> · </span>` : ''}<span>${f}</span>`)}${badge ? html` ${badge}` : ''}</p>`;
}
--function articlePage(v, { html: contentHtml, discussion, actor, mediaUrl, resolve, flash }) {
++function articlePage(v, { html: contentHtml, discussion, actor, mediaUrl, resolve, flash, shareUrl = '', shareText = '', shareImage = null }) {
const { space, page, revision: rev } = v;
++ const title = rev.fields.title || page.title;
const base = wpath(space, page);
const trail = [{ name: 'Wiki', url: '/' }, { name: space.name, url: `/s/${e(space.slug)}` }];
if (v.parent) trail.push({ name: v.parent.title, url: wpath(space, v.parent) });
@@@ -424,9 +426,10 @@ function articlePage(v, { html: contentHtml, discussion, actor, mediaUrl, resolv
if (v.canEdit && v.decision && !v.decision.indexable && page.state === 'published') banners.push(html`<p class="wk-notice wk-info">Search engines are told not to index this page: ${v.decision.reasons.map((r) => r.code + (r.detail ? ` (${r.detail})` : '')).join(', ')}.</p>`);
const actions = [html`<a href="${base}/history">History</a>`];
if (v.canEdit) actions.unshift(html`<a href="${base}/edit">Edit</a>`), actions.push(html`<a href="${base}/settings">Page settings</a>`);
++ if (shareUrl) actions.unshift(html`${raw(kit.share({ title, url: shareUrl, text: shareText || '', image: shareImage || null }))}`);
return html`${crumbs(trail)}
<article class="wk-article" data-page-id="${page.id}" data-revision="${String(rev.number)}">
--<header><h1>${rev.fields.title || page.title}</h1><nav class="wk-actions" aria-label="Page actions">${actions.map((a, i) => html`${i ? ' · ' : ''}${a}`)}</nav>${pageFacts(v, base)}</header>
++<header><h1>${title}</h1><nav class="wk-actions" aria-label="Page actions">${actions.map((a, i) => html`${i ? ' · ' : ''}${a}`)}</nav>${pageFacts(v, base)}</header>
${banners}
${raw(infoboxHtml(v.infobox, resolve, outRel(space), { media: (id) => { const a = v.attachments.find((x) => x.mediaId === id); return a && mediaUrl ? figureHtml(a, { urlFor: mediaUrl, unavailableText: UNAVAILABLE[a.brokenReason] || UNAVAILABLE.not_found }) : null; } }))}
<div class="wk-content">${raw(contentHtml)}</div>
ddiff --git a/test/share-sheet.test.js b/test/share-sheet.test.js
nnew file mode 100644
iindex 0000000..bf67d71
---- /dev/null
++++ b/test/share-sheet.test.js
@@@ -0,0 +1,30 @@
++'use strict';
++/**
++ * A wiki article carries the network's one Share button (openvibe-shared 4.114.0): one [data-ov-share-sheet] in the
++ * page's own actions, with the article's canonical public address, its title and its summary. The navbar loads the
++ * sheet on the first press, so the page itself loads nothing more.
++ */
++const assert = require('assert');
++const H = require('./helpers');
++
++(async () => {
++ const h = await H.boot();
++ const me = { kind: 'user', subject: H.subject() };
++ try {
++ const space = await h.svc.createSpace({ name: 'Share demo', slug: 'share-demo' }, me);
++ const { page } = await h.svc.createPage(space.id, {
++ title: 'A shareable page', body: `The body of the page. ${H.LONG}`, summary: 'One line about the page.',
++ }, me);
++ await h.svc.publish(page.id, {}, me);
++ const r = await H.req(h, 'GET', `/w/share-demo/${page.slug}`);
++ assert.strictEqual(r.status, 200);
++ assert.strictEqual((r.text.match(/data-ov-share-sheet/g) || []).length, 1, 'one Share button');
++ assert.ok(r.text.includes('data-url="http://wiki.test/w/share-demo/a-shareable-page"'), 'the article address');
++ assert.ok(r.text.includes('data-title="A shareable page"'), 'its title');
++ assert.ok(r.text.includes('data-text="One line about the page."'), 'its summary');
++ assert.ok(r.text.includes('class="ovk-btn ovk-btn--quiet"') && r.text.includes('<span>Share</span>'), 'the shared kit button');
++ console.log('share sheet ok');
++ } finally {
++ await h.stop();
++ }
++})().catch((e) => { console.error(e); process.exit(1); });