This commit is contained in:
Max Pozdeev 2009-09-26 16:35:35 +04:00
commit 3b46ebb5b0
12 changed files with 648 additions and 379 deletions

View file

@ -21,15 +21,19 @@ var img = {
};
var taskCnt = { total:0, past: 0, today:0, soon:0 };
var tmp = {};
var oBtnMenu = {};
var tabLists;
var curList = 0;
var tagsList = [];
function loadTasks()
{
tz = -1 * (new Date()).getTimezoneOffset();
setAjaxErrorTrigger();
if(filter.search) search = '&s='+encodeURIComponent(filter.search); else search = '';
if(filter.tag) tag = '&t='+encodeURIComponent(filter.tag); else tag = '';
nocache = '&rnd='+Math.random();
$.getJSON('ajax.php?loadTasks&compl='+filter.compl+'&sort='+sortBy+search+tag+'&tz='+tz+nocache, function(json){
var search = filter.search ? '&s='+encodeURIComponent(filter.search) : '';
var tag = filter.tag ? '&t='+encodeURIComponent(filter.tag) : '';
var nocache = '&rnd='+Math.random();
$.getJSON('ajax.php?loadTasks&list='+curList.id+'&compl='+filter.compl+'&sort='+sortBy+search+tag+'&tz='+tz+nocache, function(json){
resetAjaxErrorTrigger();
taskList = new Array();
taskOrder = new Array();
@ -56,18 +60,19 @@ function loadTasks()
function prepareTaskStr(item)
{
id = parseInt(item.id);
prio = parseInt(item.prio);
readOnly = (flag.needAuth && flag.canAllRead && !flag.isLogged) ? true : false;
var id = parseInt(item.id);
var prio = parseInt(item.prio);
var readOnly = (flag.needAuth && flag.canAllRead && !flag.isLogged) ? true : false;
return '<li id="taskrow_'+id+'" class="'+(item.compl?'task-completed ':'')+item.dueClass+'" onDblClick="editTask('+id+')"><div class="task-actions">'+
'<a href="#" onClick="return toggleTaskNote('+id+')"><img src="'+img.note[0]+'" onMouseOver="this.src=img.note[1]" onMouseOut="this.src=img.note[0]" title="'+lang.actionNote+'"></a>'+
'<a href="#" onClick="return editTask('+id+')"><img src="'+img.edit[0]+'" onMouseOver="this.src=img.edit[1]" onMouseOut="this.src=img.edit[0]" title="'+lang.actionEdit+'"></a>'+
'<a href="#" onClick="return deleteTask('+id+')"><img src="'+img.del[0]+'" onMouseOver="this.src=img.del[1]" onMouseOut="this.src=img.del[0]" title="'+lang.actionDelete+'"></a></div>'+
'<div class="task-left"><input type="checkbox" '+(readOnly?'disabled':'')+' onClick="completeTask('+id+',this)" '+(item.compl?'checked':'')+'></div>'+
'<div class="task-left"><div class="mtt-toggle '+(item.note==''?'invisible':'')+'" onClick="toggleNote('+id+')"></div>'+
'<input type="checkbox" '+(readOnly?'disabled':'')+' onClick="completeTask('+id+',this)" '+(item.compl?'checked':'')+'></div>'+
'<div class="task-middle">'+prepareDuedate(item.duedate, item.dueClass, item.dueStr)+
'<span class="nobr"><span class="task-through">'+preparePrio(prio,id)+'<span class="task-title">'+prepareHtml(item.title)+'</span>'+
prepareTagsStr(item.tags)+'<span class="task-date">'+lang.taskDate(item.date)+'</span></span></span>'+
'<div class="task-note-block'+(item.note==''?' hidden':'')+'">'+
'<div class="task-note-block hidden">'+
'<div id="tasknote'+id+'" class="task-note"><span>'+prepareHtml(item.note)+'</span></div>'+
'<div id="tasknotearea'+id+'" class="task-note-area"><textarea id="notetext'+id+'"></textarea>'+
'<span class="task-note-actions"><a href="#" onClick="return saveTaskNote('+id+')">'+lang.actionNoteSave+
@ -79,13 +84,13 @@ function prepareTaskStr(item)
function prepareHtml(s)
{
// make URLs clickable
s = s.replace(/(^|\s|>)(www\.([\w\#$%&~\/.\-\+;:=,\?\[\]@]+?))(,|\.|:|)?(?=\s|&quot;|&lt;|&gt;|\"|<|>|$)/gi, '$1<a href="http://$2" target="_blank">$2</a>$4');
var s = s.replace(/(^|\s|>)(www\.([\w\#$%&~\/.\-\+;:=,\?\[\]@]+?))(,|\.|:|)?(?=\s|&quot;|&lt;|&gt;|\"|<|>|$)/gi, '$1<a href="http://$2" target="_blank">$2</a>$4');
return s.replace(/(^|\s|>)((?:http|https|ftp):\/\/([\w\#$%&~\/.\-\+;:=,\?\[\]@]+?))(,|\.|:|)?(?=\s|&quot;|&lt;|&gt;|\"|<|>|$)/ig, '$1<a href="$2" target="_blank">$2</a>$4');
}
function preparePrio(prio,id)
{
cl = v = '';
var cl =''; var v = '';
if(prio < 0) { cl = 'prio-neg'; v = '&minus;'+Math.abs(prio); }
else if(prio > 0) { cl = 'prio-pos'; v = '+'+prio; }
else { cl = 'prio-o'; v = '&plusmn;0'; }
@ -95,9 +100,9 @@ function preparePrio(prio,id)
function prepareTagsStr(tags)
{
if(!tags || tags == '') return '';
a = tags.split(',');
var a = tags.split(',');
if(!a.length) return '';
for(i in a) {
for(var i in a) {
a[i] = '<a href="#" class="tag" onClick=\'addFilterTag("'+a[i]+'");return false\'>'+a[i]+'</a>';
}
return '<span class="task-tags">'+a.join(', ')+'</span>';
@ -114,8 +119,8 @@ function submitNewTask(form)
if(form.task.value == '') return false;
var tz = -1 * (new Date()).getTimezoneOffset();
setAjaxErrorTrigger()
nocache = '&rnd='+Math.random();
$.post('ajax.php?newTask'+nocache, { title: form.task.value, tz:tz, tag:filter.tag }, function(json){
var nocache = '&rnd='+Math.random();
$.post('ajax.php?newTask'+nocache, { list:curList.id, title: form.task.value, tz:tz, tag:filter.tag }, function(json){
resetAjaxErrorTrigger();
if(!parseInt(json.total)) return;
$('#total').text( parseInt($('#total').text()) + parseInt(json.total) );
@ -153,7 +158,7 @@ function flashError(str, details)
function toggleMsgDetails()
{
el = $("#msgdetails");
var el = $("#msgdetails");
if(!el) return;
if(el.css('display') == 'none') el.show();
else el.hide()
@ -171,7 +176,7 @@ function deleteTask(id)
return false;
}
setAjaxErrorTrigger()
nocache = '&rnd='+Math.random();
var nocache = '&rnd='+Math.random();
$.getJSON('ajax.php?deleteTask='+id+nocache, function(json){
resetAjaxErrorTrigger();
if(!parseInt(json.total)) return;
@ -188,7 +193,7 @@ function deleteTask(id)
function completeTask(id,ch)
{
compl = 0;
var compl = 0;
if(ch.checked) compl = 1;
setAjaxErrorTrigger();
$.getJSON('ajax.php?completeTask='+id+'&compl='+compl+nocache, function(json){
@ -216,13 +221,14 @@ function completeTask(id,ch)
function toggleTaskNote(id)
{
aArea = '#tasknotearea'+id;
var aArea = '#tasknotearea'+id;
if($(aArea).css('display') == 'none')
{
$('#notetext'+id).val(taskList[id].noteText);
$('#taskrow_'+id+'>div>div.task-note-block').removeClass('hidden');
$(aArea).css('display', 'block');
$('#tasknote'+id).css('display', 'none');
if(taskList[id].note != '') $('#taskrow_'+id+' .mtt-toggle').addClass('mtt-toggle-expanded');
$('#notetext'+id).focus();
} else {
cancelTaskNote(id)
@ -243,7 +249,7 @@ function cancelTaskNote(id)
function saveTaskNote(id)
{
setAjaxErrorTrigger()
nocache = '&rnd='+Math.random();
var nocache = '&rnd='+Math.random();
$.post('ajax.php?editNote='+id+nocache, {note: $('#notetext'+id).val()}, function(json){
resetAjaxErrorTrigger();
if(!parseInt(json.total)) return;
@ -251,6 +257,8 @@ function saveTaskNote(id)
taskList[id].note = item.note;
taskList[id].noteText = item.noteText;
$('#tasknote'+item.id+'>span').html(prepareHtml(item.note));
if(item.note == '') $('#taskrow_'+id+' .mtt-toggle').removeClass('mtt-toggle-expanded').addClass('invisible');
else $('#taskrow_'+id+' .mtt-toggle').addClass('mtt-toggle-expanded').removeClass('invisible');
cancelTaskNote(item.id);
}, 'json');
return false;
@ -265,12 +273,12 @@ function editTask(id)
document.edittask.id.value = item.id;
document.edittask.tags.value = item.tags.split(',').join(', ');
document.edittask.duedate.value = item.duedate;
sel = document.edittask.prio;
for(i=0; i<sel.length; i++) {
var sel = document.edittask.prio;
for(var i=0; i<sel.length; i++) {
if(sel.options[i].value == item.prio) sel.options[i].selected = true;
}
$('<div id="overlay"></div>').appendTo('body').css('opacity', 0.5).show();
w = $('#page_taskedit');
var w = $('#page_taskedit');
if(!flag.windowTaskEditMoved)
{
var x,y;
@ -302,6 +310,7 @@ function cancelEdit(e)
document.edittask.note.value = '';
document.edittask.tags.value = '';
document.edittask.duedate.value = '';
toggleEditAllTags(0);
return false;
}
@ -309,8 +318,8 @@ function saveTask(form)
{
if(flag.needAuth && !flag.isLogged && flag.canAllRead) return false;
setAjaxErrorTrigger();
nocache = '&rnd='+Math.random();
$.post('ajax.php?editTask='+form.id.value+nocache, { title: form.task.value, note:form.note.value, prio:form.prio.value, tags:form.tags.value, duedate:form.duedate.value }, function(json){
var nocache = '&rnd='+Math.random();
$.post('ajax.php?editTask='+form.id.value+nocache, { list:curList.id, title: form.task.value, note:form.note.value, prio:form.prio.value, tags:form.tags.value, duedate:form.duedate.value }, function(json){
resetAjaxErrorTrigger();
if(!parseInt(json.total)) return;
var item = json.list[0];
@ -348,19 +357,19 @@ function orderChanged(event,ui)
{
if(!ui.item[0]) return;
var itemId = ui.item[0].id;
n = $(this).sortable('toArray');
var n = $(this).sortable('toArray');
// remove possible empty id's
for(i=0; i<sortOrder.length; i++) {
for(var i=0; i<sortOrder.length; i++) {
if(sortOrder[i] == '') { sortOrder.splice(i,1); i--; }
}
if(n.toString() == sortOrder.toString()) return;
// make assoc from array for easy index
var h0 = new Array();
for(j=0; j<sortOrder.length; j++) {
for(var j=0; j<sortOrder.length; j++) {
h0[sortOrder[j]] = j;
}
var h1 = new Array();
for(j=0; j<n.length; j++) {
for(var j=0; j<n.length; j++) {
h1[n[j]] = j;
taskOrder[j] = n[j].split('_')[1];
}
@ -368,18 +377,18 @@ function orderChanged(event,ui)
var s = '';
var diff;
var replaceOW = taskList[sortOrder[h1[itemId]].split('_')[1]].ow;
for(j in h0)
for(var j in h0)
{
diff = h1[j] - h0[j];
if(diff != 0) {
a = j.split('_');
var a = j.split('_');
if(j == itemId) diff = replaceOW - taskList[a[1]].ow;
s += a[1] +'='+ diff+ '&';
taskList[a[1]].ow += diff;
}
}
setAjaxErrorTrigger();
nocache = '&rnd='+Math.random();
var nocache = '&rnd='+Math.random();
$.post('ajax.php?changeOrder'+nocache, { order: s }, function(json){
resetAjaxErrorTrigger();
}, 'json');
@ -401,17 +410,6 @@ function searchTasks()
return false;
}
function tabSelected(event, ui)
{
// reload tasks when we return to task tab (from search tab)
if(ui.index == 0 && filter.search != '') {
filter.search = '';
$('#searchbarkeyword').text('');
$('#searchbar').hide();
loadTasks();
}
}
function dehtml(str)
{
return str.replace(/&quot;/g,'"').replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&');
@ -422,57 +420,54 @@ function errorDenied()
flashError(lang.denied);
}
function updateAccessStatus(onInit)
function updateAccessStatus()
{
if(flag.needAuth && !flag.isLogged) $("#tasklist").sortable('disable').addClass('readonly');
else if(sortBy == 0) $("#tasklist").sortable('enable').removeClass('readonly');
else $("#tasklist").removeClass('readonly');
if(!flag.canAllRead && !flag.isLogged) {
$('#page_tasks > h3,#taskcontainer').hide();
$('#tabs').hide();
// flag.needAuth is not changed after pageload
if(flag.needAuth)
{
$('#bar_auth').show();
if(flag.isLogged) {
showhide($("#bar_logout"),$("#bar_login"));
$('#bar .menu-owner').show();
$('#bar .bar-delim').show();
}
else {
showhide($("#bar_login"),$("#bar_logout"));
$('#bar .menu-owner').hide();
$('#bar .bar-delim').hide();
}
if(!flag.canAllRead && !flag.isLogged) {
$('#page_tasks').hide();
$('#lists').hide();
} else {
$('#page_tasks').show();
}
}
if(flag.needAuth && flag.canAllRead && !flag.isLogged) {
$("#tasklist").sortable('disable');
$('#page_tasks').addClass('readonly')
$("#authstr").text(lang.readonly).show();
addsearchToggle(1);
}
else {
$('#page_tasks > h3,#taskcontainer').show();
$('#tabs').show();
}
if(flag.needAuth) {
$('#bar_auth').show();
showhide($("#bar_login"),$("#bar_logout"));
}
if(!flag.needAuth) {
$('#page_tasks').removeClass('readonly')
if(sortBy == 0) $("#tasklist").sortable('enable');
$("#authstr").text('').hide();
$('#bar_auth').hide();
}
else if(flag.canAllRead && !flag.isLogged) $("#authstr").text(lang.readonly).addClass('attention').show();
else if(flag.isLogged) showhide($("#bar_logout"),$("#bar_login"));
else if(!flag.canAllRead) $("#authstr").text('').hide();
if(onInit == null || !onInit)
{
if(flag.isLogged) $("#tabs").tabs('enable',0).tabs('enable',1).tabs('select',0);
else if(flag.canAllRead) $("#tabs").tabs('enable',1).tabs('select', 1).tabs('disable',0);
else $("#tabs").tabs('disable',0).tabs('disable',1);
}
}
function doAuth(form)
{
setAjaxErrorTrigger();
nocache = '&rnd='+Math.random();
var nocache = '&rnd='+Math.random();
$.post('ajax.php?login'+nocache, { password: form.password.value }, function(json){
resetAjaxErrorTrigger();
form.password.value = '';
if(json.logged)
{
flag.isLogged = true;
if(filter.search != '') {
filter.search = '';
$('#searchbarkeyword').text('');
$('#searchbar').hide();
}
updateAccessStatus();
loadTasks();
loadLists();
}
else {
flashError(lang.invalidpass);
@ -485,7 +480,7 @@ function doAuth(form)
function logout()
{
setAjaxErrorTrigger();
nocache = '&rnd='+Math.random();
var nocache = '&rnd='+Math.random();
$.getJSON('ajax.php?logout'+nocache, function(json){
resetAjaxErrorTrigger();
});
@ -503,9 +498,9 @@ function logout()
function tasklistClick(e)
{
node = e.target.nodeName;
var node = e.target.nodeName;
if(node=='SPAN' || node=='LI' || node=='DIV') {
li = getRecursParent(e.target, 'LI', 10);
var li = getRecursParent(e.target, 'LI', 10);
if(li) {
if(selTask && li.id != selTask) $('#'+selTask).removeClass('clicked doubleclicked');
selTask = li.id;
@ -524,11 +519,11 @@ function getRecursParent(el, needle, level)
return getRecursParent(el.parentNode, needle, level);
}
function cancelTagFilter()
function cancelTagFilter(dontLoadTasks)
{
$('#tagcloudbtn>.btnstr').text($('#tagcloudbtn').attr('title'));
filter.tag = '';
loadTasks();
if(dontLoadTasks==null || !dontLoadTasks) loadTasks();
}
function addFilterTag(tag)
@ -540,10 +535,10 @@ function addFilterTag(tag)
function showAuth(el)
{
w = $('#authform');
var w = $('#authform');
if(w.css('display') == 'none')
{
offset = $(el).offset();
var offset = $(el).offset();
w.css({
position: 'absolute',
top: offset.top + el.offsetHeight + 3,
@ -563,7 +558,7 @@ function prioPopup(act, el, id)
clearTimeout(objPrio.timer);
return;
}
offset = $(el).offset();
var offset = $(el).offset();
$('#priopopup').css({ position: 'absolute', top: offset.top + 1, left: offset.left + 1 });
objPrio.taskId = id;
objPrio.el = el;
@ -575,7 +570,7 @@ function prioClick(prio, el)
el.blur();
prio = parseInt(prio);
setAjaxErrorTrigger();
nocache = '&rnd='+Math.random();
var nocache = '&rnd='+Math.random();
$.getJSON('ajax.php?setPrio='+objPrio.taskId+'&prio='+prio+nocache, function(json){
resetAjaxErrorTrigger();
});
@ -588,10 +583,10 @@ function prioClick(prio, el)
function showSort(el)
{
w = $('#sortform');
var w = $('#sortform');
if(w.css('display') == 'none')
{
offset = $(el).offset();
var offset = $(el).offset();
w.css({ position: 'absolute', top: offset.top+el.offsetHeight-1, left: offset.left , 'min-width': $(el).width() }).show();
$(document).bind("click", sortClose);
}
@ -613,7 +608,7 @@ function setSort(v, init)
else $("#tasklist").sortable('disable');
if(!init) {
changeTaskOrder();
exp = new Date();
var exp = new Date();
exp.setTime(exp.getTime() + 3650*86400*1000); //+10 years
document.cookie = "sort="+sortBy+'; expires='+exp.toUTCString();
}
@ -640,7 +635,7 @@ function changeTaskOrder(id)
{
id = parseInt(id);
if(taskOrder.length < 2) return;
oldOrder = taskOrder.slice();
var oldOrder = taskOrder.slice();
if(sortBy == 0) taskOrder.sort( function(a,b){
if(taskList[a].compl != taskList[b].compl) return taskList[a].compl-taskList[b].compl;
return taskList[a].ow-taskList[b].ow
@ -662,55 +657,55 @@ function changeTaskOrder(id)
if(id && taskList[id])
{
// optimization: determine where to insert task: top or after some task
indx = $.inArray(id,taskOrder);
var indx = $.inArray(id,taskOrder);
if(indx ==0) {
$('#tasklist').prepend($('#taskrow_'+id))
} else {
after = taskOrder[indx-1];
var after = taskOrder[indx-1];
$('#taskrow_'+after).after($('#taskrow_'+id));
}
}
else {
o = $('#tasklist');
for(i in taskOrder) {
var o = $('#tasklist');
for(var i in taskOrder) {
o.append($('#taskrow_'+taskOrder[i]));
}
}
}
function loadTags(callback)
{
setAjaxErrorTrigger();
$.getJSON('ajax.php?tagCloud&list='+curList.id+'&rnd='+Math.random(), function(json){
resetAjaxErrorTrigger();
if(!parseInt(json.total)) tagsList = [];
else tagsList = json.cloud;
var cloud = '';
$.each(tagsList, function(i,item){
cloud += '<a href="#" onClick=\'addFilterTag("'+item.tag+'");tagCloudClose();return false;\' class="tag w'+item.w+'" >'+item.tag+'</a>';
});
$('#tagcloudcontent').html(cloud)
flag.tagsChanged = false;
callback();
});
}
function showTagCloud(el)
{
w = $('#tagcloud');
var w = $('#tagcloud');
if(w.css('display') == 'none')
{
if(flag.tagsChanged)
{
$('#tagcloudcontent').html('');
$('#tagcloudload').show();
offset = $(el).offset();
l = Math.ceil(offset.left - w.outerWidth()/2 + $(el).outerWidth()/2);
if(l<0) l=0;
w.css({ position: 'absolute', top: offset.top+el.offsetHeight-1, left: l }).show();
setAjaxErrorTrigger();
nocache = '&rnd='+Math.random();
$.getJSON('ajax.php?tagCloud'+nocache, function(json){
resetAjaxErrorTrigger();
$('#tagcloudload').hide();
if(!parseInt(json.total)) return;
var cloud = '';
$.each(json.cloud, function(i,item){
cloud += '<a href="#" onClick=\'addFilterTag("'+item.tag+'");tagCloudClose();return false;\' class="tag w'+item.w+'" >'+item.tag+'</a>';
});
$('#tagcloudcontent').html(cloud)
flag.tagsChanged = false;
});
var offset = $(el).offset();
w.css({ position: 'absolute', top: offset.top+el.offsetHeight-1, left: offset.left }).show();
loadTags(function(){$('#tagcloudload').hide();});
}
else {
offset = $(el).offset();
l = Math.ceil(offset.left - w.outerWidth()/2 + $(el).outerWidth()/2);
if(l<0) l=0;
w.css({ position: 'absolute', top: offset.top+el.offsetHeight-1, left: l }).show();
var offset = $(el).offset();
w.css({ position: 'absolute', top: offset.top+el.offsetHeight-1, left: offset.left }).show();
}
$(document).bind("click", tagCloudClose);
}
@ -731,12 +726,10 @@ function tagCloudClose(e)
function preloadImg()
{
for(i in img) {
o = new Image();
o.src = img[i][0];
if(img[i][1] != img[i][0]) {
o = new Image();
o.src = img[i][1];
for(var i in img) {
for(var ii in img[i]) {
var o = new Image();
o.src = img[i][ii];
}
}
}
@ -745,7 +738,7 @@ function changeTaskCnt(cl, dir)
{
if(!dir) dir = 1;
else if(dir > 0) dir = 1;
else if(dir < 0) die = -1;
else if(dir < 0) dir = -1;
if(cl == 'soon') { taskCnt.soon += dir; return true; }
else if(cl == 'today') { taskCnt.today += dir; return true; }
else if(cl == 'past') { taskCnt.past+= dir; return true; }
@ -760,10 +753,10 @@ function refreshTaskCnt()
function showTaskview(el)
{
w = $('#taskview');
var w = $('#taskview');
if(w.css('display') == 'none')
{
offset = $(el).offset();
var offset = $(el).offset();
w.css({ position: 'absolute', top: offset.top+el.offsetHeight-1, left: offset.left , 'min-width': $(el).width() }).show();
$(document).bind("click", taskviewClose);
}
@ -782,7 +775,7 @@ function taskviewClose(e)
$('#taskview').hide();
}
function setTaskview(v)
function setTaskview(v, dontLoadTasks)
{
if(v == 0)
{
@ -796,7 +789,7 @@ function setTaskview(v)
if(filter.compl != 0) {
filter.compl = 0;
$('#total').text('...');
loadTasks();
if(dontLoadTasks==null || !dontLoadTasks) loadTasks();
}
}
else if(v == 1)
@ -829,15 +822,238 @@ function setTaskview(v)
function editFormResize(startstop, event)
{
f = $('#page_taskedit');
var f = $('#page_taskedit');
if(startstop == 1) {
tmp.editformdiff = f.height() - $('#page_taskedit textarea').height();
}
else if(startstop == 2) {
//to avoid bug http://dev.jqueryui.com/ticket/3628
if(f.is('.ui-draggable')) {
f.css('left',tmp.editformpos[0]).css('top',tmp.editformpos[1]).css('position', 'fixed');
f.css( {left:tmp.editformpos[0], top:tmp.editformpos[1], height:''} ).css('position', 'fixed');
}
}
else $('#page_taskedit textarea').height(f.height() - tmp.editformdiff);
}
function mttTabSelected(el, indx)
{
$(el.parentNode.parentNode).children('.mtt-tabs-selected').removeClass('mtt-tabs-selected');
$(el.parentNode).addClass('mtt-tabs-selected');
if(!tabLists[indx]) return;
if(indx != curList.i) {
$('#tasklist').html('');
if(filter.search != '') {
filter.search = '';
$('#searchbarkeyword').text('');
$('#searchbar').hide();
}
}
curList = tabLists[indx];
flag.tagsChanged = true;
cancelTagFilter(1);
setTaskview(0, 1);
loadTasks();
}
function btnMenu(el)
{
if(!el.id) return;
oBtnMenu.container = el.id+'container';
oBtnMenu.targets = [el.id, oBtnMenu.container];
var w = $('#'+oBtnMenu.container);
if(w.css('display') == 'none')
{
oBtnMenu.h = [];
$(w).children('.li').each( function(i,o){
if(o.onclick) {
oBtnMenu.h[i] = o.onclick;
$(o).bind("click2", o.onclick);
o.onclick = function(event) { $('#'+oBtnMenu.container).hide(); $(o).trigger('click2'); btnMenuClose(); }
} else {
oBtnMenu.h[i] = null;
}
} );
var offset = $(el).offset();
w.css({ position: 'absolute', top: offset.top+el.offsetHeight-1, left: offset.left , 'min-width': $(el).width() }).show();
$(document).bind("click", btnMenuClose);
}
else {
el.blur();
btnMenuClose();
}
}
function btnMenuClose(e)
{
if(e) {
if(isParentId(e.target, oBtnMenu.targets)) return;
}
$(document).unbind("click", btnMenuClose);
$('#'+oBtnMenu.container).hide().children('.li').each( function(i,o){
if(oBtnMenu.h[i]) {
o.onclick = oBtnMenu.h[i];
$(o).unbind('click2');
}
});
oBtnMenu = {};
}
function toggleNote(id)
{
var o = $('#taskrow_'+id+'>div>div.task-note-block');
if(o.is('.hidden')) $('#taskrow_'+id+' .mtt-toggle').addClass('mtt-toggle-expanded');
else $('#taskrow_'+id+' .mtt-toggle').removeClass('mtt-toggle-expanded');
o.toggleClass('hidden');
}
function toggleAllNotes(show)
{
for(var id in taskList)
{
if(taskList[id].note == '') continue;
if(show) {
$('#taskrow_'+id+' .mtt-toggle').addClass('mtt-toggle-expanded');
$('#taskrow_'+id+'>div>div.task-note-block').removeClass('hidden');
}
else {
$('#taskrow_'+id+' .mtt-toggle').removeClass('mtt-toggle-expanded');
$('#taskrow_'+id+'>div>div.task-note-block').addClass('hidden');
}
}
}
function loadLists(onInit)
{
if(flag.needAuth && !flag.isLogged && !flag.canAllRead) return false;
if(filter.search != '') {
filter.search = '';
$('#searchbarkeyword').text('');
$('#searchbar').hide();
}
setAjaxErrorTrigger();
var nocache = '&rnd='+Math.random();
$.getJSON('ajax.php?loadLists'+nocache, function(json){
resetAjaxErrorTrigger();
if(!parseInt(json.total)) {
$('#page_tasks').hide();
return;
}
tabLists = new Array();
var ti = '';
$.each(json.list, function(i,item){
item.i = i;
tabLists[i] = item;
ti += '<li class="'+(i==0?'mtt-tabs-selected':'')+'"><a href="#list'+item.id+'" onClick="mttTabSelected(this,'+i+');return false;">'+item.name+'</a></li>';
});
$('#lists>ul').html(ti);
$('#lists').show();
curList = tabLists[0];
loadTasks();
});
}
function addList()
{
var r = prompt(lang.addList, lang.addListDefault);
if(r == null) return;
setAjaxErrorTrigger()
var nocache = '&rnd='+Math.random();
$.post('ajax.php?'+nocache, { addList:1, name:r }, function(json){
resetAjaxErrorTrigger();
if(!parseInt(json.total)) return;
var item = json.list[0];
var i = tabLists.length;
item.i = i;
tabLists[i] = item;
$('#lists>ul').append('<li><a href="#list'+item.id+'" onClick="mttTabSelected(this,'+i+');return false;">'+item.name+'</a></li>');
}, 'json');
}
function renameCurList()
{
if(!curList) return;
var r = prompt(lang.renameList, dehtml(curList.name));
if(r == null || r == '') return;
setAjaxErrorTrigger()
var nocache = '&rnd='+Math.random();
$.post('ajax.php?'+nocache, { renameList:1, id:curList.id, name:r }, function(json){
resetAjaxErrorTrigger();
if(!parseInt(json.total)) return;
var item = json.list[0];
item.i = curList.i;
tabLists[curList.i] = item;
curList = item;
$('#lists>ul>.mtt-tabs-selected>a').html(item.name);
}, 'json');
}
function deleteCurList()
{
var r = confirm(lang.deleteList);
if(!r) return;
setAjaxErrorTrigger()
$.post('ajax.php?'+'&rnd='+Math.random(), { deleteList:1, id:curList.id }, function(json){
resetAjaxErrorTrigger();
if(!parseInt(json.total)) return;
loadLists();
}, 'json');
}
function addsearchToggle(toSearch)
{
if(toSearch)
{
showhide($('#htab_search'), $('#htab_newtask'));
$('#search').focus();
}
else
{
if(flag.needAuth && flag.canAllRead && !flag.isLogged) return false;
showhide($('#htab_newtask'), $('#htab_search'));
// reload tasks when we return to task tab (from search tab)
if(filter.search != '') {
filter.search = '';
$('#searchbarkeyword').text('');
$('#searchbar').hide();
loadTasks();
}
$('#task').focus();
}
}
function toggleEditAllTags(show)
{
if(show)
{
if(flag.tagsChanged) loadTags(fillEditAllTags);
else fillEditAllTags();
showhide($('#alltags_hide'), $('#alltags_show'));
}
else {
$('#alltags').hide();
showhide($('#alltags_show'), $('#alltags_hide'))
}
}
function fillEditAllTags()
{
var a = [];
for(var i=tagsList.length-1; i>=0; i--) {
a.push('<a href="#" class="tag" onClick=\'addEditTag("'+tagsList[i].tag+'");return false\'>'+tagsList[i].tag+'</a>');
}
$('#alltags .tags-list').html(a.join(', '));
$('#alltags').show();
}
function addEditTag(tag)
{
var v = $('#edittags').val();
if(v == '') {
$('#edittags').val(tag);
return;
}
var r = v.search(new RegExp('(^|,)\\s*'+tag+'\\s*(,|$)'));
if(r < 0) $('#edittags').val(v+', '+tag);
}

View file

@ -8,16 +8,31 @@ require_once('./lang/class.default.php');
require_once('./lang/'.$config['lang'].'.php');
$lang = new Lang();
if(isset($_GET['loadTasks']))
if(isset($_GET['loadLists']))
{
check_read_access();
$t = array();
$t['total'] = 0;
$q = $db->dq("SELECT * FROM lists ORDER BY id ASC");
while($r = $q->fetch_assoc($q))
{
$t['total']++;
$t['list'][] = array('id'=>$r['id'], 'name'=>htmlarray($r['name']));
}
echo json_encode($t);
exit;
}
elseif(isset($_GET['loadTasks']))
{
check_read_access();
stop_gpc($_GET);
if(_get('compl')) $sqlWhere = '';
else $sqlWhere = ' AND compl=0';
$listId = (int)_get('list');
$sqlWhere = ' AND list_id='. $listId;
if(_get('compl') == 0) $sqlWhere .= ' AND compl=0';
$inner = '';
$tag = trim(_get('t'));
if($tag != '') {
$tag_id = get_tag_id($tag);
$tag_id = get_tag_id($tag, $listId);
$inner = "INNER JOIN tag2task ON id=tag2task.task_id";
$sqlWhere .= " AND tag_id=$tag_id ";
}
@ -48,6 +63,7 @@ elseif(isset($_GET['newTask']))
stop_gpc($_POST);
$t = array();
$t['total'] = 0;
$listId = (int)_post('list');
$title = trim(_post('title'));
$prio = 0;
$tags = '';
@ -70,13 +86,13 @@ elseif(isset($_GET['newTask']))
$tz = (int)_post('tz');
if( (isset($config['autotz']) && $config['autotz']==0) || $tz<-720 || $tz>720 || $tz%30!=0 ) $d = strftime("%Y-%m-%d %H:%M:%S");
else $d = gmdate("Y-m-d H:i:s", time()+$tz*60);
$ow = 1 + (int)$db->sq("SELECT MAX(ow) FROM todolist WHERE compl=0");
$ow = 1 + (int)$db->sq("SELECT MAX(ow) FROM todolist WHERE list_id=$listId AND compl=0");
$db->ex("BEGIN");
$db->dq("INSERT INTO todolist (title,d,ow,prio) VALUES (?,?,$ow,$prio)", array($title, $d));
$db->dq("INSERT INTO todolist (list_id,title,d,ow,prio) VALUES ($listId,?,?,$ow,$prio)", array($title, $d));
$id = $db->last_insert_id();
if($tags)
{
$tag_ids = prepare_tags($tags);
$tag_ids = prepare_tags($tags, $listId);
if($tag_ids) {
update_task_tags($id, $tag_ids);
$db->ex("UPDATE todolist SET tags=? WHERE id=$id", $tags);
@ -156,6 +172,7 @@ elseif(isset($_GET['editTask']))
check_write_access();
$id = (int)$_GET['editTask'];
stop_gpc($_POST);
$listId = (int)_post('list');
$title = trim(_post('title'));
$note = str_replace("\r\n", "\n", trim(_post('note')));
$prio = (int)_post('prio');
@ -170,7 +187,7 @@ elseif(isset($_GET['editTask']))
}
$tags = trim(_post('tags'));
$db->ex("BEGIN");
$tag_ids = prepare_tags($tags);
$tag_ids = prepare_tags($tags, $listId);
$cur_ids = get_task_tags($id);
if($cur_ids) {
$ids = implode(',', $cur_ids);
@ -245,10 +262,11 @@ elseif(isset($_GET['logout']))
elseif(isset($_GET['suggestTags']))
{
check_read_access();
$listId = (int)_get('list');
$begin = trim(_get('q'));
$limit = (int)_get('limit');
if($limit<1) $limit = 8;
$q = $db->dq("SELECT name,id FROM tags WHERE name LIKE ". $db->quoteForLike('%s%%',$begin). " AND tags_count>0 ORDER BY name LIMIT $limit");
$q = $db->dq("SELECT name,id FROM tags WHERE list_id=$listId AND name LIKE ". $db->quoteForLike('%s%%',$begin). " AND tags_count>0 ORDER BY name LIMIT $limit");
$s = '';
while($r = $q->fetch_row()) {
$s .= "$r[0]|$r[1]\n";
@ -272,8 +290,9 @@ elseif(isset($_GET['setPrio']))
}
elseif(isset($_GET['tagCloud']))
{
$listId = (int)_get('list');
$a = array();
$q = $db->dq("SELECT name,tags_count FROM tags WHERE tags_count>0 ORDER BY tags_count ASC");
$q = $db->dq("SELECT name,tags_count FROM tags WHERE list_id=$listId AND tags_count>0 ORDER BY tags_count ASC");
while($r = $q->fetch_row()) {
$a[$r[0]] = $r[1];
}
@ -296,8 +315,60 @@ elseif(isset($_GET['tagCloud']))
echo json_encode($t);
exit;
}
elseif(isset($_POST['addList']))
{
check_write_access();
stop_gpc($_POST);
$t = array();
$t['total'] = 0;
$name = str_replace(array('"',"'",'<','>','&'),array('','','','',''),trim(_post('name')));
$db->dq("INSERT INTO lists (name) VALUES (?)", array($name));
$id = $db->last_insert_id();
$t['total'] = 1;
$r = $db->sqa("SELECT * FROM lists WHERE id=$id");
$t['list'][] = array('id'=>$r['id'], 'name'=>htmlarray($r['name']));
echo json_encode($t);
exit;
}
elseif(isset($_POST['renameList']))
{
check_write_access();
stop_gpc($_POST);
$t = array();
$t['total'] = 0;
$id = (int)_post('id');
$name = str_replace(array('"',"'",'<','>','&'),array('','','','',''),trim(_post('name')));
$db->dq("UPDATE lists SET name=? WHERE id=$id", array($name));
$t['total'] = $db->affected();
$r = $db->sqa("SELECT * FROM lists WHERE id=$id");
$t['list'][] = array('id'=>$r['id'], 'name'=>htmlarray($r['name']));
echo json_encode($t);
exit;
}
elseif(isset($_POST['deleteList']))
{
check_write_access();
stop_gpc($_POST);
$t = array();
$t['total'] = 0;
$id = (int)_post('id');
$db->ex("BEGIN");
$db->ex("DELETE FROM lists WHERE id=$id");
$t['total'] = $db->affected();
if($t['total']) {
$db->ex("DELETE FROM tags WHERE list_id=$id");
# sqlite doesnt support DELETE FROM INNNER JOIN
$db->ex("DELETE FROM tag2task WHERE task_id IN (SELECT id FROM todolist WHERE list_id=$id)");
$db->ex("DELETE FROM todolist WHERE list_id=$id");
}
$db->ex("COMMIT");
echo json_encode($t);
exit;
}
###################################################################################################
function prepareTaskRow($r, $tz=null)
{
$dueA = prepare_duedate($r['duedate'], $tz);
@ -334,7 +405,7 @@ function check_write_access()
exit;
}
function prepare_tags(&$tags_str)
function prepare_tags(&$tags_str, $listId)
{
$tag_ids = array();
$tag_names = array();
@ -344,7 +415,7 @@ function prepare_tags(&$tags_str)
# remove duplicate tags?
$tag = str_replace(array('"',"'",'<','>','&'),array('','','','',''),trim($v));
if($tag == '') continue;
list($tag_id,$tag_name) = get_or_create_tag($tag);
list($tag_id,$tag_name) = get_or_create_tag($tag, $listId);
if($tag_id && !in_array($tag_id, $tag_ids)) {
$tag_ids[] = $tag_id;
$tag_names[] = $tag_name;
@ -354,21 +425,21 @@ function prepare_tags(&$tags_str)
return $tag_ids;
}
function get_or_create_tag($name)
function get_or_create_tag($name, $listId)
{
global $db;
$tag = $db->sq("SELECT id,name FROM tags WHERE name=?", $name);
$tag = $db->sq("SELECT id,name FROM tags WHERE list_id=? AND name=?", array($listId, $name));
if($tag) return $tag;
# need to create tag
$db->ex("INSERT INTO tags (name) VALUES (?)", $name);
$db->ex("INSERT INTO tags (name,list_id) VALUES (?,?)", array($name,$listId));
return array($db->last_insert_id(), $name);
}
function get_tag_id($tag)
function get_tag_id($tag, $listId)
{
global $db;
$id = $db->sq("SELECT id FROM tags WHERE name=?", $tag);
$id = $db->sq("SELECT id FROM tags WHERE list_id=? AND name=?", array($listId, $tag));
return $id ? $id : 0;
}

View file

@ -1,158 +0,0 @@
<?php
class DatabaseResult_Sqlite
{
private $parent;
private $q;
var $query;
private $rows = NULL;
private $affected = NULL;
function __construct($query, &$h, $resultless = 0)
{
$this->parent = $h;
$this->query = $query;
if($resultless) $this->q = @$this->parent->dbh->queryExec($query, $error);
else $this->q = @$this->parent->dbh->query($query, 0, $error);
if(!$this->q)
{
if($error) throw new Exception($error);
else throw new Exception(sqlite_error_string($this->parent->dbh->lastError()));
}
}
function rows()
{
if (!is_null($this->rows)) return $this->rows;
$this->rows = $this->q->numRows();
return $this->rows;
}
function fetch_row()
{
return $this->q->fetch(SQLITE_NUM);
}
function fetch_assoc()
{
return $this->q->fetch(SQLITE_ASSOC);
}
}
class Database_Sqlite
{
var $dbh;
private $affected = null;
function __construct()
{
}
function connect($filename, $mode=0666)
{
try {
$this->dbh = new SQLiteDatabase($filename, 0666, $error);
}
catch(Exception $e) {
throw new Exception($error);
}
return true;
}
function sq($query, $p = NULL)
{
$q = $this->_dq($query, $p);
if($q->rows()) $res = $q->fetch_row();
else return NULL;
if(sizeof($res) > 1) return $res;
else return $res[0];
}
function sqa($query, $p = NULL)
{
$q = $this->_dq($query, $p);
if($q->rows()) $res = $q->fetch_assoc();
else return NULL;
if(sizeof($res) > 1) return $res;
else return $res[0];
}
function dq($query, $p = NULL)
{
return $this->_dq($query, $p);
}
/*
for resultless queries like INSERT,UPDATE
*/
function ex($query, $p = NULL)
{
return $this->_dq($query, $p, 1);
}
private function _dq($query, $p = NULL, $resultless = 0)
{
if(!isset($p)) $p = array();
elseif(!is_array($p)) $p = array($p);
$m = explode('?', $query);
if(sizeof($p)>0)
{
if(sizeof($m)< sizeof($p)+1) {
throw new Exception("params to set MORE than query params");
}
if(sizeof($m)> sizeof($p)+1) {
throw new Exception("params to set LESS than query params");
}
$query = "";
for($i=0; $i<sizeof($m)-1; $i++) {
$query .= $m[$i]. $this->quote($p[$i]);
}
$query .= $m[$i];
}
return new DatabaseResult_Sqlite($query, $this, $resultless);
}
function affected()
{
if(is_null($this->affected))
{
$this->affected = $this->dbh->changes();
}
return $this->affected;
}
function quote($s)
{
return '\''. sqlite_escape_string($s). '\'';
}
function quoteForLike($format, $s)
{
$s = str_replace(array('\\','%','_'), array('\\\\','\%','\_'), $s);
return $this->quote(sprintf($format, $s));
}
function last_insert_id()
{
return $this->dbh->lastInsertRowid();
}
function table_exists($table)
{
$table = $this->quote($table);
$q = @$this->dbh->query("SELECT 1 FROM $table WHERE 1=0");
if($q === false) return false;
else return true;
}
}
?>

View file

@ -6,9 +6,6 @@ $config = array();
# Uncomment this line if you want to use Mysql, in format: array("host","login","password","database");
#$config['mysql'] = array("localhost","user","password", "mytinytodo");
# To use old SQLite2 (instead of SQLite3) uncomment the line below
#$config['sqlite'] = 2;
# Language pack
$config['lang'] = "en";

BIN
src/images/toggle_minus.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 B

BIN
src/images/toggle_plus.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 B

View file

@ -56,10 +56,9 @@ function __($s)
<script type="text/javascript">
$().ready(function(){
$("#tabs").tabs({ select: tabSelected <?php echo $tabDisabled; ?>});
$("#tasklist").sortable({cancel:'span,input,a,textarea', delay: 150, update:orderChanged, start:sortStart, items:'> :not(.task-completed)'});
$("#tasklist").bind("click", tasklistClick);
$("#edittags").autocomplete('ajax.php?suggestTags', {scroll: false, multiple: true, selectFirst:false, max:8});
$("#edittags").autocomplete('ajax.php?suggestTags', {scroll: false, multiple: true, selectFirst:false, max:8, extraParams:{list:function(){return curList.id}}});
$("#priopopup").mouseleave(function(){$(this).hide()});
setSort(<?php echo $sort; ?>,1);
<?php
@ -68,19 +67,17 @@ $().ready(function(){
echo "\tflag.needAuth = true;\n";
if(!canAllRead()) echo "\tflag.canAllRead = false;\n";
if(is_logged()) echo "\tflag.isLogged = true;\n";
if(is_logged() || canAllRead()) echo "\tloadTasks();\n";
echo "\tupdateAccessStatus(1);\n";
} else {
echo "\tloadTasks();\n";
echo "\tupdateAccessStatus();\n";
}
echo "\tloadLists(1)\n";
?>
preloadImg();
$("#duedate").datepicker({dateFormat: '<?php echo $duedateformat; ?>', firstDay: <?php echo $config['firstdayofweek']; ?>,
showOn: 'button', buttonImage: 'images/calendar.png', buttonImageOnly: true, changeMonth:true,
changeYear:true, constrainInput: false, duration:'', nextText:'&gt;', prevText:'&lt;', dayNamesMin:lang.daysMin,
monthNamesShort:lang.monthsShort });
monthNamesShort:lang.monthsLong });
<?php if(!isset($_GET['pda'])): ?>
$("#page_taskedit").draggable({ stop: function(e,ui){ flag.windowTaskEditMoved=true; tmp.editformpos=[$(this).css('left'),$(this).css('top')]; } });
$("#page_taskedit").draggable({ handle:'h3', stop: function(e,ui){ flag.windowTaskEditMoved=true; tmp.editformpos=[$(this).css('left'),$(this).css('top')]; } });
$("#page_taskedit").resizable({ minWidth:$("#page_taskedit").width(), minHeight:$("#page_taskedit").height(), start:function(ui,e){editFormResize(1)}, resize:function(ui,e){editFormResize(0,e)}, stop:function(ui,e){editFormResize(2,e)} });
<?php endif; ?>
@ -99,9 +96,17 @@ $().ajaxStop( function(r,s) {$("#loading").fadeOut();} );
<div id="bar">
<div style="float:left"><span id="msg" onClick="toggleMsgDetails()"></span><div id="msgdetails"></div></div>
<div id="bar_auth" align="right">
<span id="bar_login"><span id="authstr">&nbsp;</span> <a href="#" class="nodecor" onClick="showAuth(this);return false;"><u><?php __('a_login');?></u> <img src="images/arrdown.gif" border=0></a></span>
<div align="right">
<span class="menu-owner">
<a href="#" id="mylists" class="nodecor" onClick="btnMenu(this);return false;"><u>My lists</u> <img src="images/arrdown.gif" border=0></a> |
<a href="settings.php">Settings</a>
</span>
<span class="bar-delim" style="display:none"> | </span>
<span id="bar_auth">
<span id="bar_login"><a href="#" class="nodecor" onClick="showAuth(this);return false;"><u><?php __('a_login');?></u> <img src="images/arrdown.gif" border=0></a></span>
<span id="authstr">&nbsp;</span>
<a href="#" id="bar_logout" onClick="logout();return false"><?php __('a_logout');?></a>
</span>
</div>
</div>
@ -109,23 +114,26 @@ $().ajaxStop( function(r,s) {$("#loading").fadeOut();} );
<div id="page_tasks">
<div id="tabs">
<ul class="">
<li><a href="#newtask"><?php __('tab_newtask');?></a></li>
<li><a href="#searchtask"><?php __('tab_search');?></a></li>
</ul><br clear="all">
<div class="tab-content" id="newtask">
<form onSubmit="return submitNewTask(this)"><input type="text" name="task" value="" maxlength="250" id="task"> <input type="submit" value="<?php __('btn_add');?>"></form>
</div>
<div class="tab-content" id="searchtask">
<form onSubmit="return searchTasks()"><input type="text" name="search" value="" maxlength="250" id="search" onKeyUp="timerSearch()" autocomplete="off"> <input type="submit" value="<?php __('btn_search');?>"></form>
<div id="searchbar"><?php __('searching');?> <span id="searchbarkeyword"></span></div>
</div>
<div id="lists" class="mtt-tabs">
<ul class=""></ul>
<div class="mtt-htabs">
<span id="htab_newtask"><?php __('htab_newtask');?> <form onSubmit="return submitNewTask(this)"><input type="text" name="task" value="" maxlength="250" id="task"> <input type="submit" value="<?php __('btn_add');?>"></form>
&nbsp;| <a href="#" class="htab-toggle" onClick="addsearchToggle(1);this.blur();return false;"><?php __('htab_search');?></a>
</span>
<span id="htab_search" style="display:none">
<a href="#" class="htab-toggle" onClick="addsearchToggle(0);this.blur();return false;"><?php __('htab_newtask');?></a> |&nbsp;
<?php __('htab_search');?> <form onSubmit="return searchTasks()"><input type="text" name="search" value="" maxlength="250" id="search" onKeyUp="timerSearch()" autocomplete="off"> <input type="submit" value="<?php __('btn_search');?>"></form>
<div id="searchbar"><?php __('searching');?> <span id="searchbarkeyword"></span></div>
</span>
</div>
</div>
<h3><span id="taskviewcontainer" onClick="showTaskview(this);"><span class="btnstr"><?php __('tasks');?></span> (<span id="total">0</span>) &nbsp;<img src="images/arrdown.gif"></span>
<span id="sort" onClick="showSort(this);"><span class="btnstr"></span> <img src="images/arrdown.gif"></span>
<h3>
<span id="sort" onClick="showSort(this);" style="float:right"><span class="btnstr"></span> <img src="images/arrdown.gif"></span>
<span id="taskviewcontainer" onClick="showTaskview(this);"><span class="btnstr"><?php __('tasks');?></span> (<span id="total">0</span>) &nbsp;<img src="images/arrdown.gif"></span>
<span id="tagcloudbtn" onClick="showTagCloud(this);" title="<?php __('tags');?>"><span class="btnstr"><?php __('tags');?></span> <img src="images/arrdown.gif"></span>
<span class="mtt-notes-showhide"><?php __('notes');?> <a href="#" onClick="toggleAllNotes(1);this.blur();return false;"><?php __('notes_show');?></a> / <a href="#" onClick="toggleAllNotes(0);this.blur();return false;"><?php __('notes_hide');?></a></span>
</h3>
<div id="taskcontainer">
@ -143,9 +151,17 @@ $().ajaxStop( function(r,s) {$("#loading").fadeOut();} );
<input type="hidden" name="id" value="">
<div class="form-row"><span class="h"><?php __('priority');?></span> <SELECT name="prio"><option value="2">+2</option><option value="1">+1</option><option value="0" selected>&plusmn;0</option><option value="-1">&minus;1</option></SELECT>
&nbsp; <span class="h"><?php __('due');?> </span> <input name="duedate" id="duedate" value="" class="in100" title="Y-M-D, M/D/Y, D.M.Y, M/D, D.M" autocomplete="off"></div>
<div class="form-row"><span class="h"><?php __('task');?></span><br> <input type="text" name="task" value="" class="in500" maxlength="250"></div>
<div class="form-row"><span class="h"><?php __('note');?></span><br> <textarea name="note" class="in500"></textarea></div>
<div class="form-row"><span class="h"><?php __('tags');?></span><br> <input type="text" name="tags" id="edittags" value="" class="in500" maxlength="250"></div>
<div class="form-row"><div class="h"><?php __('task');?></div> <input type="text" name="task" value="" class="in500" maxlength="250"></div>
<div class="form-row"><div class="h"><?php __('note');?></div> <textarea name="note" class="in500"></textarea></div>
<div class="form-row"><div class="h"><?php __('tags');?></div>
<table cellspacing="0" cellpadding="0" width="100%"><tr>
<td><input type="text" name="tags" id="edittags" value="" class="in500" maxlength="250"></td>
<td width="1" style="white-space:nowrap; padding-left:5px; text-align:right;">
<a href="#" id="alltags_show" onClick="toggleEditAllTags(1);return false;"><?php __('alltags_show');?></a>
<a href="#" id="alltags_hide" onClick="toggleEditAllTags(0);return false;" style="display:none"><?php __('alltags_hide');?></a></td>
</tr></table>
</div>
<div class="form-row" id="alltags" style="display:none;"><?php __('alltags');?> <span class="tags-list"></span></div>
<div class="form-row"><input type="submit" value="<?php __('save');?>" onClick="this.blur()"> <input type="button" value="<?php __('cancel');?>" onClick="cancelEdit();this.blur();return false"></div>
</form>
@ -183,6 +199,12 @@ $().ajaxStop( function(r,s) {$("#loading").fadeOut();} );
<div id="tagcloudcontent"></div>
</div>
<div id="mylistscontainer" class="mtt-btnmenu-container" style="display:none">
<div class="li" onClick="addList()"><?php __('list_new');?></div>
<div class="li" onClick="renameCurList()"><?php __('list_rename');?></div>
<div class="li" onClick="deleteCurList()"><?php __('list_delete');?></div>
</div>
</div>
<div id="space"></div>
</div>

View file

@ -20,13 +20,17 @@ class DefaultLang
'invalidpass' => "Wrong password",
'readonly' => "read-only",
'tagfilter' => "Tag:",
'addList' => "Create new list",
'addListDefault' => "Todo",
'renameList' => "Rename list",
'deleteList' => "This will delete current list with all tasks in it.\\nAre you sure?",
);
private $default_inc = array
(
'My Tiny Todolist' => "My Tiny Todolist",
'tab_newtask' => "new task",
'tab_search' => "search",
'htab_newtask' => "New task",
'htab_search' => "Search",
'btn_add' => "Add",
'btn_search' => "Search",
'searching' => "Searching for",
@ -61,6 +65,15 @@ class DefaultLang
'f_today' => "Today and tomorrow",
'f_soon' => "Soon",
'tasks_and_compl' => "Tasks + completed",
'notes' => "Notes:",
'notes_show' => "Show",
'notes_hide' => "Hide",
'list_new' => "New list",
'list_rename' => "Rename",
'list_delete' => "Delete",
'alltags' => "All tags:",
'alltags_show' => "Show all",
'alltags_hide' => "Hide all",
);
var $js = array();
@ -83,8 +96,8 @@ class DefaultLang
foreach($this->get('days_min') as $v) { $t[] = '"'.str_replace('"','\\"',$v).'"'; }
$a[] = "daysMin: [". implode(',', $t). "]";
$t = array();
foreach($this->get('months_short') as $v) { $t[] = '"'.str_replace('"','\\"',$v).'"'; }
$a[] = "monthsShort: [". implode(',', $t). "]";
foreach($this->get('months_long') as $v) { $t[] = '"'.str_replace('"','\\"',$v).'"'; }
$a[] = "monthsLong: [". implode(',', $t). "]";
return "lang = {\n". implode(",\n", $a). "\n};";
}

View file

@ -16,13 +16,16 @@ class Lang extends DefaultLang
'invalidpass' => "Wrong password",
'readonly' => "read-only",
'tagfilter' => "Tag:",
'addList' => "Create new list",
'renameList' => "Rename list",
'deleteList' => "This will delete current list with all tasks in it.\\nAre you sure?",
);
var $inc = array
(
'My Tiny Todolist' => "My Tiny Todolist",
'tab_newtask' => "new task",
'tab_search' => "search",
'htab_newtask' => "New task",
'htab_search' => "Search",
'btn_add' => "Add",
'btn_search' => "Search",
'searching' => "Searching for",
@ -57,6 +60,15 @@ class Lang extends DefaultLang
'f_today' => "Today and tomorrow",
'f_soon' => "Soon",
'tasks_and_compl' => "Tasks + completed",
'notes' => "Notes:",
'notes_show' => "Show",
'notes_hide' => "Hide",
'list_new' => "New list",
'list_rename' => "Rename",
'list_delete' => "Delete",
'alltags' => "All tags:",
'alltags_show' => "Show all",
'alltags_hide' => "Hide all",
);
}

View file

@ -14,15 +14,10 @@ if($needAuth && !is_logged())
$dbclass = strtolower(get_class($db));
$dbtype = ($dbclass == 'database_mysql') ? 'mysql' : 'sqlite';
$lastVer = '1.2';
$lastVer = '1.3';
echo '<html><head><meta name="robots" content="noindex,nofollow"></head><body>';
echo "<b>myTinyTodo v$lastVer Setup</b><br><br>";
# exclude sqlite2
if($dbclass == 'database_sqlite') {
exitMessage("Install/update is not available for sqlite2. Use sqlite v3.");
}
# determine current installed version
$ver = get_ver($db, $dbtype);
@ -41,6 +36,7 @@ if(!$ver)
"CREATE TABLE todolist (
`id` INT UNSIGNED NOT NULL auto_increment,
`d` DATETIME NOT NULL,
`list_id` INT UNSIGNED NOT NULL default 0,
`compl` TINYINT UNSIGNED NOT NULL default 0,
`title` VARCHAR(250) NOT NULL,
`note` TEXT,
@ -48,7 +44,8 @@ if(!$ver)
`ow` INT NOT NULL default 0, /* order weight */
`tags` VARCHAR(250) NOT NULL default '', /* denormalization - for fast access to task tags */
`duedate` DATE default NULL,
PRIMARY KEY(`id`)
PRIMARY KEY(`id`),
KEY(`list_id`)
) CHARSET=utf8 ");
$db->ex(
@ -56,8 +53,9 @@ if(!$ver)
`id` INT UNSIGNED NOT NULL auto_increment,
`name` VARCHAR(50) NOT NULL,
`tags_count` INT default 0,
`list_id` INT UNSIGNED NOT NULL default 0,
PRIMARY KEY(`id`),
UNIQUE KEY(`name`)
UNIQUE KEY `listid_nmae` (`list_id`,`name`)
) CHARSET=utf8 ");
$db->ex(
@ -68,6 +66,13 @@ if(!$ver)
KEY(`task_id`)
) CHARSET=utf8 ");
$db->ex(
"CREATE TABLE lists (
`id` INT UNSIGNED NOT NULL auto_increment,
`name` VARCHAR(50) NOT NULL default '',
PRIMARY KEY(`id`)
) CHARSET=utf8 ");
} catch (Exception $e) {
exitMessage("<b>Error:</b> ". htmlarray($e->getMessage()));
}
@ -80,6 +85,7 @@ if(!$ver)
"CREATE TABLE todolist (
id INTEGER PRIMARY KEY,
d DATETIME NOT NULL default '0000-00-00',
list_id INTEGER UNSIGNED NOT NULL default 0,
compl TINYINT UNSIGNED NOT NULL default 0,
title VARCHAR(250) NOT NULL,
note TEXT,
@ -88,27 +94,37 @@ if(!$ver)
tags VARCHAR(250) NOT NULL default '',
duedate DATE default NULL
) ");
$db->ex("CREATE INDEX list_id ON todolist (list_id)");
$db->ex(
"CREATE TABLE tags (
id INTEGER PRIMARY KEY,
name VARCHAR(50) NOT NULL COLLATE NOCASE UNIQUE,
tags_count INT default 0
name VARCHAR(50) NOT NULL,
tags_count INT default 0,
list_id INTEGER UNSIGNED NOT NULL default 0
) ");
$db->ex("CREATE UNIQUE INDEX tags_listid_name ON tags (list_id,name COLLATE NOCASE)");
$db->ex(
"CREATE TABLE tag2task (
tag_id INTEGER NOT NULL,
task_id INTEGER NOT NULL
) ");
$db->ex("CREATE INDEX tag_id ON tag2task (tag_id)");
$db->ex("CREATE INDEX task_id ON tag2task (task_id)");
$db->ex(
"CREATE TABLE lists (
id INTEGER PRIMARY KEY,
name VARCHAR(50) NOT NULL
) ");
} catch (Exception $e) {
exitMessage("<b>Error:</b> ". htmlarray($e->getMessage()));
}
}
createDefaultList($db);
}
elseif($ver == $lastVer)
{
@ -116,17 +132,22 @@ elseif($ver == $lastVer)
}
else
{
if(!in_array($ver, array('1.1'))) {
exitMessage("Can not update database. Unsupported version ($ver).");
if(!in_array($ver, array('1.1','1.2'))) {
exitMessage("Can not update database. Unsupported version (v$ver).");
}
if(!isset($_POST['update'])) {
exitMessage("Update database from v$ver to v1.2 <form method=post><input type=hidden name=update value=1><input type=submit value=' Update '></form>");
exitMessage("Update database v$ver <form method=post><input type=hidden name=update value=1><input type=submit value=' Update '></form>");
}
# update process
if($ver == '1.1')
if($ver == '1.2')
{
update_12_13($db, $dbtype);
}
elseif($ver == '1.1')
{
update_11_12($db, $dbtype);
update_12_13($db, $dbtype);
}
}
echo "Done<br><br> <b>Attention!</b> Delete this file for security reasons.";
@ -145,6 +166,8 @@ function get_ver($db, $dbtype)
if(!has_field_sqlite($db, 'todolist', 'duedate')) return $v;
}
$v = '1.2';
if(!$db->table_exists('lists')) return $v;
$v = '1.3';
return $v;
}
@ -182,11 +205,10 @@ function has_field_mysql($db, $table, $field)
### 1.1-1.2 ##########
function update_11_12($db, $dbtype)
{
echo "Changing database structure...<br>";
if($dbtype == 'mysql') $db->ex("ALTER TABLE todolist ADD `duedate` DATE default NULL");
else $db->ex("ALTER TABLE todolist ADD duedate DATE default NULL");
echo "Fixing broken tags...<br>";
# Fixing broken tags
$db->ex("BEGIN");
$db->ex("DELETE FROM tags");
$db->ex("DELETE FROM tag2task");
@ -242,4 +264,67 @@ function update_task_tags($id, $tag_ids)
### end 1.1-1.2 #####
### 1.2-1.3 ##########
function update_12_13($db, $dbtype)
{
$db->ex("BEGIN");
if($dbtype=='mysql')
{
$db->ex(
"CREATE TABLE lists (
`id` INT UNSIGNED NOT NULL auto_increment,
`name` VARCHAR(50) NOT NULL default '',
PRIMARY KEY(`id`)
) CHARSET=utf8 ");
$db->ex("ALTER TABLE todolist ADD `list_id` INT UNSIGNED NOT NULL default 0");
$db->ex("ALTER TABLE tags ADD `list_id` INT UNSIGNED NOT NULL default 0");
$db->ex("ALTER TABLE todolist ADD KEY(`list_id`)");
$db->ex("DROP INDEX `name` ON tags");
$db->ex("ALTER TABLE tags ADD UNIQUE KEY `listid_name` (`list_id`,`name`)");
}
else
{
$db->ex(
"CREATE TABLE lists (
id INTEGER PRIMARY KEY,
name VARCHAR(50) NOT NULL
) ");
$db->ex("ALTER TABLE todolist ADD list_id INTEGER UNSIGNED NOT NULL default 0");
$db->ex("CREATE INDEX todolist_list_id ON todolist (list_id)");
$db->ex(
"CREATE TEMPORARY TABLE tags_backup (
id INTEGER,
name VARCHAR(50) NOT NULL,
tags_count INT default 0
) ");
$db->ex("INSERT INTO tags_backup SELECT id,name,tags_count FROM tags");
$db->ex("DROP TABLE tags");
$db->ex(
"CREATE TABLE tags (
id INTEGER PRIMARY KEY,
name VARCHAR(50) NOT NULL,
tags_count INT default 0,
list_id INTEGER UNSIGNED NOT NULL default 0
) ");
$db->ex("INSERT INTO tags (id,name,tags_count) SELECT id,name,tags_count FROM tags_backup");
$db->ex("CREATE UNIQUE INDEX tags_listid_name ON tags (list_id,name COLLATE NOCASE) ");
$db->ex("DROP TABLE tags_backup");
}
$db->ex("COMMIT");
createDefaultList($db);
}
function createDefaultList($db)
{
$db->ex("INSERT INTO lists (name) VALUES (?)", array('Todo'));
$db->ex("UPDATE todolist SET list_id=1");
$db->ex("UPDATE tags SET list_id=1");
}
### end 1.2-1.3 #####
?>

View file

@ -8,6 +8,7 @@ form { display: inline; }
h2,h3 { margin:0; }
h2 { font-size:15pt; float:left; padding-right:10px; background-color:#ffffff; }
h3 { border-bottom:2px solid #B5D5FF; margin-bottom:10px; padding:6px 0; font-size:11pt; }
#page_tasks h3 { padding-left:4px; padding-right:4px; }
a { color:#0000ff; }
#space { height:30px; }
#footer { height:30px; margin-top:-30px; }
@ -22,15 +23,15 @@ a { color:#0000ff; }
#authform div { padding:2px 0px; }
#authform div.h { font-weight:bold; }
#tabs ul { list-style: none; padding:0; margin:0; }
#tabs ul li { margin:0; font-size: 9pt; font-weight:bold; float: left; width:89px; text-align:center; margin-right: 6px; border-left:1px solid #fff; }
#tabs ul a { margin:0px; text-decoration: none; color:#444444; display: block; height:21px; width: 100%; padding-top: 6px; outline:none; }
#tabs ul li.ui-tabs-selected { background:#ededed; border-left:1px solid #ededed; }
#tabs ul li.ui-tabs-selected a { background:url(images/corner_right.gif) no-repeat top right; }
#tabs ul li.ui-state-hover { border-left:1px solid #ededed; }
#tabs ul li.ui-state-hover a { color: #888888; background:url(images/tab_hover.gif) no-repeat top right; }
.ui-tabs .ui-tabs-hide { display: none; }
#tabs ul li.ui-state-disabled a { color: #cccccc; }
.mtt-tabs ul { list-style: none; padding:0; margin:0; }
.mtt-tabs ul li { margin:0; font-size: 9pt; font-weight:bold; float: left; width:89px; text-align:center; margin-right: 6px; border-left:1px solid #fff; }
.mtt-tabs ul a { margin:0px; text-decoration: none; color:#444444; display: block; height:21px; width: 100%; padding-top: 6px; outline:none; }
.mtt-tabs ul li.mtt-tabs-selected { background:#ededed; border-left:1px solid #ededed; }
.mtt-tabs ul li.mtt-tabs-selected a { background:url(images/corner_right.gif) no-repeat top right; }
.mtt-tabs ul li:hover { border-left:1px solid #ededed; }
.mtt-tabs ul li:hover a { color: #888888; background:url(images/tab_hover.gif) no-repeat top right; }
.mtt-htabs { clear:both; background-color:#ededed; padding:8px; border-bottom:2px solid #DEDEDE; }
#page_tasks.readonly #htab_search a.htab-toggle { color:#444; }
.tab-content { padding:8px; border-bottom:2px solid #DEDEDE; background:url(images/corner_right.gif) no-repeat top right #ededed; }
#loading { float:left; padding-top:5px; background-color:#ffffff; display:none; padding-right:6px;}
@ -48,9 +49,12 @@ a { color:#0000ff; }
#sortform .li { margin:1px 0px; padding:2px; cursor:pointer; }
#sortform .li:hover { background-color:#316AC5; color:white; }
.task-left { width:25px; float:left; }
.task-middle { margin-left:25px; margin-right:65px; }
.nobr input { margin-left:0px; margin-right:4px; }
.mtt-notes-showhide { font-size:8pt; font-weight:normal; margin-left:5px; }
.task-left { float:left; }
.task-left .mtt-toggle { margin-top:2px; cursor:pointer; width:15px; height:15px; float:left; background:url(images/toggle_plus.gif) left top no-repeat; }
.task-left .mtt-toggle.mtt-toggle-expanded { background-image:url(images/toggle_minus.gif); }
.task-middle { margin-left:40px; margin-right:65px; }
#tasklist { list-style-type: none; margin: 0; padding: 0;}
#tasklist li { padding:6px 2px 6px 6px; border-bottom:1px solid #DEDEDE; min-height:18px; margin-bottom:1px; background-color:#fff; }
#tasklist li:hover { background-color:#f6f6f6; }
@ -60,7 +64,7 @@ a { color:#0000ff; }
.task-date { color:#999999; font-size:8pt; margin-left:4px; display:none; }
.task-title a { color:#000000; }
.task-title a:hover { color:#af0000; }
#tasklist.readonly li .task-actions { display:none; }
#page_tasks.readonly #tasklist li .task-actions { display:none; }
.task-tags { margin-left:4px; padding:0px 2px; }
.task-tags .tag { font-size:8pt; font-weight:bold; color:#333333; text-decoration:underline; }
.task-tags .tag:hover { }
@ -72,7 +76,8 @@ li.task-completed span.task-through { text-decoration:line-through; color:#77777
li.task-completed .task-title a { color:#777777; }
li.task-completed .task-actions a { color:#7070ff; }
#tasklist li.task-completed .duedate { color:#777777; border-color:#777777; }
li.task-completed { opacity:0.7; }
li.task-completed { opacity:0.8; }
li.task-completed .mtt-toggle { opacity:0.8; }
#tasklist.filter-past li, #tasklist.filter-today li, #tasklist.filter-soon li { display:none; }
#tasklist.filter-past li.past, #tasklist.filter-today li.today, #tasklist.filter-soon li.soon { display:block; }
@ -84,27 +89,29 @@ div.task-note-area { display:none; margin-bottom:5px; }
div.task-note-area textarea { color:#999999; width:100%; display:block; height:65px; }
.task-note-actions { font-size:8pt; }
.hidden { display:none; }
.invisible { visibility:hidden; }
.in500 { width:500px; color:#444444; }
.in100 { width:100px; color:#444444; }
.task-note span a { color:#777777; }
.task-note span a:hover { color:#af0000; }
.task-prio { padding-left:2px; padding-right:2px; margin-left: 2px; margin-right:3px; cursor:default; }
.task-prio { padding-left:2px; padding-right:2px; margin-left:0px; margin-right:4px; cursor:default; }
.prio-neg { background-color:#3377ff; color:#ffffff; }
.prio-pos { background-color:#ff3030; color:#ffffff; }
.prio-o { background-color:#dedede; }
#tasklist li .prio-o { display:none; }
.task-prio.prio-o { display:none; }
#authstr { display: none; color:#999999; }
#authstr.attention { color:#ff0000; }
#authstr { display: none; color:#ff0000; }
.form-row { margin-top:4px; margin-bottom:4px; }
.form-row span.h { font-weight:bold; color:#333333; }
.form-row .h { font-weight:bold; color:#333333; }
#overlay { position:fixed; z-index:200; background-color:#111111; display:none; top:0px; left:0px; width:100%; height:100%; }
#page_taskedit { position:fixed; z-index:201; background-color:#fdfdfd; padding:8px; border:1px solid #cccccc; width:510px; }
#page_taskedit .form-row .in500 { width:99%; }
#page_taskedit .form-row textarea.in500 { height:130px; /*resize:none;*/ }
.ui-icon-gripsmall-diagonal-se { background-image:url(images/resizegrip.gif); }
#alltags .tag { font-weight:bold; color:#333333; }
#alltags .tag:hover { background-color:#999988; color:white; }
/* autocomplete */
.ac_results { padding: 0px; border: 1px solid #cccccc; background-color: #f0f0f0; overflow: hidden; z-index: 99999; }
@ -166,3 +173,7 @@ div.task-note-area textarea { color:#999999; width:100%; display:block; height:6
.ui-resizable-s { cursor:s-resize; height:7px; width:100%; bottom:-5px; left:0px; }
.ui-resizable-e { cursor:e-resize; width:7px; right:-5px; top:0px; height:100%; }
.ui-resizable-se { cursor:se-resize; width:12px; height:12px; right:1px; bottom:1px; }
.mtt-btnmenu-container { overflow: hidden; z-index:103; background-color:#f9f9f9; border:1px solid #cccccc; padding:3px; }
.mtt-btnmenu-container .li { margin:1px 0px; padding:2px; cursor:pointer; }
.mtt-btnmenu-container .li:hover { background-color:#316AC5; color:white; }

View file

@ -1 +1 @@
1.2.7
1.3 dev