Compare commits

...

42 Commits
v0.7 ... master

Author SHA1 Message Date
Bel LaPointe f0f4b14310 gogs.inhome mods 2023-04-10 11:16:19 -06:00
Bel LaPointe 62dc4fa565 Merge branch 'master' of https://gogs.inhome.blapointe.com/local/todo-server 2023-04-10 11:15:20 -06:00
Bel LaPointe 651ff0e04d white space 2021-10-04 13:34:41 -06:00
Bel LaPointe 078674a06f fatter task action button, fix weird spacing 2021-09-17 09:43:13 -06:00
Bel LaPointe 0ae0609759 remove unused jq file, return false on form to avoid reload 2021-09-17 09:04:28 -06:00
Bel LaPointe f67f3dd8a1 Upgrade to 1-6-5-UI and images 2021-09-17 08:53:35 -06:00
Bel LaPointe a121503777 gitignore v1.6.5 2021-09-17 08:26:36 -06:00
Bel LaPointe 28b0110e2d go.mod 2021-09-17 08:24:59 -06:00
bel f5e3a6e867 shrink 2021-09-08 14:25:43 -06:00
bel 734fe9d286 shrink 2021-09-08 14:25:43 -06:00
Bel LaPointe 80b058a869 set looped task to latest idx 2021-08-30 09:37:40 -06:00
Bel LaPointe 01adec7db5 set looped task to latest idx 2021-08-30 09:37:40 -06:00
Bel LaPointe 2bca997483 support only looping 2021-08-17 11:47:10 -06:00
Bel LaPointe 95b10fd9f6 support only looping 2021-08-17 11:47:10 -06:00
bel 568aa6a229 haflways 2021-08-05 23:45:11 -06:00
bel fc088ec240 haflways 2021-08-05 23:45:11 -06:00
bel 435ff82683 either of cron or loop can be set and unset, mark invalids as invalid and unfinish 2021-07-17 23:58:51 -06:00
bel 2763b68bc4 either of cron or loop can be set and unset, mark invalids as invalid and unfinish 2021-07-17 23:58:51 -06:00
bel 327fdb925c add cron to loop 2021-07-17 23:35:24 -06:00
bel f84614a8da add cron to loop 2021-07-17 23:35:24 -06:00
bel 5e70a49c2c add cron to ui 2021-07-17 23:17:09 -06:00
bel c2ed541604 add cron to ui 2021-07-17 23:17:09 -06:00
bel 0f8637c9ff async triggers for either interval or next due, accept cron 2021-07-17 23:14:54 -06:00
bel 8c7fe2e9ef async triggers for either interval or next due, accept cron 2021-07-17 23:14:54 -06:00
bel c90cbfc7be support combo new and old 2021-07-17 22:51:54 -06:00
bel 9301ddd467 support combo new and old 2021-07-17 22:51:54 -06:00
bel 8a47f5f321 support 1w, 1d for loop 2021-07-17 22:49:10 -06:00
bel d5ec073f75 support 1w, 1d for loop 2021-07-17 22:49:10 -06:00
Bel LaPointe b8f0efc01c every -loop duration, look for completed tasks with loop set and incomplete them 2021-07-17 11:04:52 -06:00
Bel LaPointe 81c8743de7 accept loop param on task 2021-07-17 10:34:22 -06:00
Bel LaPointe 6abfab229a log 2021-04-20 07:55:49 -05:00
Bel LaPointe ec780f7d9b actually do handler 2021-04-20 07:54:33 -05:00
Bel LaPointe 94a14f8b9d set content type 2021-04-20 07:40:13 -05:00
Bel LaPointe 90dbfd6f5a gr 2021-04-20 07:32:46 -05:00
Bel LaPointe de5f17e2c9 impl oauth 2021-04-20 07:04:05 -05:00
Bel LaPointe 0e22586e12 fix method 2021-04-20 06:27:57 -05:00
Bel LaPointe 80becbb7a7 weird paths just redir to root 2021-04-20 06:09:02 -05:00
bel 2e98bdff2d Oh hey html has a solution for my css bullshit 2020-03-17 03:28:39 +00:00
bel 8f966c98a4 whoops on css 2020-03-12 04:41:31 +00:00
bel a0f336ca67 CSS but not lighter for mobile 2020-03-12 04:36:36 +00:00
bel f8b5eb71e0 remove unused param 2020-03-12 00:57:58 +00:00
bel 7c70ba27cb fix multi-line task note preview 2020-02-02 06:13:27 +00:00
54 changed files with 1396 additions and 962 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ todo-server
exec-todo-server exec-todo-server
notes-server notes-server
exec-notes-server exec-notes-server
testdata/mytinytodo-v1.6.5*

View File

@ -2,19 +2,21 @@ package config
import ( import (
"fmt" "fmt"
"local/args" "gogs.inhome.blapointe.com/local/args"
"os" "os"
"strings" "strings"
"time"
) )
var ( var (
Port string Port string
StoreType string StoreType string
StoreAddr string StoreAddr string
StoreUser string StoreUser string
StorePass string StorePass string
Root string Root string
MyTinyTodo string OAuth string
Loop time.Duration
) )
func init() { func init() {
@ -32,8 +34,9 @@ func Refresh() {
as.Append(args.STRING, "storeaddr", "addr of store", "") as.Append(args.STRING, "storeaddr", "addr of store", "")
as.Append(args.STRING, "storeuser", "user of store", "") as.Append(args.STRING, "storeuser", "user of store", "")
as.Append(args.STRING, "storepass", "pass of store", "") as.Append(args.STRING, "storepass", "pass of store", "")
as.Append(args.STRING, "mtt", "url of php server", "http://localhost:38808") as.Append(args.STRING, "oauth", "url for boauthz", "")
as.Append(args.STRING, "root", "root of static files", "./public") as.Append(args.STRING, "root", "root of static files", "./public")
as.Append(args.DURATION, "loop", "loop duration for refreshing completed tasks", time.Minute)
if err := as.Parse(); err != nil { if err := as.Parse(); err != nil {
panic(err) panic(err)
} }
@ -44,5 +47,6 @@ func Refresh() {
StoreUser = as.Get("storeuser").GetString() StoreUser = as.Get("storeuser").GetString()
StorePass = as.Get("storepass").GetString() StorePass = as.Get("storepass").GetString()
Root = as.Get("root").GetString() Root = as.Get("root").GetString()
MyTinyTodo = as.Get("mtt").GetString() Loop = as.Get("loop").GetDuration()
OAuth = as.Get("oauth").GetString()
} }

13
go.mod Normal file
View File

@ -0,0 +1,13 @@
module gogs.inhome.blapointe.com/local/todo-server
go 1.16
require (
github.com/google/uuid v1.3.0
github.com/robfig/cron/v3 v3.0.1
gogs.inhome.blapointe.com/local/args v0.0.0-20230410154220-44370f257b34
gogs.inhome.blapointe.com/local/gziphttp v0.0.0-20230410171240-32da87640b26
gogs.inhome.blapointe.com/local/oauth2 v0.0.0-20230410162733-d39498ff8454
gogs.inhome.blapointe.com/local/router v0.0.0-20230410162418-08ccdc13df87
gogs.inhome.blapointe.com/local/storage v0.0.0-20230410162102-db39d7b02e29
)

269
go.sum Normal file
View File

@ -0,0 +1,269 @@
bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
cloud.google.com/go v0.33.1 h1:fmJQWZ1w9PGkHR1YL/P7HloDvqlmKQ4Vpb7PC2e+aCk=
cloud.google.com/go v0.33.1/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/Azure/azure-pipeline-go v0.1.8/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg=
github.com/Azure/azure-storage-blob-go v0.0.0-20181023070848-cf01652132cc/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Unknwon/goconfig v0.0.0-20181105214110-56bd8ab18619 h1:6X8iB881g299aNEv6KXrcjL31iLOH7yA6NXoQX+MbDg=
github.com/Unknwon/goconfig v0.0.0-20181105214110-56bd8ab18619/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw=
github.com/a8m/tree v0.0.0-20180321023834-3cf936ce15d6/go.mod h1:FSdwKX97koS5efgm8WevNf7XS3PqtyFkKDDXrz778cg=
github.com/abbot/go-http-auth v0.4.0 h1:QjmvZ5gSC7jm3Zg54DqWE/T5m1t2AfDu6QlXJT0EVT0=
github.com/abbot/go-http-auth v0.4.0/go.mod h1:Cz6ARTIzApMJDzh5bRMSUou6UMSp0IEXg9km/ci7TJM=
github.com/anacrolix/dms v0.0.0-20180117034613-8af4925bffb5/go.mod h1:DGqLjaZ3ziKKNRt+U5Q9PLWJ52Q/4rxfaaH/b3QYKaE=
github.com/aws/aws-sdk-go v1.15.81 h1:va7uoFaV9uKAtZ6BTmp1u7paoMsizYRRLvRuoC07nQ8=
github.com/aws/aws-sdk-go v1.15.81/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
github.com/billziss-gh/cgofuse v1.1.0/go.mod h1:LJjoaUojlVjgo5GQoEJTcJNqZJeRU0nCR84CyxKt2YM=
github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/coreos/bbolt v0.0.0-20180318001526-af9db2027c98/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/cpuguy83/go-md2man v1.0.8/go.mod h1:N6JayAiVKtlHSnuTCeuLSQVs75hb8q+dYQLjr7cDsKY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/djherbis/times v1.1.0/go.mod h1:CGMZlo255K5r4Yw0b9RRfFQpM2y7uOmxg4jm9HsaVf8=
github.com/dropbox/dropbox-sdk-go-unofficial v5.4.0+incompatible/go.mod h1:lr+LhMM3F6Y3lW1T9j2U5l7QeuWm87N9+PPXo3yH4qY=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
github.com/goftp/file-driver v0.0.0-20180502053751-5d604a0fc0c9/go.mod h1:GpOj6zuVBG3Inr9qjEnuVTgBlk2lZ1S9DcoFiXWyKss=
github.com/goftp/server v0.0.0-20190111142836-88de73f463af/go.mod h1:k/SS6VWkxY7dHPhoMQ8IdRu8L4lQtmGbhyXGg+vCnXE=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc=
github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jlaffaye/ftp v0.0.0-20181101112434-47f21d10f0ee/go.mod h1:lli8NYPQOFy3O++YmYbqVgOcQ1JPCwdOy+5zSjKJ9qY=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M=
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.3 h1:CCtW0xUnWGVINKvE/WWOYKdsPV6mawAtvQuSl8guwQs=
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4=
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
github.com/minio/minio-go/v6 v6.0.57 h1:ixPkbKkyD7IhnluRgQpGSpHdpvNVaW6OD5R9IAO/9Tw=
github.com/minio/minio-go/v6 v6.0.57/go.mod h1:5+R/nM9Pwrh0vqF+HbYYDQ84wdUFPyXHkrdT4AIkifM=
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/ncw/go-acd v0.0.0-20171120105400-887eb06ab6a2/go.mod h1:MLIrzg7gp/kzVBxRE1olT7CWYMCklcUWU+ekoxOD9x0=
github.com/ncw/rclone v1.46.0 h1:5SY9lB6LIIXqwOaCWp5twUqNWgJVZMW+0D4rX90A2+E=
github.com/ncw/rclone v1.46.0/go.mod h1:+uFY4HNpat/yXXIEin5ETWXxIwEplC+eDe/vT8vlk1w=
github.com/ncw/swift v1.0.44 h1:EKvOTvUxElbpDWqxsyVaVGvc2IfuOqQnRmjnR2AGhQ4=
github.com/ncw/swift v1.0.44/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/nsf/termbox-go v0.0.0-20181027232701-60ab7e3d12ed/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd/go.mod h1:4soZNh0zW0LtYGdQ416i0jO0EIqMGcbtaspRS4BDvRQ=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pengsrc/go-shared v0.2.0/go.mod h1:jVblp62SafmidSkvWrXyxAme3gaTfEtWwRPGz5cpvHg=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.8.3/go.mod h1:NxmoDg/QLVWluQDUYG7XBZTLUpKeFa8e3aMf1BfjyHk=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rfjakob/eme v0.0.0-20171028163933-2222dbd4ba46 h1:w2CpS5muK+jyydnmlkqpAhzKmHmMBzBkfYUDjQNS1Dk=
github.com/rfjakob/eme v0.0.0-20171028163933-2222dbd4ba46/go.mod h1:U2bmx0hDj8EyDdcxmD5t3XHDnBFnyNNc22n1R4008eM=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sevlyar/go-daemon v0.1.4/go.mod h1:6dJpPatBT9eUwM5VCw9Bt6CdX9Tk6UWvhW3MebLDRKE=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c h1:fyKiXKO1/I/B6Y2U8T7WdQGWzwehOuGIrljPtt7YTTI=
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/t3rm1n4l/go-mega v0.0.0-20190205172012-55a226cf41da/go.mod h1:XWL4vDyd3JKmJx+hZWUVgCNmmhZ2dTBcaNDcxH465s0=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yunify/qingstor-sdk-go v2.2.15+incompatible/go.mod h1:w6wqLDQ5bBTzxGJ55581UrSwLrsTAsdo9N6yX/8d9RY=
go.mongodb.org/mongo-driver v1.7.2 h1:pFttQyIiJUHEn50YfZgC9ECjITMT44oiN36uArf/OFg=
go.mongodb.org/mongo-driver v1.7.2/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8=
gogs.inhome.blapointe.com/local/args v0.0.0-20230410154220-44370f257b34 h1:0tuX5dfOksiOQD1vbJjVNVTVxTTIng7UrUdSLF5T+Ao=
gogs.inhome.blapointe.com/local/args v0.0.0-20230410154220-44370f257b34/go.mod h1:YG9n3Clg7683ohkVnJK2hdX8bBS9EojIsd1qPZumX0Y=
gogs.inhome.blapointe.com/local/gziphttp v0.0.0-20230410171240-32da87640b26 h1:zo9E05aBiyvtuuQiT3XjzBnpbm8+bVbzHe7soBQS0Tk=
gogs.inhome.blapointe.com/local/gziphttp v0.0.0-20230410171240-32da87640b26/go.mod h1:Sdj/NB9h3xrzPDqViQAHoDhA5gmpHkrWRXUauvLSA74=
gogs.inhome.blapointe.com/local/logb v0.0.0-20230410154319-880efa39d871 h1:cMGPiwvK/QGg4TfW8VasO6SsS/O7UQmwyKDErV/ozoA=
gogs.inhome.blapointe.com/local/logb v0.0.0-20230410154319-880efa39d871/go.mod h1:E0pLNvMLzY0Kth1W078y+06z1AUyVMWnChMpRFf4w2Q=
gogs.inhome.blapointe.com/local/oauth2 v0.0.0-20230410162733-d39498ff8454 h1:U8gUhe9E97/uG3ne6D1VONCCVC6jjBbF1gDMKn3GCeo=
gogs.inhome.blapointe.com/local/oauth2 v0.0.0-20230410162733-d39498ff8454/go.mod h1:YDG4DAUbmKcQUDWdZAJyoUtX+N2zQIFQ0fz88lAPuiU=
gogs.inhome.blapointe.com/local/router v0.0.0-20230410162418-08ccdc13df87 h1:jlIDVPGFk42puv6NYzRkGFMhsZ0L1AHGRyx5ooGb4Ew=
gogs.inhome.blapointe.com/local/router v0.0.0-20230410162418-08ccdc13df87/go.mod h1:FCXhK6+lzJcxBsptnei6vw9pChuQvr4NtuosngjVJDk=
gogs.inhome.blapointe.com/local/storage v0.0.0-20230410162102-db39d7b02e29 h1:SPSz7yQsEfScqyLlBS5uNSOGeT203BkIkFCL8jrm/FA=
gogs.inhome.blapointe.com/local/storage v0.0.0-20230410162102-db39d7b02e29/go.mod h1:zk8Fe2Ezc2f6oOe2yllsbEhXqssUU1K2faoS0eQ9alY=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/oauth2 v0.0.0-20181120190819-8f65e3013eba h1:YDkOrzGLLYybtuP6ZgebnO4OWYEYVMFSniazXsxrFN8=
golang.org/x/oauth2 v0.0.0-20181120190819-8f65e3013eba/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20181120235003-faade3cbb06a h1:yMfgT1baklxtECXVk3UtZBELVXtVhDbK3/7xLFkFypw=
google.golang.org/api v0.0.0-20181120235003-faade3cbb06a/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/appengine v1.3.0 h1:FBSsiFRMz3LBeXIomRnVzrQwSDj4ibvcRexLG0LZGQk=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,8 +1,8 @@
package main package main
import ( import (
"local/todo-server/config" "gogs.inhome.blapointe.com/local/todo-server/config"
"local/todo-server/server" "gogs.inhome.blapointe.com/local/todo-server/server"
"log" "log"
"net/http" "net/http"
) )
@ -12,6 +12,7 @@ func main() {
if err := s.Routes(); err != nil { if err := s.Routes(); err != nil {
panic(err) panic(err)
} }
go s.Async()
log.Println("listening on", config.Port) log.Println("listening on", config.Port)
if err := http.ListenAndServe(config.Port, s); err != nil { if err := http.ListenAndServe(config.Port, s); err != nil {
panic(err) panic(err)

View File

@ -4,14 +4,16 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>todo breel</title> <title>todo breel</title>
<link rel="stylesheet" type="text/css" href="/themes/default/style.css?v=1.4.3" media="all"/> <link rel="stylesheet" type="text/css" href="/themes/default/style.css?v=1.4.3" media="all"/>
<link rel="stylesheet" type="text/css" href="/themes/default/print.css?v=1.4.3" media="print"/> <link rel="stylesheet" type="text/css" href="/themes/default/print.css?v=1.4.3" media="print"/>
<link rel="stylesheet" type="text/css" href="/themes/default/pda.css?v=1.4.3" media="only screen and (max-device-width: 720px)"/>
<meta name="viewport" content="width=device-width, user-scalable=no">
</head> </head>
<body> <body>
<script type="text/javascript" src="/jquery/jquery-1.4.4.min.js"></script> <script type="text/javascript" src="/jquery/jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="/jquery/jquery-ui-1.8.7.custom.min.js"></script> <script type="text/javascript" src="/jquery/jquery-ui-1.8.7.custom.min.js"></script>
<script type="text/javascript" src="/jquery/jquery.autocomplete-1.1.js"></script>
<script type="text/javascript" src="/mytinytodo.js?v=1.4.3"></script> <script type="text/javascript" src="/mytinytodo.js?v=1.4.3"></script>
<script type="text/javascript" src="/mytinytodo_lang.php?v=1.4.3"></script> <script type="text/javascript" src="/mytinytodo_lang.php?v=1.4.3"></script>
<script type="text/javascript" src="/mytinytodo_ajax_storage.js?v=1.4.3"></script> <script type="text/javascript" src="/mytinytodo_ajax_storage.js?v=1.4.3"></script>
@ -71,6 +73,7 @@
<ul class="mtt-tabs"></ul> <ul class="mtt-tabs"></ul>
<div class="mtt-tabs-add-button" title="New list"><span></span> <div class="mtt-tabs-add-button" title="New list"><span></span>
</div> </div>
<div style="flex-grow: 100"></div>
<div id="tabs_buttons"> <div id="tabs_buttons">
<div class="mtt-tabs-select-button mtt-tabs-button" title="Select list"> <div class="mtt-tabs-select-button mtt-tabs-button" title="Select list">
<span></span></div> <span></span></div>
@ -150,7 +153,7 @@
</div> </div>
</h3> </h3>
<form id="taskedit_form" name="edittask" method="post"> <form id="taskedit_form" name="edittask" method="post" onsubmit="return false;">
<input type="hidden" name="isadd" value="0"/> <input type="hidden" name="isadd" value="0"/>
<input type="hidden" name="id" value=""/> <input type="hidden" name="id" value=""/>
<div class="form-row form-row-short"> <div class="form-row form-row-short">
@ -166,6 +169,14 @@
<span class="h">Due </span> <span class="h">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"/> <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>
<div class="form-row form-row-short">
<span class="h">Loop </span>
<input type="text" name="loop" value="" class="in100" maxlength="30"/>
</div>
<div class="form-row form-row-short">
<span class="h">Cron </span>
<input type="text" name="cron" value="" class="in100" maxlength="30"/>
</div>
<div class="form-row-short-end"></div> <div class="form-row-short-end"></div>
<div class="form-row"> <div class="form-row">
<div class="h">Task</div> <div class="h">Task</div>
@ -255,6 +266,8 @@
<li class="mtt-menu-delimiter"></li> <li class="mtt-menu-delimiter"></li>
<li class="mtt-need-list" id="btnShowCompleted"> <li class="mtt-need-list" id="btnShowCompleted">
<div class="menu-icon"></div>Show completed tasks</li> <div class="menu-icon"></div>Show completed tasks</li>
<li class="mtt-need-list" id="btnShowLooping">
<div class="menu-icon"></div>Show looping tasks</li>
</ul> </ul>
</div> </div>

View File

@ -1,839 +0,0 @@
/*
* jQuery Autocomplete plugin 1.1
*
* Copyright (c) 2009 Jörn Zaefferer
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
*/
/*
* Changes for myTinyTodo, www.mytinytodo.net
* Copyright (c) 2010 Max Pozdeev
* Dual licensed under the MIT and GPL licenses
*/
;(function($) {
$.fn.extend({
autocomplete: function(urlOrData, options) {
var isUrl = typeof urlOrData == "string";
var isFunc = typeof urlOrData == "function";
options = $.extend({}, $.Autocompleter.defaults, {
url: isUrl ? urlOrData : null,
data: !isUrl && !isFunc ? urlOrData : null,
func: isFunc ? urlOrData : null,
delay: isUrl ? $.Autocompleter.defaults.delay : 10,
max: options && !options.scroll ? 10 : 150
}, options);
// if highlight is set to false, replace it with a do-nothing function
options.highlight = options.highlight || function(value) { return value; };
// if the formatMatch option is not specified, then use formatItem for backwards compatibility
options.formatMatch = options.formatMatch || options.formatItem;
return this.each(function() {
new $.Autocompleter(this, options);
});
},
result: function(handler) {
return this.bind("result", handler);
},
search: function(handler) {
return this.trigger("search", [handler]);
},
flushCache: function() {
return this.trigger("flushCache");
},
setOptions: function(options){
return this.trigger("setOptions", [options]);
},
unautocomplete: function() {
return this.trigger("unautocomplete");
}
});
$.Autocompleter = function(input, options) {
var KEY = {
UP: 38,
DOWN: 40,
DEL: 46,
TAB: 9,
RETURN: 13,
ESC: 27,
COMMA: 188,
PAGEUP: 33,
PAGEDOWN: 34,
BACKSPACE: 8
};
// Create $ object for input element
var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
var timeout;
var previousValue = "";
var cache = $.Autocompleter.Cache(options);
var hasFocus = 0;
var lastKeyPressCode;
var config = {
mouseDownOnSelect: false
};
var select = $.Autocompleter.Select(options, input, selectCurrent, config);
var blockSubmit;
// prevent form submit in opera when selecting with return key
$.browser.opera && $(input.form).bind("submit.autocomplete", function() {
if (blockSubmit) {
blockSubmit = false;
return false;
}
});
// only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
$input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
// a keypress means the input has focus
// avoids issue where input had focus before the autocomplete was applied
hasFocus = 1;
// track last key pressed
lastKeyPressCode = event.keyCode;
switch(event.keyCode) {
case KEY.UP:
event.preventDefault();
if ( select.visible() ) {
select.prev();
} else {
onChange(0, true);
}
break;
case KEY.DOWN:
event.preventDefault();
if ( select.visible() ) {
select.next();
} else {
onChange(0, true);
}
break;
case KEY.PAGEUP:
event.preventDefault();
if ( select.visible() ) {
select.pageUp();
} else {
onChange(0, true);
}
break;
case KEY.PAGEDOWN:
event.preventDefault();
if ( select.visible() ) {
select.pageDown();
} else {
onChange(0, true);
}
break;
// matches also semicolon
case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
case KEY.TAB:
case KEY.RETURN:
if( selectCurrent() ) {
// stop default to prevent a form submit, Opera needs special handling
event.preventDefault();
blockSubmit = true;
return false;
}
break;
case KEY.ESC:
select.hide();
break;
default:
clearTimeout(timeout);
timeout = setTimeout(onChange, options.delay);
break;
}
}).focus(function(){
// track whether the field has focus, we shouldn't process any
// results if the field no longer has focus
hasFocus++;
}).blur(function() {
hasFocus = 0;
if (!config.mouseDownOnSelect) {
hideResults();
}
}).click(function() {
// show select when clicking in a focused field
if ( hasFocus++ > 1 && !select.visible() ) {
onChange(0, true);
}
}).bind("search", function() {
// TODO why not just specifying both arguments?
var fn = (arguments.length > 1) ? arguments[1] : null;
function findValueCallback(q, data) {
var result;
if( data && data.length ) {
for (var i=0; i < data.length; i++) {
if( data[i].result.toLowerCase() == q.toLowerCase() ) {
result = data[i];
break;
}
}
}
if( typeof fn == "function" ) fn(result);
else $input.trigger("result", result && [result.data, result.value]);
}
$.each(trimWords($input.val()), function(i, value) {
request(value, findValueCallback, findValueCallback);
});
}).bind("flushCache", function() {
cache.flush();
}).bind("setOptions", function() {
$.extend(options, arguments[1]);
// if we've updated the data, repopulate
if ( "data" in arguments[1] )
cache.populate();
}).bind("unautocomplete", function() {
select.unbind();
$input.unbind();
$(input.form).unbind(".autocomplete");
});
function selectCurrent() {
var selected = select.selected();
if( !selected )
return false;
var v = selected.result;
previousValue = v;
if ( options.multiple ) {
var words = trimWords($input.val());
if ( words.length > 1 ) {
var seperator = options.multipleSeparator.length;
var cursorAt = $(input).selection().start;
var wordAt, progress = 0;
$.each(words, function(i, word) {
progress += word.length;
if (cursorAt <= progress) {
wordAt = i;
return false;
}
progress += seperator;
});
words[wordAt] = v;
// TODO this should set the cursor to the right position, but it gets overriden somewhere
//$.Autocompleter.Selection(input, progress + seperator, progress + seperator);
v = words.join( options.multipleSeparator );
}
v += options.multipleSeparator;
}
$input.val(v);
hideResultsNow();
$input.trigger("result", [selected.data, selected.value]);
return true;
}
function onChange(crap, skipPrevCheck) {
if( lastKeyPressCode == KEY.DEL ) {
select.hide();
return;
}
var currentValue = $input.val();
if ( !skipPrevCheck && currentValue == previousValue )
return;
previousValue = currentValue;
currentValue = lastWord(currentValue);
if ( currentValue.length >= options.minChars) {
$input.addClass(options.loadingClass);
if (!options.matchCase)
currentValue = currentValue.toLowerCase();
request(currentValue, receiveData, hideResultsNow);
} else {
stopLoading();
select.hide();
}
};
function trimWords(value) {
if (!value)
return [""];
if (!options.multiple)
return [$.trim(value)];
return $.map(value.split(options.multipleSeparator), function(word) {
return $.trim(value).length ? $.trim(word) : null;
});
}
function lastWord(value) {
if ( !options.multiple )
return value;
var words = trimWords(value);
if (words.length == 1)
return words[0];
var cursorAt = $(input).selection().start;
if (cursorAt == value.length) {
words = trimWords(value)
} else {
words = trimWords(value.replace(value.substring(cursorAt), ""));
}
return words[words.length - 1];
}
// fills in the input box w/the first match (assumed to be the best match)
// q: the term entered
// sValue: the first matching result
function autoFill(q, sValue){
// autofill in the complete box w/the first match as long as the user hasn't entered in more data
// if the last user key pressed was backspace, don't autofill
if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
// fill in the value (keep the case the user has typed)
$input.val($input.val() + sValue.substring(lastWord(previousValue).length));
// select the portion of the value not typed by the user (so the next character will erase)
$(input).selection(previousValue.length, previousValue.length + sValue.length);
}
};
function hideResults() {
clearTimeout(timeout);
timeout = setTimeout(hideResultsNow, 200);
};
function hideResultsNow() {
var wasVisible = select.visible();
select.hide();
clearTimeout(timeout);
stopLoading();
if (options.mustMatch) {
// call search and run callback
$input.search(
function (result){
// if no value found, clear the input box
if( !result ) {
if (options.multiple) {
var words = trimWords($input.val()).slice(0, -1);
$input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
}
else {
$input.val( "" );
$input.trigger("result", null);
}
}
}
);
}
};
function receiveData(q, data) {
if ( data && data.length && hasFocus ) {
stopLoading();
select.display(data, q);
autoFill(q, data[0].value);
select.show();
} else {
hideResultsNow();
}
};
function request(term, success, failure) {
if (!options.matchCase)
term = term.toLowerCase();
var data = cache.load(term);
// recieve the cached data
if (data && data.length) {
success(term, data);
}
// if function was supplied
else if(options.func)
{
var extraParams = {
timestamp: +new Date()
};
$.each(options.extraParams, function(key, param) {
extraParams[key] = typeof param == "function" ? param() : param;
});
options.func({
data: $.extend({
q: lastWord(term),
limit: options.max
}, extraParams)},
function(data){
var parsed = options.parse && options.parse(data) || parse(data);
cache.add(term, parsed)
success(term, parsed);
}
);
}
// if an AJAX url has been supplied, try loading the data now
else if( (typeof options.url == "string") && (options.url.length > 0) ){
var extraParams = {
timestamp: +new Date()
};
$.each(options.extraParams, function(key, param) {
extraParams[key] = typeof param == "function" ? param() : param;
});
$.ajax({
// try to leverage ajaxQueue plugin to abort previous requests
mode: "abort",
// limit abortion to this input
port: "autocomplete" + input.name,
dataType: options.dataType,
url: options.url,
data: $.extend({
q: lastWord(term),
limit: options.max
}, extraParams),
success: function(data) {
var parsed = options.parse && options.parse(data) || parse(data);
cache.add(term, parsed);
success(term, parsed);
}
});
} else {
// if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
select.emptyList();
failure(term);
}
};
function parse(data) {
var parsed = [];
var rows = data.split("\n");
for (var i=0; i < rows.length; i++) {
var row = $.trim(rows[i]);
if (row) {
row = row.split("|");
parsed[parsed.length] = {
data: row,
value: row[0],
result: options.formatResult && options.formatResult(row, row[0]) || row[0]
};
}
}
return parsed;
};
function stopLoading() {
$input.removeClass(options.loadingClass);
};
};
$.Autocompleter.defaults = {
inputClass: "ac_input",
resultsClass: "ac_results",
loadingClass: "ac_loading",
minChars: 1,
delay: 400,
matchCase: false,
matchSubset: true,
matchContains: false,
cacheLength: 10,
max: 100,
mustMatch: false,
extraParams: {},
selectFirst: true,
formatItem: function(row) { return row[0]; },
formatMatch: null,
autoFill: false,
width: 0,
multiple: false,
multipleSeparator: ", ",
highlight: function(value, term) {
return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
},
scroll: true,
scrollHeight: 180
};
$.Autocompleter.Cache = function(options) {
var data = {};
var length = 0;
function matchSubset(s, sub) {
if (!options.matchCase)
s = s.toLowerCase();
var i = s.indexOf(sub);
if (options.matchContains == "word"){
i = s.toLowerCase().search("\\b" + sub.toLowerCase());
}
if (i == -1) return false;
return i == 0 || options.matchContains;
};
function add(q, value) {
if (length > options.cacheLength){
flush();
}
if (!data[q]){
length++;
}
data[q] = value;
}
function populate(){
if( !options.data ) return false;
// track the matches
var stMatchSets = {},
nullData = 0;
// no url was specified, we need to adjust the cache length to make sure it fits the local data store
if( !options.url && !options.func ) options.cacheLength = 1;
// track all options for minChars = 0
stMatchSets[""] = [];
// loop through the array and create a lookup structure
for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
var rawValue = options.data[i];
// if rawValue is a string, make an array otherwise just reference the array
rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
var value = options.formatMatch(rawValue, i+1, options.data.length);
if ( value === false )
continue;
var firstChar = value.charAt(0).toLowerCase();
// if no lookup array for this character exists, look it up now
if( !stMatchSets[firstChar] )
stMatchSets[firstChar] = [];
// if the match is a string
var row = {
value: value,
data: rawValue,
result: options.formatResult && options.formatResult(rawValue) || value
};
// push the current match into the set list
stMatchSets[firstChar].push(row);
// keep track of minChars zero items
if ( nullData++ < options.max ) {
stMatchSets[""].push(row);
}
};
// add the data items to the cache
$.each(stMatchSets, function(i, value) {
// increase the cache size
options.cacheLength++;
// add to the cache
add(i, value);
});
}
// populate any existing data
setTimeout(populate, 25);
function flush(){
data = {};
length = 0;
}
return {
flush: flush,
add: add,
populate: populate,
load: function(q) {
if (!options.cacheLength || !length)
return null;
/*
* if dealing w/local data and matchContains than we must make sure
* to loop through all the data collections looking for matches
*/
if( (!options.url && !options.func) && options.matchContains ){
// track all matches
var csub = [];
// loop through all the data grids for matches
for( var k in data ){
// don't search through the stMatchSets[""] (minChars: 0) cache
// this prevents duplicates
if( k.length > 0 ){
var c = data[k];
$.each(c, function(i, x) {
// if we've got a match, add it to the array
if (matchSubset(x.value, q)) {
csub.push(x);
}
});
}
}
return csub;
} else
// if the exact item exists, use it
if (data[q]){
return data[q];
} else
if (options.matchSubset) {
for (var i = q.length - 1; i >= options.minChars; i--) {
var c = data[q.substr(0, i)];
if (c) {
var csub = [];
$.each(c, function(i, x) {
if (matchSubset(x.value, q)) {
csub[csub.length] = x;
}
});
return csub;
}
}
}
return null;
}
};
};
$.Autocompleter.Select = function (options, input, select, config) {
var CLASSES = {
ACTIVE: "ac_over"
};
var listItems,
active = -1,
data,
term = "",
needsInit = true,
element,
list;
// Create results
function init() {
if (!needsInit)
return;
element = $("<div/>")
.hide()
.addClass(options.resultsClass)
.css("position", "absolute")
.appendTo(document.body);
list = $("<ul/>").appendTo(element).mouseover( function(event) {
if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
$(target(event)).addClass(CLASSES.ACTIVE);
}
}).click(function(event) {
$(target(event)).addClass(CLASSES.ACTIVE);
select();
// TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
input.focus();
return false;
}).mousedown(function() {
config.mouseDownOnSelect = true;
}).mouseup(function() {
config.mouseDownOnSelect = false;
});
if( options.width > 0 )
element.css("width", options.width);
needsInit = false;
}
function target(event) {
var element = event.target;
while(element && element.tagName.toUpperCase() != "LI")
element = element.parentNode;
// more fun with IE, sometimes event.target is empty, just ignore it then
if(!element)
return [];
return element;
}
function moveSelect(step) {
listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
movePosition(step);
var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
if(options.scroll) {
var offset = 0;
listItems.slice(0, active).each(function() {
offset += this.offsetHeight;
});
if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
} else if(offset < list.scrollTop()) {
list.scrollTop(offset);
}
}
};
function movePosition(step) {
active += step;
if (active < 0) {
active = listItems.size() - 1;
} else if (active >= listItems.size()) {
active = 0;
}
}
function limitNumberOfItems(available) {
return options.max && options.max < available
? options.max
: available;
}
function fillList() {
list.empty();
var max = limitNumberOfItems(data.length);
for (var i=0; i < max; i++) {
if (!data[i])
continue;
var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
if ( formatted === false )
continue;
var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
$.data(li, "ac_data", data[i]);
}
listItems = list.find("li");
if ( options.selectFirst ) {
listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
active = 0;
}
// apply bgiframe if available
if ( $.fn.bgiframe )
list.bgiframe();
}
return {
display: function(d, q) {
init();
data = d;
term = q;
fillList();
},
next: function() {
moveSelect(1);
},
prev: function() {
moveSelect(-1);
},
pageUp: function() {
if (active != 0 && active - 8 < 0) {
moveSelect( -active );
} else {
moveSelect(-8);
}
},
pageDown: function() {
if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
moveSelect( listItems.size() - 1 - active );
} else {
moveSelect(8);
}
},
hide: function() {
element && element.hide();
listItems && listItems.removeClass(CLASSES.ACTIVE);
active = -1;
},
visible : function() {
return element && element.is(":visible");
},
current: function() {
return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
},
show: function() {
var offset = $(input).offset();
element.css({
width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
top: offset.top + input.offsetHeight,
left: offset.left
}).show();
if(options.scroll) {
list.scrollTop(0);
list.css({
maxHeight: options.scrollHeight,
overflow: 'auto'
});
if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
var listHeight = 0;
listItems.each(function() {
listHeight += this.offsetHeight;
});
var scrollbarsVisible = listHeight > options.scrollHeight;
list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
if (!scrollbarsVisible) {
// IE doesn't recalculate width when scrollbar disappears
listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
}
}
}
},
selected: function() {
var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
return selected && selected.length && $.data(selected[0], "ac_data");
},
emptyList: function (){
list && list.empty();
},
unbind: function() {
element && element.remove();
}
};
};
$.fn.selection = function(start, end) {
if (start !== undefined) {
return this.each(function() {
if( this.createTextRange ){
var selRange = this.createTextRange();
if (end === undefined || start == end) {
selRange.move("character", start);
selRange.select();
} else {
selRange.collapse(true);
selRange.moveStart("character", start);
selRange.moveEnd("character", end);
selRange.select();
}
} else if( this.setSelectionRange ){
this.setSelectionRange(start, end);
} else if( this.selectionStart ){
this.selectionStart = start;
this.selectionEnd = end;
}
});
}
var field = this[0];
if ( field.createTextRange ) {
var range = document.selection.createRange(),
orig = field.value,
teststring = "<->",
textLength = range.text.length;
range.text = teststring;
var caretAt = field.value.indexOf(teststring);
field.value = orig;
this.selection(caretAt, caretAt + textLength);
return {
start: caretAt,
end: caretAt + textLength
}
} else if( field.selectionStart !== undefined ){
return {
start: field.selectionStart,
end: field.selectionEnd
}
}
};
})(jQuery);

View File

@ -1,7 +1,7 @@
/* /*
This file is part of myTinyTodo. This file is part of myTinyTodo.
(C) Copyright 2009-2010 Max Pozdeev <maxpozdeev@gmail.com> (C) Copyright 2009-2010 Max Pozdeev <maxpozdeev@gmail.com>
Licensed under the GNU GPL v2 license. See file COPYRIGHT for details. Licensed under the GNU GPL v2 license. See file COPYRIGHT for details.
*/ */
/** /**
@ -50,7 +50,7 @@ function getGetParamValue(url, paramName) {
this._lists = {}; this._lists = {};
this._length = 0; this._length = 0;
this._order = []; this._order = [];
this._alltasks = {id: -1, showCompl: 0, sort: 3}; this._alltasks = {id: -1, showCompl: 0, showLooping: 0, sort: 3};
}, },
length: function () { length: function () {
return this._length; return this._length;
@ -204,7 +204,7 @@ function getGetParamValue(url, paramName) {
$('#search').keyup(function (event) { $('#search').keyup(function (event) {
if (event.keyCode == 27) return; if (event.keyCode == 27) return;
if ($(this).val() == '') $('#search_close').hide(); //actual value is only on keyup if ($(this).val() == '') $('#search_close').hide(); //actual value is only on keyup
else $('#search_close').show(); else $('#search_close').show();
clearTimeout(searchTimer); clearTimeout(searchTimer);
searchTimer = setTimeout(function () { searchTimer = setTimeout(function () {
@ -308,12 +308,12 @@ function getGetParamValue(url, paramName) {
$('#lists li.mtt-tab .list-action').live('click', function () { $('#lists li.mtt-tab .list-action').live('click', function () {
listMenu(this); listMenu(this);
return false; //stop bubble to tab click return false; //stop bubble to tab click
}); });
$('#list_all .list-action').click(function (event) { $('#list_all .list-action').click(function (event) {
listMenu(this); listMenu(this);
return false; //stop bubble to tab click return false; //stop bubble to tab click
}); });
//Priority popup //Priority popup
@ -851,6 +851,7 @@ function getGetParamValue(url, paramName) {
_mtt.db.request('loadTasks', { _mtt.db.request('loadTasks', {
list: curList.id, list: curList.id,
compl: curList.showCompl, compl: curList.showCompl,
looping: curList.showLooping,
sort: curList.sort, sort: curList.sort,
search: filter.search, search: filter.search,
tag: _mtt.filter.getTags(true), tag: _mtt.filter.getTags(true),
@ -875,6 +876,43 @@ function getGetParamValue(url, paramName) {
} }
function prepareTaskStr(item, noteExp) { function prepareTaskStr(item, noteExp) {
return '' +
'<li id="taskrow_'+item.id+'" class="task-row ' + (item.compl?'task-completed ':'') + item.dueClass + (item.note!=''?' task-has-note':'') +
((curList.showNotes && item.note != '') || noteExp ? ' task-expanded' : '') + prepareTagsClass(item.tags_ids) + '"><div class="task-container">' +
prepareTaskBlocks(item) + "</div></li>\n";
}
function prepareTaskBlocks(item, noteExp) {
var id = item.id;
return ''+
'<div class="task-left">' +
'<div class="task-toggle"></div>' +
'<label><input type="checkbox" '+(flag.readOnly?'disabled="disabled"':'')+(item.compl?'checked="checked"':'')+'/></label>' +
"</div>\n" +
'<div class="task-middle">' +
'<div class="task-middle-top">' +
'<div class="task-through">' +
preparePrio(item.prio,id) +
'<span class="task-title">' + prepareHtml(item.title) + '</span> ' +
(curList.id == -1 ? '<span class="task-listname">'+ tabLists.get(item.listId).name +'</span>' : '') +
prepareTagsStr(item) +
'<span class="task-date">'+item.dateInlineTitle+'</span>' +
'</div>' +
'<div class="task-through-right">' + prepareDueDate(item) + prepareCompletedDate(item) + "</div>" +
'</div>' +
'<div class="task-note-block">' +
'<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="#" class="mtt-action-note-save">'+_mtt.lang.get('actionNoteSave') +
'</a> | <a href="#" class="mtt-action-note-cancel">'+_mtt.lang.get('actionNoteCancel')+'</a></span>' +
'</div>' +
'</div>'+
"</div>" +
'<div class="task-actions"><div class="taskactionbtn"></div></div>';
/*
// &mdash; = &#8212; = — // &mdash; = &#8212; = —
var id = item.id; var id = item.id;
var prio = item.prio; var prio = item.prio;
@ -896,6 +934,7 @@ function getGetParamValue(url, paramName) {
'</a> | <a href="#" class="mtt-action-note-cancel">' + _mtt.lang.get('actionNoteCancel') + '</a></span></div>' + '</a> | <a href="#" class="mtt-action-note-cancel">' + _mtt.lang.get('actionNoteCancel') + '</a></span></div>' +
'</div>' + '</div>' +
"</div></li>\n"; "</div></li>\n";
*/
} }
function prepareHtml(s) { function prepareHtml(s) {
@ -910,7 +949,7 @@ function getGetParamValue(url, paramName) {
if (prio < 0) { if (prio < 0) {
cl = 'prio-neg prio-neg-' + Math.abs(prio); cl = 'prio-neg prio-neg-' + Math.abs(prio);
v = '&#8722;' + Math.abs(prio); v = '&#8722;' + Math.abs(prio);
} // &#8722; = &minus; = } // &#8722; = &minus; =
else if (prio > 0) { else if (prio > 0) {
cl = 'prio-pos prio-pos-' + prio; cl = 'prio-pos prio-pos-' + prio;
v = '+' + prio; v = '+' + prio;
@ -918,7 +957,7 @@ function getGetParamValue(url, paramName) {
else { else {
cl = 'prio-zero'; cl = 'prio-zero';
v = '&#177;0'; v = '&#177;0';
} // &#177; = &plusmn; = ± } // &#177; = &plusmn; = ±
return '<span class="task-prio ' + cl + '">' + v + '</span>'; return '<span class="task-prio ' + cl + '">' + v + '</span>';
} }
@ -943,11 +982,24 @@ function getGetParamValue(url, paramName) {
return ' ' + a.join(' '); return ' ' + a.join(' ');
} }
function prepareDueDate(item) {
return prepareDuedate(item);
}
function prepareDuedate(item) { function prepareDuedate(item) {
if (!item.duedate) return ''; if (!item.duedate) return '';
return '<span class="duedate" title="' + item.dueTitle + '"><span class="duedate-arrow">→</span> ' + item.dueStr + '</span>'; return '<span class="duedate" title="' + item.dueTitle + '"><span class="duedate-arrow">→</span> ' + item.dueStr + '</span>';
} }
function prepareCompletedDate(item) {
// &mdash; = &#8212; = —
return '<span class="task-date-completed">' +
'<span title="' + item.dateInlineTitle + '">' + item.dateInline + '</span>&#8212;' +
'<span title="' + item.dateCompletedInlineTitle + '">' + item.dateCompletedInline + '</span>' +
'</span>';
}
function submitNewTask(form) { function submitNewTask(form) {
if (form.task.value == '') return false; if (form.task.value == '') return false;
_mtt.db.request('newTask', { _mtt.db.request('newTask', {
@ -1233,6 +1285,9 @@ function getGetParamValue(url, paramName) {
case 'btnRssFeed': case 'btnRssFeed':
feedCurList(); feedCurList();
break; break;
case 'btnShowLooping':
showLoopingToggle();
break;
case 'btnShowCompleted': case 'btnShowCompleted':
showCompletedToggle(); showCompletedToggle();
break; break;
@ -1354,6 +1409,8 @@ function getGetParamValue(url, paramName) {
form.tags.value = item.tags.split(',').join(', '); form.tags.value = item.tags.split(',').join(', ');
form.duedate.value = item.duedate; form.duedate.value = item.duedate;
form.prio.value = item.prio; form.prio.value = item.prio;
form.loop.value = item.loop;
form.cron.value = item.cron;
$('#taskedit-date .date-created>span').text(item.date); $('#taskedit-date .date-created>span').text(item.date);
if (item.compl) $('#taskedit-date .date-completed').show().find('span').text(item.dateCompleted); if (item.compl) $('#taskedit-date .date-completed').show().find('span').text(item.dateCompleted);
else $('#taskedit-date .date-completed').hide(); else $('#taskedit-date .date-completed').hide();
@ -1370,6 +1427,8 @@ function getGetParamValue(url, paramName) {
form.duedate.value = ''; form.duedate.value = '';
form.prio.value = '0'; form.prio.value = '0';
form.id.value = ''; form.id.value = '';
form.loop.value = '';
form.cron.value = '';
toggleEditAllTags(0); toggleEditAllTags(0);
} }
@ -1408,11 +1467,17 @@ function getGetParamValue(url, paramName) {
if (flag.readOnly) return false; if (flag.readOnly) return false;
if (form.isadd.value != 0) if (form.isadd.value != 0)
return submitFullTask(form); return submitFullTask(form);
var requestBody = {
_mtt.db.request('editTask', { id: form.id.value,
id: form.id.value, title: form.task.value, note: form.note.value, title: form.task.value,
prio: form.prio.value, tags: form.tags.value, duedate: form.duedate.value note: form.note.value,
}, prio: form.prio.value,
tags: form.tags.value,
duedate: form.duedate.value,
loop: form.loop.value,
cron: form.cron.value,
}
_mtt.db.request('editTask', requestBody,
function (json) { function (json) {
if (!parseInt(json.total)) return; if (!parseInt(json.total)) return;
var item = json.list[0]; var item = json.list[0];
@ -1531,7 +1596,9 @@ function getGetParamValue(url, paramName) {
note: form.note.value, note: form.note.value,
prio: form.prio.value, prio: form.prio.value,
tags: form.tags.value, tags: form.tags.value,
duedate: form.duedate.value duedate: form.duedate.value,
loop: form.loop.value,
cron: form.cron.value,
}, function (json) { }, function (json) {
if (!parseInt(json.total)) return; if (!parseInt(json.total)) return;
form.task.value = ''; form.task.value = '';
@ -1621,7 +1688,7 @@ function getGetParamValue(url, paramName) {
submenu = new mttMenu($(this).attr('submenu')); submenu = new mttMenu($(this).attr('submenu'));
submenu.$caller = $(this); submenu.$caller = $(this);
submenu.parent = menu; submenu.parent = menu;
if (menu.root) submenu.root = menu.root; //!! be careful with circular references if (menu.root) submenu.root = menu.root; //!! be careful with circular references
else submenu.root = menu; else submenu.root = menu;
menu.submenu.push(submenu); menu.submenu.push(submenu);
submenu.ts = submenu.container.mttmenu = submenu.root.ts; submenu.ts = submenu.container.mttmenu = submenu.root.ts;
@ -1880,6 +1947,8 @@ function getGetParamValue(url, paramName) {
} }
if (list.showCompl) $('#btnShowCompleted').addClass('mtt-item-checked'); if (list.showCompl) $('#btnShowCompleted').addClass('mtt-item-checked');
else $('#btnShowCompleted').removeClass('mtt-item-checked'); else $('#btnShowCompleted').removeClass('mtt-item-checked');
if (list.showLooping) $('#btnShowLooping').addClass('mtt-item-checked');
else $('#btnShowLooping').removeClass('mtt-item-checked');
} }
function listOrderChanged(event, ui) { function listOrderChanged(event, ui) {
@ -1893,6 +1962,14 @@ function getGetParamValue(url, paramName) {
_mtt.doAction('listOrderChanged', {order: order}); _mtt.doAction('listOrderChanged', {order: order});
} }
function showLoopingToggle() { // todo
var act = curList.showLooping ? 0 : 1;
curList.showLooping = tabLists.get(curList.id).showLooping = act;
if (act) $('#btnShowLooping').addClass('mtt-item-checked');
else $('#btnShowLooping').removeClass('mtt-item-checked');
loadTasks({setLooping: 1});
}
function showCompletedToggle() { function showCompletedToggle() {
var act = curList.showCompl ? 0 : 1; var act = curList.showCompl ? 0 : 1;
curList.showCompl = tabLists.get(curList.id).showCompl = act; curList.showCompl = tabLists.get(curList.id).showCompl = act;
@ -2061,7 +2138,7 @@ function getGetParamValue(url, paramName) {
} }
/* /*
Errors and Info messages Errors and Info messages
*/ */
function flashError(str, details) { function flashError(str, details) {
@ -2087,7 +2164,7 @@ function getGetParamValue(url, paramName) {
/* /*
Authorization Authorization
*/ */
function updateAccessStatus() { function updateAccessStatus() {
// flag.needAuth is not changed after pageload // flag.needAuth is not changed after pageload
@ -2169,7 +2246,7 @@ function getGetParamValue(url, paramName) {
/* /*
Settings Settings
*/ */
function showSettings() { function showSettings() {

View File

@ -46,7 +46,7 @@
}) })
*/ */
$.getJSON(this.mtt.mttUrl + 'ajax.php?loadTasks&list=' + params.list + '&compl=' + params.compl + '&sort=' + params.sort + q, callback); $.getJSON(this.mtt.mttUrl + 'ajax.php?loadTasks&list=' + params.list + '&compl=' + params.compl + '&looping=' + params.looping + '&sort=' + params.sort + q, callback);
}, },
@ -64,7 +64,9 @@
note: params.note, note: params.note,
prio: params.prio, prio: params.prio,
tags: params.tags, tags: params.tags,
duedate: params.duedate duedate: params.duedate,
loop: params.loop,
cron: params.cron,
}, },
callback, 'json'); callback, 'json');
}, },
@ -78,7 +80,9 @@
note: params.note, note: params.note,
prio: params.prio, prio: params.prio,
tags: params.tags, tags: params.tags,
duedate: params.duedate duedate: params.duedate,
loop: params.loop,
cron: params.cron,
}, },
callback, 'json'); callback, 'json');
}, },

View File

@ -1,13 +1,5 @@
Image files page_white_text.png and calendar.png and some icons in buttons.png rss.svg, rss-disabled.svg - are (or based on) icons by Icons8 from https://icons8.com/icon/13841/rss
are (or based on) icons from Silk Icons set by Mark James (http://www.famfamfam.com/lab/icons/silk/), calendar.svg - icon by Icons8 from https://icons8.com/icon/__LA9wZgJaqd/calendar
licensed under the Creative Commons Attribution 2.5 License (http://creativecommons.org/licenses/by/2.5/). loading48.gif - generated at Preloaders.net
Some icons in buttons.png are based on "Silk Companion 1" icons set by Damien Guard
(http://damieng.com/creative/icons/silk-companion-1-icons), licensed under the
Creative Commons Attribution 2.5 License (http://creativecommons.org/licenses/by/2.5/).
Icons in mzl.png are (or based on) icons from Mozilla Source Code,
(http://www.mozilla.org/MPL/#source-code), licensed under the terms
of tri-license (MPL 1.1/GPL 2.0/LGPL 2.1).
Other images in this directory were made by Max Pozdeev and licensed under the terms of GNU GPL v2+. Other images in this directory were made by Max Pozdeev and licensed under the terms of GNU GPL v2+.

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<polyline points="15 4, 15 9, 2 9" stroke-width="1.5" stroke="#000" fill="none" />
<polyline points="6 5, 1 9, 6 13" stroke-width="1.5" stroke="#000" fill="none" />
</svg>

After

Width:  |  Height:  |  Size: 237 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<polygon points="10 3, 4 8, 10 13" fill="#000"/>
</svg>

After

Width:  |  Height:  |  Size: 118 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<polygon points="6 3, 12 8, 6 13" fill="#000"/>
</svg>

After

Width:  |  Height:  |  Size: 117 B

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<!--<rect x="0" y="0" width="16" height="16" fill="red"/>-->
<rect x="1" y="2" width="14" height="12" rx="3" fill="#999999"/>
<polygon points="4 6, 12 6, 8 10" fill="#ffffff"/>
</svg>

After

Width:  |  Height:  |  Size: 248 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<polygon points="4 6, 12 6, 8 10" fill="#888888"/>
</svg>

After

Width:  |  Height:  |  Size: 121 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8">
<polygon points="0 2, 8 2, 4 6" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 115 B

View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path fill="#fff" d="M0.5 1.5H15.5V14.5H0.5z"/>
<path fill="#788b9c" d="M15,2v12H1V2H15 M16,1H0v14h16V1L16,1z"/>
<path fill="#f78f8f" d="M0.5 1.5H15.5V4.5H0.5z"/>
<path fill="#c74343" d="M15,2v2H1V2H15 M16,1H0v4h16V1L16,1z"/>
<path fill="#c5d4de" d="M5 7H6V8H5zM7 7H8V8H7zM9 7H10V8H9zM11 7H12V8H11zM3 9H4V10H3zM5 9H6V10H5zM7 9H8V10H7zM9 9H10V10H9zM11 9H12V10H11zM3 11H4V12H3zM5 11H6V12H5zM7 11H8V12H7zM9 11H10V12H9z"/>
</svg>

After

Width:  |  Height:  |  Size: 491 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<polyline points="4 8, 7 12, 13 5" fill="none" stroke-width="2" stroke="#000" />
</svg>

After

Width:  |  Height:  |  Size: 149 B

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<g stroke-width="1.5" fill="none">
<path d="M12.0 12.0l-8-8" stroke="#7f7f7f"/>
<path d="M4.0 12.0l+8-8" stroke="#7f7f7f"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 196 B

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<g stroke-width="1.5" fill="none">
<path d="M12.0 12.0l-8-8" stroke="#000"/>
<path d="M4.0 12.0l+8-8" stroke="#000"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 190 B

View File

@ -1 +1 @@
Direct access disallowed! Place for Images

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" >
<!-- <rect x="0" y="0" width="16" height="16" fill="lightpink" /> -->
<g stroke="#7f7f7f" fill="none">
<polyline points="10.5 1, 1 1, 1 15, 13 15, 13 7.5" stroke-width="1.0" stroke-linejoin="round"/>
<g stroke-width="1.0" >
<polyline points="7 7, 6 10, 9 9, 15 3, 13 1, 7 7, 6 10" />
<line x1="7" y1="7" x2="9" y2="9" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 406 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14">
<!--<rect x="0" y="0" width="14" height="14" fill="lightpink"/>-->
<polyline points="5 2, 10 7, 5 12" stroke-width="1.5" stroke="#000" fill="none" />
</svg>

After

Width:  |  Height:  |  Size: 217 B

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs>
<linearGradient id="gradient1" x1="10%" y1="90%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#fff"/>
<stop offset="100%" stop-color="#eee"/>
</linearGradient>
<style type="text/css"><![CDATA[
.line1 { stroke:#333; stroke-width:0.3; }
]]></style>
</defs>
<polygon points="2 1, 11 1, 14 4, 14 15, 2 15" stroke-width="0.2" stroke="#333" fill="#fff" fill-opacity="0.0" />
<line x1="5" y1="4" x2="10" y2="4" class="line1"/>
<line x1="5" y1="6" x2="11" y2="6" class="line1"/>
<line x1="5" y1="8" x2="11" y2="8" class="line1"/>
<line x1="5" y1="10" x2="11" y2="10" class="line1"/>
<line x1="5" y1="12" x2="11" y2="12" class="line1"/>
<polygon points="3 2, 10 2, 10 5, 13 5, 13 14, 3 14" fill="url(#gradient1)" fill-opacity="0.4" />
</svg>

After

Width:  |  Height:  |  Size: 856 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<line x1="3" y1="8" x2="13" y2="8" stroke-width="2" stroke="#333" />
<line x1="8" y1="3" x2="8" y2="13" stroke-width="2" stroke="#333" />
</svg>

After

Width:  |  Height:  |  Size: 207 B

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8">
<title>RSS feed icon</title>
<style type="text/css">
.button {stroke: none; fill: #bbb;}
.symbol {stroke: none; fill: white;}
</style>
<rect class="button" width="8" height="8" rx="1.5" />
<circle class="symbol" cx="2" cy="6" r="1" />
<path class="symbol" d="m 1,4 a 3,3 0 0 1 3,3 h 1 a 4,4 0 0 0 -4,-4 z" />
<path class="symbol" d="m 1,2 a 5,5 0 0 1 5,5 h 1 a 6,6 0 0 0 -6,-6 z" />
</svg>

After

Width:  |  Height:  |  Size: 517 B

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 8 8">
<title>RSS feed icon</title>
<style type="text/css">
.button {stroke: none; fill: orange;}
.symbol {stroke: none; fill: white;}
</style>
<rect class="button" width="8" height="8" rx="1.5" />
<circle class="symbol" cx="2" cy="6" r="1" />
<path class="symbol" d="m 1,4 a 3,3 0 0 1 3,3 h 1 a 4,4 0 0 0 -4,-4 z" />
<path class="symbol" d="m 1,2 a 5,5 0 0 1 5,5 h 1 a 6,6 0 0 0 -6,-6 z" />
</svg>

After

Width:  |  Height:  |  Size: 519 B

View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<g stroke-width="1.5" fill="none">
<circle cx="8" cy="8" r="7" fill="#000"/>
<path d="M11.0 11.0l-6-6" stroke="#ffffff"/>
<path d="M5.0 11.0l+6-6" stroke="#ffffff"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 238 B

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<g stroke-width="1.5" stroke="#7f7f7f" fill="none">
<path d="M14 14l-4-4"/>
<circle cx="7" cy="7" r="4.5"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 180 B

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<circle cx="3" cy="8" r="1.5" fill="#333"/>
<circle cx="8" cy="8" r="1.5" fill="#333"/>
<circle cx="13" cy="8" r="1.5" fill="#333"/>
</svg>

After

Width:  |  Height:  |  Size: 200 B

View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<g fill="none" stroke-width="1.5" stroke="#333" stroke-linecap="round">
<line x1="2" y1="3" x2="14" y2="3"/>
<line x1="2" y1="8" x2="14" y2="8"/>
<line x1="4" y1="13" x2="14" y2="13"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 260 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14">
<!--<rect x="0" y="0" width="14" height="14" fill="lightpink"/>-->
<polyline points="2 6, 7 11, 12 6" stroke-width="2" stroke="#000" fill="none" />
</svg>

After

Width:  |  Height:  |  Size: 216 B

View File

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14">
<!--<rect x="0" y="0" width="14" height="14" fill="lightpink"/>-->
<g fill="#000">
<circle cx="7" cy="2" r="1.5" />
<circle cx="7" cy="7" r="1.5" />
<circle cx="7" cy="12" r="1.5" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 259 B

View File

@ -188,3 +188,34 @@ h3 {
.mtt-notes-showhide { .mtt-notes-showhide {
display: none; display: none;
} }
.mtt-tab {
display: none;
}
.mtt-tabs-selected {
display: block;
}
/* BEL */
#taskview ,
#bar ,
br[clear="all"] ,
#task_placeholder > span ,
#mtt_body > h2:first-child {
display: none !important;
}
#toolbar ,
#taskcontainer {
z-index: 15;
}
#taskcontainer {
position: fixed;
top: 6em;
left: 0;
right: 0;
bottom: 0;
overflow-y: scroll;
}

View File

@ -114,3 +114,48 @@ li.task-completed {
#taskview img { #taskview img {
display: none; display: none;
} }
/* 165 */
@media print {
html { height:0; }
body { height:0; min-height:0; margin:0; }
h2{ display: none; }
h3 { border-bottom:2px solid #777777; }
#toolbar { display: none; }
.topblock { display:none; }
.mtt-tab { display:none; }
.mtt-tab.mtt-tabs-selected { display:block; border:none; background:none; margin:0; }
.mtt-tab.mtt-tabs-selected a { padding:0; display:inline-block; height:auto; }
.mtt-tab.mtt-tabs-selected .list-action { display:none; }
.mtt-tab a span { text-align:left; padding:0; max-width:none; font-size:1.3rem; color:#000; }
.mtt-tabs-add-button { display:none; }
#list_all { display:none; }
#tabs_buttons { display:none; }
#taskview { padding-left:0; font-weight:normal; }
#taskview .arrdown { display:none; }
#tasklist { list-style-type: decimal; list-style-position: outside; }
#tasklist li { border-bottom:none; margin-left:2.5rem; /*border-bottom:1px solid #f0f0f0;*/ }
div.task-note-block { border-left:1px solid #777777; background:none; padding-left:5px; margin-top:5px; padding-top:0px; font-size:9pt; color:#333333; }
.task-middle { margin-left:0px; margin-right:3px; }
.task-left { display:none; }
.task-actions { display:none; }
.task-date { white-space:nowrap; margin-left:10px; }
#tasklist li.today, #tasklist li.past { background-color:#ffffff; border-color:#dedede; }
.task-prio { font-weight:bold; }
li.task-completed { opacity:1; }
#footer_content { border-top:1px solid #777777; background:none; }
#footer_content a { text-decoration:none; color:#000000; }
#mobileordesktop { display: none; }
#tagcloudbtn { display:none; }
.mtt-notes-showhide { display:none; }
#taskview img { display:none; }
}

View File

@ -198,7 +198,7 @@ a {
.mtt-tab a { .mtt-tab a {
position: relative; position: relative;
margin: 0; margin: 0;
font-size: 0.9em; /*font-size: 0.9em;*/
font-weight: bold; font-weight: bold;
text-decoration: none; text-decoration: none;
text-align: center; text-align: center;
@ -454,8 +454,8 @@ a {
} }
.mtt-taskbox-icon.mtt-icon-submittask { .mtt-taskbox-icon.mtt-icon-submittask {
background: url(images/mzl.png) 0px -32px no-repeat; /*background: url(images/mzl.png) 0px -32px no-repeat;
right: 4px; right: 4px;*/
} }
#newtask_adv span { #newtask_adv span {
@ -627,9 +627,9 @@ li.task-expanded .task-toggle {
} }
.task-actions { .task-actions {
float: right; /*float: right;*/
width: 20px; /*width: 20px;*/
text-align: right; /*text-align: right;*/
} }
.task-date { .task-date {
@ -760,18 +760,20 @@ li.task-completed .task-title a {
} }
a.taskactionbtn { a.taskactionbtn {
display: block; /*display: block;*/
/*
float: right; float: right;
height: 15px; height: 15px;
width: 15px; width: 15px;
*/
text-decoration: none; text-decoration: none;
background: url(images/icons.gif) 0 0 no-repeat; /*background: url(images/icons.gif) 0 0 no-repeat;*/
display: none; /*display: none;*/
} }
li:hover a.taskactionbtn, a.taskactionbtn.mtt-menu-button-active { li:hover a.taskactionbtn, a.taskactionbtn.mtt-menu-button-active {
background-position: -16px 0; /*background-position: -16px 0;*/
display: block; /*display: block;*/
} }
#tasklist.filter-past li, #tasklist.filter-today li, #tasklist.filter-soon li { #tasklist.filter-past li, #tasklist.filter-today li, #tasklist.filter-soon li {
@ -794,6 +796,7 @@ li:hover a.taskactionbtn, a.taskactionbtn.mtt-menu-button-active {
min-height: 16px; min-height: 16px;
display: none; display: none;
margin: .7em .5em 0 0; margin: .7em .5em 0 0;
white-space: pre;
} }
li.task-expanded .task-note-block { li.task-expanded .task-note-block {
@ -1367,3 +1370,402 @@ li.mtt-item-hidden {
min-width: 350px; min-width: 350px;
} }
body { filter: invert(80%); background-color: #222; } body { filter: invert(80%); background-color: #222; }
#newtask_adv ,
#tagcloudbtn ,
#settings {
display: none;
}
/* 165 */
/*
This file is a part of myTinyTodo.
Copyright 2009-2010,2020 Max Pozdeev <maxpozdeev@gmail.com>
*/
/* default style */
html { height:100%; overflow-y:scroll; font-size:14px; /* =1rem */ }
body { margin:0px; padding:0px; height:100%; /*background-color:#fff;*/ font-family:"Helvetica Neue",helvetica,arial,sans-serif; }
#wrapper { display:flex; flex-direction:column; align-items:center; height:100%; }
#container { flex: 1 0 auto; width:100%; max-width:1000px; }
#mtt_body { padding:8px; margin-bottom:8px; } /* TODO: can combine container and mtt_body */
#footer { flex-shrink:0; width:100%; max-width:1000px; }
td, th, input, textarea, select { font-family:"Helvetica Neue",helvetica,arial,sans-serif; font-size:1rem; }
form { display: inline; }
h2,h3 { margin:0; }
h2 { font-size:1.5rem; padding-right:10px; }
h3 { border-bottom:2px solid #B5D5FF; margin-bottom:10px; padding:0.6rem 0; font-size:1.1rem; }
a { color:#0000ff; cursor:pointer; text-decoration:underline; }
.topblock { display:flex; align-items:flex-start; margin-bottom:1rem; }
#footer_content { background-color:#b5d5ff; padding:0.6rem; font-size:0.9rem; display:flex; justify-content:space-between; }
#footer_content span:last-child { text-align:center; }
#footer_content a { color:#000000; }
#footer_content a.powered-by-link { font-weight:bold; }
.topblock-title { display:flex; align-items:center; }
.topblock-bar { flex-grow:1; display:flex; justify-content:flex-start; border-bottom:1px solid #b5d5ff; padding-bottom:5px; }
.bar-menu { flex-grow:1; display:flex; justify-content:flex-end; text-align:right; min-height:16px; /* for loading.gif */ }
.nodecor { text-decoration:none; }
#bar_auth::before { content:'\00a0| '; } /* &nbsp; = \00a0 */
#bar_logout { display:none; }
#mtt_body.no-need-auth #bar_auth { display:none; }
#mtt_body.readonly .need-owner { display:none; }
#mtt_body.readonly #bar_auth::before { display:none; }
#authform { overflow: hidden; z-index:100; background-color:#f9f9f9; border:1px solid #cccccc; border-radius:2px; padding:10px; min-width:160px; box-shadow:1px 2px 5px rgba(0,0,0,0.5); }
#authform div { padding:2px 0px; }
#authform div.h { font-weight:bold; }
#authform input { padding:3px; border:1px solid #ccc; border-radius:2px; }
#authform input[type="submit"] { padding:4px; border-radius:3px; background-color:#efefef; }
#loading { background-color:#ffffff; display:none; margin-right:6px; width:16px; height:16px; background:url(images/loading48.gif) no-repeat; background-size:16px 16px; }
#msg { }
#msg .msg-text { font-weight:bold; cursor:pointer; }
#msg .msg-details { padding:1px 4px; background-color:#fff; display:none; max-width:700px; position:absolute; z-index:2; }
#msg.mtt-error .msg-text { background-color:#ff3333; }
#msg.mtt-error .msg-details { border:1px solid #ff3333; }
#msg.mtt-info .msg-text { background-color:#EFC300; }
#msg.mtt-info .msg-details { border:1px solid #EFC300;}
#lists { font-size:0.95rem; display:flex; align-items:flex-start; justify-content:flex-end; }
.tabs-n-button { flex-grow:1; display:flex; align-items:flex-start; }
.tab-height-wrapper { box-sizing:border-box; height:2.2rem; display:flex; align-items:center; }
.mtt-tabs { list-style:none; padding:0; margin:0; display:flex; justify-content:flex-start; flex-wrap:wrap; }
.mtt-tabs li { margin:1px 3px 0 0; }
.mtt-tab { background-color:#fbfbfb; border:1px solid #ededed; border-bottom:none; border-top-right-radius:8px; transition:background-color 0.1s ease-in; }
.mtt-tab a {
margin:0; text-decoration:none; white-space:nowrap; color:#333333; display:inline-block; outline:none;
box-sizing:border-box; height:2.2rem; padding:1px 0.3rem 0 0.3rem; display:flex; align-items:center;
}
.mtt-tab a span { display:inline-block; text-align:center; min-width:75px; max-width:195px; cursor:pointer; padding:0; overflow:hidden; padding-left:0.3rem; padding-right:0.3rem;}
.mtt-tab .list-action { display:none; width:16px; height:16px; background:transparent url(images/arrdown.svg) no-repeat; cursor:pointer; }
.mtt-tab .list-action:hover, .mtt-tab .list-action.mtt-menu-button-active { background-image:url(images/arrdown-hover.svg); }
.mtt-tab.mtt-tabs-selected .list-action { display:block; }
.mtt-tab.mtt-tabs-selected { border-color:transparent; background-color:#ededed; }
.mtt-tab:hover { background-color:#ddd; }
.mtt-tab.mtt-tabs-selected:hover { background-color:#ededed; }
.mtt-tabs.mtt-tabs-only-one li { display:none; }
.mtt-tabs.mtt-tabs-only-one li.mtt-tabs-selected { display:block; }
.mtt-tabs-hidden { display:none; }
.mtt-tabs .mtt-list-sort-placeholder { background-color:#ddd; border:1px solid #aaa; }
.mtt-tabs-alltasks { margin:1px 3px 0 3px; }
.mtt-tabs-alltasks.mtt-tab { border-top-right-radius:0px; border-top-left-radius:8px; }
#tabs_buttons {
padding-left:2px; padding-right:2px;
border-top:1px solid transparent;
margin-top:1px;
}
.mtt-tabs-add-button { display:inline-block; margin-top:1px; border:1px solid #ededed; border-bottom:none; border-top-right-radius: 8px; background-color:#fbfbfb;
padding-left:3px; padding-right:3px;
}
.mtt-tabs-add-button span { display:block; width:16px; height:16px; background:url(images/plus.svg) no-repeat; }
.mtt-tabs-add-button:hover { cursor:pointer; background-color:#ddd; }
#mtt_body.readonly .mtt-tabs-add-button { display:none; }
.mtt-tabs-select-button>span { background:url(images/selectlist2.svg) no-repeat; }
.mtt-img-button { padding:4px; display:block; border-radius:4px; transition:background-color 0.1s ease-in; cursor:pointer; }
.mtt-img-button:hover, .mtt-img-button.mtt-menu-button-active { background-color:#efefef; cursor:pointer; }
.mtt-img-button span { display:block; width:16px; height:16px; }
#mtt_body.no-lists #toolbar > * { visibility:hidden; }
#toolbar { padding:8px; border-bottom:1px solid #DEDEDE; background:#ededed; }
#toolbar .mtt-img-button:hover { background-color:#ddd; }
.arrdown { display:inline-block; height:9px; width:9px; background:url(images/arrdown2.svg) no-repeat; }
.arrdown2 { display:inline-block; height:7px; width:7px; background:url(images/arrdown2.svg) no-repeat; }
.newtask-n-search-container { display:flex; justify-content:flex-end; }
/* Quick Task Add */
.taskbox-c { flex-grow:1; display:flex; align-items:center; }
.mtt-taskbox { position:relative; /*padding-left:22px;*/ /*input padding+border*/ flex-grow:1; max-width:430px; }
#task { color:#444444; background:#fff; height:1.35rem; padding:2px 4px; padding-right:20px; border:1px solid #ccc; border-radius:3px; width:100%; margin-left:-24px; }
#mtt_body.show-all-tasks .taskbox-c, #mtt_body.readonly .taskbox-c { display:none; }
.mtt-taskbox-icon { width:16px; height:16px; position:absolute; top:50%; margin-top:-8px; }
.mtt-taskbox-icon { background:url(images/add.svg) no-repeat; opacity:0.45; right:2px; cursor:pointer; transition:opacity .1s ease-in; }
.mtt-taskbox-icon:hover { opacity:0.7; }
#newtask_adv { margin-left:0.5rem; }
#newtask_adv span { background:url(images/newtask-ext.svg) no-repeat; }
/* Live Search */
#search {
color:#444444; background:#fff; height:1.35rem; padding:2px 20px; width:100%; margin-left:-42px; /*padding+border*/
border:1px solid #ccc; border-radius:10px;
}
#search_close { display:none; }
.mtt-searchbox { position:relative; padding-left:42px; /*input padding+border*/ }
.mtt-searchbox-icon { width:16px; height:16px; position:absolute; top:50%; margin-top:-8px; }
.mtt-searchbox-icon.mtt-icon-search { background:url(images/search.svg) no-repeat; left:4px; }
.mtt-searchbox-icon.mtt-icon-cancelsearch { background:url(images/search-cancel.svg) no-repeat; opacity:0.45; right:4px; cursor:pointer; transition:opacity .1s ease-in; }
.mtt-searchbox-icon.mtt-icon-cancelsearch:hover { opacity:0.7; }
#searchbar { font-size:1rem; font-weight:normal; display:none; margin-top:0.5rem; }
#searchbarkeyword { font-weight:bold; }
/* */
#page_tasks h3 { display:flex; align-items:baseline; }
#mtt_body.no-lists #page_tasks h3 > * { visibility:hidden; }
.mtt-notes-showhide { font-size:1rem; font-weight:normal; margin-left:5px; margin-right:5px; }
.mtt-notes-showhide a { text-decoration:none; border-bottom:1px dotted; }
/* Tag Toolbar */
#mtt-tag-toolbar { font-size:1.0rem; font-weight:normal; margin-top:0.5rem; line-height:1.5rem; display:flex; }
.tag-toolbar-content { flex:auto; margin-bottom:-3px; }
.tag-toolbar-close { flex-shrink:0; }
.tag-toolbar-header { font-weight:normal; }
.tag-filter { margin-left:3px; margin-right:3px; display:inline-flex; align-items:center;
border:1px solid #ddd; border-radius:2rem; background-color:#fff; padding:0.1rem 0.5rem; margin-bottom:3px; cursor:pointer;
}
.tag-filter-exclude { text-decoration:line-through; }
.mtt-filter-header { font-weight:bold; margin-right:.33rem; }
.tag-filter-btn { margin-left:3px; display:inline-block; width:1em; height:1em; /* em! */
background:url(images/closetag.svg) no-repeat; background-size:1em 1em; background-position:bottom center;
opacity:0.45; transition:opacity .1s ease-in; }
.tag-filter:hover .tag-filter-btn { opacity:0.7; }
#mtt-tag-toolbar-close span { background:url(images/close.svg) no-repeat; }
.task-toggle { visibility:hidden; cursor:pointer; width:1rem; height:1rem; display:inline-block; margin-right:2px;
background:url(images/note-toggle.svg) no-repeat; background-size:cover; opacity:0.45;
transition:transform .1s linear, opacity .1s ease-in;
}
.task-toggle::after { content:'0'; color:transparent; } /* for baseline */
.task-toggle:hover { opacity:0.7; }
li.task-has-note .task-toggle { visibility:visible; }
li.task-expanded .task-toggle { transform:rotate(90deg); }
/* #tasklist input[type="checkbox"] { vertical-align:-1px; } /* Chrome */
#tasklist { list-style-type: none; margin: 0; padding: 0;}
#tasklist li { padding:0px 2px; border-bottom:1px solid #DEDEDE; min-height:18px; margin-bottom:1px; background-color:#fff; }
#tasklist .task-container { display:flex; justify-content:flex-start; align-items:baseline; }
#tasklist li:hover, #tasklist li.menu-active { background-color:#f6f6f6; }
.task-left { display:inline-block; }
.task-middle { flex-grow:1; margin:0.6rem 0px; margin-left:5px; min-width:0; /*for long text*/ flex-basis:0; /* IE11 */}
.task-middle-top { display:flex; align-items:baseline; }
.task-actions { flex:0 0 1rem; margin-left:5px; }
.task-left label { min-width:18px; text-align:center; } /* Safari has small checkboxes */
.task-date { color:#999999; font-size:0.8rem; margin-left:4px; display:none; }
.task-date-completed { color:#999999; display:none; margin-left:5px; }
.show-inline-date .task-date { display:inline; }
.show-inline-date li.task-completed .task-date-completed { display:inline; }
.show-inline-date li.task-completed .task-date { display:none; }
.task-through { overflow:hidden; flex-grow:1; }
.task-through-right { }
.task-title a { color:#000000; }
.task-title a:hover { color:#af0000; }
#mtt_body.readonly #tasklist li .task-actions { display:none; }
.task-listname { background-color:#eee; color:#555; padding:0px 3px; }
.task-tags { padding:0px 2px; }
.task-tags .tag { font-size:0.9rem; font-weight:bold; color:#333333; text-decoration:underline; }
.task-tags .tag:hover { }
.duedate { color:#333333; padding:0px; padding-left:1px; margin-left:5px; white-space:nowrap; }
.duedate:before { content:'\2192\20'; }
li.task-completed .duedate { /*font-size:0.8rem;*/ display:none; }
#tasklist li.soon .duedate { color:#008000; }
#tasklist li.today .duedate { color:#FF0000; }
#tasklist li.past .duedate { color:#A52A2A; }
li.task-completed .task-middle { color:#777777;}
li.task-completed .task-through { text-decoration:line-through; }
li.task-completed .task-title a { color:#777777; }
#tasklist li.task-completed { opacity:0.6; }
#tasklist li.task-completed:hover { opacity:1.0; }
#tasklist li.not-in-tagpreview { opacity:0.1; }
#tasklist .mtt-task-placeholder {
min-height:0px; padding:0px; height:18px; line-height:18px;
background-color:#ddd; border:1px solid #aaa;
border-radius:5px;
}
.taskactionbtn { height:1rem; width:1rem; background:url(images/task-menu2.svg) center no-repeat; background-size:1rem; visibility:hidden; /* allocate space */
opacity:0.45; transition:opacity .1s ease-in; }
.taskactionbtn::after { content:'0'; color:transparent; } /* for baseline */
li:hover .taskactionbtn { visibility:visible; }
.taskactionbtn:hover, .taskactionbtn.mtt-menu-button-active { opacity:0.7; cursor:pointer; visibility:visible; }
#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; }
#tasklist.filter-past li.task-completed, #tasklist.filter-today li.task-completed, #tasklist.filter-soon li.task-completed { display:none; }
.task-note-block { margin-left:2px; color:#777777; background:url(images/note.svg) left 0px no-repeat; background-size:16px 16px;
padding-left:19px; min-height:16px; margin-top:6px; display:none; white-space:normal; word-wrap:break-word; }
li.task-expanded .task-note-block { display:block; }
li.task-completed .task-note-block .task-note { text-decoration:line-through; }
.task-note-area { display:none; margin-bottom:5px; }
.task-note-area textarea { color:#999999; width:100%; display:block; height:65px; }
.task-note-actions { font-size:0.8rem; }
.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:0px; margin-right:5px; cursor:default; }
.prio-neg { background-color:#3377ff; color:#ffffff; }
.prio-pos { background-color:#ff3333; color:#ffffff; }
.prio-pos-1 { background-color:#ff7700; color:#ffffff; }
.prio-zero { /*background-color:#dedede;*/ }
.task-prio.prio-zero { display:none; }
.form-row { margin-top:0.6rem; }
.form-row .h { font-weight:bold; color:#333333; }
.form-row div.h { margin-bottom:3px; }
.form-row-short-end { clear:both; }
#page_taskedit .form-input { padding:3px; border:1px solid #ccc; border-radius:2px; }
#page_taskedit select.form-input { padding:2px; }
#page_taskedit .form-bottom-buttons input { padding:4px; border:1px solid #ccc; border-radius:3px; background-color:#efefef; margin:2px; }
#page_taskedit .form-row .in500 { width:100%; box-sizing:border-box; }
#page_taskedit .form-row textarea.in500 { height:200px; /*resize:none;*/ }
#page_taskedit .form-row-short { float:left; margin-right:12px; }
#page_taskedit .form-bottom-buttons { text-align:center; margin-top:1rem; }
#alltags .tag { font-weight:bold; color:#333333; }
#alltags .tag:hover { background-color:#999988; color:white; }
.alltags-cell { width:1%; white-space:nowrap; padding-left:5px; }
#page_taskedit.mtt-inadd .mtt-inedit { display:none; }
#page_taskedit.mtt-inedit .mtt-inadd { display:none; }
#taskedit-date { font-size:1rem; font-weight:normal; display:inline; color:#777; margin-left:8px; }
a.mtt-back-button { font-size:1rem; }
/* autocomplete */
.ui-helper-hidden-accessible { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
.ui-autocomplete { position: absolute; padding:0px; border:1px solid #cccccc; background-color:#f9f9f9; overflow:hidden; z-index:99999; box-shadow:1px 2px 5px rgba(0,0,0,0.5); }
.ui-autocomplete .ui-menu-item { margin: 0px; cursor:default; overflow: hidden; }
.ui-autocomplete .ui-menu-item-wrapper { position: relative; padding:0.3rem 4px; }
.ui-autocomplete .ui-menu-item-wrapper.ui-state-active { background-color:#5a8df0; color:white; }
#priopopup { overflow: hidden; z-index:100; background-color:#f9f9f9; border:1px solid #cccccc; padding:5px; }
#priopopup span { cursor:pointer; border:1px solid #f9f9f9; padding:1px; }
#priopopup .prio-zero:hover { border-color:#dedede; }
#priopopup .prio-neg:hover { border-color:#3377ff; }
#priopopup .prio-pos:hover { border-color:#ff3333; }
#priopopup .prio-pos-1:hover { border-color:#ff7700; }
#tagcloudbtn { font-size:1rem; font-weight:normal; margin-left:auto; }
#mtt_body.show-all-tasks #tagcloudbtn { display:none; }
#tagcloudload { display:none; height:24px; background:url(images/loading48.gif) center no-repeat; background-size:24px 24px; }
#tagcloud {
overflow: hidden; z-index:100; background-color:#fff; border:1px solid #cccccc; padding:5px;
width:100%; max-width:450px; text-align:center;
box-shadow:1px 2px 5px rgba(0,0,0,0.5);
}
#tagcloud.mtt-left-adjusted { margin-left:5px; }
#tagcloud.mtt-right-adjusted { margin-right:5px; }
#tagcloud.mtt-left-adjusted.mtt-right-adjusted { margin-bottom:5px; }
#tagcloud .tag { margin:1px 0px; padding:2px; line-height:140%; color:black; }
#tagcloud .tag:hover { background-color:#999988; color:white; }
#tagcloud .w0 { font-size:80%; }
#tagcloud .w1 { font-size:90%; }
#tagcloud .w2 { font-size:100%; }
#tagcloud .w3 { font-size:110%; }
#tagcloud .w4 { font-size:120%; }
#tagcloud .w5 { font-size:130%; }
#tagcloud .w6 { font-size:140%; }
#tagcloud .w7 { font-size:150%; }
#tagcloud .w8 { font-size:160%; }
#tagcloud .w9 { font-size:170%; }
#tagcloudcancel { float:right; }
#tagcloudcancel span { background:url(images/close.svg) no-repeat; }
.ui-datepicker { width:220px; z-index:202; border: 1px solid #cccccc; background: #ffffff; display:none; padding:2px; box-shadow:1px 2px 5px rgba(0,0,0,0.5); border-radius:5px; }
.ui-datepicker-trigger { cursor:pointer; vertical-align:text-bottom; margin-left:4px; margin-right:4px; width:16px; height:16px; }
.ui-datepicker-calendar { width:100%; border-collapse:collapse; }
.ui-datepicker-calendar thead th { text-align:center; padding:0px; font-size:0.9rem; }
.ui-datepicker-calendar tbody td { text-align:right; padding:1px; }
.ui-datepicker-calendar td a { display:block; text-decoration:none; color:#444444; border:1px solid #cccccc; background-color:#f9f9f9; color:#111; padding:2px; }
.ui-datepicker-calendar td.ui-datepicker-current-day a { background-color:#EAF5FF; color:#222222; border-color:#5980FF; }
.ui-datepicker-calendar td.ui-datepicker-today a { color:#fff; background-color:#ccc; }
.ui-datepicker-calendar td a:hover { border-color:#5a8df0; }
.ui-datepicker-header { padding:3px 0px; }
.ui-datepicker-prev { position:absolute; left:2px; height:20px; text-decoration:none; }
.ui-datepicker-next { position:absolute; right:2px; height:20px; text-decoration:none; }
.ui-datepicker-title { text-align:center; line-height:20px; }
.ui-icon { width:16px; height:16px; text-indent:-99999px; overflow:hidden; }
.ui-datepicker .ui-icon-circle-triangle-w { display:block; position:absolute; top:50%; margin-top:-8px; left:50%; background:url(images/arr-left.svg) no-repeat; }
.ui-datepicker .ui-icon-circle-triangle-e { display:block; position:absolute; top:50%; margin-top:-8px; right:50%; background:url(images/arr-right.svg) no-repeat; }
.mtt-menu-button {
user-select: none;
cursor:pointer;
padding:4px;
transition:background-color 0.1s ease-in;
}
.mtt-menu-button:hover, .mtt-menu-button.mtt-menu-button-active {
background-color:#efefef; border-radius:4px;
}
.mtt-menu-container {
overflow:hidden; z-index:100;
background-color:#f9f9f9; border:1px solid #cccccc; padding:2px 0px;
box-shadow:1px 2px 5px rgba(0,0,0,0.5);
border-radius:5px;
user-select:none;
}
.mtt-menu-container.mtt-left-adjusted { margin-left:5px; }
.mtt-menu-container.mtt-right-adjusted { margin-right:5px; }
.mtt-menu-container.mtt-right-adjusted.mtt-left-adjusted { margin-bottom:5px; }
.mtt-menu-container ul { list-style: none; padding:0; margin:0; }
.mtt-menu-container li { margin:1px 0px; cursor:default; color:#000; white-space:nowrap; padding-top:0.20rem; padding-bottom:0.20rem; padding-left:28px; padding-right:28px; position:relative; }
.mtt-menu-container li:hover, .mtt-menu-container li.mtt-menu-item-active {
background-color:#5a8df0; color:white;
}
.mtt-menu-container li.mtt-item-disabled, .mtt-menu-container li.mtt-item-disabled a { color:#ACA899; }
.mtt-menu-container a { display:block; cursor:default; text-decoration:none; outline:none; color:#000; }
.mtt-menu-container li:hover a { color:white; }
.mtt-menu-container li.mtt-menu-delimiter { height:0px; line-height:0; border-bottom:1px solid #cccccc; margin:2px -1px; padding:0px; font-size:0px; }
.mtt-menu-container .menu-icon { width:16px; height:16px; position:absolute; left:6px; top:50%; margin-top:-8px; }
li.mtt-item-checked .menu-icon { background:url(images/checkmark.svg) no-repeat; }
li.mtt-menu-indicator .submenu-icon {
position:absolute; right:6px; top:50%; margin-top:-8px;
width:16px; height:16px; background:url(images/arr-right.svg) no-repeat;
}
li.mtt-item-hidden { display:none; }
#slmenucontainer li.mtt-list-hidden a { font-style:italic; }
#cmenulistscontainer li.mtt-list-hidden { font-style:italic; }
#mtt_body.readonly .mtt-need-list { display:none; }
#btnRssFeed .menu-icon { background:url(images/rss.svg) no-repeat; }
#btnRssFeed.mtt-item-disabled .menu-icon { background:url(images/rss-disabled.svg) no-repeat; }
#task, #search, #page_taskedit .form-input, #page_taskedit .form-bottom-buttons input { transition: box-shadow .15s ease-in-out; }
#task:focus, #search:focus, #page_taskedit .form-input:focus,
#page_taskedit .form-bottom-buttons input:focus { outline:none; border-color:#5a8df0; box-shadow:0 0 0 2px rgba(90,141,240,0.7); }
.mtt-settings-table { width:100%; border-collapse:collapse; }
.mtt-settings-table th, .mtt-settings-table td { border-bottom:1px solid #dedede; padding:8px; vertical-align:top; }
.mtt-settings-table .form-bottom-buttons { border-bottom:none; text-align:center; }
.mtt-settings-table th { text-align:left; width:210px; padding-left:8px; }
.mtt-settings-table .descr { font-size:0.8rem; font-weight:normal; color:#222; }
.mtt-settings-table .in350 { min-width:350px; }
.mtt-settings-table input { padding:3px; border:1px solid #ccc; border-radius:2px; }
.mtt-settings-table select { padding:2px; border:1px solid #ccc; border-radius:2px; }
.mtt-settings-table .form-bottom-buttons input { padding:4px; border:1px solid #ccc; border-radius:3px; background-color:#efefef; margin:2px; }
.mtt-settings-table input:focus, .mtt-settings-table select:focus { outline:none; border-color:#5a8df0; box-shadow:0 0 0 2px rgba(90,141,240,0.7); }
/* bel post 165 */
.task-actions .taskactionbtn {
width: 2.5em;
}
.task-note {
white-space: pre;
}

View File

@ -135,3 +135,46 @@ h2 {
padding-left: 0; padding-left: 0;
padding-right: 5px; padding-right: 5px;
} }
/* 165 */
body { direction:rtl; }
h2 { padding-left:10px; padding-right:0px; }
#loading { margin-left:6px; margin-right:0px; }
.mtt-tabs li { margin-left:3px; margin-right:0px; }
.mtt-tab { border-top-right-radius:0px; border-top-left-radius:8px; }
.mtt-tabs-add-button { border-top-right-radius:0px; border-top-left-radius:8px; }
.mtt-tabs-select-button>span { transform:rotateY(180deg); }
#task { padding-left:20px; padding-right:4px; }
.mtt-taskbox-icon { left:2px; right:auto; transform:rotateY(180deg); }
#newtask_adv { margin-left:0; margin-right:0.5rem; }
.mtt-searchbox-icon.mtt-icon-search { right:4px; left:auto; }
.mtt-searchbox-icon.mtt-icon-cancelsearch { left:4px; right:auto; }
#tagcloudbtn { margin-left:0; margin-right:auto; }
.task-toggle { margin-left:2px; margin-right:0; transform:rotate(180deg); }
.task-middle { margin-left:0; margin-right:5px; }
.task-actions { margin-left:0; margin-right:5px; }
.task-prio, .task-title, .task-date, .task-tags { display:inline-block; } /* TODO: fix this */
.task-prio { margin-left:5px; margin-right:0; }
.task-note-block { margin-left:0; margin-right:2px; padding-left:0; padding-right:19px; background-position:right 0px;}
.task-date { margin-left:0; margin-right:4px; }
.duedate { margin-left:0; margin-right:5px; }
.duedate-arrow { display:none; }
.duedate:before { content:'\20\2190\20'; }
.task-date-completed { margin-left:0; margin-right:5px; }
#tagcloud { box-shadow:-1px 2px 5px rgba(0,0,0,0.5); }
#tagcloudcancel { float:left; }
#taskedit-date { float:left; }
#page_taskedit .form-row-short { float:right; margin-left:12px; margin-right:0; }
.alltags-cell { padding-left:0; padding-right:5px; }
.mtt-menu-container { box-shadow:-1px 2px 5px rgba(0,0,0,0.5); }
.mtt-menu-container .menu-icon { left:auto; right:6px; }
li.mtt-menu-indicator .submenu-icon { left:6px; right:auto; transform:rotate(180deg); }

View File

@ -1,10 +1,13 @@
package ajax package ajax
import ( import (
"local/storage" "gogs.inhome.blapointe.com/local/storage"
"local/todo-server/config" "gogs.inhome.blapointe.com/local/todo-server/config"
"gogs.inhome.blapointe.com/local/todo-server/server/ajax/task"
"log"
"net/http" "net/http"
"net/url" "net/url"
"time"
) )
type Ajax struct { type Ajax struct {
@ -82,3 +85,78 @@ func has(params url.Values, k string) bool {
_, ok := params[k] _, ok := params[k]
return ok return ok
} }
func (a *Ajax) Async() {
var err error
nextDue := time.Now().Add(config.Loop)
c := time.NewTicker(config.Loop)
c2 := time.NewTicker(config.Loop)
for {
c.Stop()
c.Reset(config.Loop)
c2.Stop()
c2.Reset(time.Until(nextDue))
log.Println("next loop at", time.Until(nextDue), "or", config.Loop)
select {
case <-c.C:
case <-c2.C:
}
nextDue, err = a.loopTasks()
if err != nil {
log.Println("failed to loop tasks", err)
}
}
}
func (a *Ajax) loopTasks() (time.Time, error) {
nextDue := time.Now().Add(time.Hour * 240)
lists, err := a.storageListLists()
if err != nil {
return nextDue, err
}
for _, list := range lists {
tasks, err := a.storageListTasks(list.UUID, func(t *task.Task) bool {
return t.Complete
})
if err != nil {
return nextDue, err
}
for _, task := range tasks {
if !task.Complete {
continue
}
if task.Loop == 0 && task.Cron == "" {
continue
}
var nextTask time.Time
if task.Loop > 0 {
nextTask = task.Completed.Add(task.Loop)
}
if string(task.Cron) != "" {
nextTask2 := task.Cron.Next(task.Completed)
if nextTask2 != (time.Time{}) && (nextTask == (time.Time{}) || nextTask2.Before(nextTask)) {
nextTask = nextTask2
}
}
if time.Now().After(nextTask) {
task.Complete = false
task.Completed = time.Time{}
if nextTask == (time.Time{}) {
task.Title += " !!!INVALID CRON/LOOP!!!"
}
task.Index = list.NextIndex()
if err := a.storageSetTask(list.UUID, task); err != nil {
return nextDue, err
}
if err := a.storageSetList(list); err != nil {
return nextDue, err
}
} else {
if nextTask.Before(nextDue) {
nextDue = nextTask
}
}
}
}
return nextDue, nil
}

View File

@ -1,8 +1,8 @@
package ajax package ajax
import ( import (
"local/todo-server/config" "gogs.inhome.blapointe.com/local/todo-server/config"
"local/todo-server/server/ajax/list" "gogs.inhome.blapointe.com/local/todo-server/server/ajax/list"
"testing" "testing"
) )

19
server/ajax/form/cron.go Normal file
View File

@ -0,0 +1,19 @@
package form
import (
"log"
"time"
"github.com/robfig/cron/v3"
)
type Cron string
func (c Cron) Next(since time.Time) time.Time {
schedule, err := cron.ParseStandard(string(c))
if err != nil {
log.Printf("failed to parse cron %q: %v", string(c), err)
return time.Time{}
}
return schedule.Next(since)
}

View File

@ -7,6 +7,7 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"regexp"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -60,6 +61,38 @@ func ToStrArr(k string) []string {
return outArr return outArr
} }
func ToDuration(s string) time.Duration {
var d time.Duration
for _, c := range []struct {
key string
d time.Duration
}{
{"d", time.Hour * 24},
{"w", time.Hour * 24 * 7},
} {
daysPattern := regexp.MustCompile(`(^|[a-z])[0-9]+` + c.key + `($|[0-9])`)
idxes := daysPattern.FindAllStringIndex(s, -1)
if len(idxes) > 1 {
return 0
}
for _, idx := range idxes {
substr := s[idx[0]:idx[1]]
for len(substr) > 0 && (substr[0] < '0' || substr[0] > '9') {
substr = substr[1:]
}
for len(substr) > 0 && (substr[len(substr)-1] >= '0' && substr[len(substr)-1] <= '9') {
substr = substr[:len(substr)-1]
}
s = strings.ReplaceAll(s, substr, "")
substr = strings.TrimSuffix(substr, c.key)
n, _ := strconv.Atoi(substr)
d += c.d * time.Duration(n)
}
}
d2, _ := time.ParseDuration(s)
return d2 + d
}
func ToTime(s string) time.Time { func ToTime(s string) time.Time {
v, err := time.Parse("2006-01-02 15:04:05", s) v, err := time.Parse("2006-01-02 15:04:05", s)
if err != nil || v.IsZero() { if err != nil || v.IsZero() {

View File

@ -5,6 +5,7 @@ import (
"net/http/httptest" "net/http/httptest"
"strings" "strings"
"testing" "testing"
"time"
) )
func TestGet(t *testing.T) { func TestGet(t *testing.T) {
@ -142,3 +143,29 @@ func testReq() *http.Request {
"d": "e, f,g" "d": "e, f,g"
}`)) }`))
} }
func TestToDuration(t *testing.T) {
cases := map[string]struct {
input string
want time.Duration
}{
"invalid": {},
"simple": {input: "1s", want: time.Second},
"compound": {input: "1m1s", want: time.Minute + time.Second},
"compound:unsorted": {input: "1s1m", want: time.Minute + time.Second},
"compound:extension": {input: "1d1m", want: time.Minute + time.Hour*24},
"extension:day": {input: "1d", want: 24 * time.Hour},
"extension:week": {input: "1w", want: 24 * 7 * time.Hour},
"extension:week,day": {input: "1w1d", want: 24 * 8 * time.Hour},
}
for name, d := range cases {
c := d
t.Run(name, func(t *testing.T) {
got := ToDuration(c.input)
if got != c.want {
t.Fatal(c.input, c.want, got)
}
})
}
}

View File

@ -3,8 +3,8 @@ package ajax
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"local/todo-server/server/ajax/form" "gogs.inhome.blapointe.com/local/todo-server/server/ajax/form"
"local/todo-server/server/ajax/list" "gogs.inhome.blapointe.com/local/todo-server/server/ajax/list"
"net/http" "net/http"
"sort" "sort"
) )

View File

@ -2,20 +2,21 @@ package list
import ( import (
"errors" "errors"
"local/todo-server/server/ajax/form" "gogs.inhome.blapointe.com/local/todo-server/server/ajax/form"
"net/http" "net/http"
) )
type List struct { type List struct {
Name string `json:"name"` Name string `json:"name"`
UUID string `json:"id"` UUID string `json:"id"`
Sort int `json:"sort"` Sort int `json:"sort"`
Published int `json:"published"` Published int `json:"published"`
ShowCompl int `json:"showCompl"` ShowCompl int `json:"showCompl"`
ShowNotes int `json:"showNotes"` ShowLooping int `json:"showLooping"`
Hidden int `json:"hidden"` ShowNotes int `json:"showNotes"`
Max int `json:"max"` Hidden int `json:"hidden"`
Index int `json:"index"` Max int `json:"max"`
Index int `json:"index"`
} }
func New(r *http.Request) (*List, error) { func New(r *http.Request) (*List, error) {
@ -41,6 +42,10 @@ func (l *List) SetShowCompl(state bool) {
set(state, &l.ShowCompl) set(state, &l.ShowCompl)
} }
func (l *List) SetShowLooping(state bool) {
set(state, &l.ShowLooping)
}
func (l *List) SetShowNotes(state bool) { func (l *List) SetShowNotes(state bool) {
set(state, &l.ShowNotes) set(state, &l.ShowNotes)
} }

View File

@ -4,8 +4,8 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"local/todo-server/server/ajax/form" "gogs.inhome.blapointe.com/local/todo-server/server/ajax/form"
"local/todo-server/server/ajax/list" "gogs.inhome.blapointe.com/local/todo-server/server/ajax/list"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"strings" "strings"

View File

@ -3,10 +3,10 @@ package ajax
import ( import (
"bytes" "bytes"
"encoding/gob" "encoding/gob"
"local/storage" "gogs.inhome.blapointe.com/local/storage"
"local/todo-server/server/ajax/form" "gogs.inhome.blapointe.com/local/todo-server/server/ajax/form"
"local/todo-server/server/ajax/list" "gogs.inhome.blapointe.com/local/todo-server/server/ajax/list"
"local/todo-server/server/ajax/task" "gogs.inhome.blapointe.com/local/todo-server/server/ajax/task"
"net/http" "net/http"
"path" "path"
"sort" "sort"
@ -62,11 +62,11 @@ func (a *Ajax) storageListTasks(listID string, filters ...func(t *task.Task) boo
if err != nil { if err != nil {
return nil, err return nil, err
} }
includeComplete := true includeComplete := false
for _, f := range filters { for _, f := range filters {
t := &task.Task{Complete: true} t := &task.Task{Complete: true}
if !f(t) { if f(t) {
includeComplete = false includeComplete = true
} }
} }
if includeComplete { if includeComplete {
@ -77,11 +77,16 @@ func (a *Ajax) storageListTasks(listID string, filters ...func(t *task.Task) boo
results = append(results, completeResults...) results = append(results, completeResults...)
} }
tasks := []*task.Task{} tasks := []*task.Task{}
uuids := map[string]struct{}{}
for _, result := range results { for _, result := range results {
taskID := path.Base(result) taskID := path.Base(result)
if taskID == "" { if taskID == "" {
continue continue
} }
if _, ok := uuids[taskID]; ok {
continue
}
uuids[taskID] = struct{}{}
task, err := a.storageGetTask(taskID) task, err := a.storageGetTask(taskID)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -1,8 +1,8 @@
package ajax package ajax
import ( import (
"local/todo-server/server/ajax/list" "gogs.inhome.blapointe.com/local/todo-server/server/ajax/list"
"local/todo-server/server/ajax/task" "gogs.inhome.blapointe.com/local/todo-server/server/ajax/task"
"net/http/httptest" "net/http/httptest"
"testing" "testing"
) )

View File

@ -4,8 +4,8 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"local/todo-server/server/ajax/form" "gogs.inhome.blapointe.com/local/todo-server/server/ajax/form"
"local/todo-server/server/ajax/task" "gogs.inhome.blapointe.com/local/todo-server/server/ajax/task"
"net/http" "net/http"
"sort" "sort"
"strconv" "strconv"
@ -20,15 +20,24 @@ type taskWithDelta struct {
func (a *Ajax) loadTasks(w http.ResponseWriter, r *http.Request) error { func (a *Ajax) loadTasks(w http.ResponseWriter, r *http.Request) error {
listID, _, _ := a.Cur(r) listID, _, _ := a.Cur(r)
filterComplete := filterComplete(form.Get(r, "compl")) filterComplete := filterComplete(form.Get(r, "compl"))
filterLooping := filterLooping(form.Get(r, "looping"))
filterTags := filterTags(form.ToStrArr(form.Get(r, "t"))) filterTags := filterTags(form.ToStrArr(form.Get(r, "t")))
filterSubstr := filterSubstr(form.Get(r, "s")) filterSubstr := filterSubstr(form.Get(r, "s"))
tasks, err := a.storageListTasks(listID, filterComplete, filterTags, filterSubstr) tasks, err := a.storageListTasks(listID, filterComplete, filterTags, filterSubstr, filterLooping)
if err != nil { if err != nil {
return err return err
} }
return json.NewEncoder(w).Encode(map[string]interface{}{"list": tasks}) return json.NewEncoder(w).Encode(map[string]interface{}{"list": tasks})
} }
func filterLooping(looping string) func(t *task.Task) bool {
return func(t *task.Task) bool {
hasLoop := t.Loop > 0 || t.Cron != ""
onlyLooping := looping == "1"
return !onlyLooping || hasLoop
}
}
func filterComplete(compl string) func(t *task.Task) bool { func filterComplete(compl string) func(t *task.Task) bool {
return func(t *task.Task) bool { return func(t *task.Task) bool {
return compl == "" || !t.Complete || (compl == "1" && t.Complete) return compl == "" || !t.Complete || (compl == "1" && t.Complete)

View File

@ -4,7 +4,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"local/todo-server/server/ajax/form" "gogs.inhome.blapointe.com/local/todo-server/server/ajax/form"
"net/http" "net/http"
"regexp" "regexp"
"strings" "strings"
@ -23,6 +23,8 @@ type Task struct {
Complete bool Complete bool
Note []string Note []string
Due time.Time Due time.Time
Loop time.Duration
Cron form.Cron
Index int Index int
} }
@ -42,8 +44,9 @@ func New(r *http.Request) (*Task, error) {
Tags: append(StrList(form.ToStrArr(form.Get(r, "tag"))), StrList(form.ToStrArr(form.Get(r, "tags")))...), Tags: append(StrList(form.ToStrArr(form.Get(r, "tag"))), StrList(form.ToStrArr(form.Get(r, "tags")))...),
Created: time.Now(), Created: time.Now(),
Edited: time.Now(), Edited: time.Now(),
Due: form.ToTime(form.Get(r, "duedate")),
Due: form.ToTime(form.Get(r, "duedate")), Loop: form.ToDuration(form.Get(r, "loop")),
Cron: form.Cron(form.Get(r, "cron")),
} }
task.SetNote(form.Get(r, "note")) task.SetNote(form.Get(r, "note"))
return task, task.validate() return task, task.validate()
@ -73,7 +76,9 @@ func (t *Task) MarshalJSON() ([]byte, error) {
// "dueClass":"", // "dueClass":"",
// "dueStr":"", // "dueStr":"",
// "dueInt":33330000, // "dueInt":33330000,
// "dueTitle":"Due "} // "dueTitle":"Due ",
// "loop": "1m",
// "cron": "* * * * *"}
// ]} // ]}
fullFormat := "02 Jan 2006 03:04 PM" fullFormat := "02 Jan 2006 03:04 PM"
shortFormat := "02 Jan" shortFormat := "02 Jan"
@ -109,6 +114,8 @@ func (t *Task) MarshalJSON() ([]byte, error) {
"dueStr": t.Due.Format(shortFormat), "dueStr": t.Due.Format(shortFormat),
"dueInt": t.Due.Unix(), "dueInt": t.Due.Unix(),
"dueTitle": "Due ", "dueTitle": "Due ",
"loop": t.Loop.String(),
"cron": t.Cron,
} }
if t.Due.IsZero() { if t.Due.IsZero() {
for k := range m { for k := range m {

View File

@ -2,8 +2,8 @@ package ajax
import ( import (
"encoding/json" "encoding/json"
"local/todo-server/server/ajax/form" "gogs.inhome.blapointe.com/local/todo-server/server/ajax/form"
"local/todo-server/server/ajax/task" "gogs.inhome.blapointe.com/local/todo-server/server/ajax/task"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"path" "path"

View File

@ -3,9 +3,6 @@ package server
import ( import (
"fmt" "fmt"
"io" "io"
"local/gziphttp"
"local/router"
"local/todo-server/config"
"log" "log"
"net/http" "net/http"
"net/url" "net/url"
@ -13,6 +10,11 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"strings" "strings"
"gogs.inhome.blapointe.com/local/gziphttp"
"gogs.inhome.blapointe.com/local/oauth2/oauth2client"
"gogs.inhome.blapointe.com/local/router"
"gogs.inhome.blapointe.com/local/todo-server/config"
) )
func (s *Server) Routes() error { func (s *Server) Routes() error {
@ -22,28 +24,31 @@ func (s *Server) Routes() error {
}{ }{
{ {
path: "/", path: "/",
handler: s.gzip(s.index), handler: s.index,
}, },
{ {
path: "/mytinytodo_lang.php", path: "/mytinytodo_lang.php",
handler: s.gzip(s.lang), handler: s.lang,
}, },
{ {
path: fmt.Sprintf("/themes/%s%s", router.Wildcard, router.Wildcard), path: fmt.Sprintf("/themes/%s%s", router.Wildcard, router.Wildcard),
handler: s.gzip(s.handleDeviceCSS), handler: s.handleDeviceCSS,
}, },
{ {
path: fmt.Sprintf("%s%s", router.Wildcard, router.Wildcard), path: fmt.Sprintf("%s%s", router.Wildcard, router.Wildcard),
handler: s.gzip(s.phpProxy), handler: s.phpProxy,
}, },
{ {
path: "/ajax.php", path: "/ajax.php",
handler: s.gzip(s.HandleAjax), handler: s.HandleAjax,
}, },
} }
for _, route := range routes { for _, route := range routes {
if err := s.Add(route.path, route.handler); err != nil { handler := route.handler
handler = s.gzip(handler)
handler = s.oauth(handler)
if err := s.Add(route.path, handler); err != nil {
return err return err
} }
} }
@ -79,6 +84,10 @@ func (s *Server) lang(w http.ResponseWriter, r *http.Request) {
`) `)
} }
func (s *Server) toindex(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/", http.StatusSeeOther)
}
func (s *Server) index(w http.ResponseWriter, r *http.Request) { func (s *Server) index(w http.ResponseWriter, r *http.Request) {
f, err := os.Open(path.Join(config.Root, "index.html")) f, err := os.Open(path.Join(config.Root, "index.html"))
if err != nil { if err != nil {
@ -96,19 +105,61 @@ func (s *Server) phpProxy(w http.ResponseWriter, r *http.Request) {
s.static(w, r) s.static(w, r)
return return
} }
url, err := url.Parse(config.MyTinyTodo) url, err := url.Parse("http://127.0.0.1:64123")
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
} else { } else {
log.Println("WOULD proxy", url.String(), r.URL.Path) log.Println("WOULD proxy", url.String(), r.URL.Path)
s.index(w, r) s.toindex(w, r)
//proxy := httputil.NewSingleHostReverseProxy(url) //proxy := httputil.NewSingleHostReverseProxy(url)
//proxy.ServeHTTP(w, r) //proxy.ServeHTTP(w, r)
} }
} }
func (s *Server) static(w http.ResponseWriter, r *http.Request) { func (s *Server) static(w http.ResponseWriter, r *http.Request) {
s.fileServer.ServeHTTP(w, r) if err := s._static(w, r); err != nil {
s.toindex(w, r)
}
}
func (s *Server) _static(w http.ResponseWriter, r *http.Request) error {
if r.Method != http.MethodGet {
http.FileServer(s.fileDir).ServeHTTP(w, r)
return nil
}
f, err := s.fileDir.Open(path.Clean(r.URL.Path))
if err != nil {
return err
}
defer f.Close()
info, err := f.Stat()
if err != nil {
return err
}
if info.IsDir() {
r.URL.Path = path.Join(r.URL.Path, "index.html")
f, err = s.fileDir.Open(r.URL.Path)
defer f.Close()
if err != nil {
return err
}
}
gziphttp.SetContentTypeIfMedia(w, r)
_, err = io.Copy(w, f)
return err
}
func (s *Server) oauth(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if config.OAuth != "" {
err := oauth2client.Authenticate(config.OAuth, r.Host, w, r)
if err != nil {
log.Println("oauth failure", r.Host, ":", err)
return
}
}
h(w, r)
}
} }
func (s *Server) gzip(h http.HandlerFunc) http.HandlerFunc { func (s *Server) gzip(h http.HandlerFunc) http.HandlerFunc {

View File

@ -1,16 +1,16 @@
package server package server
import ( import (
"local/router" "gogs.inhome.blapointe.com/local/router"
"local/todo-server/config" "gogs.inhome.blapointe.com/local/todo-server/config"
"local/todo-server/server/ajax" "gogs.inhome.blapointe.com/local/todo-server/server/ajax"
"net/http" "net/http"
) )
type Server struct { type Server struct {
*ajax.Ajax *ajax.Ajax
*router.Router *router.Router
fileServer http.Handler fileDir http.Dir
} }
func New() *Server { func New() *Server {
@ -18,10 +18,10 @@ func New() *Server {
if err != nil { if err != nil {
panic(err) panic(err)
} }
fileServer := http.FileServer(http.Dir(config.Root)) fileDir := http.Dir(config.Root)
return &Server{ return &Server{
Ajax: ajax, Ajax: ajax,
Router: router.New(), Router: router.New(),
fileServer: fileServer, fileDir: fileDir,
} }
} }

@ -1 +0,0 @@
Subproject commit e21afea391ecac5c5f5b47639e5ce8cb8b7eb693