[TW5] Plugin does not listen to changes

233 views
Skip to first unread message

Felix Küppers

unread,
Oct 22, 2014, 3:33:24 PM10/22/14
to tiddly...@googlegroups.com
Hi,

Short Introduction:
My goal is to create a plugin that visualizes certain tiddlers via vis.js on a canvas and update the canvas everytime a tiddler is saved or deleted. Hence, I need to subscribe to save-tiddler and delete-tiddler events.

My Problem:
The object TaskGraphWidget is never instanciated by TW (as the console message "creating object" is not issued) and the event listeners are not registered (no handler code is executed). However, if I compile the code below it creates a wiki that contains the plugin (I can verify that via ControlPanel->Plugins) and also the console message "hello world" (at the very bottom of the code) is executed.

/*\
title: $:/plugins/felixhayashi/taskgraph/taskgraph.js
type: application/javascript
module-type: widget

TaskGraphWidget class

\*/

(function(){

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

var Widget = require("$:/core/modules/widgets/widget.js").widget;

var TaskGraphWidget = function(parseTreeNode, options) {
 
  console
.log("creating object");
 
 
// Main initialisation inherited from widget.js
 
this.initialise(parseTreeNode, options);
 
 
this.addEventListeners([
   
{type: "tm-delete-tiddler", handler: "handleWikiContentChange"},
   
{type: "tm-save-tiddler", handler: "handleWikiContentChange"}
 
]);
 
};

/*
Inherit from the base widget class
*/

TaskGraphWidget.prototype = new Widget();

TaskGraphWidget.prototype.handleWikiContentChange = function(event) {
  console
.log("content change");
};

console.log("hello world");

exports
.taskgraph = TaskGraphWidget;

})();


I looked at all the docs and compared my code to the code in the repository.

My plugin.info looks like this

{
  "title": "$:/plugins/felixhayashi/taskgraph",
  "description": "Extending TW5 to become an innovative ticket system",
  "author": "felixhayashi",
  "version": "0.0.1",
  "core-version": ">=5.1.3",
  "source": "https://github.com/felixhayashi/taskgraph",
  "type": "application/json",
  "plugin-type": "plugin"
}

Any help is much appreciated.

Regards Felix


BJ

unread,
Oct 22, 2014, 6:09:59 PM10/22/14
to tiddly...@googlegroups.com
Hi Felix,
the message "hello world" will appear once when the tiddler containing you code is loaded. The "creating object" will only appear when you use your widget - you need to put <$taskgraph> </$taskgraph> into to some tiddler then view that tiddler (this will have once you have finished editing it).

Be aware that messages such as "tm-save-tiddler" travel from the leaves of the widget tree to the root, this means you widget will only see these messages from other widgets that descend from it (ie messages are passed up from its child widget).  If you want to listen for changes to tiddlers in general, the names of changed tiddler are broadcast through the refresh mechanism.

Cheers

BJ

Felix Küppers

unread,
Oct 23, 2014, 5:49:52 AM10/23/14
to tiddly...@googlegroups.com
Hello BJ,

thank you for your response, you helped me quite a lot with your answer, however, I am still stuck a bit :(

Putting <$taskgraph></$taskgraph> into a tiddler instantiated the object.
But isn't it possible to start the widget automatically after everything else has booted? Similar to init scripts in linux which get called during boot?

I looked at the widget base class and overrode the refresh method.

TaskGraphWidget.prototype.refresh = function(changedTiddlers) {
  console
.log("refresh");
};

While this method certainly got triggered, it is called also for changes that are not save and delete events.

Why doesn't "addEventListeners" work?

A guess: Maybe the module-type "widget" is wrong? I looked at http://tiddlywiki.com/#ModuleType. However, there is no explanation for the various module-types.

In the dev wiki, the sartup module-type http://tiddlywiki.com/dev/#Startup%20Process looks promising, but how to I register my listeners for save and delete tiddler events?

Regards
Felix

TheDiveO

unread,
Oct 23, 2014, 6:13:20 AM10/23/14
to tiddly...@googlegroups.com
Hi Felix,

if you need to do something during startup once, then widgets are the wrong thing. Module-type "startup" would come to my mind here, albeit I'm unsure as to whether they are would you need here. What exactly do you want to achieve? This is important, as TW5 has so many different module type for all the different tasks to tackle. For instance, there are libraries, globals, and so many more types.

Regards,
TheDiveO

Felix Küppers

unread,
Oct 23, 2014, 6:55:35 AM10/23/14
to tiddly...@googlegroups.com
Hi TheDiveO,

Well to put it shortly:

My Plugin should insert a canvas into the dom automatically at startup and then register listeners for save and delete events of tiddlers (maybe some other events too). Tiddlers that possess a certain tag are drawn onto the canvas at startup. Everytime tiddlers are saved or deleted, the canvas should be updated.

I am a bit puzzled by the event mechanism. I am used to frameworks where I can just subscribe to any system event centrally. However, in TW, system-events seem to be bound to different objects.

Using the startup module-type works fine to run the code after the basic modules have been enabled (I am using exports.after = ["startup"]).

But how do I listen to the events named above (or any events issued by the system)?

Thanks for the help
Felix

TheDiveO

unread,
Oct 23, 2014, 7:21:45 AM10/23/14
to tiddly...@googlegroups.com
From your description I would say that startup modules are not what you are looking for. Your initial attempt using a widget seems much more plausible. You probably want your canvas to be in a tiddler and not somewhere else.

One thing to decide on is whether you want to track tiddlers or their rendered representation. Monitoring tiddlers is about monitoring changes to the store. I don't yet remember the details, but looking at the core syncer should tell you how to monitor changes to the store, as the syncer needs to do exactly this.

Monitoring events won't allow you to see all the changes. Instead, events control and reflect user actions.

Regards,
TheDiveO

TheDiveO

unread,
Oct 23, 2014, 8:22:46 AM10/23/14
to tiddly...@googlegroups.com
Looking at https://github.com/Jermolene/TiddlyWiki5/blob/master/core/modules/syncer.js#L36 I see that you need to register an event listener with the wiki object:

$tw.wiki.addEventListener("change",function(changes) {...});

This is different from the widget-related events you were probably looking at before, that is, the event names starting with "tm-".

Regards,
TheDiveO

Felix Küppers

unread,
Oct 23, 2014, 8:29:13 AM10/23/14
to tiddly...@googlegroups.com
Hi TheDiveO,

From your description I would say that startup modules are not what you are looking for. Your initial attempt using a widget seems much more plausible. You probably want your canvas to be in a tiddler and not somewhere else.

No, the canvas is displayed outside any tiddler at a fixed spot somewhere in the sidebar (tc-sidebar-scrollable).
 

Monitoring tiddlers is about monitoring changes to the store. I don't yet remember the details, but looking at the core syncer should tell you how to monitor changes to the store, as the syncer needs to do exactly this.

Sorry, I am a newbie here. what do you mean by "looking at the core syncer"? I looked at the source code and tried to understand the docs. Yet I still don't understand how to register an event that listens for save and delete events.

The $tw.wiki object is accessible during runtime. It provides methods for creating tiddlers or filtering them. All is very accessible.

But my key problem remains, how is it possible (for a startup module-type plugin) to register listeners for system events like delete- or save-tiddler.

Which classes do I have to extend to register listeners? How do I subscribe to the store events?

Where do I put it into my code (see below)?

/*\
title: $:/plugins/felixhayashi/taskgraph/taskgraph.js
type: application/javascript
module-type: startup

Task graph

\*/

(function(){

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


exports
.name = "taskgraph";
exports
.after = ["load-modules"];
exports
.synchronous = true;

exports
.startup = function() {

 
// SOMETHING LIKE THIS
  UNKNOWN
.addEventListener("tm-delete-tiddler", function(event) {
    console
.log("deleted");
 
};

}

})();

Thanks in advance

Regards Felix

Felix Küppers

unread,
Oct 23, 2014, 8:35:46 AM10/23/14
to tiddly...@googlegroups.com
Sorry, I didn't notice your message while write my own message.

Looking at https://github.com/Jermolene/TiddlyWiki5/blob/master/core/modules/syncer.js#L36 I see that you need to register an event listener with the wiki object:

$tw.wiki.addEventListener("change",function(changes) {...});

I also discovered this method in the wiki object also but it only allows to subscribe to the "change" event which is too broad. It dispatches events on every keystroke that is made...

BJ

unread,
Oct 23, 2014, 3:18:31 PM10/23/14
to tiddly...@googlegroups.com
Hi Felix,

firstly you are looking in the wrong place, look at the list widget - it dynamically re-creates elements in a list when tiddlers it contains are updated and deleted. You will see that it gets the information about tiddler updates thru the refresh mechanism.

Secondly, tiddlers can be tagged in a way that makes them automatically inserted into the widget tree as it is constructed -  for example search for tiddlers tagged with $:/tags/PageTemplate, so you can created a tiddler containing your widget(s) and tag it so that it will be included in the widget tree.

You might also look at the edit-bitmap widget - it uses canvas

Cheers

BJ

Felix Küppers

unread,
Oct 23, 2014, 6:09:22 PM10/23/14
to tiddly...@googlegroups.com
Hi BJ,

I will take your advice and give it a chance tomorrow!

Good night
Felix

Felix Küppers

unread,
Oct 24, 2014, 10:56:56 PM10/24/14
to tiddly...@googlegroups.com
Hi BuggyJ,

Your answer brought me quite far :) thank you.

it was not easy to understand that it's not about listening to events, but to compare changes and trigger a refresh or not.

Unfortunately, the changedTiddlers object does not provide information if a tiddler was renamed or deleted. Because in both cases, the old title is given and specified as "deleted". However, this is not an issue for me at the moment and I actually got a good solution for that.

Also I now understood, that the widgets use tags to hook into the code (widget tree). I thought this was only a feature for users in the frontend.

So thanks again for explaining.

regards
Felix

Danielo Rodríguez

unread,
Oct 26, 2014, 2:59:43 PM10/26/14
to tiddly...@googlegroups.com
Félix you have triggered my curiosity. What are you working on?

Danielo Rodríguez

unread,
Oct 26, 2014, 3:02:59 PM10/26/14
to tiddly...@googlegroups.com

Felix Küppers

unread,
Oct 27, 2014, 7:10:16 AM10/27/14
to tiddly...@googlegroups.com
Hi Danielo,

Glad that you ask :)

Yes, it's related to my proposal at https://groups.google.com/forum/?hl=de#!topic/tiddlywikidev/UafAzk5Bt7k.

It's a two level project:

First Step: I will introduce a mechanism to explicitly link tiddlers and visualize them as nodes on a canvas.

Motivation: TW allows you only to implicitly specify relations among tiddlers via links in a text or grouping via tags. however, it lacks a clean, explicit relationship mechanism e.g "Tiddler A is a child of Tiddler B" or "C depends on D" or "E suggests G" etc. Moreover, TW cannot display/visualize a relationship network like this in a graph yet. With my Plugin, you can for example create new tiddlers by creating nodes on a canvas or interconnecting them, by drawing lines, all that stuff...

Second step: I am working on a personal-use-ticketing system for TW5, which can be used to organize tasks, bugs, enhancements, requests, due-dates etc. and represent all in a graph-like strukture that can be filtered and manipulated in the graph and from the tiddlers alike. The graph is drawn and updated on a canvas via vis.js. A node on the canvas changes from blue to red depending on its priority (automatically calculated by due-date, relationships, importance...)

Motivation: If you take a look at various opensource ticket-systems (like Trac, Redmine, Request Tracker (RT) Apache Bloodhound, BugZilla) you will discover that they have alot of shortcomings:
* they are build for team/public usage/participation in a network environment, not focussing individual usage (like TW does).
* they are often hard to setup and maintain.
* They are based on Python, Ruby, PHP (but not on javascript) and require a webserver, which doesn't make them easily portable
* Their Wikis are not as smooth, dynamic and fast as TW5.
* They lack visual representation and are often quite

I will use the ticket-system to organize my projects and my life. Think of it as an sophisticated TW-based todo-system. As much of my life is already stored in TW, this makes sense to make an effort in this direction.

The two screenshots at the end of my post (https://groups.google.com/forum/?hl=de#!topic/tiddlywikidev/UafAzk5Bt7k.) give you a first, very simple idea of one functionality-aspect the plugin will provide. Unfortunately, nobody has commented this yet, regardless, I will file a pull request at some point.

By the way, Danielo, thanks for the "context plugin" and especially "keyboard-snippets", without the latter, I would refuse to use tiddlywiki :)

Regards Felix

Danielo Rodríguez

unread,
Oct 27, 2014, 11:50:16 AM10/27/14
to tiddly...@googlegroups.com
Hello Felix,

Glad you like my plugins. I was in a similar situation that you are currently when I develop them: I use TW a lot and I missed those kind of features.

Your plugin is definitively something that I also miss a lot, but I don't have the time to spend it developing, so glad to see you are working on it.

If you are using vis.js take a look at this: 

Maybe can speed up your work.

In my opinion, this should be released as a standalone plugin rather than a pull request to the core. That way I will be able to enjoy it earlier, and I really want to try it out!!

Regards.

Felix Küppers

unread,
Oct 27, 2014, 12:26:51 PM10/27/14
to tiddly...@googlegroups.com
Hi Danielo


Glad you like my plugins. I was in a similar situation that you are currently when I develop them: I use TW a lot and I missed those kind of features.

I know, I read some of your old discussions :) Very helpful

In one you said:
 

I discovered that the navigator widget is instantiated on PageTemplate, that's why it is capturing events and mine not. I get my inspiration from the fieldmanglerWidget which mades me suspect.

This solved one of my problems a few days ago ;)
 
If you are using vis.js take a look at this: 

Maybe can speed up your work.

Thanks for pointing that out. I did that already a while ago, however, my plugin is very different. The only similarity is that it uses the same vis.js library.
 
In my opinion, this should be released as a standalone plugin rather than a pull request to the core. That way I will be able to enjoy it earlier, and I really want to try it out!! 

Yeah, I will do that! I meant, that I will create a separate pull request for a minor issue which I brought to discussion in https://groups.google.com/forum/?hl=de#!topic/tiddlywikidev/UafAzk5Bt7k

So thank you very much for your feedback!

regards
Reply all
Reply to author
Forward
0 new messages