[solved] How do I periodically update specific page elements?

188 views
Skip to first unread message

Lost Admin

unread,
Sep 16, 2018, 12:58:20 PM9/16/18
to tiddl...@googlegroups.com
Background

I've set-up rrdtool to generate graphs of various data elements. I'm using a tiddlywiki to display those graphs. The graphs are refreshed every 5 minutes (some will be refreshed less often in the future). I would like to have TiddlyWiki refresh the images periodically (once every 5 minutes initially).

What I think I want to do

I think the way I should do this is to create a javascript macro that gets called when the tiddler is displayed and uses setInterval() to periodically refresh the images within the tiddler.

How do I get from "this" to the list of image elements within a tiddler?

I can't figure out how to identify the images in question. I've currently got the following in the javascript macro (based on the example from TW5 Magick:

/*\
title: $:/macros/lost/5mImgRefresh.js
type: application/javascript
module-type: macro

<<5mImgRefresh>>

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

exports.name = "5mImgRefresh";

exports.params = [];

/*
Run the macro
*/
exports.run = function() {

   var imgElements = this.getElementsByTagName('img');

/* loop through elements in imgElements and update once every 5 minutes */ setInterval(function() { for (var i = 0; i < imgElements.length; i++) { var img = imgElements[i]; img.src = img.src + '?c=' + Math.random(); }, 300000); /* for debugging, print the source list once */ var output = 'Img Urls:'; for (var i = 0; i < imgElements.length; i++) { var img = imgElements[i]; output += img.src; } return output; }; })();



Alternative

I'm quite happy to tie this specifically to the image being displayed (in some way). I will eventually want to define the refresh time and
probably limit the which images get refreshed.

I would also be happy to have a refresh that doesn't need to include a pointless query parameter to the image.

Future

I would like to modify it so that I can insert data other than images. Like possibly logs put inside a div or converted into tables.

Jed Carty

unread,
Sep 16, 2018, 1:10:33 PM9/16/18
to TiddlyWiki
I think that the easiest way to do it would be to give each image a unique class name, or each group that is supposed to be updated on a specific interval the same class name, then use getElementsByClassName instead of by tag.

I think that an alternative method for doing this that may be a bit more flexible for your future plans is to make a daemon process in a startup module that triggers once ever n minutes and then runs a script then. The startup actions in the core is an example and the trigger actions plugin I made does a similar thing but the trigger is a change to a tiddler instead of a timer.

My trigger actions plugin is here if you want it as a reference https://ooktech.com/jed/ExampleWikis/TriggerActions/
I am not sure if there is a way to use it directly. Eventually I need to rewrite it using the same logic as the startup actions in the core, but it works.

If the data comes from server-side components that you can access than you could use websockets to update it but that may take a bit more work. It would give you much more control over how and when things up date though.

Lost Admin

unread,
Sep 16, 2018, 1:30:23 PM9/16/18
to tiddl...@googlegroups.com
I will look into the startup action once I've got a macro working. That does sound like a better idea.

Websockets would be good, but that will require that I figure out how to make websockets work.

Lost Admin

unread,
Sep 16, 2018, 4:17:21 PM9/16/18
to tiddl...@googlegroups.com
After much fiddling, I have a working update macro.

/*\
title: $:/macros/lost/imageupdate.js
type: application/javascript
module-type: macro

embed images with class='u5m'
put <<imageupdate>> at the bottom
all images with that class will be updated every 5 minutes


\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

exports.name = "imageupdate";


exports.params = [];

/*
Run the macro
*/
exports.run = function() {

   setInterval(function() {
      var imgElements = document.getElementsByClassName('u5m');
      /* var srclist = ''; */

      for (var i = 0; i < imgElements.length; i++) {
         var img = imgElements[i];
         img.src = ( (img.src.indexOf('?') == -1) ? img.src : img.src.substr(0,img.src.indexOf('?')) ) + '?c=' + Math.random();
         /* srclist = srclist + " " + img.src; */
     }
     document.getElementById('iuon').innerHTML = 'Refreshed ' + Date(); /*+ "<br>" + srclist; */
   }, 300000); /* 300000 for 5 minutes */


   /* for debugging, print the source list once */
   var imgElements = document.getElementsByClassName('u5m');

   var output = 'Img Urls:';
   for (var i = 0; i < imgElements.length; i++) {
      var img = imgElements[i];
      output = output + " " + img.src;
   }

   return '<span id="iuon">Refreshed ' + Date() /* + output */ + '</span>';
};

})();

Mat

unread,
Sep 16, 2018, 4:47:15 PM9/16/18
to TiddlyWiki
@Lost Admin

This is of great interest for a thing I'm working on for TWederation, hopefully soon to be published. As you may know Jed has built a special server (Bob) and also a plugin (TWederBob) that enables a wiki to fetch tiddlers from the remote server. I would like for this fetching (an action widget) to trigger periodically.

Would it be possible to use your creation for that? I.e to trigger an action widget at set time intervals?

<:-)

Jed Carty

unread,
Sep 17, 2018, 8:37:10 AM9/17/18
to TiddlyWiki
The biggest problem I see with a macro based solution like this is that it may get called multiple times (and start multiple timers that all do the same thing) because it runs unconditionally when rendered and nothing removes the setInterval.

I think that a much better solution would be to make a startup module that starts a background daemon that will run a set of action widgets at configurable intervals. It shouldn't be too difficult to make, if I have the time I will try and put something together.

Lost Admin

unread,
Sep 17, 2018, 11:15:44 AM9/17/18
to TiddlyWiki
Hi Mat,

It would certainly be possible to do so but, I agree with what Jed said, if the macro gets called multiple times it will create multiple instances of the timer event. This is probably not what what you want (and certainly not what I want).

The relevant bit of code (from above) that creates the timer event is this ...

setInterval(function() {
      /* Put your code here, it gets triggered every 300000 milliseconds (5 minutes) */

   }, 300000); /* 300000 for 5 minutes */

Jed had also suggested (in an earlier thread) that it would probably be better to put it into a startup module. I'll be figuring out how to create a startup module and moving the logic there. If I have time, I'll figure out how to add to the settings so that people can define the trigger period and class name.

On Monday, September 17, 2018 at 8:37:10 AM UTC-4, Jed Carty wrote:
The biggest problem I see with a macro based solution like this is that it may get called multiple times (and start multiple timers that all do the same thing) because it runs unconditionally when rendered and nothing removes the setInterval.

I think that a much better solution would be to make a startup module that starts a background daemon that will run a set of action widgets at configurable intervals. It shouldn't be too difficult to make, if I have the time I will try and put something together.

I agree. That's my next step. 

TonyM

unread,
Sep 17, 2018, 8:10:10 PM9/17/18
to TiddlyWiki
Lost Admin,

This sounds like a useful feature to develop especially for dashboard style tiddlywikis that display information sourced externally. 

All I would like to suggest to make this as modular and generic as possible with the minimum impact on performance that can be achived.

The reason I say this is in the case of a dash board solution it would be very easy to quickly load it with multiple refresh requirements, and the simpler and better performance the solution the more you will avoid a performance bottle neck.

Please share your eventual solution if possible.
I will assist if I can.

Tony

TonyM

unread,
Sep 17, 2018, 8:12:52 PM9/17/18
to TiddlyWiki
Jed,

Perhaps the code in the startup modul could process a "refresh queue". Ie if tiddler a b and C displayed in the story river refresh at each interval, ideally those with a specific tag or field name.

Regards
Tony

Lost Admin

unread,
Sep 18, 2018, 9:57:02 AM9/18/18
to tiddl...@googlegroups.com
I am using it for a simple dashboard type wiki. It is very much still a prototype.When I develop my tiddlywiki development skills sufficiently I plan to move it from a macro to a startup module and built a small plugin so others can use it.

At the moment it only updates images with a class of "u5m" (update every 5 minutes). It is only fetching updates to images that are actually displayed (well actually show up in the document DOM).

My dashboard uses [img class="u5m"[/path/to/image.jpg]] to insert the images. The images I'm using are generated by rrdtool. I built it this way so I could get some basic system reporting on a tiny (512MB RAM) VPS. I initially tried installing an open source tool to do the monitoring but it was using too much RAM. Now I run a shell script from cron once every 5 minutes that updates the rrds maintained by rrdtool and updates the graphs. Nice and simple. And conveniently, I use the tiddlywiki Journal to make notes.

Capture.PNG

the month long and year long (2nd and 3rd image) don't have a class tag and don't get updated since they change very slowly. So only the top graph actually gets refreshed once every 5 minutes and only when it is actually shown (the ones in Disk and Memory won't unless I flip to those tabs or open the tiddlers directly).
Reply all
Reply to author
Forward
0 new messages