From 78fb4a2c1dbb638b50a716e2df92d115a60ce687 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Wed, 29 May 2024 15:06:33 +0100 Subject: [PATCH] Custom copy clipboard notifications (#8211) * Initial Commit * Improve plugin tests Fixes #8209 * Fix RSOE * Fix extraneous copy to clipboard at startup --- core/modules/startup/rootwidget.js | 5 ++- core/modules/startup/story.js | 18 +++++++-- core/modules/utils/dom/dom.js | 4 +- editions/test/tiddlers/tests/test-plugins.js | 38 +++++++++++-------- .../WidgetMessage_ tm-copy-to-clipboard.tid | 4 +- .../messages/WidgetMessage_ tm-permalink.tid | 4 +- .../messages/WidgetMessage_ tm-permaview.tid | 4 +- 7 files changed, 53 insertions(+), 24 deletions(-) diff --git a/core/modules/startup/rootwidget.js b/core/modules/startup/rootwidget.js index 716275cda..512fc580a 100644 --- a/core/modules/startup/rootwidget.js +++ b/core/modules/startup/rootwidget.js @@ -68,7 +68,10 @@ exports.startup = function() { }); // Install the copy-to-clipboard mechanism $tw.rootWidget.addEventListener("tm-copy-to-clipboard",function(event) { - $tw.utils.copyToClipboard(event.param); + $tw.utils.copyToClipboard(event.param,{ + successNotification: event.paramObject.successNotification, + failureNotification: event.paramObject.failureNotification + }); }); // Install the tm-focus-selector message $tw.rootWidget.addEventListener("tm-focus-selector",function(event) { diff --git a/core/modules/startup/story.js b/core/modules/startup/story.js index 734f6ae76..c58c759c3 100644 --- a/core/modules/startup/story.js +++ b/core/modules/startup/story.js @@ -93,7 +93,9 @@ exports.startup = function() { updateAddressBar: $tw.wiki.getTiddlerText(CONFIG_PERMALINKVIEW_UPDATE_ADDRESS_BAR,"yes").trim() === "yes" ? "permalink" : "none", updateHistory: $tw.wiki.getTiddlerText(CONFIG_UPDATE_HISTORY,"no").trim(), targetTiddler: event.param || event.tiddlerTitle, - copyToClipboard: $tw.wiki.getTiddlerText(CONFIG_PERMALINKVIEW_COPY_TO_CLIPBOARD,"yes").trim() === "yes" ? "permalink" : "none" + copyToClipboard: $tw.wiki.getTiddlerText(CONFIG_PERMALINKVIEW_COPY_TO_CLIPBOARD,"yes").trim() === "yes" ? "permalink" : "none", + successNotification: event.paramObject && event.paramObject.successNotification, + failureNotification: event.paramObject && event.paramObject.failureNotification }); }); // Listen for the tm-permaview message @@ -102,7 +104,9 @@ exports.startup = function() { updateAddressBar: $tw.wiki.getTiddlerText(CONFIG_PERMALINKVIEW_UPDATE_ADDRESS_BAR,"yes").trim() === "yes" ? "permaview" : "none", updateHistory: $tw.wiki.getTiddlerText(CONFIG_UPDATE_HISTORY,"no").trim(), targetTiddler: event.param || event.tiddlerTitle, - copyToClipboard: $tw.wiki.getTiddlerText(CONFIG_PERMALINKVIEW_COPY_TO_CLIPBOARD,"yes").trim() === "yes" ? "permaview" : "none" + copyToClipboard: $tw.wiki.getTiddlerText(CONFIG_PERMALINKVIEW_COPY_TO_CLIPBOARD,"yes").trim() === "yes" ? "permaview" : "none", + successNotification: event.paramObject && event.paramObject.successNotification, + failureNotification: event.paramObject && event.paramObject.failureNotification }); }); } @@ -177,6 +181,8 @@ options.updateAddressBar: "permalink", "permaview" or "no" (defaults to "permavi options.updateHistory: "yes" or "no" (defaults to "no") options.copyToClipboard: "permalink", "permaview" or "no" (defaults to "no") options.targetTiddler: optional title of target tiddler for permalink +options.successNotification: optional title of tiddler to use as the notification in case of success +options.failureNotification: optional title of tiddler to use as the notification in case of failure */ function updateLocationHash(options) { // Get the story and the history stack @@ -205,14 +211,18 @@ function updateLocationHash(options) { break; } // Copy URL to the clipboard + var url = ""; switch(options.copyToClipboard) { case "permalink": - $tw.utils.copyToClipboard($tw.utils.getLocationPath() + "#" + encodeURIComponent(targetTiddler)); + url = $tw.utils.getLocationPath() + "#" + encodeURIComponent(targetTiddler); break; case "permaview": - $tw.utils.copyToClipboard($tw.utils.getLocationPath() + "#" + encodeURIComponent(targetTiddler) + ":" + encodeURIComponent($tw.utils.stringifyList(storyList))); + url = $tw.utils.getLocationPath() + "#" + encodeURIComponent(targetTiddler) + ":" + encodeURIComponent($tw.utils.stringifyList(storyList)); break; } + if(url) { + $tw.utils.copyToClipboard(url,{successNotification: options.successNotification, failureNotification: options.failureNotification}); + } // Only change the location hash if we must, thus avoiding unnecessary onhashchange events if($tw.utils.getLocationHash() !== $tw.locationHash) { if(options.updateHistory === "yes") { diff --git a/core/modules/utils/dom/dom.js b/core/modules/utils/dom/dom.js index 338d96280..4ba037ed5 100644 --- a/core/modules/utils/dom/dom.js +++ b/core/modules/utils/dom/dom.js @@ -292,7 +292,9 @@ exports.copyToClipboard = function(text,options) { } catch (err) { } if(!options.doNotNotify) { - $tw.notifier.display(succeeded ? "$:/language/Notifications/CopiedToClipboard/Succeeded" : "$:/language/Notifications/CopiedToClipboard/Failed"); + var successNotification = options.successNotification || "$:/language/Notifications/CopiedToClipboard/Succeeded", + failureNotification = options.failureNotification || "$:/language/Notifications/CopiedToClipboard/Failed" + $tw.notifier.display(succeeded ? successNotification : failureNotification); } document.body.removeChild(textArea); }; diff --git a/editions/test/tiddlers/tests/test-plugins.js b/editions/test/tiddlers/tests/test-plugins.js index 663192a9c..8e79efe24 100644 --- a/editions/test/tiddlers/tests/test-plugins.js +++ b/editions/test/tiddlers/tests/test-plugins.js @@ -22,22 +22,30 @@ if($tw.node) { describe("every plugin should have the required standard fields", function() { var titles = Object.keys(tiddlers); $tw.utils.each(titles,function(title) { - it("plugin " + title + " should have the required standard fields",function() { - var fields = tiddlers[title]; - expect(fields["plugin-type"]).toMatch(/^(?:plugin|language|theme)$/); - switch(fields["plugin-type"]) { - case "plugin": - expect(!!(fields.name && fields.description && fields.list)).toEqual(true); - expect(fields.stability).toMatch(/^(?:STABILITY_0_DEPRECATED|STABILITY_1_EXPERIMENTAL|STABILITY_2_STABLE|STABILITY_3_LEGACY)$/); - break; - case "language": - expect(!!(fields.name && fields.description)).toEqual(true); - break; - case "theme": - expect(!!(fields.name && fields.description)).toEqual(true); - break; - } + var fields = tiddlers[title]; + it("plugin should have a recognised plugin-type field",function() { + expect(["plugin","language","theme"].indexOf(fields["plugin-type"]) !== -1).toEqual(true); }); + switch(fields["plugin-type"]) { + case "plugin": + it("plugin " + title + " should have name, description and list fields",function() { + expect(!!(fields.name && fields.description && fields.list)).toBe(true); + }); + it("plugin " + title + " should have a valid stability field",function() { + expect(["STABILITY_0_DEPRECATED","STABILITY_1_EXPERIMENTAL","STABILITY_2_STABLE","STABILITY_3_LEGACY"].indexOf(fields.stability) !== -1).toBe(true); + }); + break; + case "language": + it("language " + title + " should have name and description fields",function() { + expect(!!(fields.name && fields.description)).toEqual(true); + }); + break; + case "theme": + it("theme " + title + " should have name and description fields",function() { + expect(!!(fields.name && fields.description)).toEqual(true); + }); + break; + } }); }); }); diff --git a/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-copy-to-clipboard.tid b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-copy-to-clipboard.tid index 70cf2a24a..b9c07465a 100644 --- a/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-copy-to-clipboard.tid +++ b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-copy-to-clipboard.tid @@ -1,6 +1,6 @@ caption: tm-copy-to-clipboard created: 20171215150056004 -modified: 20171215150600888 +modified: 20240523174013095 tags: Messages title: WidgetMessage: tm-copy-to-clipboard type: text/vnd.tiddlywiki @@ -11,6 +11,8 @@ It requires the following properties on the `event` object: |!Name |!Description | |param |Text to be copied to the clipboard | +|successNotification |<<.from-version "5.3.4">> Optional title of tiddler containing notification to be used if the operation succeeds | +|failureNotification |<<.from-version "5.3.4">> Optional title of tiddler containing notification to be used if the operation fails | This message is usually generated with the ButtonWidget. It is handled by the TiddlyWiki core. diff --git a/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-permalink.tid b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-permalink.tid index d2e17952b..60d9362a2 100644 --- a/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-permalink.tid +++ b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-permalink.tid @@ -1,5 +1,5 @@ created: 20140723103751357 -modified: 20140723103751357 +modified: 20240523174013095 tags: Messages title: WidgetMessage: tm-permalink type: text/vnd.tiddlywiki @@ -12,5 +12,7 @@ The permalink message supports the following properties on the `event` object: |!Name |!Description | |param |Title of the tiddler to be permalinked | |tiddlerTitle |The current tiddler (used by default if the tiddler title isn't specified in the `param`) | +|successNotification |<<.from-version "5.3.4">> Optional title of tiddler containing notification to be used if the operation succeeds | +|failureNotification |<<.from-version "5.3.4">> Optional title of tiddler containing notification to be used if the operation fails | The permalink message can be generated by the ButtonWidget, and is handled by the story mechanism. diff --git a/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-permaview.tid b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-permaview.tid index 648cf9a7a..e2959c38e 100644 --- a/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-permaview.tid +++ b/editions/tw5.com/tiddlers/messages/WidgetMessage_ tm-permaview.tid @@ -1,5 +1,5 @@ created: 20140723103751357 -modified: 20140723103751357 +modified: 20240523174013095 tags: Messages title: WidgetMessage: tm-permaview type: text/vnd.tiddlywiki @@ -12,5 +12,7 @@ The permaview message supports the following properties on the `event` object: |!Name |!Description | |param |Title of the tiddler to be navigated within the permaview | |tiddlerTitle |The current tiddler (used by default if the tiddler title isn't specified in the `param`) | +|successNotification |<<.from-version "5.3.4">> Optional title of tiddler containing notification to be used if the operation succeeds | +|failureNotification |<<.from-version "5.3.4">> Optional title of tiddler containing notification to be used if the operation fails | The permaview message can be generated by the ButtonWidget, and is handled by the story mechanism.