diff --git a/src/ajax.js b/src/ajax.js index aebbef8..3a09291 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -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 '
  • '+ ''+ ''+ '
    '+ - '
    '+ + '
    '+ + '
    '+ '
    '+prepareDuedate(item.duedate, item.dueClass, item.dueStr)+ ''+preparePrio(prio,id)+''+prepareHtml(item.title)+''+ prepareTagsStr(item.tags)+''+lang.taskDate(item.date)+''+ - '
    '+ + '
  • '+item.name+'
  • '; + }); + $('#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('
  • '+item.name+'
  • '); + }, '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(''+tagsList[i].tag+''); + } + $('#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); +} diff --git a/src/ajax.php b/src/ajax.php index 7e2e32a..895cbf4 100644 --- a/src/ajax.php +++ b/src/ajax.php @@ -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; } diff --git a/src/class.db.sqlite.php b/src/class.db.sqlite.php deleted file mode 100644 index fcadcb1..0000000 --- a/src/class.db.sqlite.php +++ /dev/null @@ -1,158 +0,0 @@ -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; $iquote($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; - } -} - -?> \ No newline at end of file diff --git a/src/db/config.php.default b/src/db/config.php.default index 2250ccc..4027271 100644 --- a/src/db/config.php.default +++ b/src/db/config.php.default @@ -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"; diff --git a/src/images/toggle_minus.gif b/src/images/toggle_minus.gif new file mode 100644 index 0000000..19d433b Binary files /dev/null and b/src/images/toggle_minus.gif differ diff --git a/src/images/toggle_plus.gif b/src/images/toggle_plus.gif new file mode 100644 index 0000000..14a7ab2 Binary files /dev/null and b/src/images/toggle_plus.gif differ diff --git a/src/index.php b/src/index.php index 9a61a50..6c6fb10 100644 --- a/src/index.php +++ b/src/index.php @@ -56,10 +56,9 @@ function __($s)