TaskTimerPlugin enhancements - ATT: Eric Shulman

30 views
Skip to first unread message

JasonM

unread,
Sep 25, 2011, 3:43:01 AM9/25/11
to TiddlyWikiDev
Hi, I have added two features to the TaskTimerPlugin.

*Button Styling*
I have added config.macros.taskTimer.class to allow a class name to be
specified for the input button.
When using the specified class name the plugin appends "_TimerOn" or
"_TimerOff" depending on the status of the timer.
This can be used to apply state relevant CSS styles to the timer
buttons.

For example,
Tiddler - TaskTimerPluginConfig add,

---
// e.g. class="TaskTimer_TimerOn". Use this in congunction with a
style to change the look of the timer button.
config.macros.taskTimer.class="TaskTimer";
---

In an active stylesheet add:
---
.TaskTimer_TimerOff {
background-color:none;
}
.TaskTimer_TimerOn {
background-color:lightgreen;
}
---
this will turn the button light green when the timer is running.

*Field parsing in record format*
You can now place in the format string a Field value from any
tiddler. The field is retrieved just before the record is written.
For example,
<<taskTimer today:YYYY-wWW "|%4|[[billCode@Client Project Alpha]] |%0|
%1|%2|%3|\n" "Activity: " " " | ">>

This useful when used in conjunction with the ListBoxPlugin. Two
scenarios in particular,
1. You need change a part of the format on a active timer without
stopping it.
2. Your timers are all defined in a infrequently refreshed tiddler
(e.g. MainMenu) and you require the ability to change the format
without reloading all the time.

Code below has only been tested on Firefox 6.0.2, Fedora 15 Linux
6.2.40.4

@Eric - If you think this might be useful to others and it is suitable
for inclusion into your main plugin please feel free to merge the
changes.

--- code start ---
/***
|Name|TaskTimerPlugin|
|Source|http://www.TiddlyTools.com/#TaskTimerPlugin|
|Documentation|http://www.TiddlyTools.com/#TaskTimerPluginInfo|
|Version|1.4.2|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and
[[Creative Commons Attribution-ShareAlike 2.5 License|http://
creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|'timer' button automatically writes start/end/elapsed
time into tiddler content|
Quickly generate 'timed task' logs that can be used for status
reports, billing purposes, etc.
!!!!!Documentation
> see [[TaskTimerPluginInfo]]
!!!!!Configuration
> see [[TaskTimerPluginConfig]]
!!!!!Revisions
<<<
2011.09.25 [1.4.2] jm - Added ability to style the button. Added field
(format {{{field@tiddler}}} or {{{[[field@tiddler with more
words]]}}} ) parsing in the record format.
2008.11.10 [1.4.1] in elapsed time calculation, truncate start/stop
times to nearest second (avoids 1-second 'round-down' error)
|please see [[TaskTimerPluginInfo]] for additional revision details|
2007.03.14 [0.5.0] converted from inline script
<<<
!!!!!Code
***/
//{{{
version.extensions.TaskTimerPlugin= {major: 1, minor:4, revision: 1,
date: new Date(2008,11,10)};

config.macros.taskTimer = {
label: "start timer",
title: "press to start the task timer",
format: "|%4|%0|%1|%2|%3|\\n", // note: double-backslash-en, also
date is %4 (for backward compatibility)
defText: " ", // default description text
todayKeyword: "today",
todayFormat: "0MM/0DD/YYYY", // default format - superceded by
CalendarPlugin, DatePlugin, or DatePluginConfig
datestampFormat: "YYYY-0MM-0DD", // date stamp format
buttonFormat: "%0 - %2", // timer button formats: %0=current time,
%1=start time, %2=elapsed time
defHeader: "|//Date//|//Description//|//Started//|//Stopped//|//
Elapsed//|\n",
defTarget: "ActivityReport",
descrMsg: "Enter a short description for this activity. Press
[cancel] to continue timer.",
askMsg: "Enter the title of a tiddler in which to record this
activity. Press [cancel] to continue timer.",
errMsg: "'%0' is not a valid tiddler title. Please try again...\n
\n",
createdMsg: "'%0' has been created",
updatedMsg: "'%0' has been updated",
marker: "/%"+"tasktimer"+"%/",
tag: "task",
handler:
function(place,macroName,params,wikifier,paramString,tiddler) {
var target=params.shift(); // get optional target tiddler title
if (!target) target="";
var format=this.format; if (params[0]) format=params.shift(); // get
optional output format
var descrMsg=this.descrMsg; if (params[0])
descrMsg=params.shift(); // get optional message text
var defText=this.defText; if (params[0]) defText=params.shift(); //
get optional default text
var onclick="config.macros.taskTimer.toggle(this,'"+target
+"','"+format+"','"+descrMsg+"','"+defText+"')";
createTiddlyElement(place,"span").innerHTML =
'<input type="button" value="start timer" class="'+
config.macros.taskTimer.class+"_TimerOff" +'" title="'+this.title+'"
onclick="'+onclick+'">';
},
toggle: function(here,target,format,msg,defText) {
if (!target || !target.length || target=="here") {
var tid=story.findContainingTiddler(here);
target=tid?tid.getAttribute("tiddler"):"ask";
}
if (!here.running) { // not running... start timer...
here.startTime=new Date();
var now=here.startTime.formatString("0hh:0mm:0ss");
here.title=(here.target||target)+" - started at "+now;
here.value=this.buttonFormat.format([now,now,"00:00:00"]);
here.id=new Date().getTime()+Math.random().toString(); // unique ID
here.className=config.macros.taskTimer.class+"_TimerOn";
here.ticker=setTimeout("config.macros.taskTimer.tick('"+here.id
+"')",500);
here.running=true;
} else {
if (target=="ask") {
target=prompt(this.askMsg,here.target||this.defTarget);
while (target && !target.trim().length)
target=prompt(this.errMsg.format([target])
+this.askMsg,here.target||this.defTarget);
if (!target) return; // user cancelled input... continue timer
}
var txt=prompt(msg,defText); // get description from user
if (!txt) return; // user cancelled input... continue timer
if (target==this.todayKeyword ||
target.substr(0,this.todayKeyword.length+1)==this.todayKeyword+":")
target=(new Date()).formatString(this.getJournalFormat(target));
here=document.getElementById(here.id); // RE-get button element
after timer has stopped...
here.className=config.macros.taskTimer.class+"_TimerOff";
clearTimeout(here.ticker);
here.target=target;
var before=this.defHeader;
var after=this.marker+"\n";
var tiddler=store.getTiddler(here.target);
if (tiddler && tiddler.text.length) {
var pos=tiddler.text.indexOf(this.marker);
if (pos==-1) pos=tiddler.text.length; // no marker, append content
to end
var before=tiddler.text.substr(0,pos); // everything up to marker
if (before.length&&before.substr(before.length-1)!="\n") before
+="\n"; // start on a new line
var after=tiddler.text.substr(pos); // marker+everything else
}
var now=new Date(Math.floor(new Date()/1000)*1000);
var then=new Date(Math.floor(here.startTime/1000)*1000);
var diff=new Date(now-then);
var s=diff.getUTCSeconds(); if (s<10) s="0"+s;
var m=diff.getUTCMinutes(); if (m<10) m="0"+m;
var h=diff.getUTCHours(); if (h<10) h="0"+h;
var start=then.formatString("0hh:0mm:0ss");
var stop=now.formatString("0hh:0mm:0ss");
var elapsed=h+":"+m+":"+s;
var
dateStamp=now.formatString(config.macros.taskTimer.datestampFormat);
var fieldPatternRe =new RegExp('(\\w+@.*? )|(\\[\\[\\w+@[\\w\\W ]+?
\\]{2})', 'gi');
var newFormat="";
var currentIndex=0;
var arrMatch;

while (arrMatch = fieldPatternRe.exec( format )){
fieldSplit=arrMatch[0].replace(/[\[\]]{2}/g,"").split("@");
newFormat+=format.substring(currentIndex, arrMatch.index);
if (field=store.getValue(fieldSplit[1], fieldSplit[0])) {
newFormat+=field;
} else {
newFormat+=format.substring(arrMatch.index,
fieldPatternRe.lastIndex);
}
currentIndex=fieldPatternRe.lastIndex;
}
newFormat+=format.substring(currentIndex);

format=newFormat;

var newtxt=before+format.format([txt,start,stop,elapsed,dateStamp])
+after;
var newtags=(tiddler?tiddler.tags:['task']); // include 'task' tag
when creating new tiddlers

store.saveTiddler(here.target,here.target,newtxt,config.options.txtUserName,new
Date(),newtags,tiddler?tiddler.fields:null);
if (!tiddler)
displayMessage(this.createdMsg.format([here.target]));
else displayMessage(this.updatedMsg.format([here.target]));
here.running=false;
here.value=this.label;
here.title=this.title;
var tid=story.findContainingTiddler(here);
if (!tid || tid.getAttribute("tiddler")!=target) // display target
tiddler, but only when button is not IN the target tiddler

{ story.displayTiddler(story.findContainingTiddler(here),here.target);
story.refreshTiddler(here.target,1,true); }
}
},
tick: function(id) {
var here=document.getElementById(id); if (!here) return;
var now=new Date();
var diff=new Date(now-here.startTime);
var s=diff.getUTCSeconds(); if (s<10) s="0"+s;
var m=diff.getUTCMinutes(); if (m<10) m="0"+m;
var h=diff.getUTCHours(); if (h<10) h="0"+h;
var elapsed=h+":"+m+":"+s;
now=now.formatString("0hh:0mm:0ss");
var start=here.startTime.formatString("0hh:0mm:0ss");
here.value=this.buttonFormat.format([now,start,elapsed]);
here.ticker=setTimeout("config.macros.taskTimer.tick('"+id+"')",
500);
},
getJournalFormat: function(target) {
var fmt=target.split(":"); fmt.shift(); fmt=fmt.join(":");
if (!fmt || !fmt.length) { // if date format was not specified
if (config.macros.date) // if installed, use default from
DatePlugin
fmt=config.macros.date.linkformat;
if (config.macros.calendar) { // if installed, use default from
CalendarPlugin
if (!config.macros.date) // hard-coded calendar fallback if no
DatePlugin
fmt=config.macros.calendar.tiddlerformat;
else // journalDateFmt is set when calendar is rendered with
DatePlugin
fmt=config.macros.calendar.journalDateFmt;
}
}
if (!fmt) { // if not specified and no DatePlugin/CalendarPlugin
// get format from <<newJournal>> in SideBarOptions
var text = store.getTiddlerText("SideBarOptions");
var re=new RegExp("<<(?:newJournal)([^>]*)>>","mg"); var
fm=re.exec(text);
if (fm && fm[1]!=null) { var pa=fm[1].readMacroParams(); if (pa[0])
fmt = pa[0]; }
}
if (!fmt) var fmt=this.todayFormat; // no "newJournal"... final
fallback.
return fmt;
}
}
//}}}
--- code end ---



Måns

unread,
Sep 25, 2011, 3:31:23 PM9/25/11
to TiddlyWikiDev
Hi JasonM

That sounds marvelous could you please provide a live example ? ( -
or a Github sample)
Automatic wrapping of text in google groups makes it impossible to
copy/paste longer bits of code...

Cheers Måns Mårtensson

JasonM

unread,
Sep 28, 2011, 9:38:13 AM9/28/11
to TiddlyWikiDev
I have put the modified plug-in here http://jmtiddly.tiddlyspot.com/
jason
> ...
>
> read more »

Eric Shulman

unread,
Sep 28, 2011, 1:21:11 PM9/28/11
to TiddlyWikiDev


> I have put the modified plug-in herehttp://jmtiddly.tiddlyspot.com/
> jason

Please read http://www.TiddlyTools.com/#LegalStatements for "Terms of
Use" and instructions for modifying TiddlyTools plugins.
Specifically, you need to:

1) RENAME your modified plugin (e.g. TaskTimerPluginJM) to avoid
confusion with the official distribution.

2) Add comments *inline* in the code where you have made changes (so
it is easy to see what the differences are).

Also, I note that the 'header table' in your copy of the plugin has a
few older slices ("overrides", "configuration", etc.) and the "legal
statement" links are different from the current plugin (I no longer
directly link to CreativeCommons license). I suspect you got your
copy of the plugin from another document. When modifying TiddlyTools
plugins, you MUST make sure to start from the most recent official
published copy. ALWAYS go to http://www.TiddlyTools.com/, rather than
copying the plugin from some other document in which it was previously
installed.

-e

Bruce Delagi

unread,
Sep 28, 2011, 1:56:52 PM9/28/11
to Eric Shulman, tiddly...@googlegroups.com
Hi Eric,

I've posted messages using the facility provided at tiddlytools.com
concerning the use of store.saveTiddler() in in QuickEdit_split,
SplitTiddler, and StorySaverPlugin within the TiddlySpace environment.
I don't know if that facility is working since in the several weeks
since posting my first message there, I've seen no response. Perhaps
some filter somewhere is dropping stuff on the floor.

The messages include a fix that I think is compatible with standalone
use of TiddlyWikis. The fix consists of replacing calls to
store.saveTiddler() with calls to a function defined as saveNewTiddler()
below:

> var saveNewTiddler = function(title, text, tags, fields) {
> var newTiddler = store.saveTiddler(title, title, text,
> config.options.txtUserName, new Date(), tags,
> merge(merge({},fields),config.defaultCustomFields));
> autoSaveChanges(null, [newTiddler]);
> return newTiddler; }
The problem with calling store.saveTiddler() without merging in
config.defaultCustomFields within the TiddlySpace environment is, of
course, endemic and, by experience, crops up quite generally with the
plugins I've been (most gratefully) using from tiddlytools.com. Without
the fix, new tiddlers intended to be saved do not, in fact, get saved on
the hosting server.

What are your thoughts on the fix?

/b

JasonM

unread,
Sep 29, 2011, 10:01:20 AM9/29/11
to TiddlyWikiDev
Eric,
Thanks for the direction. Updates have been made that I hope meets
your reuse / licensing requirements.

I hope you will consider merging these features into your version of
the plugin. I dislike branching (creating a derived work) for such
minor improvements.

jm


On Sep 29, 2:21 am, Eric Shulman <elsdes...@gmail.com> wrote:
> > I have put the modified plug-in herehttp://jmtiddly.tiddlyspot.com/
> > jason
>
> Please readhttp://www.TiddlyTools.com/#LegalStatementsfor "Terms of
> Use" and instructions for modifying TiddlyTools plugins.
> Specifically, you need to:
>
> 1) RENAME your modified plugin (e.g. TaskTimerPluginJM) to avoid
> confusion with the official distribution.
>
> 2) Add comments *inline* in the code where you have made changes (so
> it is easy to see what the differences are).
>
> Also, I note that the 'header table' in your copy of the plugin has a
> few older slices ("overrides", "configuration", etc.) and the "legal
> statement" links are different from the current plugin (I no longer
> directly link to CreativeCommons license).  I suspect you got your
> copy of the plugin from another document.  When modifying TiddlyTools
> plugins, you MUST make sure to start from the most recent official
> published copy.  ALWAYS go tohttp://www.TiddlyTools.com/, rather than
Reply all
Reply to author
Forward
0 new messages