diff --git a/plugins/tiddlywiki/confetti/confetti-manager.js b/plugins/tiddlywiki/confetti/confetti-manager.js new file mode 100644 index 000000000..343412d67 --- /dev/null +++ b/plugins/tiddlywiki/confetti/confetti-manager.js @@ -0,0 +1,50 @@ +/*\ +title: $:/plugins/tiddlywiki/confetti/confetti-manager.js +type: application/javascript +module-type: global + +Confetti manager + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +var confetti = require("$:/plugins/tiddlywiki/confetti/confetti.js"); + +function ConfettiManager() { + this.outstandingTimers = []; +} + +ConfettiManager.prototype.launch = function (delay,options) { + var self = this; + if(delay > 0) { + var id = setTimeout(function() { + var p = self.outstandingTimers.indexOf(id); + if(p !== -1) { + self.outstandingTimers.splice(p,1); + } else { + console.log("Confetti Manager Error: Cannot find previously stored timer ID"); + debugger; + } + confetti(options); + },delay); + this.outstandingTimers.push(id); + } else { + confetti(options); + } +}; + +ConfettiManager.prototype.reset = function () { + $tw.utils.each(this.outstandingTimers,function(id) { + clearTimeout(id); + }); + this.outstandingTimers = []; + confetti.reset(); +}; + +exports.ConfettiManager = ConfettiManager; + +})(); diff --git a/plugins/tiddlywiki/confetti/confetti-widget.js b/plugins/tiddlywiki/confetti/confetti-widget.js new file mode 100644 index 000000000..6c78f7066 --- /dev/null +++ b/plugins/tiddlywiki/confetti/confetti-widget.js @@ -0,0 +1,67 @@ +/*\ +title: $:/plugins/tiddlywiki/confetti/confetti-widget.js +type: application/javascript +module-type: widget + +Confetti widget + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +var Widget = require("$:/core/modules/widgets/widget.js").widget; + +var confetti = require("$:/plugins/tiddlywiki/confetti/confetti.js"); + +var ConfettiWidget = function(parseTreeNode,options) { + this.initialise(parseTreeNode,options); +}; + +/* +Inherit from the base widget class +*/ +ConfettiWidget.prototype = new Widget(); + +/* +Render this widget into the DOM +*/ +ConfettiWidget.prototype.render = function(parent,nextSibling) { + var self = this; + // Remember parent + this.parentDomNode = parent; + // Compute attributes and execute state + this.computeAttributes(); + this.execute(); + // Launch confetti + if($tw.browser) { + var options = {}; + $tw.utils.each(this.attributes,function(attribute,name) { + options[name] = self.getAttribute(name); + }); + $tw.confettiManager.launch(options.delay,options); + } + // Render children + this.renderChildren(parent,nextSibling); +}; + +/* +Compute the internal state of the widget +*/ +ConfettiWidget.prototype.execute = function() { + // Make child widgets + this.makeChildWidgets(); +}; + +/* +Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering +*/ +ConfettiWidget.prototype.refresh = function(changedTiddlers) { + return this.refreshChildren(changedTiddlers); +}; + +exports.confetti = ConfettiWidget; + +})(); diff --git a/plugins/tiddlywiki/confetti/examples/staggered.tid b/plugins/tiddlywiki/confetti/examples/staggered.tid new file mode 100644 index 000000000..8b45ceef4 --- /dev/null +++ b/plugins/tiddlywiki/confetti/examples/staggered.tid @@ -0,0 +1,9 @@ +title: $:/plugins/tiddlywiki/confetti/examples/staggered +tags: $:/tags/ConfettiExample + +<$button> +<$action-sendmessage $message="tm-confetti-launch"/> +<$action-sendmessage $message="tm-confetti-launch" originY=0.6 spread=70 delay=300/> +<$action-sendmessage $message="tm-confetti-launch" originY=0.55 spread=30 delay=600/> +Launch three staggered rounds of confetti + diff --git a/plugins/tiddlywiki/confetti/examples/typing-trigger.tid b/plugins/tiddlywiki/confetti/examples/typing-trigger.tid new file mode 100644 index 000000000..a87bf7aab --- /dev/null +++ b/plugins/tiddlywiki/confetti/examples/typing-trigger.tid @@ -0,0 +1,10 @@ +title: $:/plugins/tiddlywiki/confetti/examples/typing-trigger +tags: $:/tags/ConfettiExample + +<$edit-text tiddler="$:/temp/confetti/launchstatus" tag="input" placeholder="Type here"/> + +<$list filter="[{$:/temp/confetti/launchstatus}match:caseinsensitive[launch]]" variable="ignore"> +Launched! +<$confetti particleCount=100/> +<$confetti particleCount=100 delay=300/> + diff --git a/plugins/tiddlywiki/confetti/readme.tid b/plugins/tiddlywiki/confetti/readme.tid index faed88c6a..d9606ea6a 100644 --- a/plugins/tiddlywiki/confetti/readme.tid +++ b/plugins/tiddlywiki/confetti/readme.tid @@ -1,16 +1,50 @@ title: $:/plugins/tiddlywiki/confetti/readme +\define show-example(name) +<$let title={{{ [[$:/plugins/tiddlywiki/confetti/examples/]addsuffix<__name__>] }}}> + +For example: + +<$macrocall $name="copy-to-clipboard-above-right" src=<<__src__>>/> + +<$codeblock code={{{ [get[text]] }}}/> + +Renders as: + +<$transclude tiddler=<<title>> mode="block"/> + +</$let> +\end + ! Introduction This plugin adds a programmable confetti cannon to your TiddlyWiki. It is based on https://www.kirilv.com/canvas-confetti/ by Kiril Vatev. ! Usage -The confetti cannon is controlled using messages. +The confetti cannon can be controlled using messages or via the `<$confetti>` widget. Use the message approach when triggering confetti in response to an action (such as clicking a button). Use the widget approach when confetti is to be triggered by a condition (such as a target number of words being reached). -!! Message: tm-confetti-launch +!! Messages: tm-confetti-launch and tm-confetti-reset -The `tm-confetti-launch` message launches the confetti cannon. The following options are supported: +The `tm-confetti-launch` message launches the confetti cannon. See below for the available parameters. + +The `tm-confetti-reset` message cancels any confetti that is in progress. + +<<show-example staggered>> + +!! Widget: `<$confetti>` + +The `<$confetti>` widget launches the confetti cannon when it is first rendered. See below for the available attributes. + +Typically it is used in conjunction with a `<$list>` or `<$reveal>` widget that shows the widget when the conditions required to trigger the confetti are satisfied. + +In this example, the confetti will be launched when the word "launch" in typed into the box. + +<<show-example typing-trigger>> + +!! Confetti Launch parameters + +The following options are supported: |!Name |!Description |!Default | |''delay'' |Number of milliseconds to delay the launch |0 | @@ -29,14 +63,3 @@ The `tm-confetti-launch` message launches the confetti cannon. The following opt |''scalar'' |Scale factor for each confetti particle. Use decimals to make the confetti smaller |1 | |''zIndex'' |Z-index of confetti. Increase the value if the confetti is appearing behind other on-screen elements|100 | |''disableForReducedMotion'' |Set to `yes` to entirely disable confetti for users that [[prefer reduced motion|https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion]] |`no` | - -<$button> -<$action-sendmessage $message="tm-confetti-launch"/> -<$action-sendmessage $message="tm-confetti-launch" originY=0.6 spread=70 delay=300/> -<$action-sendmessage $message="tm-confetti-launch" originY=0.55 spread=30 delay=600/> -Launch -</$button> - -!! Message: tm-confetti-reset - -The `tm-confetti-reset` message stops any active confetti. diff --git a/plugins/tiddlywiki/confetti/startup.js b/plugins/tiddlywiki/confetti/startup.js index 391da3878..773d8e9fe 100644 --- a/plugins/tiddlywiki/confetti/startup.js +++ b/plugins/tiddlywiki/confetti/startup.js @@ -12,8 +12,6 @@ Setup the root widget event handlers /*global $tw: false */ "use strict"; -var confetti = require("$:/plugins/tiddlywiki/confetti/confetti.js"); - // Export name and synchronous status exports.name = "confetti"; exports.platforms = ["browser"]; @@ -22,7 +20,7 @@ exports.synchronous = true; // Install the root widget event handlers exports.startup = function() { - var manager = new ConfettiManager(); + $tw.confettiManager = new $tw.ConfettiManager(); $tw.rootWidget.addEventListener("tm-confetti-launch",function(event) { var paramObject = event.paramObject || {}, options = {}, @@ -47,42 +45,11 @@ exports.startup = function() { }; extractBooleanParameter("disableForReducedMotion"); var delay = paramObject.delay ? $tw.utils.parseNumber(paramObject.delay) : 0; - manager.launch(delay,options); + $tw.confettiManager.launch(delay,options); }); $tw.rootWidget.addEventListener("tm-confetti-reset",function(event) { - manager.reset(); + $tw.confettiManager.reset(); }); }; -function ConfettiManager() { - this.outstandingTimers = []; -} - -ConfettiManager.prototype.launch = function (delay,options) { - var self = this; - if(delay > 0) { - var id = setTimeout(function() { - var p = self.outstandingTimers.indexOf(id); - if(p !== -1) { - self.outstandingTimers.splice(p,1); - } else { - console.log("Confetti Manager Error: Cannot find previously stored timer ID"); - debugger; - } - confetti(options); - },delay); - this.outstandingTimers.push(id); - } else { - confetti(options); - } -}; - -ConfettiManager.prototype.reset = function () { - $tw.utils.each(this.outstandingTimers,function(id) { - clearTimeout(id); - }); - this.outstandingTimers = []; - confetti.reset(); -}; - })();