How to convert a script into a button with a prompt?

52 views
Skip to first unread message

Måns

unread,
Apr 11, 2009, 2:48:16 PM4/11/09
to TiddlyWiki
Hi
I've got a very nice script from Mark S.
1)
I would like to use it from a button in a custom toolbar for a
tiddler.
It should convert the list in the tiddler to a row of tags in the same
tiddler.

2)
It could also reside in the sidebar - If it did, it should prompt
twice 1) for the sourcetiddler and 2) for the targettiddler.

3)
Maybe an even better solution would be to have a newTiddlerbutton,
which I would call: List2Tags - to open a new tiddler, which I would
fill with my list and when I click done - the script will run on the
tiddler content - delete the original list - while putting it into the
tagline - and refresh it - to be able to display the result at once..

Now the script needs a tiddler which already exists and it doesn't
refresh, nor does it delete the sourcelist..

The script looks like this:
<script>
var t=store.getTiddlerText('SourceTiddler','');
var target = store.getTiddler('TargetTiddler') ;
var taglist = t.split('\n') ;
for(var i=0 ; i < taglist.length ; i++) {
if ( taglist[i] && ! target.tags.contains(taglist[i]) )
target.tags.push( taglist[i] ) ;
}
return 'Mischief Managed' ;
</script>

YS Måns Mårtensson

Eric Shulman

unread,
Apr 11, 2009, 5:06:58 PM4/11/09
to TiddlyWiki
> I've got a very nice script from Mark S.
> 1)
> I would like to use it from a button in a custom toolbar for a
> tiddler.

InlineJavascriptPlugin enables you to quickly create an 'onclick'
command link from *any* script, simply by adding label="..." (and
optional title="...") to the script definition syntax, like this:

<script label="click here" title="this text appears on mousover">
... code goes here ...
</script>

When the plugin detects the label="..." syntax, it creates a command
link using the indicated label text, so that instead of immediately
invoking the script as soon as it is rendered, it is only invoked when
that link is subsequently clicked upon.

To use this command link in a tiddler toolbar definition, first put
the script into a separate tiddler (e.g., "MyCommand") and then
either:

A) In the ViewTemplate or EditTemplate, you can insert the following
immediately preceding or following any existing toolbar definition,
e.g.,:
<div class='toolbar' macro='tiddler MyCommand'></div>
<div class='toolbar' macro='toolbar
[[ToolbarCommands::ViewToolbar]]'></div>

OR

B) Install
http://www.TiddlyTools.com/#CoreTweaks
specifically tweak #608/609/610, which extends the core's toolbar
syntax so that -- in addition to standard toolbar command keywords --
TiddlerNames can be used to 'transclude' content directly into a
toolbar definition. This allows you to use the tiddler name,
MyCommand, anywhere within the standard
[[ToolbarCommands::ViewToolbar]] slice, like this:

|~ViewToolbar|MyCommand closeTiddler closeOthers +editTiddler > fields
syncing permalink references jump|

In either case, the result will be that the 'onclick' inline script
defined in MyCommand will appear as a button in each tiddler's
toolbar, ready to be clicked upon to perform it's scripted actions.

Note that either technique can also be very use for embedding
'regular' macro-based command links as well. For example, create a
tiddler called [[NewTiddlerCommand]] containing just this single
macro:
<<newTiddler>>
Then, either edit the template or the toolbar slice definition to add
a reference to "NewTiddlerCommand". The result will be that the "new
tiddler" command link will then automatically appear in the toolbar of
every tiddler.

enjoy,
-e


Måns

unread,
Apr 11, 2009, 5:54:56 PM4/11/09
to TiddlyWiki
Great Eric - Thank you very much for the good explanation and
especially the CoreTweaks which allow me to make my own button appear
by tiddlername in the ToolbarCommands.
It is also good to know how to prevent the script from running every
time I click done - and getting a link instead - That's really great!!

Now I need to input 2 prompts in the script - one for the
sourcetiddler (with the list)
and another for the targettiddler (which could be the same tiddler- or
not)

I've found this:
var title=prompt("Enter the title of a tiddler to edit (case
sensitive)");
while (title && title.length && !store.tiddlerExists(title)) {
displayMessage("The tiddler '%0' doesn't exist".format
([title]));
var title=prompt("Please enter a tiddler title",title);
}
if (!title||!title.length) return; /* cancelled by user */
story.displayTiddler(null,title,2);

I need to use some of it in this:
<script label="L2T" title="List2Tags">
var t=store.getTiddlerText('prompt for source tiddlertitle','');
var target = store.getTiddler('prompt for target tiddlertitle') ;
var taglist = t.split('\n') ;
for(var i=0 ; i < taglist.length ; i++) {
if ( taglist[i] && ! target.tags.contains(taglist[i]) )
target.tags.push( taglist[i] ) ;
}
return 'List 2 tags Done - Now click edit and finish in
targettiddler to make the tags active' ;
</script>

YS Måns Mårtensson

Måns

unread,
Apr 11, 2009, 6:14:22 PM4/11/09
to TiddlyWiki
It would suffice if I could refer to the tiddler in which the toolbar
is active..
none of these works:
{{tiddler.title}} '+tiddler.title+'
What can i write instead of:
var t=store.getTiddlerText('Source tiddlertitle','');
var target = store.getTiddler('Source tiddlertitle') ;
??

YS Måns Mårtensson

Eric Shulman

unread,
Apr 12, 2009, 1:43:57 AM4/12/09
to TiddlyWiki
> It would suffice if I could refer to the tiddler in which the toolbar
> is active..
> none of these works:
> {{tiddler.title}} '+tiddler.title+'
> What can i write instead of:
>  var t=store.getTiddlerText('Source tiddlertitle','');
>    var target = store.getTiddler('Source tiddlertitle') ;

You can find the current tiddler object like this:

var here=store.findContainingTiddler(place); // tiddler DOM element
if (!here) return; // not in a tiddler
var title=here.getAttribute("tiddler"); // attribute holds title of
tiddler
var tiddler=store.getTiddler(title);

(in your case, you just want the title, so skip the last line).

Although the above code is guaranteed to always work, it's somewhat
inconvenient and 'bulky'.

However, inline scripting normally has access to a core-defined
variable, 'tiddler' that holds a reference to the current tiddler
object, so simple references like 'tiddler.title' are supposed to work
when processing inline scripts.

Unfortunately, even though 'tiddler.title' can be used in a regular
inline script, it wasn't working properly when used in an 'onclick'
scripts, because they aren't invoked until the link is actually
clicked upon, which can occur long after the tiddler in which the
script occurs has been rendered.

Fortunately, I've fixed this... get the update (v1.9.5) here:
http://www.TiddlyTools.com/#InlineJavascriptPlugin

enjoy,
-e
Eric Shulman
TiddlyTools / ELS Design Studios

Måns

unread,
Apr 12, 2009, 10:47:04 AM4/12/09
to TiddlyWiki
Hmm..

I'm trying and trying again - but I can't make it work...
Last try was:
var t=store.getTiddlerText('tiddler.title') ;
var target = store.getTiddler('tiddler.title') ;
Response was TypeError t is null...

If I'm going to put all the text from your "guaranteed to work code" -
How am I to distribute the text inside the existing code?

<script label="L2T" title="List2Tags">
var t=store.getTiddlerText('source tiddlertitle','');
var target = store.getTiddler('target tiddlertitle') ;
var taglist = t.split('\n') ;
for(var i=0 ; i < taglist.length ; i++) {
if ( taglist[i] && ! target.tags.contains(taglist[i]) )
target.tags.push( taglist[i] ) ;
}
return 'List 2 tags Done - Now click edit and finish in
targettiddler to make the tags active' ;
</script>

YS Måns Mårtensson

Eric Shulman

unread,
Apr 12, 2009, 11:10:30 AM4/12/09
to TiddlyWiki
> Last try was:
>  var t=store.getTiddlerText('tiddler.title') ;
>    var target = store.getTiddler('tiddler.title') ;
> Response was TypeError t is null...

'tiddler.title'
is just a text string
tiddler
is an object
tiddler.title
is an attribute of that object

Thus:
var t=store.getTiddlerText(tiddler.title)
(i.e., remove the quotes)

enjoy,
-e

Måns

unread,
Apr 12, 2009, 11:50:14 AM4/12/09
to TiddlyWiki
Hi again

I'd like the script to be active in the tiddler it is invoked from.
I thought that tiddler.title would do that for me - when I used the
script from another tiddler with <<tiddler MyScript>>
However it runs the script in the original tiddler instead (putting
the script itself into the tagline!!)..

What am I doing wrong?

YS Måns Mårtensson

Eric Shulman

unread,
Apr 12, 2009, 12:26:27 PM4/12/09
to TiddlyWiki
> I'd like the script to be active in the tiddler it is invoked from.
> I thought that tiddler.title would do that for me - when I used the
> script from another tiddler with <<tiddler MyScript>>
> However it runs the script in the original tiddler instead (putting
> the script itself into the tagline!!)..

The 'tiddler' object that is provided by the core always refers to the
tiddler in which the wiki source is *stored* (the 'source tiddler'),
and is usually the same as the tiddler being *rendered* (the
'containing tiddler'). However, when you use <<tiddler>> to
transclude content from a separate TiddlerName, the source tiddler is
different from the containing tiddler. In this case, in order to
ensure that you get the correct tiddler title and/or tiddler object,
you'll need to use the 'findContainingTiddler()' technique I
previously described:

var here=store.findContainingTiddler(place);
if (!here) return;
var title=here.getAttribute("tiddler");
var tiddler=store.getTiddler(title);

-e

Måns

unread,
Apr 12, 2009, 1:29:26 PM4/12/09
to TiddlyWiki
TypeError: store.findContainingTiddler is not a function....

Måns

unread,
Apr 12, 2009, 3:06:03 PM4/12/09
to TiddlyWiki
I tried this:
<script label="L2T" title="List2Tags">
var here=store.findContainingTiddler(place);
if (!here) return;
var title=here.getAttribute("tiddler");
var tiddler=store.getTiddler(title);
var t=store.getTiddlerText(tiddler.title) ;
var target = store.getTiddler(tiddler.title) ;
var taglist = t.split('\n') ;
for(var i=0 ; i < taglist.length ; i++) {
if ( taglist[i] && ! target.tags.contains(taglist[i]) )
target.tags.push( taglist[i] ) ;
}
return 'Liste er overført til tags - klik redigér og færdig i
tiddleren' ;
</script>
And got this: TypeError: store.findContainingTiddler is not a function
when I tried to invoke it...

What am I doing wrong?

YS Måns Mårtensson

Måns

unread,
Apr 12, 2009, 3:27:11 PM4/12/09
to TiddlyWiki
I wonder if I could have a scenario like this:

I paste a list of students into a tiddler and call it
"ListToTags" (Maybe overwriting earlier version-(doesn't matter)).
When I hit my scriptbutton to make a new class - it prompts for a
classtitle and teachers initials - now it takes the text from
"ListToTags" and puts it into the newClasstiddlers tagfield - done...
ProtoType: (doesn't work yet..)

<script label="L2T" title="List2Tags">
var tid=prompt("ClassTitle","");
if (!tid || !tid.length) return;
var txt="";
var who=config.options.txtUserName;
var when=new Date();
var tags=['Fag'];
var initialer=prompt("Teachers initials","");
if (!initials || !initials.length) return;
var fields={ teacher: initials };
store.saveTiddler(tid,tid,txt,who,when,tags,fields);
story.displayTiddler(null,tid);
var t=store.getTiddlerText(tiddler.title) ;
var target = store.getTiddler(tiddler.title) ;
var taglist = t.split('\n') ;
for(var i=0 ; i < taglist.length ; i++) {
if ( taglist[i] && ! target.tags.contains(taglist[i]) )
target.tags.push( taglist[i] ) ;
}
return 'List 2 tags - click edit and done' ;
</script>

Could this become reality??

YS Måns Mårtensson

Eric Shulman

unread,
Apr 12, 2009, 3:30:19 PM4/12/09
to TiddlyWiki
>    var here=store.findContainingTiddler(place);
> And got this: TypeError: store.findContainingTiddler is not a function

oops! typo... change "store" to "story":

var here=story.findContainingTiddler(place);

-e

Måns

unread,
Apr 12, 2009, 3:43:32 PM4/12/09
to TiddlyWiki
Of course it should be more like:

<script label="L2T" title="List2Tags">
var tid=prompt("Skriv navnet på det nye hold","");
if (!tid || !tid.length) return;
var txt="";
var who=config.options.txtUserName;
var when=new Date();
var tags=['Class'];
var initialer=prompt("Teachers initials","");
if (!initials || !initials.length) return;
var fields={ teacher: initials };
store.saveTiddler(tid,tid,txt,who,when,tags,fields);
story.displayTiddler(null,tid);
var t=store.getTiddlerText("ListToTags");
var here=story.findContainingTiddler(place);
if (!here) return;
var title=here.getAttribute("tiddler");
var tiddler=store.getTiddler(title);
var target = store.getTiddler(tiddler.title) ;
var taglist = t.split('\n') ;
for(var i=0 ; i < taglist.length ; i++) {
if ( taglist[i] && ! target.tags.contains(taglist[i]) )
target.tags.push( taglist[i] ) ;
}
return 'List 2 tags - click edit and done' ;
</script>

It still fetches the list from ListToTags and puts the result in the
tiddler holding the script..

YS Måns Mårtensson

Måns

unread,
Apr 12, 2009, 3:46:27 PM4/12/09
to TiddlyWiki
It should ideally fetch the list from the ListToTags tiddler and put
it into the just generated newClasstiddler...

Måns

unread,
Apr 12, 2009, 3:56:37 PM4/12/09
to TiddlyWiki
The simple script for a list to tag works now!! - Thank you very much
Eric!!
I will put it (as a button) in the customViewTemplate for classes -
thereby making it possible to paste a list of students into the
Classtiddler - push the button and get a tagline referring to all
students in the class... (Now I can delete the list in edit mode - and
get it back in viewmode - read on..)
I'm using a script to show a sortable list of the tagged students in
the ClassTiddler - like this:
<script>
var out=[];
var exclude=['Class'];
var fmt='|[[%0]]|';
var here=story.findContainingTiddler(place); if (!here)
return;
var tid=store.getTiddler(here.getAttribute('tiddler'));
if (tid.tags.length) out.push('|Elever på holdet|h\n|sortable|
k');
for (var t=0; t<tid.tags.length; t++)
if (!exclude.contains(tid.tags[t]))
out.push(fmt.format([tid.tags[t]]));
return out.join('\n');
</script>

YS Måns Mårtensson
Reply all
Reply to author
Forward
0 new messages