From 7292d2ef2121b5cfcf0cb935bbeb50069d14d208 Mon Sep 17 00:00:00 2001 From: DanyLE Date: Mon, 27 Mar 2023 20:38:17 +0200 Subject: [PATCH] Docify: Use libsqlite to handle database in Docify --- Blogger/dialogs.ts | 2 +- Docify/README.md | 1 + Docify/api/api.lua | 323 +------------------ Docify/assets/scheme.html | 1 - Docify/build.json | 38 ++- Docify/build/debug/README.md | 1 + Docify/build/debug/api.lua | 323 +------------------ Docify/build/debug/main.js | 2 +- Docify/build/debug/package.json | 75 ++++- Docify/build/debug/scheme.html | 1 - Docify/build/release/Docify.zip | Bin 8189 -> 7399 bytes Docify/coffees/dialogs.coffee | 329 ------------------- Docify/coffees/main.coffee | 290 ----------------- Docify/package.json | 75 ++++- Docify/project.json | 7 - Docify/ts/dialogs.ts | 354 +++++++++++++++++++++ Docify/ts/main.ts | 543 ++++++++++++++++++++++++++++++++ packages.json | 6 +- 18 files changed, 1098 insertions(+), 1273 deletions(-) delete mode 100644 Docify/coffees/dialogs.coffee delete mode 100644 Docify/coffees/main.coffee delete mode 100644 Docify/project.json create mode 100644 Docify/ts/dialogs.ts create mode 100644 Docify/ts/main.ts diff --git a/Blogger/dialogs.ts b/Blogger/dialogs.ts index f0167dc..d661ec3 100644 --- a/Blogger/dialogs.ts +++ b/Blogger/dialogs.ts @@ -87,7 +87,7 @@ namespace OS { -\s +\ `; // This dialog is use for cv section editing diff --git a/Docify/README.md b/Docify/README.md index 5dd2277..666b1ca 100644 --- a/Docify/README.md +++ b/Docify/README.md @@ -2,6 +2,7 @@ Simple PDF document manager ## Change logs +- v0.1.0-b: use libsqlite for database handling - v0.0.9-b: Adapt to support AntOS 2.0.x - v0.0.8-b: Allow upload files directly from the app - v0.0.7-a: Change category and icon diff --git a/Docify/api/api.lua b/Docify/api/api.lua index 9fb4241..54c172f 100644 --- a/Docify/api/api.lua +++ b/Docify/api/api.lua @@ -1,12 +1,10 @@ local arg = ... ulib = require("ulib") -sqlite = modules.sqlite() vfs = require("vfs") local handle = {} local docpath = nil -local dbpath = nil local result = function(data) return { @@ -31,7 +29,7 @@ local mkdirp =function(p) return true, nil end -local merge_files = function(data) +handle.merge_files = function(data) local firstfile = data.file[1] local fpath = docpath.."/"..data.cid local r, e = mkdirp(fpath) @@ -57,14 +55,14 @@ local merge_files = function(data) end end -- move the thumb file to the cache folder - local thumb = docpath.."/cache/"..std.sha1(firstfile:gsub(docpath, ""))..".png" - local desthumb = docpath.."/cache/"..std.sha1(fpath:gsub(docpath, ""))..".png" + local thumb = docpath.."/cache/"..enc.sha1(firstfile:gsub(docpath, ""))..".png" + local desthumb = docpath.."/cache/"..enc.sha1(fpath:gsub(docpath, ""))..".png" if vfs.exists(thumb) then vfs.move(thumb, desthumb) end -- remove all other thumb files for i,v in ipairs(data.file) do - thumb = docpath.."/cache/"..std.sha1(v:gsub(docpath, ""))..".png" + thumb = docpath.."/cache/"..enc.sha1(v:gsub(docpath, ""))..".png" if vfs.exists(thumb) then vfs.delete(thumb) end @@ -76,166 +74,15 @@ local merge_files = function(data) return result(fpath) end -handle.init = function(args) - - local r, e = mkdirp(docpath) - if not r then return e end - - r, e = mkdirp(docpath.."/unclassified") - if not r then return e end - - r, e = mkdirp(docpath.."/cache") - if not r then return e end - - local db = sqlite._getdb(vfs.ospath(dbpath)) - if not db then - return error("Unable to initialized database "..dbpath) - end - local sql - -- check if table exists - if sqlite.hasTable(db, "categories") == 0 then - -- create the table - sql = [[ - CREATE TABLE "categories" ( - "id" INTEGER, - "name" TEXT NOT NULL, - PRIMARY KEY("id" AUTOINCREMENT) - ); - ]] - if sqlite.query(db, sql) ~= 1 then - sqlite.dbclose(db) - return error("Unable to create table categories") - end - -- insert unknown category - sql = [[ - INSERT INTO categories("id","name") VALUES (0,'Uncategoried'); - ]] - if sqlite.query(db, sql) ~= 1 then - sqlite.dbclose(db) - return error("Unable to create default category") - end - end - - if sqlite.hasTable(db, "owners") == 0 then - -- create the table - sql = [[ - CREATE TABLE "owners" ( - "id" INTEGER, - "name" TEXT NOT NULL, - PRIMARY KEY("id" AUTOINCREMENT) - ); - ]] - if sqlite.query(db, sql) ~= 1 then - sqlite.dbclose(db) - return error("Unable to create table owners") - end - -- insert unknown category - sql = [[ - INSERT INTO owners("id","name") VALUES (0,'None'); - ]] - if sqlite.query(db, sql) ~= 1 then - sqlite.dbclose(db) - return error("Unable to create default None owner") - end - end - - if sqlite.hasTable(db, "docs") == 0 then - -- create the table - sql = [[ - CREATE TABLE "docs" ( - "id" INTEGER, - "name" TEXT NOT NULL, - "ctime" INTEGER, - "day" INTEGER, - "month" INTEGER, - "year" INTEGER, - "cid" INTEGER DEFAULT 0, - "oid" INTEGER DEFAULT 0, - "file" TEXT NOT NULL, - "tags" TEXT, - "note" TEXT, - "mtime" INTEGER, - FOREIGN KEY("oid") REFERENCES "owners"("id") ON DELETE SET DEFAULT ON UPDATE NO ACTION, - FOREIGN KEY("cid") REFERENCES "categories"("id") ON DELETE SET DEFAULT ON UPDATE NO ACTION, - PRIMARY KEY("id" AUTOINCREMENT) - ); - ]] - if sqlite.query(db, sql) ~= 1 then - sqlite.dbclose(db) - return error("Unable to create table docs") - end - end - sqlite.dbclose(db) - return result("Docify initialized") -end - -handle.select = function(param) - local db = sqlite._getdb(vfs.ospath(dbpath)) - if not db then - return error("Unable to get database "..dbpath) - end - local r = sqlite.select(db, param.table, "*", param.cond) - sqlite.dbclose(db) - if r == nil then - return error("Unable to select data from "..param.table) - else - return result(r) - end -end - -handle.fetch = function(table) - local db = sqlite._getdb(vfs.ospath(dbpath)) - if not db then - return error("Unable to get database "..dbpath) - end - local r = sqlite.select(db, table, "*", "1=1") - sqlite.dbclose(db) - if r == nil then - return error("Unable to fetch data from "..table) - else - return result(r) - end -end - -handle.insert = function(param) - local db = sqlite._getdb(vfs.ospath(dbpath)) - if not db then - return error("Unable to get database "..dbpath) - end - local keys = {} - local values = {} - for k,v in pairs(param.data) do - if k ~= "id" then - table.insert(keys,k) - if type(v) == "number" then - table.insert(values, v) - elseif type(v) == "boolean" then - table.insert( values, v and 1 or 0 ) - else - local t = "\""..v:gsub('"', '""').."\"" - table.insert(values,t) - end - end - end - local sql = "INSERT INTO "..param.table.." ("..table.concat(keys,',')..') VALUES (' - sql = sql..table.concat(values,',')..');' - local r = sqlite.query(db, sql) - sqlite.dbclose(db) - if r == nil then - return error("Unable to insert data to "..param.table) - else - return result("Data inserted") - end -end - handle.preview = function(path) -- convert -resize 300x500 noel.pdf[0] thumb.png - local name = std.sha1(path:gsub(docpath,""))..".png" + local name = enc.sha1(path:gsub(docpath,""))..".png" -- try to find the thumb local tpath = docpath.."/cache/"..name if not vfs.exists(tpath) then -- regenerate thumb local cmd = "convert -resize 250x500 \""..vfs.ospath(path).."\"[0] "..vfs.ospath(tpath) + LOG_ERROR(cmd) os.execute(cmd) end @@ -248,57 +95,12 @@ handle.preview = function(path) end end -handle.get_doc = function(id) - local db = sqlite._getdb(vfs.ospath(dbpath)) - if not db then - return error("Unable to get database "..dbpath) - end - local r = sqlite.select(db, "docs", "*", "id = "..id) - if r == nil or #r == 0 then - sqlite.dbclose(db) - return error("Unable to select data from "..param.table) - else - r = r[1] - local ret, meta = vfs.fileinfo(r.file) - if ret then - r.fileinfo = meta - end - local o = sqlite.select(db, "owners", "*", "id = "..r.oid) - sqlite.dbclose(db) - if o == nil or #o == 0 then - return result(r) - else - o = o[1] - r.owner = o.name - if r.ctime then - r.ctime = os.date("%d/%m/%Y %H:%M:%S", r.ctime) - end - - if r.mtime then - r.mtime = os.date("%d/%m/%Y %H:%M:%S", r.mtime) - end - local edate = "" - return result(r) - end - end -end - handle.deletedoc = function(param) - local db = sqlite._getdb(vfs.ospath(dbpath)) - if not db then - return error("Unable to get database "..dbpath) - end - local sql = "DELETE FROM docs WHERE id="..param.id..";" - local ret = sqlite.query(db, sql) == 1 - sqlite.dbclose(db) - if not ret then - return error("Unable to delete doc meta-data from database") - end -- move file to unclassified - local newfile = docpath.."/unclassified/"..std.basename(param.file) + local newfile = docpath.."/unclassified/"..utils.basename(param.file) vfs.move(param.file, newfile) -- delete thumb file - local thumb = docpath.."/cache/"..std.sha1(param.file:gsub(docpath,""))..".png" + local thumb = docpath.."/cache/"..enc.sha1(param.file:gsub(docpath,""))..".png" if vfs.exists(thumb) then vfs.delete(thumb) end @@ -306,20 +108,20 @@ handle.deletedoc = function(param) end handle.updatedoc = function(param) - local r = merge_files(param.data) + local r = handle.merge_files(param.data) if r.error then return r end if param.rm then -- move ve the old file to unclassified - local newfile = docpath.."/unclassified/"..std.basename(param.rm) + local newfile = docpath.."/unclassified/"..utils.basename(param.rm) local cmd = "rm -f "..vfs.ospath(param.rm) os.execute(cmd) --if vfs.exists(param.rm) then -- vfs.move(param.rm, newfile) --end -- move the thumb file if needed - local thumb = docpath.."/cache/"..std.sha1(param.rm:gsub(docpath,""))..".png" - local newwthumb = docpath.."/cache/"..std.sha1(newfile:gsub(docpath, ""))..".png" + local thumb = docpath.."/cache/"..enc.sha1(param.rm:gsub(docpath,""))..".png" + local newwthumb = docpath.."/cache/"..enc.sha1(newfile:gsub(docpath, ""))..".png" if vfs.exists(thumb) then vfs.move(thumb, newwthumb) end @@ -327,107 +129,16 @@ handle.updatedoc = function(param) param.data.file = r.result print(r.result) param.data.mtime = os.time(os.date("!*t")) - return handle.update({ - table = "docs", - data = param.data - }) + return result(param.data) + --return handle.update({ + -- table = "docs", + -- data = param.data + --}) end - -handle.insertdoc = function(data) - local r = merge_files(data) - if r.error then return r end - -- save data - data.file = r.result - data.ctime = os.time(os.date("!*t")) - data.mtime = os.time(os.date("!*t")) - local ret = handle.insert({ - table = "docs", - data = data - }) - return ret -end - -handle.update = function(param) - if not param.data.id or param.data.id == 0 then - return error("Record id is 0 or not found") - end - local db = sqlite._getdb(vfs.ospath(dbpath)) - if not db then - return error("Unable to get database "..dbpath) - end - local lst = {} - for k,v in pairs(param.data) do - if(type(v)== "number") then - table.insert(lst,k.."="..v) - elseif type(v) == "boolean" then - table.insert( lst, k.."="..(v and 1 or 0) ) - else - table.insert(lst,k.."=\""..v:gsub('"', '""').."\"") - end - end - - local sql = "UPDATE "..param.table.." SET "..table.concat(lst,",").." WHERE id="..param.data.id..";" - local r = sqlite.query(db, sql) - sqlite.dbclose(db) - if r == nil then - return error("Unable to update data to "..param.table) - else - return result("Data Updated") - end -end - -handle.delete = function(param) - if param.id == 0 then - return error("Record with id = 0 cannot be deleted") - end - - local db = sqlite._getdb(vfs.ospath(dbpath)) - if not db then - return error("Unable to get database "..dbpath) - end - local sql = "DELETE FROM "..param.table.." WHERE id="..param.id..";" - local r = sqlite.query(db, sql) - sqlite.dbclose(db) - if r == nil then - return error("Unable to delete data from "..param.table) - else - return result("Data deleted") - end -end - -handle.printdoc = function(opt) - local cmd = "lp " - if opt.printer and opt.printer ~= "" then - cmd = cmd .. " -d "..opt.printer - end - if opt.side == 0 then - cmd = cmd.. " -o sides=one-sided" - elseif opt.side == 1 then - cmd = cmd.. " -o sides=two-sided-long-edge" - elseif opt.side == 2 then - cmd = cmd .. " -o sides=two-sided-short-edge" - end - -- orientation landscape - if opt.orientation == 1 then - cmd = cmd.." -o orientation-requested=5" - end - - if opt.range == 1 then - cmd = cmd.." -P "..opt.pages - end - - cmd = cmd.. " "..vfs.ospath(opt.file) - print(cmd) - os.execute(cmd) - return result("A print job has been posted on server. Check if it successes") -end - - if arg.action and handle[arg.action] then -- check if the database exits docpath = arg.docpath - dbpath = docpath.."/docify.db" return handle[arg.action](arg.args) else diff --git a/Docify/assets/scheme.html b/Docify/assets/scheme.html index 6b98f30..f3e98cd 100644 --- a/Docify/assets/scheme.html +++ b/Docify/assets/scheme.html @@ -25,7 +25,6 @@
-
diff --git a/Docify/build.json b/Docify/build.json index 27525e2..ae3e803 100644 --- a/Docify/build.json +++ b/Docify/build.json @@ -13,17 +13,35 @@ } ] }, - "coffee": { + "locale": { + "require": ["locale"], + "jobs": [ + { + "name":"locale-gen", + "data": { + "src": "", + "exclude": ["build/", "api/", "css/", "coffees/"], + "locale": "en_GB", + "dest": "package.json" + } + } + ] + }, + "ts": { "require": [ - "coffee" + "ts" ], "jobs": [ { - "name": "coffee-compile", + "name": "ts-import", + "data": ["sdk://core/ts/core.d.ts", "sdk://core/ts/jquery.d.ts","sdk://core/ts/antos.d.ts"] + }, + { + "name": "ts-compile", "data": { "src": [ - "coffees/dialogs.coffee", - "coffees/main.coffee" + "ts/dialogs.ts", + "ts/main.ts" ], "dest": "build/debug/main.js" } @@ -65,7 +83,7 @@ ], "depend": [ "init", - "coffee", + "ts", "uglify", "copy" ], @@ -78,6 +96,14 @@ } } ] + }, + + "debug": { + "depend": [ + "init", + "ts", + "copy" + ] } } } \ No newline at end of file diff --git a/Docify/build/debug/README.md b/Docify/build/debug/README.md index 5dd2277..666b1ca 100644 --- a/Docify/build/debug/README.md +++ b/Docify/build/debug/README.md @@ -2,6 +2,7 @@ Simple PDF document manager ## Change logs +- v0.1.0-b: use libsqlite for database handling - v0.0.9-b: Adapt to support AntOS 2.0.x - v0.0.8-b: Allow upload files directly from the app - v0.0.7-a: Change category and icon diff --git a/Docify/build/debug/api.lua b/Docify/build/debug/api.lua index 9fb4241..54c172f 100644 --- a/Docify/build/debug/api.lua +++ b/Docify/build/debug/api.lua @@ -1,12 +1,10 @@ local arg = ... ulib = require("ulib") -sqlite = modules.sqlite() vfs = require("vfs") local handle = {} local docpath = nil -local dbpath = nil local result = function(data) return { @@ -31,7 +29,7 @@ local mkdirp =function(p) return true, nil end -local merge_files = function(data) +handle.merge_files = function(data) local firstfile = data.file[1] local fpath = docpath.."/"..data.cid local r, e = mkdirp(fpath) @@ -57,14 +55,14 @@ local merge_files = function(data) end end -- move the thumb file to the cache folder - local thumb = docpath.."/cache/"..std.sha1(firstfile:gsub(docpath, ""))..".png" - local desthumb = docpath.."/cache/"..std.sha1(fpath:gsub(docpath, ""))..".png" + local thumb = docpath.."/cache/"..enc.sha1(firstfile:gsub(docpath, ""))..".png" + local desthumb = docpath.."/cache/"..enc.sha1(fpath:gsub(docpath, ""))..".png" if vfs.exists(thumb) then vfs.move(thumb, desthumb) end -- remove all other thumb files for i,v in ipairs(data.file) do - thumb = docpath.."/cache/"..std.sha1(v:gsub(docpath, ""))..".png" + thumb = docpath.."/cache/"..enc.sha1(v:gsub(docpath, ""))..".png" if vfs.exists(thumb) then vfs.delete(thumb) end @@ -76,166 +74,15 @@ local merge_files = function(data) return result(fpath) end -handle.init = function(args) - - local r, e = mkdirp(docpath) - if not r then return e end - - r, e = mkdirp(docpath.."/unclassified") - if not r then return e end - - r, e = mkdirp(docpath.."/cache") - if not r then return e end - - local db = sqlite._getdb(vfs.ospath(dbpath)) - if not db then - return error("Unable to initialized database "..dbpath) - end - local sql - -- check if table exists - if sqlite.hasTable(db, "categories") == 0 then - -- create the table - sql = [[ - CREATE TABLE "categories" ( - "id" INTEGER, - "name" TEXT NOT NULL, - PRIMARY KEY("id" AUTOINCREMENT) - ); - ]] - if sqlite.query(db, sql) ~= 1 then - sqlite.dbclose(db) - return error("Unable to create table categories") - end - -- insert unknown category - sql = [[ - INSERT INTO categories("id","name") VALUES (0,'Uncategoried'); - ]] - if sqlite.query(db, sql) ~= 1 then - sqlite.dbclose(db) - return error("Unable to create default category") - end - end - - if sqlite.hasTable(db, "owners") == 0 then - -- create the table - sql = [[ - CREATE TABLE "owners" ( - "id" INTEGER, - "name" TEXT NOT NULL, - PRIMARY KEY("id" AUTOINCREMENT) - ); - ]] - if sqlite.query(db, sql) ~= 1 then - sqlite.dbclose(db) - return error("Unable to create table owners") - end - -- insert unknown category - sql = [[ - INSERT INTO owners("id","name") VALUES (0,'None'); - ]] - if sqlite.query(db, sql) ~= 1 then - sqlite.dbclose(db) - return error("Unable to create default None owner") - end - end - - if sqlite.hasTable(db, "docs") == 0 then - -- create the table - sql = [[ - CREATE TABLE "docs" ( - "id" INTEGER, - "name" TEXT NOT NULL, - "ctime" INTEGER, - "day" INTEGER, - "month" INTEGER, - "year" INTEGER, - "cid" INTEGER DEFAULT 0, - "oid" INTEGER DEFAULT 0, - "file" TEXT NOT NULL, - "tags" TEXT, - "note" TEXT, - "mtime" INTEGER, - FOREIGN KEY("oid") REFERENCES "owners"("id") ON DELETE SET DEFAULT ON UPDATE NO ACTION, - FOREIGN KEY("cid") REFERENCES "categories"("id") ON DELETE SET DEFAULT ON UPDATE NO ACTION, - PRIMARY KEY("id" AUTOINCREMENT) - ); - ]] - if sqlite.query(db, sql) ~= 1 then - sqlite.dbclose(db) - return error("Unable to create table docs") - end - end - sqlite.dbclose(db) - return result("Docify initialized") -end - -handle.select = function(param) - local db = sqlite._getdb(vfs.ospath(dbpath)) - if not db then - return error("Unable to get database "..dbpath) - end - local r = sqlite.select(db, param.table, "*", param.cond) - sqlite.dbclose(db) - if r == nil then - return error("Unable to select data from "..param.table) - else - return result(r) - end -end - -handle.fetch = function(table) - local db = sqlite._getdb(vfs.ospath(dbpath)) - if not db then - return error("Unable to get database "..dbpath) - end - local r = sqlite.select(db, table, "*", "1=1") - sqlite.dbclose(db) - if r == nil then - return error("Unable to fetch data from "..table) - else - return result(r) - end -end - -handle.insert = function(param) - local db = sqlite._getdb(vfs.ospath(dbpath)) - if not db then - return error("Unable to get database "..dbpath) - end - local keys = {} - local values = {} - for k,v in pairs(param.data) do - if k ~= "id" then - table.insert(keys,k) - if type(v) == "number" then - table.insert(values, v) - elseif type(v) == "boolean" then - table.insert( values, v and 1 or 0 ) - else - local t = "\""..v:gsub('"', '""').."\"" - table.insert(values,t) - end - end - end - local sql = "INSERT INTO "..param.table.." ("..table.concat(keys,',')..') VALUES (' - sql = sql..table.concat(values,',')..');' - local r = sqlite.query(db, sql) - sqlite.dbclose(db) - if r == nil then - return error("Unable to insert data to "..param.table) - else - return result("Data inserted") - end -end - handle.preview = function(path) -- convert -resize 300x500 noel.pdf[0] thumb.png - local name = std.sha1(path:gsub(docpath,""))..".png" + local name = enc.sha1(path:gsub(docpath,""))..".png" -- try to find the thumb local tpath = docpath.."/cache/"..name if not vfs.exists(tpath) then -- regenerate thumb local cmd = "convert -resize 250x500 \""..vfs.ospath(path).."\"[0] "..vfs.ospath(tpath) + LOG_ERROR(cmd) os.execute(cmd) end @@ -248,57 +95,12 @@ handle.preview = function(path) end end -handle.get_doc = function(id) - local db = sqlite._getdb(vfs.ospath(dbpath)) - if not db then - return error("Unable to get database "..dbpath) - end - local r = sqlite.select(db, "docs", "*", "id = "..id) - if r == nil or #r == 0 then - sqlite.dbclose(db) - return error("Unable to select data from "..param.table) - else - r = r[1] - local ret, meta = vfs.fileinfo(r.file) - if ret then - r.fileinfo = meta - end - local o = sqlite.select(db, "owners", "*", "id = "..r.oid) - sqlite.dbclose(db) - if o == nil or #o == 0 then - return result(r) - else - o = o[1] - r.owner = o.name - if r.ctime then - r.ctime = os.date("%d/%m/%Y %H:%M:%S", r.ctime) - end - - if r.mtime then - r.mtime = os.date("%d/%m/%Y %H:%M:%S", r.mtime) - end - local edate = "" - return result(r) - end - end -end - handle.deletedoc = function(param) - local db = sqlite._getdb(vfs.ospath(dbpath)) - if not db then - return error("Unable to get database "..dbpath) - end - local sql = "DELETE FROM docs WHERE id="..param.id..";" - local ret = sqlite.query(db, sql) == 1 - sqlite.dbclose(db) - if not ret then - return error("Unable to delete doc meta-data from database") - end -- move file to unclassified - local newfile = docpath.."/unclassified/"..std.basename(param.file) + local newfile = docpath.."/unclassified/"..utils.basename(param.file) vfs.move(param.file, newfile) -- delete thumb file - local thumb = docpath.."/cache/"..std.sha1(param.file:gsub(docpath,""))..".png" + local thumb = docpath.."/cache/"..enc.sha1(param.file:gsub(docpath,""))..".png" if vfs.exists(thumb) then vfs.delete(thumb) end @@ -306,20 +108,20 @@ handle.deletedoc = function(param) end handle.updatedoc = function(param) - local r = merge_files(param.data) + local r = handle.merge_files(param.data) if r.error then return r end if param.rm then -- move ve the old file to unclassified - local newfile = docpath.."/unclassified/"..std.basename(param.rm) + local newfile = docpath.."/unclassified/"..utils.basename(param.rm) local cmd = "rm -f "..vfs.ospath(param.rm) os.execute(cmd) --if vfs.exists(param.rm) then -- vfs.move(param.rm, newfile) --end -- move the thumb file if needed - local thumb = docpath.."/cache/"..std.sha1(param.rm:gsub(docpath,""))..".png" - local newwthumb = docpath.."/cache/"..std.sha1(newfile:gsub(docpath, ""))..".png" + local thumb = docpath.."/cache/"..enc.sha1(param.rm:gsub(docpath,""))..".png" + local newwthumb = docpath.."/cache/"..enc.sha1(newfile:gsub(docpath, ""))..".png" if vfs.exists(thumb) then vfs.move(thumb, newwthumb) end @@ -327,107 +129,16 @@ handle.updatedoc = function(param) param.data.file = r.result print(r.result) param.data.mtime = os.time(os.date("!*t")) - return handle.update({ - table = "docs", - data = param.data - }) + return result(param.data) + --return handle.update({ + -- table = "docs", + -- data = param.data + --}) end - -handle.insertdoc = function(data) - local r = merge_files(data) - if r.error then return r end - -- save data - data.file = r.result - data.ctime = os.time(os.date("!*t")) - data.mtime = os.time(os.date("!*t")) - local ret = handle.insert({ - table = "docs", - data = data - }) - return ret -end - -handle.update = function(param) - if not param.data.id or param.data.id == 0 then - return error("Record id is 0 or not found") - end - local db = sqlite._getdb(vfs.ospath(dbpath)) - if not db then - return error("Unable to get database "..dbpath) - end - local lst = {} - for k,v in pairs(param.data) do - if(type(v)== "number") then - table.insert(lst,k.."="..v) - elseif type(v) == "boolean" then - table.insert( lst, k.."="..(v and 1 or 0) ) - else - table.insert(lst,k.."=\""..v:gsub('"', '""').."\"") - end - end - - local sql = "UPDATE "..param.table.." SET "..table.concat(lst,",").." WHERE id="..param.data.id..";" - local r = sqlite.query(db, sql) - sqlite.dbclose(db) - if r == nil then - return error("Unable to update data to "..param.table) - else - return result("Data Updated") - end -end - -handle.delete = function(param) - if param.id == 0 then - return error("Record with id = 0 cannot be deleted") - end - - local db = sqlite._getdb(vfs.ospath(dbpath)) - if not db then - return error("Unable to get database "..dbpath) - end - local sql = "DELETE FROM "..param.table.." WHERE id="..param.id..";" - local r = sqlite.query(db, sql) - sqlite.dbclose(db) - if r == nil then - return error("Unable to delete data from "..param.table) - else - return result("Data deleted") - end -end - -handle.printdoc = function(opt) - local cmd = "lp " - if opt.printer and opt.printer ~= "" then - cmd = cmd .. " -d "..opt.printer - end - if opt.side == 0 then - cmd = cmd.. " -o sides=one-sided" - elseif opt.side == 1 then - cmd = cmd.. " -o sides=two-sided-long-edge" - elseif opt.side == 2 then - cmd = cmd .. " -o sides=two-sided-short-edge" - end - -- orientation landscape - if opt.orientation == 1 then - cmd = cmd.." -o orientation-requested=5" - end - - if opt.range == 1 then - cmd = cmd.." -P "..opt.pages - end - - cmd = cmd.. " "..vfs.ospath(opt.file) - print(cmd) - os.execute(cmd) - return result("A print job has been posted on server. Check if it successes") -end - - if arg.action and handle[arg.action] then -- check if the database exits docpath = arg.docpath - dbpath = docpath.."/docify.db" return handle[arg.action](arg.args) else diff --git a/Docify/build/debug/main.js b/Docify/build/debug/main.js index a43d741..b34f59c 100644 --- a/Docify/build/debug/main.js +++ b/Docify/build/debug/main.js @@ -1 +1 @@ -(function(){var t,i,a,r,n;(r=class t extends this.OS.GUI.BasicDialog{constructor(){super("OwnerDialog",t.scheme)}main(){return super.main(),this.oview=this.find("ownview"),this.oview.buttons=[{text:"",iconclass:"fa fa-plus-circle",onbtclick:t=>this.openDialog("PromptDialog",{title:__("Owner"),label:__("Name")}).then(t=>this.parent.exec("insert",{table:"owners",data:{name:t}}).then(t=>t.error?this.error(t.error):this.owner_refresh()).catch(t=>this.error(__("Unable to insert owner: {0}",t.toString()),t))).catch(t=>this.error(t.toString(),t))},{text:"",iconclass:"fa fa-minus-circle",onbtclick:t=>{var e;if(e=this.oview.selectedItem)return this.ask({text:__("Do you realy want to delete: `{0}`",e.data.text)}).then(t=>{if(t)return this.parent.exec("delete",{table:"owners",id:parseInt(e.data.id)}).then(t=>t.error?this.error(t.error):this.owner_refresh()).catch(t=>this.error(__("Unable delete category: {0}",t.toString()),t))})}},{text:"",iconclass:"fa fa-pencil-square-o",onbtclick:t=>{var e;if(e=this.oview.selectedItem)return this.openDialog("PromptDialog",{title:__("Owner"),label:__("Name"),value:e.data.name}).then(t=>this.parent.exec("update",{table:"owners",data:{id:parseInt(e.data.id),name:t}}).then(t=>t.error?this.error(t.error):this.owner_refresh()).catch(t=>this.error(__("Unable to update owner: {0}",t.toString()),t))).catch(t=>this.error(t.toString()))}}],this.owner_refresh()}owner_refresh(){return this.parent.exec("fetch","owners").then(t=>{var e,i,a,r;for(e=0,i=(a=t.result).length;ethis.error(__("Unable to fetch owners: {0}",t.toString()),e))}}).scheme="\n \n \n \n",(t=class t extends this.OS.GUI.BasicDialog{constructor(){super("DocDialog",t.scheme)}main(){var t,e,i,r,n,s,h,l;for(super.main(),this.flist=this.find("file-list"),this.dlist=this.find("dlist"),this.mlist=this.find("mlist"),this.ylist=this.find("ylist"),this.olist=this.find("olist"),this.setting=this.parent.setting,this.exec=this.parent.exec,this.preview=this.parent.preview,this.exec("fetch","owners").then(t=>{var e,i,a,r,n,s,h;if(t.error)return this.error(t.error);for(e=0,a=(n=t.result).length;ethis.error(__("Unable to fetch owner list: {0}",t.toString()),t)),this.dlist.push({text:"None",value:0}),h=0,t=i=1;i<=31;t=++i)this.dlist.push({text:""+t,value:t}),this.data&&parseInt(this.data.day)===t&&(h=t);for(this.dlist.selected=h,this.mlist.push({text:"None",value:0}),h=0,t=r=1;r<=12;t=++r)this.mlist.push({text:""+t,value:t}),this.data&&parseInt(this.data.month)===t&&(h=t);for(this.mlist.selected=h,this.ylist.push({text:"None",value:0}),this.ylist.selected=0,l=n=1960,s=(new Date).getFullYear();1960<=s?n<=s:n>=s;l=1960<=s?++n:--n)this.ylist.push({text:""+l,value:l,selected:this.data&&parseInt(this.data.year)===l});if(this.flist.buttons=[{text:"",iconclass:"fa fa-plus-circle",onbtclick:t=>this.openDialog(new a).then(t=>(t.text=t.filename,this.flist.push(t)))},{text:"",iconclass:"fa fa-minus-circle",onbtclick:t=>{var e;if(e=this.flist.selectedItem)return this.flist.delete(e)}}],this.flist.onlistselect=t=>this.parent.preview(t.data.item.data.path,this.find("preview-canvas")),this.find("btsave").onbtclick=t=>{var e,i;return(e={name:this.find("title").value.trim(),day:this.dlist.selectedItem.data.value,month:this.mlist.selectedItem.data.value,year:this.ylist.selectedItem.data.value,file:function(){var t,e,a,r;for(r=[],t=0,e=(a=this.flist.data).length;t0?(this.handle&&this.handle(e),this.quit()):this.notify(__("Please attach files to the entry")):this.notify(__("Please enter title"))},this.data)return this.find("title").value=this.data.name,this.find("note").value=this.data.note,this.find("tag").value=this.data.tags,(e=this.data.file.asFileHandle()).text=e.filename,this.flist.data=[e]}}).scheme='\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n
\n \n
\n
\n
\n
',(a=class t extends this.OS.GUI.BasicDialog{constructor(){super("FilePreviewDialog",t.scheme)}main(){return super.main(),this.flist=this.find("file-list"),this.flist.buttons=[{text:"",iconclass:"fa fa-refresh",onbtclick:t=>this.refresh()}],this.flist.onlistselect=t=>this.parent.preview(t.data.item.data.path,this.find("preview-canvas")),this.find("btok").onbtclick=t=>{var e;return(e=this.flist.selectedItem)?(this.handle&&this.handle(e.data),this.quit()):this.quit()},this.refresh()}refresh(){return(this.parent.setting.docpath+"/unclassified").asFileHandle().read().then(t=>{var e,i,a,r;if(t.error)return this.error(t.error);for(e=0,i=(a=t.result).length;ethis.error(__("Unable to fetch unclassified file list: {0}",t.toString()),t))}}).scheme='\n \n \n \n \n \n \n
\n \n
\n
\n \n
\n \n
\n
\n
',(n=class t extends this.OS.GUI.BasicDialog{constructor(){super("PrintDialog",t.scheme)}main(){return super.main(),this.find("printerName").value=this.parent.setting.printer,this.find("btnprint").onbtclick=t=>{var e;return(e={}).range=parseInt($("input[name=range]:checked",this.scheme).val()),e.pages=this.find("txtPageRange").value,e.printer=this.find("printerName").value,e.orientation=parseInt($("input[name=orientation]:checked",this.scheme).val()),e.side=parseInt($("input[name=side]:checked",this.scheme).val()),this.handle&&this.handle(e),this.quit()}}}).scheme='\n \n \n \n \n
\n \n
\n \n \n \n
\n \n
\n \n
\n \n \n
\n \n
\n \n
\n \n
\n \n \n
\n
\n \n
\n
\n
',i=class extends this.OS.application.BaseApplication{constructor(t){super("Docify",t)}main(){return this.setting.printer||(this.setting.printer=""),this.catview=this.find("catview"),this.docview=this.find("docview"),this.docpreview=this.find("preview-canvas"),this.docgrid=this.find("docgrid"),this.docgrid.header=[{text:"",width:100},{text:""}],this.find("btdld").onbtclick=t=>{var e;if(e=this.docview.selectedItem)return e.data.file.asFileHandle().download().catch(t=>this.error(__("Unable to download: {}",t.toString()),t))},this.find("btopen").onbtclick=t=>{var e;if(e=this.docview.selectedItem)return e.data.file.asFileHandle().meta().then(t=>t.error?this.error(t.error):this._gui.openWith(t.result)).catch(t=>this.error(t.toString(),t))},this.find("btprint").onbtclick=t=>{var e;if(e=this.docview.selectedItem)return this.openDialog(new n,{}).then(t=>{if(t)return t.file=e.data.file,this.exec("printdoc",t).then(t=>t.error?this.error(t.error):this.notify(t.result)).catch(t=>this.error(__("Unable to insert category: {0}",t.toString()),t))})},this.catview.buttons=[{text:"",iconclass:"fa fa-plus-circle",onbtclick:t=>this.openDialog("PromptDialog",{title:__("Category"),label:__("Name")}).then(t=>this.exec("insert",{table:"categories",data:{name:t}}).then(t=>t.error?this.error(t.error):this.cat_refresh()).catch(t=>this.error(__("Unable to insert category: {0}",t.toString()),t))).catch(t=>this.error(t.toString(),t))},{text:"",iconclass:"fa fa-minus-circle",onbtclick:t=>{var e;if(e=this.catview.selectedItem)return this.ask({text:__("Do you realy want to delete: `{0}`",e.data.text)}).then(t=>{if(t)return this.exec("delete",{table:"categories",id:parseInt(e.data.id)}).then(t=>t.error?this.error(t.error):this.cat_refresh()).catch(t=>this.error(__("Unable delete category: {0}",t.toString()),t))})}},{text:"",iconclass:"fa fa-pencil-square-o",onbtclick:t=>{var e;if(e=this.catview.selectedItem)return this.openDialog("PromptDialog",{title:__("Category"),label:__("Name"),value:e.data.name}).then(t=>this.exec("update",{table:"categories",data:{id:parseInt(e.data.id),name:t}}).then(t=>t.error?this.error(t.error):this.cat_refresh()).catch(t=>this.error(__("Unable to update category: {0}",t.toString()),t))).catch(t=>this.error(t.toString(),t))}}],this.docview.onlistselect=t=>{var e;if(this.clear_preview(),e=t.data.item)return this.exec("get_doc",e.data.id).then(t=>{var e,i,a,r,n,s;if(t.error)return this.error(t.error);for(i in this.preview(t.result.file,this.docpreview),n=[],t.result.fileinfo&&(t.result.size=(t.result.fileinfo.size/1024).toFixed(2)+" Kb"),a={ctime:"Created on",mtime:"Modified on",note:"Note",tags:"Tags",name:"Title",owner:"Owner",edate:"Effective date",file:"File",size:"Size"},t.result.edate=`${t.result.day}/${t.result.month}/${t.result.year}`,r=t.result)s=r[i],(e=a[i])&&n.push([{text:e},{text:s}]);return this.docgrid.rows=n}).catch(t=>this.error(t.toString(),t))},this.catview.onlistselect=t=>{var e;if(this.clear_preview(),e=t.data.item)return this.update_doclist(e.data.id)},this.find("bt-add-doc").onbtclick=e=>{var i;return(i=this.catview.selectedItem)?this.openDialog(new t).then(t=>(t.cid=parseInt(i.data.id),this.exec("insertdoc",t).then(t=>t.error?this.error(t.error):(t.result&&this.notify(t.result),this.update_doclist(i.data.id),this.clear_preview())).catch(t=>this.error(t.toString(),t)))):this.notify(__("Please select a category"))},this.find("bt-del-doc").onbtclick=t=>{var e;if(e=this.docview.selectedItem)return this.ask({text:__("Do you really want to delete: `{0}`",e.data.name)}).then(t=>{if(t)return this.exec("deletedoc",{id:e.data.id,file:e.data.file}).then(t=>t.error?this.error(t.error):(this.notify(t.result),this.update_doclist(e.data.cid),this.clear_preview())).catch(t=>this.error(t.toString(),t))})},this.find("bt-upload-doc").onbtclick=t=>(this.setting.docpath+"/unclassified").asFileHandle().upload().then(t=>this.notify(__("File uploaded"))).catch(t=>this.error(t.toString(),t)),this.find("bt-edit-doc").onbtclick=e=>{var i,a;if(a=this.docview.selectedItem,i=this.catview.selectedItem,a)return this.openDialog(new t,a.data).then(t=>(t.cid=parseInt(i.data.id),t.id=a.data.id,this.exec("updatedoc",{data:t,rm:!t.file.includes(a.data.file)&&a.data.file}).then(t=>t.error?this.error(t.error):(t.result&&this.notify(t.result),this.update_doclist(i.data.id),this.clear_preview())).catch(t=>this.error(t.toString(),t))))},this.initialize()}update_doclist(t){return this.exec("select",{table:"docs",cond:`cid = ${t} ORDER BY year DESC, month DESC, day DESC`}).then(t=>{var e,i,a,r;if(t.error)return this.error(t.error);for(e=0,i=(a=t.result).length;ethis.error(t.toString(),t))}clear_preview(){return this.docpreview.getContext("2d").clearRect(0,0,this.docpreview.width,this.docpreview.height),this.docgrid.rows=[]}preview(t,e){return this.exec("preview",t).then(t=>{var i;return t.error?this.error(t.error):(i=t.result.asFileHandle()).read("binary").then(t=>{var a,r;return(r=new Image).onload=()=>{var t;return t=e.getContext("2d"),e.height=r.height,e.width=r.width,t.drawImage(r,0,0)},a=new Blob([t],{type:i.info.mime}),r.src=URL.createObjectURL(a)}).catch(t=>this.error(t.toString(),t))}).catch(t=>this.error(t.toString(),t))}cat_refresh(){return this.docview.data=[],this.clear_preview(),this.exec("fetch","categories").then(t=>{var e,i,a,r;for(e=0,i=(a=t.result).length;ethis.error(__("Unable to fetch categories: {0}",t.toString()),t))}initialize(){return this.setting.docpath?this.initdb():this.openDialog("FileDialog",{title:__("Please select a doc path"),mimes:["dir"]}).then(t=>(this.setting.docpath=t.file.path,this._api.setting(),this.initdb())).catch(t=>this.error(t.toString(),t))}exec(t,e){var i;return i={path:this.path()+"/api.lua",parameters:{action:t,docpath:this.setting.docpath,args:e}},this.call(i)}initdb(){return this.setting.docpath?this.exec("init").then(t=>t.error?this.error(t.error):(this.notify(t.result),this.cat_refresh())).catch(t=>this.error(__("Unable to init database: {0}",t.toString()),t)):this.error(__("No configured docpath"))}menu(){return[{text:"__(Options)",nodes:[{text:"__(Owners)",id:"owners"},{text:"__(Preview)",id:"preview"},{text:"__(Change doc path)",id:"setdocp"},{text:"__(Set default printer)",id:"setprinter"}],onchildselect:t=>this.fileMenuHandle(t.data.item.data.id)}]}fileMenuHandle(t){switch(t){case"owners":return this.openDialog(new r,{title:__("Owners")});case"preview":return this.openDialog(new a).then(t=>this.notify(t.path));case"setdocp":return this.setting.docpath=void 0,this.initialize();case"setprinter":return this.openDialog("PromptDialog",{title:__("Default Printer"),label:__("Enter printer name")}).then(t=>this.setting.printer=t)}}},this.OS.register("Docify",i)}).call(this); \ No newline at end of file +var OS;!function(t){let e;!function(e){let i;!function(e){class i extends t.GUI.BasicDialog{constructor(){super("OwnerDialog",i.scheme)}main(){if(super.main(),this.oview=this.find("ownview"),!this.data.dbhandle)throw new Error(__("Unable to get owner data handle").__());return this.oview.buttons=[{text:"",iconclass:"fa fa-plus-circle",onbtclick:async t=>{try{const t=await this.openDialog("PromptDialog",{title:__("Owner"),label:__("Name")});this.data.dbhandle.cache={name:t};const e=await this.data.dbhandle.write(void 0);if(e.error)throw new Error(e.error);await this.owner_refresh()}catch(t){this.error(t.toString(),t)}}},{text:"",iconclass:"fa fa-minus-circle",onbtclick:async t=>{try{const t=this.oview.selectedItem;if(!t)return;if(!await this.ask({text:__("Do you realy want to delete: `{0}`",t.data.text)}))return;const e=t.data.$vfs;let i=await e.remove();if(i.error)throw new Error(i.error.toString());await this.owner_refresh()}catch(t){this.error(t.toString(),t)}}},{text:"",iconclass:"fa fa-pencil-square-o",onbtclick:async t=>{try{const t=this.oview.selectedItem;if(!t)return;const e=await this.openDialog("PromptDialog",{title:__("Owner"),label:__("Name"),value:t.data.name}),i=t.data.$vfs;i.cache={name:e};const a=await i.write(void 0);if(a.error)throw new Error(a.error.toString());await this.owner_refresh()}catch(t){this.error(t.toString(),t)}}}],this.owner_refresh()}async owner_refresh(){const t=await this.data.dbhandle.read();for(let e of t)e.text=e.name;this.oview.data=t}}e.OwnerDialog=i,i.scheme="\n \n \n \n ";class a extends t.GUI.BasicDialog{constructor(){super("DocDialog",a.scheme)}main(){let t;super.main(),this.flist=this.find("file-list"),this.dlist=this.find("dlist"),this.mlist=this.find("mlist"),this.ylist=this.find("ylist"),this.olist=this.find("olist");const e=this.parent;`sqlite://${e.setting.docpath.asFileHandle().genealogy.join("/")}/docify.db@owners`.asFileHandle().read().then(t=>{if(t.error)return this.error(t.error);for(let e of t)e.text=e.name,e.selected=this.data&&this.data.oid===e.id;return this.olist.data=t,this.olist.selectedItem?void 0:this.olist.selected=0}).catch(t=>this.error(__("Unable to fetch owner list: {0}",t.toString()),t)),this.dlist.push({text:"None",value:0});let i=0;for(t=1;t<=31;t++)this.dlist.push({text:""+t,value:t}),this.data&&parseInt(this.data.day)===t&&(i=t);for(this.dlist.selected=i,this.mlist.push({text:"None",value:0}),i=0,t=1;t<=12;t++)this.mlist.push({text:""+t,value:t}),this.data&&parseInt(this.data.month)===t&&(i=t);this.mlist.selected=i,this.ylist.push({text:"None",value:0}),this.ylist.selected=0;for(let t=1960,e=(new Date).getFullYear(),i=1960<=e;i?t<=e:t>=e;i?t++:t--)this.ylist.push({text:""+t,value:t,selected:this.data&&parseInt(this.data.year)===t});if(this.flist.buttons=[{text:"",iconclass:"fa fa-plus-circle",onbtclick:t=>this.openDialog(new r,{app:e}).then(t=>(t.text=t.filename,this.flist.push(t)))},{text:"",iconclass:"fa fa-minus-circle",onbtclick:t=>{const e=this.flist.selectedItem;if(e)return this.flist.delete(e)}}],this.flist.onlistselect=async t=>await e.preview(t.data.item.data.path,this.find("preview-canvas")),this.find("btsave").onbtclick=t=>{const e={name:this.find("title").value.trim(),day:this.dlist.selectedItem.data.value,month:this.mlist.selectedItem.data.value,year:this.ylist.selectedItem.data.value,file:Array.from(this.flist.data).map(t=>t.path),note:this.find("note").value.trim(),tags:this.find("tag").value.trim(),oid:parseInt(this.olist.selectedItem.data.id)};return e.name&&""!==e.title?e.file.length>0?(this.handle&&this.handle(e),this.quit()):this.notify(__("Please attach files to the entry")):this.notify(__("Please enter title"))},!this.data)return;this.find("title").value=this.data.name,this.find("note").value=this.data.note,this.find("tag").value=this.data.tags;const a=this.data.file.asFileHandle();return a.text=a.filename,this.flist.data=[a]}}e.DocDialog=a,a.scheme='\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n
\n \n
\n
\n
\n
';class r extends t.GUI.BasicDialog{constructor(){super("FilePreviewDialog",r.scheme)}main(){super.main(),this.flist=this.find("file-list"),this.flist.buttons=[{text:"",iconclass:"fa fa-refresh",onbtclick:t=>this.refresh()}];const t=this.data.app;return this.flist.onlistselect=async e=>await t.preview(e.data.item.data.path,this.find("preview-canvas")),this.find("btok").onbtclick=t=>{const e=this.flist.selectedItem;return e?(this.handle&&this.handle(e.data),this.quit()):this.quit()},this.refresh()}async refresh(){try{const t=this.data.app,e=await(t.setting.docpath+"/unclassified").asFileHandle().read();if(e.error)return this.error(e.error);for(let t of e.result)t.text=t.filename;return this.flist.data=e.result.filter(t=>"."!==t.filename[0])}catch(t){return this.error(__("Unable to fetch unclassified file list: {0}",t.toString()),t)}}}e.FilePreviewDialog=r,r.scheme='\n \n \n \n \n \n \n
\n \n
\n
\n \n
\n \n
\n
\n
'}(i=e.docify||(e.docify={}))}(e=t.application||(t.application={}))}(OS||(OS={})),function(t){let e;!function(t){class e extends t.BaseApplication{constructor(t){super("Docify",t)}async init_db(){try{if(!this.setting.docpath)return this.error(__("No configured docpath"));const t=this.setting.docpath.asFileHandle();this.dbhandle=`sqlite://${t.genealogy.join("/")}/docify.db`.asFileHandle();const e=await this.dbhandle.read();await(""+this.setting.docpath).asFileHandle().mk("unclassified"),await(""+this.setting.docpath).asFileHandle().mk("cache");let i=void 0;if(this.catdb=(this.dbhandle.path+"@categories").asFileHandle(),!e.categories){if(this.dbhandle.cache={name:"TEXT"},i=await this.dbhandle.write("categories"),i.error)throw new Error(i.error);if(this.catdb.cache={name:"Uncategoried"},i=await this.catdb.write(void 0),i.error)throw new Error(i.error)}if(this.ownerdb=(this.dbhandle.path+"@owners").asFileHandle(),!e.owners){if(this.dbhandle.cache={name:"TEXT"},i=await this.dbhandle.write("owners"),i.error)throw new Error(i.error);if(this.ownerdb.cache={name:"None"},i=await this.ownerdb.write(void 0),i.error)throw new Error(i.error)}if(this.docdb=(this.dbhandle.path+"@docs").asFileHandle(),!e.docs&&(this.dbhandle.cache={name:"TEXT NOT NULL",ctime:"INTEGER",day:"INTEGER",month:"INTEGER",year:"INTEGER",cid:"INTEGER DEFAULT 0",oid:"INTEGER DEFAULT 0",file:"TEXT NOT NULL",tags:"TEXT",note:"TEXT",mtime:"INTEGER"},i=await this.dbhandle.write("docs"),i.error))throw new Error(i.error);return await this.cat_refresh()}catch(t){this.error(__("Unable to init database file: {0}",t.toString()),t),this.dbhandle=void 0}}main(){return this.setting.printer||(this.setting.printer=""),this.catview=this.find("catview"),this.docview=this.find("docview"),this.docpreview=this.find("preview-canvas"),this.docgrid=this.find("docgrid"),this.docgrid.header=[{text:"",width:100},{text:""}],this.find("btdld").onbtclick=async t=>{try{const t=this.docview.selectedItem;if(!t)return;await t.data.file.asFileHandle().download()}catch(t){this.error(__("Unable to download: {0}",t.toString()),t)}},this.find("btopen").onbtclick=async t=>{try{const t=this.docview.selectedItem;if(!t)return;const e=await t.data.file.asFileHandle().meta();if(e.error)throw new Error(e.error);return this._gui.openWith(e.result)}catch(t){this.error(__("Unable to open file: {0}",t.toString()),t)}},this.catview.buttons=[{text:"",iconclass:"fa fa-plus-circle",onbtclick:async t=>{try{const t=await this.openDialog("PromptDialog",{title:__("Category"),label:__("Name")});this.catdb.cache={name:t};const e=await this.catdb.write(void 0);if(e.error)throw new Error(e.error.toString());return await this.cat_refresh()}catch(t){this.error(__("Unable to insert category: {0}",t.toString()),t)}}},{text:"",iconclass:"fa fa-minus-circle",onbtclick:async t=>{try{const t=this.catview.selectedItem;if(!t)return;if(!await this.ask({text:__("Do you realy want to delete: `{0}`",t.data.text)}))return;const e=await this.catdb.remove({where:{id:t.data.id}});if(e.error)throw new Error(e.error.toString());await this.cat_refresh()}catch(t){this.error(__("Unable delete category: {0}",t.toString()),t)}}},{text:"",iconclass:"fa fa-pencil-square-o",onbtclick:async t=>{try{const t=this.catview.selectedItem;if(!t)return;const e=t.data;if(!e)return;const i=await this.openDialog("PromptDialog",{title:__("Category"),label:__("Name"),value:t.data.name}),a=e.$vfs;a.cache={id:parseInt(t.data.id),name:i};const r=await a.write(void 0);if(r.error)throw new Error(r.error.toString());await this.cat_refresh()}catch(t){this.error(__("Unable to update category: {0}",t.toString()),t)}}}],this.docview.onlistselect=async t=>{try{this.clear_preview();const e=t.data.item;if(!e)return;const i=e.data.$vfs,a=await i.read();await this.preview(a.file,this.docpreview);const r=[],s={ctime:"Created on",mtime:"Modified on",note:"Note",tags:"Tags",name:"Title",owner:"Owner",edate:"Effective date",file:"File",size:"Size"};a.edate=`${a.day}/${a.month}/${a.year}`;for(let t in a){let e=a[t];const i=s[t];"ctime"!==t&&"mtime"!=t||(e=new Date(1e3*e).toDateString()),i&&r.push([{text:i},{text:e}])}return this.docgrid.rows=r}catch(t){this.error(__("Unable to fetch document detail: {0}",t.toString()),t)}},this.catview.onlistselect=t=>{this.clear_preview();const e=t.data.item;if(e)return this.update_doclist(e.data.id)},this.find("bt-add-doc").onbtclick=async e=>{try{const e=this.catview.selectedItem;if(!e)return this.notify(__("Please select a category"));const i=await this.openDialog(new t.docify.DocDialog);i.cid=parseInt(e.data.id);const a=Math.floor(Date.now()/1e3);i.ctime=a,i.mtime=a;const r=await this.exec("merge_files",i);if(r.error)throw new Error(r.error.toString());i.file=r.result,this.docdb.cache=i;const s=await this.docdb.write(void 0);if(s.error)throw new Error(s.error.toString());s.result&&this.toast(s.result),this.update_doclist(e.data.id),this.clear_preview()}catch(t){this.error(__("Unable to add document: {0}",t.toString()),t)}},this.find("bt-del-doc").onbtclick=async t=>{try{const t=this.docview.selectedItem;if(!t)return;if(!await this.ask({text:__("Do you really want to delete: `{0}`",t.data.name)}))return;let e=await this.docdb.remove({where:{id:t.data.id}});if(e.error)throw new Error(e.error.toString());if(e=await this.exec("deletedoc",{file:t.data.file}),e.error)throw new Error(e.error.toString());return this.notify(e.result.toString()),this.update_doclist(t.data.cid),this.clear_preview()}catch(t){this.error(__("Unable to delete document: {0}",t.tostring()),t)}},this.find("bt-upload-doc").onbtclick=async t=>{try{await(this.setting.docpath+"/unclassified").asFileHandle().upload(),this.toast(__("File uploaded"))}catch(t){this.error(__("Unable to upload document: {0}",t.toString()),t)}},this.find("bt-edit-doc").onbtclick=async e=>{try{const e=this.docview.selectedItem,i=this.catview.selectedItem;if(!e)return;const a=await this.openDialog(new t.docify.DocDialog,e.data);a.cid=parseInt(i.data.id),a.id=e.data.id;const r=Math.floor(Date.now()/1e3);a.mtime=r;let s=await this.exec("updatedoc",{data:a,rm:!a.file.includes(e.data.file)&&e.data.file});if(s.error)throw new Error(s.error);const n=e.data.$vfs;if(n.cache=s.result,s=await n.write(void 0),s.error)throw new Error(s.error);return s.result&&this.toast(s.result),this.update_doclist(i.data.id),this.clear_preview()}catch(t){this.error(__("Unable to edit document metadata: {0}",t.toString()))}},this.initialize()}async update_doclist(t){try{const e=await this.docdb.read({where:{cid:t},order:["year$desc","month$desc","day$desc"]});if(e.error)throw new Error(e.error);for(let t of e)t.text=t.name;return this.docview.data=e}catch(t){this.error(__("Unable to update document list: {0}",t.toString()),t)}}clear_preview(){return this.docpreview.getContext("2d").clearRect(0,0,this.docpreview.width,this.docpreview.height),this.docgrid.rows=[]}async preview(t,e){try{const i=await this.exec("preview",t);if(i.error)throw new Error(i.error);const a=i.result.asFileHandle(),r=await a.read("binary"),s=new Image;s.onload=()=>{const t=e.getContext("2d");return e.height=s.height,e.width=s.width,t.drawImage(s,0,0)};const n=new Blob([r],{type:a.info.mime});return s.src=URL.createObjectURL(n)}catch(t){this.error(__("Unable to generate document thumbnail: {0}",t.toString()),t)}}cat_refresh(){return new Promise(async(t,e)=>{try{this.docview.data=[],this.clear_preview();const t=await this.catdb.read();for(let e of t)e.text=e.name;return this.catview.data=t}catch(t){e(__e(t))}})}async initialize(){try{if(this.setting.docpath)return await this.init_db();{const t=await this.openDialog("FileDialog",{title:__("Please select a doc path"),type:"dir"});return this.setting.docpath=t.file.path,await this.init_db()}}catch(t){this.error(__("Error initialize database: {0}",t.toString()),t)}}exec(t,e){const i={path:this.path()+"/api.lua",parameters:{action:t,docpath:this.setting.docpath,args:e}};return this.call(i)}menu(){return[{text:"__(Options)",nodes:[{text:"__(Owners)",id:"owners"},{text:"__(Preview)",id:"preview"},{text:"__(Change doc path)",id:"setdocp"}],onchildselect:t=>this.fileMenuHandle(t.data.item.data.id)}]}fileMenuHandle(e){switch(e){case"owners":return this.openDialog(new t.docify.OwnerDialog,{title:__("Owners"),dbhandle:this.ownerdb});case"preview":return this.openDialog(new t.docify.FilePreviewDialog,{app:this}).then(t=>this.notify(t.path));case"setdocp":return this.setting.docpath=void 0,this.initialize()}}}t.Docify=e,e.dependencies=["pkg://SQLiteDB/libsqlite.js"]}(e=t.application||(t.application={}))}(OS||(OS={})); \ No newline at end of file diff --git a/Docify/build/debug/package.json b/Docify/build/debug/package.json index a237c69..3f09d19 100644 --- a/Docify/build/debug/package.json +++ b/Docify/build/debug/package.json @@ -1,15 +1,68 @@ { "pkgname": "Docify", - "app":"Docify", - "name":"Docify", - "description":"Docify", - "info":{ - "author": "", - "email": "" + "app": "Docify", + "name": "Docify", + "description": "Simple document manager", + "info": { + "author": "Dany LE", + "email": "mrsang@iohub.dev" }, - "version":"0.0.9-b", - "category":"Office", - "iconclass":"bi bi-collection-fill", - "mimes":["none"], - "locale": {} + "version": "0.1.0-b", + "category": "Office", + "iconclass": "bi bi-collection-fill", + "mimes": [ + "none" + ], + "dependencies": [ + "SQLiteDB@0.1.0-a" + ], + "locale": {}, + "locales": { + "en_GB": { + "title": "title", + "Day": "Day", + "Month": "Month", + "Year": "Year", + "Files": "Files", + "Note": "Note", + "Owner": "Owner", + "Tags": "Tags", + "Save": "Save", + "Document preview": "Document preview", + "Ok": "Ok", + "Unable to get owner data handle": "Unable to get owner data handle", + "Name": "Name", + "Do you realy want to delete: `{0}`": "Do you realy want to delete: `{0}`", + "Unable to fetch owner list: {0}": "Unable to fetch owner list: {0}", + "Please enter title": "Please enter title", + "Please attach files to the entry": "Please attach files to the entry", + "Unable to fetch unclassified file list: {0}": "Unable to fetch unclassified file list: {0}", + "Options": "Options", + "Owners": "Owners", + "Preview": "Preview", + "Change doc path": "Change doc path", + "No configured docpath": "No configured docpath", + "Unable to init database file: {0}": "Unable to init database file: {0}", + "Unable to download: {0}": "Unable to download: {0}", + "Unable to open file: {0}": "Unable to open file: {0}", + "Category": "Category", + "Unable to insert category: {0}": "Unable to insert category: {0}", + "Unable delete category: {0}": "Unable delete category: {0}", + "Unable to update category: {0}": "Unable to update category: {0}", + "Unable to fetch document detail: {0}": "Unable to fetch document detail: {0}", + "Please select a category": "Please select a category", + "Unable to add document: {0}": "Unable to add document: {0}", + "Do you really want to delete: `{0}`": "Do you really want to delete: `{0}`", + "Unable to delete document: {0}": "Unable to delete document: {0}", + "File uploaded": "File uploaded", + "Unable to upload document: {0}": "Unable to upload document: {0}", + "Unable to edit document metadata: {0}": "Unable to edit document metadata: {0}", + "Unable to update document list: {0}": "Unable to update document list: {0}", + "Unable to generate document thumbnail: {0}": "Unable to generate document thumbnail: {0}", + "Please select a doc path": "Please select a doc path", + "Error initialize database: {0}": "Error initialize database: {0}", + "Categories": "Categories", + "Documents": "Documents" + } + } } \ No newline at end of file diff --git a/Docify/build/debug/scheme.html b/Docify/build/debug/scheme.html index 6b98f30..f3e98cd 100644 --- a/Docify/build/debug/scheme.html +++ b/Docify/build/debug/scheme.html @@ -25,7 +25,6 @@
-
diff --git a/Docify/build/release/Docify.zip b/Docify/build/release/Docify.zip index 5b3f32a736bcfa88f4dbe50083d5048ad7ab25d4..d47517edb9ef77545d64b643608db8d96cfc43ca 100644 GIT binary patch literal 7399 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 literal 8189 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 i{wV - super "OwnerDialog", OwnerDialog.scheme - - main: () -> - super.main() - @oview = @find("ownview") - @oview.buttons = [ - { - text: "", - iconclass: "fa fa-plus-circle", - onbtclick: (e) => - @openDialog("PromptDialog", { title: __("Owner"), label: __("Name")}) - .then (d) => - @parent.exec("insert", { table: "owners", data: { name: d } }) - .then (r) => - return @error r.error if r.error - @owner_refresh() - .catch (e) => @error __("Unable to insert owner: {0}", e.toString()),e - .catch (e) => @error e.toString(),e - }, - { - text: "", - iconclass: "fa fa-minus-circle", - onbtclick: (e) => - item = @oview.selectedItem - return unless item - @ask({ text:__("Do you realy want to delete: `{0}`", item.data.text)}) - .then (d) => - return unless d - @parent.exec("delete", {table:"owners", id: parseInt(item.data.id)}) - .then (d) => - return @error d.error if d.error - @owner_refresh() - .catch (e) => - @error __("Unable delete category: {0}", e.toString()), e - }, - { - text: "", - iconclass: "fa fa-pencil-square-o", - onbtclick: (e) => - item = @oview.selectedItem - return unless item - @openDialog("PromptDialog", { title: __("Owner"), label: __("Name"), value: item.data.name }) - .then (d) => - @parent.exec("update", { table: "owners", data: { id: parseInt(item.data.id), name: d } }) - .then (r) => - return @error r.error if r.error - @owner_refresh() - .catch (e) => @error __("Unable to update owner: {0}", e.toString()), e - .catch (e) => @error e.toString() - } - ] - @owner_refresh() - - owner_refresh: () -> - @parent.exec("fetch", "owners") - .then (d) => - v.text = v.name for v in d.result - @oview.data = d.result - .catch (err) => @error __("Unable to fetch owners: {0}", err.toString()), e - -OwnerDialog.scheme = """ - - - - - -""" - -class DocDialog extends this.OS.GUI.BasicDialog - constructor: () -> - super "DocDialog", DocDialog.scheme - - main: () -> - super.main() - @flist = @find("file-list") - @dlist = @find("dlist") - @mlist = @find("mlist") - @ylist = @find("ylist") - @olist = @find("olist") - - @setting = @parent.setting - @exec = @parent.exec - @preview = @parent.preview - - @exec("fetch", "owners") - .then (d) => - return @error d.error if d.error - v.text = v.name for v in d.result - v.selected = (@data and @data.oid is v.id) for v in d.result - @olist.data = d.result - @olist.selected = 0 if not @olist.selectedItem - .catch (e) => - @error __("Unable to fetch owner list: {0}", e.toString()), e - - @dlist.push { - text:"None", - value: 0 - } - selected = 0 - for d in [1..31] - @dlist.push { - text:"#{d}", - value: d - } - selected = d if @data and parseInt(@data.day) is d - @dlist.selected = selected - - @mlist.push { - text:"None", - value: 0 - } - selected = 0 - for d in [1..12] - @mlist.push { - text:"#{d}", - value: d - } - selected = d if @data and parseInt(@data.month) is d - @mlist.selected = selected - - @ylist.push { - text:"None", - value: 0 - } - @ylist.selected = 0 - for y in [1960..new Date().getFullYear()] - @ylist.push { - text:"#{y}", - value: y, - selected: @data and parseInt(@data.year) is y - } - - @flist.buttons = [ - { - text: "", - iconclass: "fa fa-plus-circle", - onbtclick: (e) => - @openDialog(new FilePreviewDialog()) - .then (d) => - d.text = d.filename - @flist.push d - }, - { - text: "", - iconclass: "fa fa-minus-circle", - onbtclick: (e) => - item = @flist.selectedItem - return unless item - @flist.delete item - } - ] - @flist.onlistselect = (e) => - @parent.preview(e.data.item.data.path, @find("preview-canvas")) - - @find("btsave").onbtclick = (e) => - data = { - name: @find("title").value.trim(), - day: @dlist.selectedItem.data.value, - month: @mlist.selectedItem.data.value, - year: @ylist.selectedItem.data.value, - file: (v.path for v in @flist.data), - note: @find("note").value.trim(), - tags: @find("tag").value.trim(), - oid: parseInt(@olist.selectedItem.data.id) - } - return @notify __("Please enter title") unless data.name and data.title != "" - return @notify __("Please attach files to the entry") unless data.file.length > 0 - - @handle data if @handle - @quit() - - return unless @data - @find("title").value = @data.name - @find("note").value = @data.note - @find("tag").value = @data.tags - file = @data.file.asFileHandle() - file.text = file.filename - @flist.data = [ file ] - # owner - - -DocDialog.scheme = """ - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
-
- -
-
-
-
-""" - -class FilePreviewDialog extends this.OS.GUI.BasicDialog - constructor: () -> - super "FilePreviewDialog", FilePreviewDialog.scheme - - main: () -> - super.main() - @flist = @find("file-list") - @flist.buttons = [ - { - text: "", - iconclass: "fa fa-refresh", - onbtclick: (e) => @refresh() - } - ] - - @flist.onlistselect = (e) => - # console.log e.data.item.data - @parent.preview(e.data.item.data.path, @find("preview-canvas")) - @find("btok").onbtclick = (e) => - item = @flist.selectedItem - return @quit() unless item - @handle(item.data) if @handle - @quit() - - @refresh() - - refresh: () -> - "#{@parent.setting.docpath}/unclassified".asFileHandle().read() - .then (d) => - return @error d.error if d.error - v.text = v.filename for v in d.result - @flist.data = (v for v in d.result when v.filename[0] isnt '.') - .catch (e) => - @error __("Unable to fetch unclassified file list: {0}", e.toString()), e - -FilePreviewDialog.scheme = """ - - - - - - - -
- -
-
- -
- -
-
-
-""" - -class PrintDialog extends this.OS.GUI.BasicDialog - constructor: () -> - super "PrintDialog", PrintDialog.scheme - - main: () -> - super.main() - @find("printerName").value = @parent.setting.printer - @find("btnprint").onbtclick = (e) => - data = {} - data.range = parseInt($('input[name=range]:checked', @scheme).val()) - data.pages = @find("txtPageRange").value - data.printer = @find("printerName").value - data.orientation = parseInt($('input[name=orientation]:checked', @scheme).val()) - data.side = parseInt($('input[name=side]:checked', @scheme).val()) - @handle data if @handle - @quit() - -PrintDialog.scheme = """ - - - - - -
- -
- - - -
- -
- -
- - -
- -
- -
- -
- - -
-
- -
-
-
-""" \ No newline at end of file diff --git a/Docify/coffees/main.coffee b/Docify/coffees/main.coffee deleted file mode 100644 index f4de028..0000000 --- a/Docify/coffees/main.coffee +++ /dev/null @@ -1,290 +0,0 @@ -class Docify extends this.OS.application.BaseApplication - constructor: ( args ) -> - super "Docify", args - - main: () -> - - @setting.printer = "" unless @setting.printer - - @catview = @find "catview" - @docview = @find "docview" - @docpreview = @find "preview-canvas" - @docgrid = @find "docgrid" - @docgrid.header = [ - { text: "", width: 100 }, - { text: "" }, - ] - @find("btdld").onbtclick = (e) => - item = @docview.selectedItem - return unless item - item.data.file.asFileHandle() - .download() - .catch (e) => @error __("Unable to download: {}", e.toString()), e - @find("btopen").onbtclick = (e) => - item = @docview.selectedItem - return unless item - item.data.file.asFileHandle().meta() - .then (m) => - return @error m.error if m.error - @_gui.openWith m.result - .catch (e) => @error e.toString(), e - @find("btprint").onbtclick = (e) => - item = @docview.selectedItem - return unless item - @openDialog new PrintDialog(), {} - .then (d) => - return unless d - d.file = item.data.file - @exec("printdoc", d) - .then (r) => - return @error r.error if r.error - @notify r.result - .catch (e) => @error __("Unable to insert category: {0}", e.toString()), e - @catview.buttons = [ - { - text: "", - iconclass: "fa fa-plus-circle", - onbtclick: (e) => - @openDialog("PromptDialog", { title: __("Category"), label: __("Name")}) - .then (d) => - @exec("insert", { table: "categories", data: { name: d } }) - .then (r) => - return @error r.error if r.error - @cat_refresh() - .catch (e) => @error __("Unable to insert category: {0}", e.toString()), e - .catch (e) => @error e.toString(), e - }, - { - text: "", - iconclass: "fa fa-minus-circle", - onbtclick: (e) => - item = @catview.selectedItem - return unless item - @ask({ text:__("Do you realy want to delete: `{0}`", item.data.text)}) - .then (d) => - return unless d - @exec("delete", {table:"categories", id: parseInt(item.data.id)}) - .then (d) => - return @error d.error if d.error - @cat_refresh() - .catch (e) => - @error __("Unable delete category: {0}", e.toString()), e - }, - { - text: "", - iconclass: "fa fa-pencil-square-o", - onbtclick: (e) => - item = @catview.selectedItem - return unless item - @openDialog("PromptDialog", { title: __("Category"), label: __("Name"), value: item.data.name }) - .then (d) => - @exec("update", { table: "categories", data: { id: parseInt(item.data.id), name: d } }) - .then (r) => - return @error r.error if r.error - @cat_refresh() - .catch (e) => @error __("Unable to update category: {0}", e.toString()), e - .catch (e) => @error e.toString(), e - } - ] - - @docview.onlistselect = (e) => - @clear_preview() - item = e.data.item - return unless item - @exec("get_doc", item.data.id) - .then (d) => - return @error d.error if d.error - @preview d.result.file, @docpreview - rows = [] - d.result.size = (d.result.fileinfo.size / 1024.0).toFixed(2) + " Kb" if d.result.fileinfo - map = { - ctime: "Created on", - mtime: "Modified on", - note: "Note", - tags: "Tags", - name: "Title", - owner: "Owner", - edate: "Effective date", - file: "File", - size: "Size" - } - d.result.edate = "#{d.result.day}/#{d.result.month}/#{d.result.year}" - for key, value of d.result - field = map[key] - rows.push [{text: field}, {text: value}] if field - @docgrid.rows = rows - .catch (e) => @error e.toString(), e - - @catview.onlistselect = (e) => - @clear_preview() - item = e.data.item - return unless item - @update_doclist(item.data.id) - - @find("bt-add-doc").onbtclick = (e) => - catiem = @catview.selectedItem - return @notify __("Please select a category") unless catiem - - @openDialog(new DocDialog()) - .then (data) => - data.cid = parseInt(catiem.data.id) - @exec("insertdoc", data) - .then (d) => - return @error d.error if d.error - @notify d.result if d.result - @update_doclist(catiem.data.id) - @clear_preview() - .catch (e) => @error e.toString(), e - - @find("bt-del-doc").onbtclick = (e) => - item = @docview.selectedItem - return unless item - @ask({ text: __("Do you really want to delete: `{0}`", item.data.name) }) - .then (d) => - return unless d - @exec("deletedoc", {id: item.data.id, file: item.data.file}) - .then (r) => - return @error r.error if r.error - @notify r.result - @update_doclist(item.data.cid) - @clear_preview() - .catch (e) => - @error e.toString(), e - @find("bt-upload-doc").onbtclick = (e) => - "#{@setting.docpath}/unclassified".asFileHandle().upload() - .then (r) => - @notify __("File uploaded") - .catch (e) => - @error e.toString(), e - @find("bt-edit-doc").onbtclick = (e) => - item = @docview.selectedItem - catiem = @catview.selectedItem - return unless item - @openDialog(new DocDialog(), item.data) - .then (data) => - data.cid = parseInt(catiem.data.id) - data.id = item.data.id - @exec("updatedoc", { - data:data, - rm: if not data.file.includes(item.data.file) then item.data.file else false - }) - .then (d) => - return @error d.error if d.error - @notify d.result if d.result - @update_doclist(catiem.data.id) - @clear_preview() - .catch (e) => @error e.toString(), e - - @initialize() - - update_doclist: (cid) -> - @exec("select",{table: "docs", cond:"cid = #{cid} ORDER BY year DESC, month DESC, day DESC"}) - .then (d) => - return @error d.error if d.error - v.text = v.name for v in d.result - @docview.data = d.result - .catch (e) => - @error e.toString(), e - - clear_preview: () -> - @docpreview.getContext('2d').clearRect(0,0,@docpreview.width,@docpreview.height) - @docgrid.rows = [] - - preview: (path, canvas) -> - @exec("preview", path) - .then (d) => - return @error d.error if d.error - file = d.result.asFileHandle() - file.read("binary") - .then (d) => - img = new Image() - #($ me.view).append img - img.onload = () => - context = canvas.getContext '2d' - canvas.height = img.height - canvas.width = img.width - #console.log canvas.width, canvas.height - context.drawImage img, 0, 0 - - blob = new Blob [d], { type: file.info.mime } - img.src = URL.createObjectURL blob - - .catch (e) => @error e.toString(), e - .catch (e) => - @error e.toString(), e - - cat_refresh: () -> - @docview.data = [] - @clear_preview() - @exec("fetch", "categories") - .then (d) => - v.text = v.name for v in d.result - @catview.data = d.result - .catch (err) => @error __("Unable to fetch categories: {0}", err.toString()), err - - initialize: () -> - # Check if we have configured docpath - if @setting.docpath - # check data base - @initdb() - else - # ask user to choose a docpath - @openDialog "FileDialog", { title:__("Please select a doc path"), mimes: ['dir'] } - .then (d) => - @setting.docpath = d.file.path - @_api.setting() - @initdb() - .catch (msg) => @error msg.toString(), msg - - exec: (action, args) -> - cmd = - path: "#{@path()}/api.lua", - parameters: - action: action, - docpath: @setting.docpath, - args: args - return @call(cmd) - - initdb: () -> - return @error __("No configured docpath") unless @setting.docpath - # fetch the categories from the database - @exec("init") - .then (d) => - return @error d.error if d.error - @notify d.result - # load categories - @cat_refresh() - .catch (e) => - @error __("Unable to init database: {0}", e.toString()), e - - menu: () -> - [ - { - text: "__(Options)", - nodes: [ - { text: "__(Owners)", id:"owners"}, - { text: "__(Preview)", id:"preview"}, - { text: "__(Change doc path)", id:"setdocp"}, - { text: "__(Set default printer)", id:"setprinter"} - ], - onchildselect: (e) => @fileMenuHandle e.data.item.data.id - } - ] - - fileMenuHandle:(id) -> - switch id - when "owners" - @openDialog new OwnerDialog(), { title: __("Owners")} - when "preview" - @openDialog(new FilePreviewDialog()) - .then (d) => - @notify d.path - when "setdocp" - @setting.docpath = undefined - @initialize() - when "setprinter" - @openDialog "PromptDialog", {title: __("Default Printer"), label: __("Enter printer name")} - .then (n) => - @setting.printer = n - -this.OS.register "Docify", Docify \ No newline at end of file diff --git a/Docify/package.json b/Docify/package.json index a237c69..3f09d19 100644 --- a/Docify/package.json +++ b/Docify/package.json @@ -1,15 +1,68 @@ { "pkgname": "Docify", - "app":"Docify", - "name":"Docify", - "description":"Docify", - "info":{ - "author": "", - "email": "" + "app": "Docify", + "name": "Docify", + "description": "Simple document manager", + "info": { + "author": "Dany LE", + "email": "mrsang@iohub.dev" }, - "version":"0.0.9-b", - "category":"Office", - "iconclass":"bi bi-collection-fill", - "mimes":["none"], - "locale": {} + "version": "0.1.0-b", + "category": "Office", + "iconclass": "bi bi-collection-fill", + "mimes": [ + "none" + ], + "dependencies": [ + "SQLiteDB@0.1.0-a" + ], + "locale": {}, + "locales": { + "en_GB": { + "title": "title", + "Day": "Day", + "Month": "Month", + "Year": "Year", + "Files": "Files", + "Note": "Note", + "Owner": "Owner", + "Tags": "Tags", + "Save": "Save", + "Document preview": "Document preview", + "Ok": "Ok", + "Unable to get owner data handle": "Unable to get owner data handle", + "Name": "Name", + "Do you realy want to delete: `{0}`": "Do you realy want to delete: `{0}`", + "Unable to fetch owner list: {0}": "Unable to fetch owner list: {0}", + "Please enter title": "Please enter title", + "Please attach files to the entry": "Please attach files to the entry", + "Unable to fetch unclassified file list: {0}": "Unable to fetch unclassified file list: {0}", + "Options": "Options", + "Owners": "Owners", + "Preview": "Preview", + "Change doc path": "Change doc path", + "No configured docpath": "No configured docpath", + "Unable to init database file: {0}": "Unable to init database file: {0}", + "Unable to download: {0}": "Unable to download: {0}", + "Unable to open file: {0}": "Unable to open file: {0}", + "Category": "Category", + "Unable to insert category: {0}": "Unable to insert category: {0}", + "Unable delete category: {0}": "Unable delete category: {0}", + "Unable to update category: {0}": "Unable to update category: {0}", + "Unable to fetch document detail: {0}": "Unable to fetch document detail: {0}", + "Please select a category": "Please select a category", + "Unable to add document: {0}": "Unable to add document: {0}", + "Do you really want to delete: `{0}`": "Do you really want to delete: `{0}`", + "Unable to delete document: {0}": "Unable to delete document: {0}", + "File uploaded": "File uploaded", + "Unable to upload document: {0}": "Unable to upload document: {0}", + "Unable to edit document metadata: {0}": "Unable to edit document metadata: {0}", + "Unable to update document list: {0}": "Unable to update document list: {0}", + "Unable to generate document thumbnail: {0}": "Unable to generate document thumbnail: {0}", + "Please select a doc path": "Please select a doc path", + "Error initialize database: {0}": "Error initialize database: {0}", + "Categories": "Categories", + "Documents": "Documents" + } + } } \ No newline at end of file diff --git a/Docify/project.json b/Docify/project.json deleted file mode 100644 index ec2e84e..0000000 --- a/Docify/project.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "Docify", - "css": ["css/main.css"], - "javascripts": [], - "coffees": ["coffees/dialogs.coffee", "coffees/main.coffee"], - "copies": ["assets/scheme.html", "api/api.lua", "package.json", "README.md"] -} \ No newline at end of file diff --git a/Docify/ts/dialogs.ts b/Docify/ts/dialogs.ts new file mode 100644 index 0000000..ed0b5ea --- /dev/null +++ b/Docify/ts/dialogs.ts @@ -0,0 +1,354 @@ +namespace OS { + export namespace application { + export namespace docify { + export class OwnerDialog extends OS.GUI.BasicDialog { + private oview: GUI.tag.ListViewTag; + constructor() { + super("OwnerDialog", OwnerDialog.scheme); + } + + main() { + super.main(); + this.oview = this.find("ownview") as GUI.tag.ListViewTag; + if(!this.data.dbhandle) + { + throw new Error(__("Unable to get owner data handle").__()); + } + + this.oview.buttons = [ + { + text: "", + iconclass: "fa fa-plus-circle", + onbtclick: async (e: any) => { + try + { + const d = await this.openDialog("PromptDialog", { + title: __("Owner"), + label: __("Name") + }); + this.data.dbhandle.cache = { name: d }; + const r = await this.data.dbhandle.write(undefined); + if(r.error) + { + throw new Error(r.error); + } + await this.owner_refresh(); + } + catch(e) + { + this.error(e.toString(), e); + } + } + }, + { + text: "", + iconclass: "fa fa-minus-circle", + onbtclick: async (e: any) => { + try{ + const item = this.oview.selectedItem; + if (!item) { return; } + let d = await this.ask({ text:__("Do you realy want to delete: `{0}`", item.data.text)}); + if (!d) { return; } + const handle = item.data.$vfs as API.VFS.BaseFileHandle; + let r = await handle.remove(); + if(r.error) + { + throw new Error(r.error.toString()); + } + await this.owner_refresh(); + } + catch(e) + { + this.error(e.toString(), e); + } + } + }, + { + text: "", + iconclass: "fa fa-pencil-square-o", + onbtclick: async (e: any) => { + try + { + const item = this.oview.selectedItem; + if (!item) { return; } + const d = await this.openDialog("PromptDialog", { + title: __("Owner"), + label: __("Name"), + value: item.data.name + }); + const handle = item.data.$vfs as API.VFS.BaseFileHandle; + handle.cache = { name: d }; + const r = await handle.write(undefined); + if(r.error) + { + throw new Error(r.error.toString()); + } + await this.owner_refresh(); + } + catch(e) + { + this.error(e.toString(), e); + } + } + } + ]; + return this.owner_refresh(); + } + + private async owner_refresh() { + + const d = await this.data.dbhandle.read(); + for (let v of d) { v.text = v.name; } + this.oview.data = d; + } + } + + OwnerDialog.scheme = `\ + + + + +\ + `; + + export class DocDialog extends OS.GUI.BasicDialog { + private flist: GUI.tag.ListViewTag; + private dlist: GUI.tag.ListViewTag; + private mlist: GUI.tag.ListViewTag; + private ylist: GUI.tag.ListViewTag; + private olist: GUI.tag.ListViewTag; + constructor() { + super("DocDialog", DocDialog.scheme); + } + + main() { + let d: number; + super.main(); + this.flist = this.find("file-list") as GUI.tag.ListViewTag; + this.dlist = this.find("dlist") as GUI.tag.ListViewTag; + this.mlist = this.find("mlist") as GUI.tag.ListViewTag; + this.ylist = this.find("ylist") as GUI.tag.ListViewTag; + this.olist = this.find("olist") as GUI.tag.ListViewTag; + const app = this.parent as Docify; + const target=app.setting.docpath.asFileHandle(); + const dbhandle=`sqlite://${target.genealogy.join("/")}/docify.db@owners`.asFileHandle(); + dbhandle.read() + .then((d) => { + if (d.error) { return this.error(d.error); } + for (let v of d) { + v.text = v.name; + v.selected = this.data && (this.data.oid === v.id); + } + this.olist.data = d; + if (!this.olist.selectedItem) { return this.olist.selected = 0; } + }).catch((e) => { + return this.error(__("Unable to fetch owner list: {0}", e.toString()), e); + }); + + this.dlist.push({ + text:"None", + value: 0 + }); + let selected = 0; + for (d = 1; d <= 31; d++) { + this.dlist.push({ + text:`${d}`, + value: d + }); + if (this.data && (parseInt(this.data.day) === d)) { selected = d; } + } + this.dlist.selected = selected; + + this.mlist.push({ + text:"None", + value: 0 + }); + selected = 0; + for (d = 1; d <= 12; d++) { + this.mlist.push({ + text:`${d}`, + value: d + }); + if (this.data && (parseInt(this.data.month) === d)) { selected = d; } + } + this.mlist.selected = selected; + + this.ylist.push({ + text:"None", + value: 0 + }); + this.ylist.selected = 0; + for (let y = 1960, end = new Date().getFullYear(), asc = 1960 <= end; asc ? y <= end : y >= end; asc ? y++ : y--) { + this.ylist.push({ + text:`${y}`, + value: y, + selected: this.data && (parseInt(this.data.year) === y) + }); + } + + this.flist.buttons = [ + { + text: "", + iconclass: "fa fa-plus-circle", + onbtclick: (e: any) => { + return this.openDialog(new FilePreviewDialog(), { + app: app + }) + .then((d: { text: any; filename: any; }) => { + d.text = d.filename; + return this.flist.push(d); + }); + } + }, + { + text: "", + iconclass: "fa fa-minus-circle", + onbtclick: (e: any) => { + const item = this.flist.selectedItem; + if (!item) { return; } + return this.flist.delete(item); + } + } + ]; + this.flist.onlistselect = async (e) => { + return await app.preview(e.data.item.data.path, this.find("preview-canvas") as HTMLCanvasElement); + }; + + (this.find("btsave") as GUI.tag.ButtonTag).onbtclick = (e: any) => { + const data: GenericObject = { + name: (this.find("title") as HTMLInputElement).value.trim(), + day: this.dlist.selectedItem.data.value, + month: this.mlist.selectedItem.data.value, + year: this.ylist.selectedItem.data.value, + file: (Array.from(this.flist.data).map((v: { path: any; }) => v.path)), + note: (this.find("note") as HTMLTextAreaElement).value.trim(), + tags: (this.find("tag") as HTMLInputElement).value.trim(), + oid: parseInt(this.olist.selectedItem.data.id) + }; + if (!data.name || (data.title === "")) { return this.notify(__("Please enter title")); } + if (!(data.file.length > 0)) { return this.notify(__("Please attach files to the entry")); } + + if (this.handle) { this.handle(data); } + return this.quit(); + }; + + if (!this.data) { return; } + (this.find("title") as HTMLInputElement).value = this.data.name; + (this.find("note") as HTMLTextAreaElement).value = this.data.note; + (this.find("tag") as HTMLInputElement).value = this.data.tags; + const file = this.data.file.asFileHandle(); + file.text = file.filename; + return this.flist.data = [ file ]; + } + } + + + DocDialog.scheme = `\ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+
+
+
\ + `; + + export class FilePreviewDialog extends OS.GUI.BasicDialog { + private flist: GUI.tag.ListViewTag; + constructor() { + super("FilePreviewDialog", FilePreviewDialog.scheme); + } + + main() { + super.main(); + this.flist = this.find("file-list") as GUI.tag.ListViewTag; + this.flist.buttons = [ + { + text: "", + iconclass: "fa fa-refresh", + onbtclick: (e: any) => this.refresh() + } + ]; + const app = this.data.app as Docify; + + this.flist.onlistselect = async (e) => { + // console.log e.data.item.data + return await app.preview(e.data.item.data.path, this.find("preview-canvas") as HTMLCanvasElement); + }; + (this.find("btok") as GUI.tag.ButtonTag).onbtclick = (e: any) => { + const item = this.flist.selectedItem; + if (!item) { return this.quit(); } + if (this.handle) { this.handle(item.data); } + return this.quit(); + }; + + return this.refresh(); + } + + async refresh() { + try + { + const app = this.data.app as Docify; + const d = await `${app.setting.docpath}/unclassified`.asFileHandle().read(); + if (d.error) { return this.error(d.error); } + for (let v of d.result) { v.text = v.filename; } + return this.flist.data = d.result.filter((e) => e.filename[0] !== '.'); + } + catch(e) + { + return this.error(__("Unable to fetch unclassified file list: {0}", e.toString()), e); + } + } + } + + FilePreviewDialog.scheme = `\ + + + + + + + +
+ +
+
+ +
+ +
+
+
\ + `; + } + } +} \ No newline at end of file diff --git a/Docify/ts/main.ts b/Docify/ts/main.ts new file mode 100644 index 0000000..d468020 --- /dev/null +++ b/Docify/ts/main.ts @@ -0,0 +1,543 @@ +namespace OS { + export namespace application { + + export class Docify extends BaseApplication { + private catview: GUI.tag.ListViewTag; + private docview: GUI.tag.ListViewTag; + private docpreview: HTMLCanvasElement; + private docgrid: GUI.tag.GridViewTag; + + private dbhandle: API.VFS.BaseFileHandle; + private catdb: API.VFS.BaseFileHandle; + private ownerdb: API.VFS.BaseFileHandle; + private docdb: API.VFS.BaseFileHandle; + + constructor( args: any ) { + super("Docify", args); + } + + private async init_db() { + try { + if (!this.setting.docpath) { return this.error(__("No configured docpath")); } + + const target=this.setting.docpath.asFileHandle(); + this.dbhandle=`sqlite://${target.genealogy.join("/")}/docify.db`.asFileHandle(); + const tables = await this.dbhandle.read(); + /** + * Init following tables if not exist: + * - categories + * - owners + * - docs + */ + await `${this.setting.docpath}`.asFileHandle().mk("unclassified"); + await `${this.setting.docpath}`.asFileHandle().mk("cache"); + let r = undefined; + this.catdb = `${this.dbhandle.path}@categories`.asFileHandle(); + if(!tables.categories) + { + this.dbhandle.cache = { + name: "TEXT" + } + r = await this.dbhandle.write("categories"); + if(r.error) + { + throw new Error(r.error as string); + } + this.catdb.cache = { + name: "Uncategoried" + }; + r = await this.catdb.write(undefined); + if(r.error) + { + throw new Error(r.error as string); + } + } + this.ownerdb = `${this.dbhandle.path}@owners`.asFileHandle(); + if(!tables.owners) + { + this.dbhandle.cache = { + name: "TEXT", + } + r = await this.dbhandle.write("owners"); + if(r.error) + { + throw new Error(r.error as string); + } + this.ownerdb.cache = { + name: "None" + }; + r = await this.ownerdb.write(undefined); + if(r.error) + { + throw new Error(r.error as string); + } + } + this.docdb = `${this.dbhandle.path}@docs`.asFileHandle(); + if(!tables.docs) + { + this.dbhandle.cache = { + name: "TEXT NOT NULL", + ctime: "INTEGER", + day: "INTEGER", + month: "INTEGER", + year: "INTEGER", + cid: "INTEGER DEFAULT 0", + oid: "INTEGER DEFAULT 0", + file: "TEXT NOT NULL", + tags: "TEXT", + note: "TEXT", + mtime: "INTEGER", + //'FOREIGN KEY("oid")': 'REFERENCES "owners"("id") ON DELETE SET DEFAULT ON UPDATE NO ACTION', + //'FOREIGN KEY("cid")': 'REFERENCES "categories"("id") ON DELETE SET DEFAULT ON UPDATE NO ACTION', + } + r = await this.dbhandle.write("docs"); + if(r.error) + { + throw new Error(r.error as string); + } + } + return await this.cat_refresh(); + + } + catch(e) { + this.error(__("Unable to init database file: {0}",e.toString()),e); + this.dbhandle = undefined; + } + } + + main() { + + if (!this.setting.printer) { this.setting.printer = ""; } + + this.catview = this.find("catview") as GUI.tag.ListViewTag; + this.docview = this.find("docview") as GUI.tag.ListViewTag; + this.docpreview = this.find("preview-canvas") as HTMLCanvasElement; + this.docgrid = this.find("docgrid") as GUI.tag.GridViewTag; + this.docgrid.header = [ + { text: "", width: 100 }, + { text: "" }, + ]; + (this.find("btdld") as GUI.tag.ButtonTag).onbtclick = async (e) => { + try { + const item = this.docview.selectedItem; + if (!item) { return; } + await item.data.file.asFileHandle().download(); + } + catch(e) + { + this.error(__("Unable to download: {0}", e.toString()), e); + } + }; + (this.find("btopen") as GUI.tag.ButtonTag).onbtclick = async (e) => { + try { + const item = this.docview.selectedItem; + if (!item) { return; } + const m = await item.data.file.asFileHandle().meta(); + if (m.error) + { + throw new Error(m.error); + } + return this._gui.openWith(m.result); + } + catch(e) + { + this.error(__("Unable to open file: {0}", e.toString()), e); + } + }; + this.catview.buttons = [ + { + text: "", + iconclass: "fa fa-plus-circle", + onbtclick:async (e) => { + try + { + const d = await this.openDialog("PromptDialog", { + title: __("Category"), + label: __("Name") + }); + this.catdb.cache = { name: d }; + const r = await this.catdb.write(undefined); + if (r.error) + { + throw new Error(r.error.toString()); + } + return await this.cat_refresh(); + } + catch(e) + { + this.error(__("Unable to insert category: {0}", e.toString()), e); + } + } + }, + { + text: "", + iconclass: "fa fa-minus-circle", + onbtclick: async (e) => + { + try + { + const item = this.catview.selectedItem; + if (!item) { return; } + const d = await this.ask({ text:__("Do you realy want to delete: `{0}`", item.data.text)}); + if (!d) { return; } + + const r = await this.catdb.remove({ + where: { + id: item.data.id + } + }); + if(r.error) + { + throw new Error(r.error.toString()); + } + await this.cat_refresh(); + } + catch(e) + { + this.error(__("Unable delete category: {0}", e.toString()), e); + } + } + }, + { + text: "", + iconclass: "fa fa-pencil-square-o", + onbtclick: async (_) => { + try + { + const item = this.catview.selectedItem; + if (!item) { return; }; + const cat = item.data; + if (!cat) { return; } + const d = await this.openDialog("PromptDialog", { + title: __("Category"), + label: __("Name"), + value: item.data.name + }); + const handle: API.VFS.BaseFileHandle = cat.$vfs; + handle.cache = { id: parseInt(item.data.id), name: d }; + const r = await handle.write(undefined); + if(r.error) + { + throw new Error(r.error.toString()); + } + await this.cat_refresh(); + } + catch(e) + { + this.error(__("Unable to update category: {0}", e.toString()), e); + } + } + } + ]; + + this.docview.onlistselect = async (evt) => { + try + { + this.clear_preview(); + const item = evt.data.item; + if(!item) return; + const handle = item.data.$vfs as API.VFS.BaseFileHandle; + // TODO join owner here + const d = await handle.read(); + await this.preview(d.file, this.docpreview); + const rows = []; + // TODO: if (d.result.fileinfo) { d.result.size = (d.result.fileinfo.size / 1024.0).toFixed(2) + " Kb"; } + const map = { + ctime: "Created on", + mtime: "Modified on", + note: "Note", + tags: "Tags", + name: "Title", + owner: "Owner", + edate: "Effective date", + file: "File", + size: "Size" + }; + d.edate = `${d.day}/${d.month}/${d.year}`; + for (let key in d) { + let value = d[key]; + const field = map[key]; + if(key === "ctime" || key == "mtime") + { + value = (new Date(value*1000)).toDateString(); + } + if (field) { rows.push([{text: field}, {text: value}]); } + } + return this.docgrid.rows = rows; + } + catch(e) + { + this.error(__("Unable to fetch document detail: {0}", e.toString()), e); + } + }; + + this.catview.onlistselect = (e) => { + this.clear_preview(); + const item = e.data.item; + if (!item) { return; } + return this.update_doclist(item.data.id); + }; + + (this.find("bt-add-doc") as GUI.tag.ButtonTag).onbtclick = async (evt) => { + try + { + const catiem = this.catview.selectedItem; + if (!catiem) { return this.notify(__("Please select a category")); } + const data = await this.openDialog(new docify.DocDialog()); + data.cid = parseInt(catiem.data.id); + const timestamp = Math.floor(Date.now() / 1000); + data.ctime = timestamp; + data.mtime = timestamp; + const r = await this.exec("merge_files", data); + if(r.error) + { + throw new Error(r.error.toString()); + } + data.file = r.result; + this.docdb.cache = data; + const d = await this.docdb.write(undefined); + if(d.error) + { + throw new Error(d.error.toString()); + } + if (d.result) { this.toast(d.result); } + this.update_doclist(catiem.data.id); + this.clear_preview(); + } + catch(e) + { + this.error(__("Unable to add document: {0}", e.toString()), e); + } + }; + + (this.find("bt-del-doc") as GUI.tag.ButtonTag).onbtclick = async (evt) => { + try + { + const item = this.docview.selectedItem; + if (!item) { return; } + const d = await this.ask({ text: __("Do you really want to delete: `{0}`", item.data.name) }); + if (!d) { return; } + let r = await this.docdb.remove({ + where: { + id: item.data.id + } + }); + if(r.error) + { + throw new Error(r.error.toString()); + } + r = await this.exec("deletedoc", {file: item.data.file}); + if(r.error) + { + throw new Error(r.error.toString()); + } + this.notify(r.result.toString()); + this.update_doclist(item.data.cid); + return this.clear_preview(); + } + catch(e) + { + this.error(__("Unable to delete document: {0}", e.tostring()), e); + } + }; + (this.find("bt-upload-doc") as GUI.tag.ButtonTag).onbtclick = async (evt) => { + try + { + await `${this.setting.docpath}/unclassified`.asFileHandle().upload(); + this.toast(__("File uploaded")); + } + catch(e) + { + this.error(__("Unable to upload document: {0}", e.toString()), e); + } + } + (this.find("bt-edit-doc") as GUI.tag.ButtonTag).onbtclick = async (evt) => { + try + { + const item = this.docview.selectedItem; + const catiem = this.catview.selectedItem; + if (!item) { return; } + const data = await this.openDialog(new docify.DocDialog(), item.data); + data.cid = parseInt(catiem.data.id); + data.id = item.data.id; + const timestamp = Math.floor(Date.now() / 1000); + data.mtime = timestamp; + let d = await this.exec("updatedoc", { + data, + rm: !data.file.includes(item.data.file) ? item.data.file : false + }); + if(d.error) + { + throw new Error(d.error); + } + const handle = item.data.$vfs; + handle.cache = d.result; + d = await handle.write(undefined); + if(d.error) + { + throw new Error(d.error); + } + if (d.result) { this.toast(d.result); } + this.update_doclist(catiem.data.id); + return this.clear_preview(); + } + catch(e) + { + this.error(__("Unable to edit document metadata: {0}", e.toString())); + } + }; + return this.initialize(); + } + + private async update_doclist(cid: any) { + try + { + const d = await this.docdb.read({ + where: { + cid: cid + }, + order: ["year$desc", "month$desc", "day$desc"] + }); + + // this.exec("select",{table: "docs", cond:`cid = ${cid} ORDER BY year DESC, month DESC, day DESC`}); + if(d.error) + { + throw new Error(d.error); + } + for (let v of d) + { + v.text = v.name; + } + return this.docview.data = d; + } + catch(e) + { + this.error(__("Unable to update document list: {0}", e.toString()), e); + } + } + + private clear_preview() { + this.docpreview.getContext('2d').clearRect(0,0,this.docpreview.width,this.docpreview.height); + return this.docgrid.rows = []; + } + + async preview(path: any, canvas: HTMLCanvasElement) { + try { + const d = await this.exec("preview", path); + if (d.error) { + throw new Error(d.error); + } + const file = d.result.asFileHandle(); + const data = await file.read("binary"); + const img = new Image(); + //($ me.view).append img + img.onload = () => { + const context = canvas.getContext('2d'); + canvas.height = img.height; + canvas.width = img.width; + //console.log canvas.width, canvas.height + return context.drawImage(img, 0, 0); + }; + + const blob = new Blob([data], { type: file.info.mime }); + return img.src = URL.createObjectURL(blob); + } + catch(e) + { + this.error(__("Unable to generate document thumbnail: {0}", e.toString()), e); + } + } + + private cat_refresh(): Promise { + return new Promise(async (resolve, reject) => { + try { + this.docview.data = []; + this.clear_preview(); + const d = await this.catdb.read(); + for (let v of d) { + v.text = v.name; + } + return this.catview.data = d; + } + catch(e) + { + reject(__e(e)); + } + }); + } + + private async initialize() { + try + { + // Check if we have configured docpath + if (this.setting.docpath) { + // check data base + return await this.init_db(); + } else + { + // ask user to choose a docpath + const d = await this.openDialog("FileDialog", { + title:__("Please select a doc path"), + type: 'dir' + }); + this.setting.docpath = d.file.path; + // save the doc path to local setting + //await this._api.setting(); + return await this.init_db(); + } + } + catch(e) + { + this.error(__("Error initialize database: {0}", e.toString()), e); + } + } + + exec(action: string, args?: GenericObject) { + const cmd = { + path: `${this.path()}/api.lua`, + parameters: { + action, + docpath: this.setting.docpath, + args + } + }; + return this.call(cmd); + } + + menu() { + return [ + { + text: "__(Options)", + nodes: [ + { text: "__(Owners)", id:"owners"}, + { text: "__(Preview)", id:"preview"}, + { text: "__(Change doc path)", id:"setdocp"} + ], + onchildselect: (e) => this.fileMenuHandle(e.data.item.data.id) + } + ]; + } + + private fileMenuHandle(id: any) { + switch (id) { + case "owners": + return this.openDialog(new docify.OwnerDialog(), { + title: __("Owners"), + dbhandle: this.ownerdb + }); + case "preview": + return this.openDialog(new docify.FilePreviewDialog(), { + app: this + }) + .then((d: { path: any; }) => { + return this.notify(d.path); + }); + case "setdocp": + this.setting.docpath = undefined; + return this.initialize(); + } + } + } + Docify.dependencies = ["pkg://SQLiteDB/libsqlite.js"]; + } +} \ No newline at end of file diff --git a/packages.json b/packages.json index f3fa40d..06f0ccf 100644 --- a/packages.json +++ b/packages.json @@ -154,9 +154,9 @@ "name": "Docify", "description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/2.0.x/Docify/README.md", "category": "Office", - "author": "", - "version": "0.0.9-b", - "dependencies": [], + "author": "Dany LE", + "version": "0.1.0-b", + "dependencies": ["SQLiteDB@0.1.0-a"], "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/2.0.x/Docify/build/release/Docify.zip" }, {