My company required more than a simple grocery list type Task List, so I laid out some requirements that I though every Task List should have. Hence the birth of this template(s). This Task List could be included in Project Pages, Meeting Minutes Pages, Personal Pages, in short where ever you need a Task List.
To leave feedback or gain support or report a bug please refer to the announcement forum post.
Current Features:
Future Features:
| Version | Date | Author | Description |
| 0.9b.2 | 10/27/2009 | rberinger | Changed CSS for progress meter to be a bit less shocking. |
| 0.9b.1 | 10/20/2009 | rberinger | Fixed Centering for notes viewer thanks dekc99 for the solution |
| 0.9b | 10/14/2009 | rberinger | Initial Beta Release |
For all the examples on this page, the code is shown before the working example. The code is shown with the syntax extension, and looks like this:
ToDoMaster()
This means that the actual code on the page should be enclosed in a DekiScript block. If you want to copy the code from this page, then use the same procedure as described in steps 2-4 above.
There are currently 2 Templates that are required for use of this task list.
And 1 Optional but recommended Template to obtain full use.
Suggested Use:
You can use this list however you see fit or where ever you have need but I will explain how we use it at my company.
We currently use this task list in 3 different way. Personal, Project, and Meetings.
Personal: Inserted in each users personal area for a personal task list.
Project: Referenced in out Project template for tasks associated to a specific project.
Meetings: Referenced in out Meeting Minutes Template for when action items are assigned in a meeting.
Also in each users personal area we inserted the ToDoRollup in the user dashboard area. This allows for a quick view of every task assigned to a specific user no matter where the task list resides (Project 1, Project 2, Personal, Meetings, etc). This template can also be used to gather ALL tasks from EVERYONE which is handy for our managers to see what everyone has on their plate.
There are currently no arguments for the ToDoMaster or ToDoItem Templates
See the ToDoRollup Template documentation page for the details on its arguments.
Where ever you need a task list just insert the following In a DekiScript Block or enclosed within the Double Brackets {{}} somewhere on that page.
ToDoMaster();
| Task ID | Description | Assignee(s) | Priority | Due Date | Progress | On Hold | Complete Date | Notes |
|---|---|---|---|---|---|---|---|---|
| 34601 | asdf | Anonymous | 3 | 01/06/2010 | 100% | false | 06/23/2011 | view |
| 34601 | asdf | pochacco | 3 | 01/06/2010 | 100% | false | 06/23/2011 | view |
| 83051 | just a test | Anonymous | 1 | 12/12/2010 | 50% | true | N/A | view |
| 83051 | just a test | dsaheu8239372a | 1 | 12/12/2010 | 50% | true | N/A | view |
| 98363 | testing that thing.... | khaki | 3 | 01/18/2011 | 75% | true | N/A | view |
| 73058 | spank the plank | Anonymous | 2 | 11/02/2011 | 50% | true | N/A | view |
| 73058 | spank the plank | mickdavidson | 2 | 11/02/2011 | 50% | true | N/A | view |
| 40541 | testing | neels | 1 | 03/11/2010 | 25% | false | N/A | view |
| 40541 | testing | BDuran | 1 | 03/11/2010 | 25% | false | N/A | view |
| 45763 | sttt | winzxc2000 | 1 | 07/26/2010 | 0% | false | N/A | view |
| 33536 | play with task list and determine if it will work for us | maphew | 2 | 10/22/2009 | 100% | false | 06/20/2011 | view |
| 97401 | Eldon_Test | eneusta1 | 1 | 01/14/2011 | 0% | false | N/A | view |
| 45784 | Test Task one | jarush.he | 1 | 07/26/2010 | 0% | false | N/A | view |
| 44226 | tester | SeGo | 1 | 06/03/2010 | 50% | false | N/A | view |
| 41522 | testtest | adminhw | 3 | 04/20/2010 | 100% | false | 08/25/2010 | view |
| 41522 | testtest | gouwzee | 3 | 04/20/2010 | 100% | false | 08/25/2010 | view |
| 73062 | create/format notes | Anonymous | 1 | 11/04/2010 | 0% | true | N/A | view |
| 73062 | create/format notes | mickdavidson | 1 | 11/04/2010 | 0% | true | N/A | view |
| 40944 | Something I need to do | beezoboy | 1 | 04/13/2010 | 25% | false | N/A | view |
| 50740 | Go to bed | stuartborn | 2 | 08/20/2010 | 100% | false | 08/31/2010 | view |
| 50740 | Go to bed | stu | 2 | 08/20/2010 | 100% | false | 08/31/2010 | view |
| 44796 | where do notes go? | tungsten_22 | 1 | 06/26/2010 | 25% | false | N/A | view |
| 73147 | test the ToDoMaster in v10 | jaron | 1 | 11/03/2010 | 25% | false | N/A | view |
| 34607 | This is a test Item to see how priorities work | arandall | 2 | 01/06/2010 | 50% | true | N/A | view |
| 41586 | fd | faber | 1 | 04/26/2010 | 0% | false | N/A | view |
| 63964 | Find my love | Anonymous | 2 | 10/07/2010 | 25% | false | N/A | view |
| 40908 | Test Task for Ticket-System | jhhenkel | 1 | 03/30/2010 | 0% | false | N/A | view |
| 40908 | Test Task for Ticket-System | frahe | 1 | 03/30/2010 | 0% | false | N/A | view |
| 55741 | Umlaute not wörking | mjanker | 1 | 09/14/2010 | 0% | false | N/A | view |
| 33379 | I am a test task item | rberinger | 1 | 10/31/2009 | 0% | false | N/A | view |
| 39685 | test to see how to unassign | jlpp | 1 | 03/05/2010 | 0% | false | N/A | view |
| 39685 | test to see how to unassign | rberinger | 1 | 03/05/2010 | 0% | false | N/A | view |
| 35764 | test!~! | winzxc2000 | 2 | 02/09/2010 | 75% | false | N/A | view |
| 115923 | oljnkjnojknf | thermalpaste | 1 | 08/15/2011 | 0% | false | N/A | view |
| 89817 | blah blah | FormidableInc | 1 | 12/21/2010 | 0% | false | N/A | view |
| 33982 | Yet another entry to test functionality... | jbnarducci | 1 | 11/20/2009 | 100% | false | 12/14/2009 | view |
| 99453 | qdfsd | Mseuda | 1 | 01/21/2011 | 75% | false | N/A | view |
| 40902 | test2 | winzxc2000 | 3 | 03/30/2010 | 75% | true | N/A | view |
| 40902 | test2 | nealw | 3 | 03/30/2010 | 75% | true | N/A | view |
| 34268 | test | Satu | 1 | 12/14/2009 | 75% | false | 12/14/2009 | view |
Everyone on the forums who helped mold this into what it is today.
Template:ToDoMaster
// includes
dekiapi();
jquery.ui('smoothness');
<div class="todomaster">
<form>
<table bgcolor="#ecf6fc" id="todoedit" cellspacing="1" cellpadding="1" border="1" width="100%" style="table-layout: fixed;">
<tbody>
<tr>
<td valign="middle" rowspan="3"><span style="align:center;">'Assignee(s):'</span>; <br/>;
<input type="text" id="user-search" />
<div id="user-suggest">
<div id="userlist">
</div>
</div>
<select id="assignee" size ="4" multiple="true" style="width:100%">
<option value=(user.name) selected='selected'>; user.name; </option>
</select>
</td>
<td align="right" valign="middle">'Assigner: '; <input id="assigner" type="text" value=(user.name)/>
</td>
<td align="right" valign="middle">'Start Date: '; <input id="start" type="text" value=(date.format(date.now, 'MM/dd/yyyy')) ctor="$this.datepicker();"/>
</td>
</tr>
<tr>
<td align="right" valign="middle">'Priority: ';
<select id="priority">
<option value="3" selected=((3 ? 'selected' : nil))>'3'</option>
<option value="2" selected=((2 ? 'selected' : nil))>'2'</option>
<option value="1" selected=((1 ? 'selected' : nil))>'1'</option>
</select>
' Percent: ';
<select id="percent">
<option value="5" selected=((5 ? 'selected' : nil))>'100%'</option>
<option value="4" selected=((4 ? 'selected' : nil))>'75%'</option>
<option value="3" selected=((3 ? 'selected' : nil))>'50%'</option>
<option value="2" selected=((2 ? 'selected' : nil))>'25%'</option>
<option value="1" selected=((1 ? 'selected' : nil))>'0%'</option>
</select>
</td>
<td align="right" valign="middle">'Due Date: '; <input id="due" type="text" value=(date.format(date.now, 'MM/dd/yyyy')) ctor="$this.datepicker();"/>
</td>
</tr>
<tr>
<td align="left" valign="middle" colspan="2">'Short Description: ';<input id="desc" type="text" value="" style="width:30em" maxlength="60" />
</td>
</tr>
<tr>
<td align="center" valign="middle" colspan="3">
<input id="save" type="button" value="Save" style="margin-top:15px;margin-bottom:15px" ctor="
when($this.click) {
$('#assignee option').each(function(i) {
$(this).attr('selected','selected');
});
// A bit of Sense Cheking
if($('#assignee option').size() == 0){alert('Must have at least 1 Assignee!'); return false;}
if($('#desc').val()==''){alert('Must have a Short Description!'); return false;}
if($('#due').val()==''){alert('Must have a Due Date!'); return false;}
if($('#start').val()==''){alert('Must have a Start Date!'); return false;}
var todoitem = ({ assignee: #assignee.val(),
assigner: #assigner.val(),
startdate: #start.val(),
priority: #priority.val(),
percent: #percent.val(),
duedate: #due.val(),
desc: #desc.val(),
done: false,
donedate: '',
hold: false,
holdreason:'',
projectpage:({{page.id}}),
whochanged:({{user.name}})
});
#save.blur();
$('div.todomaster').toggle()
Deki.publish('ch_save', todoitem);
}
" />
</td>
</tr>
</tbody>
</table>
</form>
</div>
<script type="text/jem">"
var dapi = '/@api/deki/pages/=';
var dparams = '/contents?abort=never';
var dpath;
// Create page
Deki.subscribe('ch_save', null, function(c, m, d) {
// listen for submit events.
dpath = Deki.url.encode('"..page.path..'/Tasks'.."' + '/' + m['desc'].replace(/ /g,'_').replace(/\\//g,'//'));
var edpath = Deki.url.encode(Deki.url.encode(dpath));
var ddata = '<p><a href=" ..page.path ..">Return To: "..page.title.."</a></p><pre class=\\'script\\'> ToDoItem() </pre><p><h2>Notes:</h2></p>';
Deki.$.ajax({
type: 'POST',
url: dapi+edpath+dparams,
data: ddata,
complete: function(xhr){
if(xhr.status == 200) {
SaveProperty(dpath, m);
} else if(xhr.status == 400){
var response = '';
alert('Bad Requst (400): ' + response);
}
else if(xhr.status == 403) alert('Permission denied (403): Are you logged in?');
else alert('Error ' + xhr.status);
}
});
}, null);
"</script>
<script type="text/javascript">"
// Create Property
var SaveProperty = function(page, properties) {
var pageapi = '/@api/deki/pages/=' + Deki.url.encode(Deki.url.encode(page));
Deki.Api.CreatePageProperty(pageapi, 'urn:custom.mindtouch.com#todo-item', YAHOO.lang.JSON.stringify(properties), function() {
// alert('Thank you. The information has been submitted.');
location.href = '/' + page;
}, function(result) {
if(result.text == '400') {
alert('Task may already exist.');
} else {
alert('An error occurred trying to create the store (status: ' + result.status + ' - ' + result.text + ')');
}
});
}
"</script>
<html><head>
// *** HERE WE START TO DEFINE THE TASK ROLL CALL TABLE ***
// <script type="text/javascript" src="http://jqueryui.com/latest/jquery-1.3.2.js"></script>
<script type="text/javascript" src="http://developer.mindtouch.com/@api/deki/files/4844/=jquery.livequery.js" />
<script type="text/javascript">"
$(document).ready(function() {
$('div.todomaster').hide();
$('div#projectProgress').hide();
$('div#projectProgress').appendTo('#progressParent');
$('div#TaskDetailViewer').hide();
$('div#TaskDetailViewer').click(function(){$(this).hide()});
$(document).click(function(){$('div#TaskDetailViewer').hide()});
$('#user-suggest #userlist a').livequery('click', function(event) {
$('#assignee').append('<option selected=\"selected\" value=\"' + $(this).text() + '\">' + $(this).text() + '</option>');
$('#user-suggest').hide();
$('#user-search').val('');
$('#user-search').focus();
return false;
});
$('#assignee').dblclick(function() {
$('#assignee option:selected').remove();
});
});
$('body').ready( function() {
$('#user-search').keyup( function() {
if ($(this).val()==''){
$('#user-suggest').hide();
return false;
}
var q = $(this).val();
clearTimeout($.data(this, 'timer'));
var ms = 400; //milliseconds
var wait = setTimeout(function() {
loadusers(q);
}, ms);
$.data(this, 'timer', wait);
});
});
function loadusers(u) {
$('#user-suggest').hide();
var userapi = 'http://developer.mindtouch.com/@api/deki/users?sortby=username&limit=20&activatedfilter=true&usernamefilter=' + u;
jQuery.get(userapi,function(xml){
// clear the previous results
$('#user-suggest #userlist div').remove();
// Establish a place holder for our name We need to do this so that we only get 1 unique username per user.
var theuser;
$(xml).find('users > user').each(function() {
$(this).find('username').each(function() {
theuser = $(this).text();
return theuser;
});
$('#user-suggest #userlist').append('<div class=\"userpick\"><a href=\"#\" id=\"' + theuser + '\">' + theuser + '</a></div>');
});
});
$('#user-suggest').show();
}
function ShowMyDetails(pid) {
$('div#TaskDetailViewer').hide();
Deki.$.ajax({
type: 'GET',
url: 'http://developer.mindtouch.com/@api/deki/pages/' + pid + '/contents?section=1&include=true',
dataType: 'xml',
success: function(data){
$('#TaskDetailViewer').html( '<p style=\"text-align:center;\">Click to Close</p>' + $(data).find('content').text() );
}
});
// centerIt($('div#TaskDetailViewer'));
$('div#TaskDetailViewer').show();
}
// function centerIt($el) {
// var frm = $('iframe',top.document.body);
// var iframeXOffset = 0, iframeYOffset = 0, windowHeight = 0, windowWidth = 0;
// var i=frm.length;
// while (i--) {
// if (frm[i].contentDocument) {
// doc = frm[i].contentDocument;
// } else {
// doc = frm[i].contentWindow.document;
// }
// if (doc === document) {
// //located our iframe!
// iframeXOffset = $(frm[i]).offset().left;
// iframeYOffset = $(frm[i]).offset().top;
// break;
// }
// };
// if (jQuery.browser.msie) {
// windowWidth = top.window.document.documentElement.clientWidth;
// windowHeight = top.window.document.documentElement.clientHeight;
// } else {
// windowWidth = top.window.innerWidth;
// windowHeight = top.window.innerHeight;
// }
// var elHeight = $el.height();
// var newTop = ((windowHeight/2) - (elHeight/2)) - iframeYOffset + $(parent.document.documentElement).scrollTop();
// if ((newTop + elHeight) > $(document).height()) {
// newTop = $(document).height() - elHeight;
// }
// $el.css ({
// left: ((windowWidth/2) - ($el.width()/2)) - iframeXOffset + $(parent.document.documentElement).scrollLeft(),
// top: newTop
// });
// }
"</script>
<style type="text/css">"
#user-suggest {
width=650px;
position:absolute;
border:1px solid #ccc;
background:#fff;
z-index:50;
}
#user-suggest div#userlist div.userpick:hover {
text-decoration: underline;
background-color:#0099CC;
}
#user-suggest div#userlist div.userpick a {
text-decoration: none;
}
#user-suggest div#userlist div.userpick {
text-decoration: none;
background-color:#FFFFcc;
padding-left:10px;
padding-right: 10px;
}
div#TaskDetailViewer{
position:fixed;
z-index:100;
border:1px solid #000000;
margin: auto;
overflow: auto;
background-color:#FFFFCC;
height: 400px;
/*width: 600px;*/
padding: 5px;
top: 25%;
left: 25%;
width: 50%;
display: none; /* so the element does not get rendered when the page loads. */
}
div#projectProgress {
width:155px;
float: right;
position:absolute;
margin-top:25px;
overflow:hidden;
}
div#progressParent {
width:155px;
margin-bottom: 5px;
float: right;
background-color:#FFFFFF;
position:relative;
}
"</style>
</head></html>
<div style="width:100%;">
</div>
<table border="0" width="100%">
<tbody>
<tr>
<td style="vertical-align:bottom; width:33%;">
<div><strong><a style="float:left" href="#" ctor="$(this).click(function(){$('div.todomaster').toggle(); return false;});" >'New Task'</a></strong></div>
</td>
<td style="vertical-align: bottom; text-align:center; width:33%">
<div><strong><a href="#" ctor="$(this).click(function(){$('div.todolist').toggle(); return false;});" >'Current Task Item(s)'</a></strong></div>
</td>
<td style="vertical-align:bottom; text-align:center;">
<div id="progressParent"><strong><a href="#" style="float:right" ctor="when($this.click) {return false;}; when($this.mouseover){ $('div#projectProgress').show()}; when($this.mouseout) {$('div#projectProgress').hide()}">'Total Progress'</a></strong></div>
</td>
</tr>
</tbody>
</table>
var percentmap = {1:'0%',2:'25%',3:'50%',4:'75%',5:'100%',default:'0%'};
var prioritymap = {1:'1',2:'2',3:'3',default:'Unk'};
var CurProgress = 0;
var ProgressPossible=0;
var OverAllProgress=0;
<div class="todolist">
if(wiki.pageexists(page.path .."/Tasks") || #wiki.pageexists(page.path .."/Tasks")>0) {
tstable();
<table id="TaskItems" border="1" width="100%">
<tr>
<th>
'Task ID'
</th>
<th>
'Description'
</th>
<th>
'Assignee(s)'
</th>
<th>
'Priority'
</th>
<th>
'Due Date'
</th>
<th>
'Progress'
</th>
<th>
'On Hold'
</th>
<th>
'Complete Date'
</th>
<th>
'Notes'
</th>
</tr>
foreach(var taskitem in wiki.getpage(page.path ..'/Tasks').subpages) {
var taskdetail = json.parse(taskitem.properties['todo-item'].text ?? "") ?? [];
foreach(var a in taskdetail.assignee) {
let ProgressPossible = ProgressPossible + 4;
let curprogress = (curprogress + taskdetail.percent -1);
<tr>
<td>
web.link(taskitem.uri, taskitem.id);
</td>
<td>
taskdetail.desc;
</td>
<td>
a;
</td>
<td>
prioritymap[((taskdetail.priority==nil || taskdetail.priority == '') ? 'default' : taskdetail.priority)];
</td>
<td>
taskdetail.duedate;
</td>
<td>
percentmap[((taskdetail.percent==nil || taskdetail.percent=='') ? 'default' : taskdetail.percent)];
</td>
<td>
(taskdetail.hold==true);
</td>
<td>
(date.isvalid(taskdetail.donedate) ? date.format(taskdetail.donedate,'MM/dd/yyyy') : 'N/A');
</td>
<td>
<a href="#" id=(taskitem.id ..'-'..__index) taskid=(taskitem.id) ctor="when($this.click){ ShowMyDetails($this.attr('taskid')); return false; };" >'view'</a>
</td>
</tr>
}
}
</table>
} else {
<div>'No Tasks Yet Created...'</div>
}
</div>
let OverAllProgress = ( num.round( ((curprogress / progresspossible) * 100), 0) );
<div id="projectProgress">
// GoogleStatusIndicator{value: OverAllProgress, text: '' ..OverAllProgress ..'%', height: '200', width: '120'};
var text = '' ..OverAllProgress ..'%';
// web.image('http://chart.apis.google.com/chart?chs=200x120&cht=gom&chd=t:' ..OverAllProgress ..'&chl=' ..web.uriencode(text));
var theUrl = 'http://chart.apis.google.com/chart?chs=200x120&cht=gom&chd=t:' ..OverAllProgress ..'&chl=' ..web.uriencode(text);
<img style="margin-top:-15px;" src=(theUrl) />
</div>
<div id="TaskDetailViewer" height="30%"></div>
Template:ToDoItem
dekiapi();
jQuery.ui("smoothness");
<script type="text/javascript">"
"</script>
var todo = json.parse(page.properties['todo-item'].text ?? "") ?? [];
'This task has been assigned and ID of: ' ..page.id;
<div>
<form>
<input id="projpage" type="hidden" value=(todo.projectpage) />
<table bgcolor="#f0ffff" id="subtodoedit" cellspacing="1" cellpadding="1" border="1" width="100%" style="table-layout: fixed;">
<tbody>
<tr>
<td valign="middle" rowspan="4"><span style="align:center;">'Assignee(s):'</span>; <br/>;
<input type="text" id="user-search" />
<div id="user-suggest">
<div id="userlist">
</div>
</div>
<select id="subassignee" size ="4" multiple="true" style="width:100%">
foreach(var u in todo.assignee) {
<option value=(u) selected=('selected')>u</option>
}
</select>
</td>
<td align="right" valign="middle">'Assigner: '; <input id="subassigner" type="text" value=((todo.assigner ?? user.name)) disabled=((todo.assigner==nil) ? nil : 'disabled') />
</td>
<td align="right" valign="middle">'Start Date: '; <input id="substart" type="text" value=(((todo.startdate==nil) ? date.format(date.now, 'MM/dd/yyyy') : todo.startdate)) disabled=((todo.startdate==nil) ? nil : 'disabled') ctor="$this.datepicker();"/>
</td>
</tr>
<tr>
<td align="right" valign="middle">'Priority: ';
<select id="subpriority">
<option value="3" selected=(((todo.priority == 3) ? 'selected' : nil))>'3'</option>
<option value="2" selected=(((todo.priority == 2) ? 'selected' : nil))>'2'</option>
<option value="1" selected=(((todo.priority == 1) ? 'selected' : nil))>'1'</option>
</select>
' Percent: ';
<select id="subpercent">
<option value="5" selected=(((todo.percent == 5) ? 'selected' : nil))>'100%'</option>
<option value="4" selected=(((todo.percent == 4) ? 'selected' : nil))>'75%'</option>
<option value="3" selected=(((todo.percent == 3) ? 'selected' : nil))>'50%'</option>
<option value="2" selected=(((todo.percent == 2) ? 'selected' : nil))>'25%'</option>
<option value="1" selected=(((todo.percent == 1) ? 'selected' : nil))>'0%'</option>
</select>
</td>
<td align="right" valign="middle">'Due Date: '; <input id="subdue" type="text" value=(((todo.duedate==nil) ? date.format(date.now, 'MM/dd/yyyy') : todo.duedate)) ctor="$this.datepicker();"/>
</td>
</tr>
<tr>
<td align="left" valign="middle" colspan="2">'Short Description: ';<input id="subdesc" type="text" value=(((todo.desc==nil) ? "" : todo.desc)) disabled=((todo.desc==nil) ? nil : 'disabled') style="width:30em" maxlength="40" />
</td>
</tr>
<tr>
<td>
'Task On Hold: '; <input type="checkbox" id="onhold" value="" checked=(((todo.hold == true) ? 'checked' : nil)) />;
<br/>;
'Reason: '; <input type="text" id="holdreason" value=(((todo.holdreason==nil) ? "" : todo.holdreason)) />;
</td>
<td>
'Task Complete: '; <input type="checkbox" id="tododone" value="" checked=(((todo.done == true) ? 'checked' : nil)) ctor="
when($this.click) {
if($this.attr('checked')){
if(#subpercent.val() != '5') {
alert('Task not marked 100% done');
$this.attr('checked', false)
return;
} else {
#onhold.attr('checked',false);
#holdreason.attr('value', '');
#donedate.attr('value', ({{date.format(date.now, 'MM/dd/yyyy')}}));
}
} else {
#donedate.attr('value', (''));
}
}
"/>;
<br/>;
'Done Date: '; <input type="text" id="donedate" value=(((todo.donedate==nil) ? "" : todo.donedate )) />;
</td>
</tr>
<tr>
<td align="center" valign="middle" colspan="3">
<input id="subupdatetodo" type="button" value="Update" style="margin-top:15px;margin-bottom:15px" ctor="
when($this.click) {
$('#subassignee option').each(function(i) {
$(this).attr('selected','selected');
});
var todoitem = ({ assignee: #subassignee.val(),
assigner: #subassigner.val(),
startdate: #substart.val(),
priority: #subpriority.val(),
percent: #subpercent.val(),
duedate: #subdue.val(),
desc: #subdesc.val(),
done: #tododone.attr('checked'),
donedate: #donedate.val(),
hold: #onhold.attr('checked'),
holdreason: #holdreason.val(),
projectpage: #projpage.val(),
whochanged: {{user.name}}
});
#save.blur();
Deki.publish('ch_updatetodo', todoitem);
}
" />
</td>
</tr>
</tbody>
</table>
</form>
</div>
<script type="text/jem">"
var dapi = '/@api/deki/pages/=';
var dpath = Deki.url.encode('"..page.path.."');
Deki.subscribe('ch_updatetodo',null, function(c, m, d) {
UpdateProperty(dpath,m);
}, null);
"</script>
<script type="text/javascript">"
// Create Property
var SaveProperty = function(page, properties) {
var pageapi = '/@api/deki/pages/=' + Deki.url.encode(Deki.url.encode(page));
Deki.Api.CreatePageProperty(pageapi, 'urn:custom.mindtouch.com#todo-item', YAHOO.lang.JSON.stringify(properties), function() {
alert('Thank you. The information has been submitted.');
}, function(result) {
alert('An error occurred trying to create the store (status: ' + result.status + ' - ' + result.text + ')');
});
}
var UpdateProperty = function(page, properties) {
var pageapi = '/@api/deki/pages/=' + Deki.url.encode(Deki.url.encode(page));
Deki.Api.ReadPageProperty(null, 'urn:custom.mindtouch.com#todo-item', function(result) {
if(result.etag) { // page property exists, write over it.
Deki.Api.UpdatePageProperty(result.href, YAHOO.lang.JSON.stringify(properties), result.etag, function() {
alert('Your task has been updated!');
}, function(result) {
alert('An error occurred trying to update the store (status: ' + result.status + ' - ' + result.text + ')');
});
}
}, function(result) {
alert('An error occurred trying to read the store (status: ' + result.status + ' - ' + result.text + ')');
});
}
"</script>
<html><head>
// <script type="text/javascript" src="http://jqueryui.com/latest/jquery-1.3.2.js"></script>
<script type="text/javascript" src="http://developer.mindtouch.com/@api/deki/files/4844/=jquery.livequery.js" />
<script type="text/javascript">"
$(document).ready(function() {
$('#user-suggest #userlist a').livequery('click', function(event) {
$('#subassignee').append('<option selected=\"selected\" value=\"' + $(this).text() + '\">' + $(this).text() + '</option>');
$('#user-suggest').hide();
$('#user-search').val('');
$('#user-search').focus();
return false;
});
$('#subassignee').dblclick(function() {
$('#subassignee option:selected').remove();
});
});
$('body').ready( function() {
$('#user-search').keyup( function() {
if ($(this).val()==''){
$('#user-suggest').hide();
return false;
}
var q = $(this).val();
clearTimeout($.data(this, 'timer'));
var ms = 400; //milliseconds
var wait = setTimeout(function() {
loadusers(q);
}, ms);
$.data(this, 'timer', wait);
});
});
function loadusers(u) {
$('#user-suggest').hide();
var userapi = 'http://developer.mindtouch.com/@api/deki/users?sortby=username&limit=20&activatedfilter=true&usernamefilter=' + u;
jQuery.get(userapi,function(xml){
// clear the previous results
$('#user-suggest #userlist div').remove();
// Establish a place holder for our name We need to do this so that we only get 1 unique username per user.
var theuser;
$(xml).find('users > user').each(function() {
$(this).find('username').each(function() {
theuser = $(this).text();
return theuser;
});
$('#user-suggest #userlist').append('<div class=\"userpick\"><a href=\"#\" id=\"' + theuser + '\">' + theuser + '</a></div>');
});
});
$('#user-suggest').show();
}
"</script>
<style type="text/css">"
#user-suggest {
width=650px;
position:absolute;
border:1px solid #ccc;
background:#fff;
z-index:50;
}
#user-suggest div#userlist div.userpick:hover {
text-decoration: underline;
background-color:#0099CC;
}
#user-suggest div#userlist div.userpick a {
text-decoration: none;
}
#user-suggest div#userlist div.userpick {
text-decoration: none;
background-color:#FFFFcc;
padding-left:10px;
padding-right: 10px;
}
"</style>
</head></html>
<html><head>
<script type="text/javascript">"
$(document).ready(function() {
$('#taskhistory').hide();
$('a#showhistory').click(function() {
$('#taskhistory').toggle('slow');
});
});
"</script>
<style type="text/css">"
#taskhistory{
border:1px solid #CCCC33;
padding:10px;
margin-top:10px;
width:500px;
font-size:10px;
overflow:scroll;
}
"</style>
</head></html>
// *** HERE WE DEFINE THE BODY OF THE TASK ITEM ***
var prevprop = {};
var summary = '';
var curprop = {};
var validkeys =['assignee','assigner','startdate','priority','percent','duedate','desc','done','donedate','hold','holdreason'];
<p>
<a href="#" id="showhistory">'Task History'</a>
</p>
<div id="taskhistory" class="hideable">
foreach(var prop in page.properties) {
foreach(var rev in prop.revisions) {
if(rev.name == 'todo-item') {
// date.format(rev.date,'u'); ' - '; rev.revision; <br/>; json.parse(rev.text);
let curprop = json.parse(rev.text);
let summary = '<b>' ..curprop.whochanged ..'</b> updated this task on: ' ..date.format(rev.date,'u') ..'<br/>';
if(rev.revision == 1) {
// This is the initial created task
let prevprop = curprop;
let summary ..= '<b>Task Created!</b><br/>'
} else {
// Compare against previous property
foreach(var k in validkeys) {
if(typeof curprop[k] == 'list') {
var prevlistprop = list.sort(prevprop[k]);
foreach(var li in list.sort(curprop[k])) {
if(li not in prevlistprop) {
let summary ..= ((curprop[k] == prevprop[k]) ? '' : 'Changed: <b>\"' ..k ..'\"</b> New Value(s): <b>\"' ..curprop[k] ..'\"</b><br/>');
break;
}
}
} else {
let summary ..= ((curprop[k] == prevprop[k]) ? '' : 'Changed: <b>\"' ..k ..'\"</b> New Value(s): <b>\"' ..curprop[k] ..'\"</b><br/>');
}
}
let prevprop = curprop;
}
web.html(summary); <br/>;
}
}
}
</div>
None.
| File | Version | Size | Modified | |
|---|---|---|---|---|
| ||||
| Images 0 | ||
|---|---|---|
| No images to display in the gallery. |
Copyright © 2011 MindTouch, Inc. Powered by
I'm having trouble getting the ToDoMaster template working on MindTouch Core v9.08.3. I've installed the jQuery and Deki AJAX API extensions per the instructions on their pages. I've also created the TsTable template and that works without error. When I copy the ToDoMaster template source, create a new template, switch to Source mode, change the H1 to contain Template:ToDoMaster, add the <pre class="script"></pre>, paste the template source inbetween the pre tags and save, I get the error "pre, line 5, column 83: EOF expected". This is on saving the template. I've tried the same but also replacing the developer.mindtouch.com URLs to be my local server's and get the same error so I don't think that's the issue. I've tried ignoring the error and using the template on another page and get a similar EOF error on that page.
Does anyone know what I'm doing wrong?
Another thing I tried was manually manipulating the source to see on what line it was failing. The first line that generates an error when saving the template is line 29 (of the template source provided on this site). That is <option value="2" selected=((2 ? 'selected' : nil))>'2'</option>. I tried adding a semi-colon after the '2' and that got it past that line. I don't know if that's a useful hint.
Any help would be really appreciated.
Thanks!
http://developer.mindtouch.com/App_Catalog/Integrated_Bug_and_Issue_Tracker#comment21
Both extensions use dekiapi. ¿Maybe the source of the bug?
what language are you running Mindtouch under? I've have had problems with templates when it's set to danish, but they work if the language is English (US)
thanks
danilo edited 09:07, 31 Jan 2011