From f8435cd87ca20af65f5b8ec15016bfae74133fa4 Mon Sep 17 00:00:00 2001 From: DanyLE Date: Tue, 27 Jun 2023 22:27:09 +0200 Subject: [PATCH] Docify: remove server side script, move all operation to client side --- Docify/README.md | 1 + Docify/api/api.lua | 146 -------------------- Docify/assets/scheme.html | 1 + Docify/build.json | 4 +- Docify/build/debug/README.md | 1 + Docify/build/debug/api.lua | 146 -------------------- Docify/build/debug/main.css | 1 - Docify/build/debug/main.js | 2 +- Docify/build/debug/package.json | 6 +- Docify/build/debug/scheme.html | 1 + Docify/build/release/Docify.zip | Bin 7399 -> 6993 bytes Docify/package.json | 6 +- Docify/ts/main.ts | 234 ++++++++++++++++++++++++++------ MarkOn/build/release/MarkOn.zip | Bin 2319 -> 2319 bytes packages.json | 14 +- release.lua | 8 +- release/Docify.md | 1 + release/Docify.zip | Bin 7399 -> 6993 bytes release/MarkOn.zip | Bin 2319 -> 2319 bytes release/libjpeg.md | 4 + release/libjpeg.zip | Bin 0 -> 195489 bytes release/packages.json | 2 +- 22 files changed, 236 insertions(+), 342 deletions(-) delete mode 100644 Docify/api/api.lua delete mode 100644 Docify/build/debug/api.lua create mode 100644 release/libjpeg.md create mode 100644 release/libjpeg.zip diff --git a/Docify/README.md b/Docify/README.md index 666b1ca..91d3e5b 100644 --- a/Docify/README.md +++ b/Docify/README.md @@ -2,6 +2,7 @@ Simple PDF document manager ## Change logs +- v0.1.1-b: move PDF merge and document thumbnail generation to client side, remove server side lua script - 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 diff --git a/Docify/api/api.lua b/Docify/api/api.lua deleted file mode 100644 index 54c172f..0000000 --- a/Docify/api/api.lua +++ /dev/null @@ -1,146 +0,0 @@ -local arg = ... - -ulib = require("ulib") -vfs = require("vfs") - -local handle = {} -local docpath = nil - -local result = function(data) - return { - error = false, - result = data - } -end - -local error = function(data) - return { - error = data, - result = false - } -end - -local mkdirp =function(p) - if not vfs.exists(p) then - if not vfs.mkdir(p) then - return false, error("Unable to create directory: "..p) - end - end - return true, nil -end - -handle.merge_files = function(data) - local firstfile = data.file[1] - local fpath = docpath.."/"..data.cid - local r, e = mkdirp(fpath) - if not r then return e end - fpath = fpath.."/"..os.date("%d-%m-%Y_%H_%M_%S")..".pdf" - -- concat the files - if #data.file > 1 then - local cmd = "gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile="..vfs.ospath(fpath) - for i,v in ipairs(data.file) do - cmd = cmd.." \""..vfs.ospath(v).."\"" - end - os.execute(cmd) - if not vfs.exists(fpath) then - return error("Unable to merge PDF files") - end - cmd = "chmod 777 "..vfs.ospath(fpath) - os.execute(cmd) - else - local cmd = "mv \""..vfs.ospath(firstfile).."\" \""..vfs.ospath(fpath).."\"" - os.execute(cmd) - if not vfs.exists(fpath) then - return error("Unable to move PDF file") - end - end - -- move the thumb file to the cache folder - 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/"..enc.sha1(v:gsub(docpath, ""))..".png" - if vfs.exists(thumb) then - vfs.delete(thumb) - end - -- delete all files - if vfs.exists(v) then - vfs.delete(v) - end - end - return result(fpath) -end - -handle.preview = function(path) - -- convert -resize 300x500 noel.pdf[0] thumb.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 - - if vfs.exists(tpath) then - local cmd = "chmod 777 "..vfs.ospath(tpath) - os.execute(cmd) - return result(tpath) - else - return error("do not exist") - end -end - -handle.deletedoc = function(param) - -- move file to unclassified - local newfile = docpath.."/unclassified/"..utils.basename(param.file) - vfs.move(param.file, newfile) - -- delete thumb file - local thumb = docpath.."/cache/"..enc.sha1(param.file:gsub(docpath,""))..".png" - if vfs.exists(thumb) then - vfs.delete(thumb) - end - return result("Document entry deleted") -end - -handle.updatedoc = function(param) - 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/"..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/"..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 - end - param.data.file = r.result - print(r.result) - param.data.mtime = os.time(os.date("!*t")) - return result(param.data) - --return handle.update({ - -- table = "docs", - -- data = param.data - --}) -end - -if arg.action and handle[arg.action] then - -- check if the database exits - docpath = arg.docpath - - return handle[arg.action](arg.args) -else - return error("Invalid action parameter") -end \ No newline at end of file diff --git a/Docify/assets/scheme.html b/Docify/assets/scheme.html index f3e98cd..0803db8 100644 --- a/Docify/assets/scheme.html +++ b/Docify/assets/scheme.html @@ -20,6 +20,7 @@
+
diff --git a/Docify/build.json b/Docify/build.json index 6ed4d77..0a63208 100644 --- a/Docify/build.json +++ b/Docify/build.json @@ -20,7 +20,7 @@ "name":"locale-gen", "data": { "src": "", - "exclude": ["build/", "api/", "css/", "coffees/"], + "exclude": ["build/", "css/", "coffees/"], "locale": "en_GB", "dest": "package.json" } @@ -70,8 +70,8 @@ "data": { "src": [ "assets/scheme.html", - "api/api.lua", "package.json", + "css/main.css", "README.md" ], "dest": "build/debug" diff --git a/Docify/build/debug/README.md b/Docify/build/debug/README.md index 666b1ca..91d3e5b 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.1-b: move PDF merge and document thumbnail generation to client side, remove server side lua script - 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 diff --git a/Docify/build/debug/api.lua b/Docify/build/debug/api.lua deleted file mode 100644 index 54c172f..0000000 --- a/Docify/build/debug/api.lua +++ /dev/null @@ -1,146 +0,0 @@ -local arg = ... - -ulib = require("ulib") -vfs = require("vfs") - -local handle = {} -local docpath = nil - -local result = function(data) - return { - error = false, - result = data - } -end - -local error = function(data) - return { - error = data, - result = false - } -end - -local mkdirp =function(p) - if not vfs.exists(p) then - if not vfs.mkdir(p) then - return false, error("Unable to create directory: "..p) - end - end - return true, nil -end - -handle.merge_files = function(data) - local firstfile = data.file[1] - local fpath = docpath.."/"..data.cid - local r, e = mkdirp(fpath) - if not r then return e end - fpath = fpath.."/"..os.date("%d-%m-%Y_%H_%M_%S")..".pdf" - -- concat the files - if #data.file > 1 then - local cmd = "gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile="..vfs.ospath(fpath) - for i,v in ipairs(data.file) do - cmd = cmd.." \""..vfs.ospath(v).."\"" - end - os.execute(cmd) - if not vfs.exists(fpath) then - return error("Unable to merge PDF files") - end - cmd = "chmod 777 "..vfs.ospath(fpath) - os.execute(cmd) - else - local cmd = "mv \""..vfs.ospath(firstfile).."\" \""..vfs.ospath(fpath).."\"" - os.execute(cmd) - if not vfs.exists(fpath) then - return error("Unable to move PDF file") - end - end - -- move the thumb file to the cache folder - 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/"..enc.sha1(v:gsub(docpath, ""))..".png" - if vfs.exists(thumb) then - vfs.delete(thumb) - end - -- delete all files - if vfs.exists(v) then - vfs.delete(v) - end - end - return result(fpath) -end - -handle.preview = function(path) - -- convert -resize 300x500 noel.pdf[0] thumb.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 - - if vfs.exists(tpath) then - local cmd = "chmod 777 "..vfs.ospath(tpath) - os.execute(cmd) - return result(tpath) - else - return error("do not exist") - end -end - -handle.deletedoc = function(param) - -- move file to unclassified - local newfile = docpath.."/unclassified/"..utils.basename(param.file) - vfs.move(param.file, newfile) - -- delete thumb file - local thumb = docpath.."/cache/"..enc.sha1(param.file:gsub(docpath,""))..".png" - if vfs.exists(thumb) then - vfs.delete(thumb) - end - return result("Document entry deleted") -end - -handle.updatedoc = function(param) - 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/"..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/"..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 - end - param.data.file = r.result - print(r.result) - param.data.mtime = os.time(os.date("!*t")) - return result(param.data) - --return handle.update({ - -- table = "docs", - -- data = param.data - --}) -end - -if arg.action and handle[arg.action] then - -- check if the database exits - docpath = arg.docpath - - return handle[arg.action](arg.args) -else - return error("Invalid action parameter") -end \ No newline at end of file diff --git a/Docify/build/debug/main.css b/Docify/build/debug/main.css index 6b0de1d..1c69b86 100644 --- a/Docify/build/debug/main.css +++ b/Docify/build/debug/main.css @@ -1,4 +1,3 @@ - afx-app-window[data-id = "Docify"] .header .label-text { font-weight: bold; diff --git a/Docify/build/debug/main.js b/Docify/build/debug/main.js index b34f59c..e3feb4f 100644 --- a/Docify/build/debug/main.js +++ b/Docify/build/debug/main.js @@ -1 +1 @@ -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 +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=""),pdfjsLib.GlobalWorkerOptions.workerSrc="pkg://libpdfjs/pdf.worker.js".asFileHandle().getlink(),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.merge_files(i);i.file=r.path,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());try{await t.data.file.asFileHandle().remove();const e=await this.get_thumb_path(t.data.file);await e.asFileHandle().remove()}catch(t){console.log(t)}return 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);if(a.mtime=r,a.file.includes(e.data.file)&&1==a.file.length)a.file=e.data.file;else{if(!a.file.includes(e.data.file))try{console.log("remove old file",e.data.file),await e.data.file.asFileHandle().remove();const t=await this.get_thumb_path(e.data.file);await t.asFileHandle().remove()}catch(t){console.log(t)}const t=await this.merge_files(a);a.file=t.path}a.mtime=Math.floor(Date.now()/1e3);const s=e.data.$vfs;s.cache=a;const n=await s.write(void 0);if(n.error)throw new Error(n.error);return this.toast(__("Document updated")),this.update_doclist(i.data.id),this.clear_preview()}catch(t){this.error(__("Unable to edit document metadata: {0}",t.toString()))}},this.initialize()}async get_thumb_path(t){const e=t.asFileHandle().path;let i=await this.sha1(e.replace(this.setting.docpath,""));return`${this.setting.docpath}/cache/${i}.png`}async merge_files(t){const e=t.file,i=t.cid.toFixed(1).toString(),a=`${this.setting.docpath}/${i}`.asFileHandle();try{await a.onready()}catch(t){const e=await a.parent().mk(i);if(e.error)throw new Error(e.error.toString());await a.onready()}const r=`${a.path}/${new Date(Date.now()).getTime().toString()}.pdf`.asFileHandle(),s=await PDFLib.PDFDocument.create();let n=[];for(const t of e){const e=await t.asFileHandle().read("binary"),i=await PDFLib.PDFDocument.load(e,{ignoreEncryption:!0}),a=await s.copyPages(i,i.getPageIndices());n=n.concat(a)}for(let t=0;tt.toString(16).padStart(2,"0")).join("")}async genthumb(t){const e=(await this.get_thumb_path(t)).asFileHandle();try{await e.onready()}catch(i){console.log("Try to generate thumb file for",t);const a=this.find("tmp-canvas"),r=a.getContext("2d"),s=await pdfjsLib.getDocument(t.asFileHandle().getlink()).promise,n=await s.getPage(1),o=n.getViewport({scale:.33}),l=window.devicePixelRatio||1;a.width=Math.floor(o.width*l),a.height=Math.floor(o.height*l),a.style.width=Math.floor(o.width)+"px",a.style.height=Math.floor(o.height)+"px";const d={canvasContext:r,transform:1!==l?[l,0,0,l,0,0]:null,viewport:o};await n.render(d).promise;const h=a.toDataURL("image/png");e.cache=h;const c=await e.write("base64");if(c.error)throw new Error(c.error.toString());await e.onready()}return e}async preview(t,e){try{const i=await this.genthumb(t),a=await i.read("binary"),r=new Image;r.onload=()=>{const t=e.getContext("2d");return e.height=r.height,e.width=r.width,t.drawImage(r,0,0)};const s=new Blob([a],{type:i.info.mime});return r.src=URL.createObjectURL(s)}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)}}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","pkg://libpdfjs/pdf.js","pkg://PDFLib/main.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 3f09d19..0848d86 100644 --- a/Docify/build/debug/package.json +++ b/Docify/build/debug/package.json @@ -7,14 +7,16 @@ "author": "Dany LE", "email": "mrsang@iohub.dev" }, - "version": "0.1.0-b", + "version": "0.1.1-b", "category": "Office", "iconclass": "bi bi-collection-fill", "mimes": [ "none" ], "dependencies": [ - "SQLiteDB@0.1.0-a" + "SQLiteDB@0.1.0-a", + "libpdfjs@2.6.347-r", + "PDFLib@1.17.1" ], "locale": {}, "locales": { diff --git a/Docify/build/debug/scheme.html b/Docify/build/debug/scheme.html index f3e98cd..0803db8 100644 --- a/Docify/build/debug/scheme.html +++ b/Docify/build/debug/scheme.html @@ -20,6 +20,7 @@
+
diff --git a/Docify/build/release/Docify.zip b/Docify/build/release/Docify.zip index 0a74a3b01206f196d06a0d7c99c434c6fbd0c5c7..53bd72915ffd9222468b63fc563105994ad7ebd8 100644 GIT binary patch literal 6993 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 Wb)8;oM|mZGB`7wXnOj- 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 diff --git a/Docify/package.json b/Docify/package.json index 3f09d19..0848d86 100644 --- a/Docify/package.json +++ b/Docify/package.json @@ -7,14 +7,16 @@ "author": "Dany LE", "email": "mrsang@iohub.dev" }, - "version": "0.1.0-b", + "version": "0.1.1-b", "category": "Office", "iconclass": "bi bi-collection-fill", "mimes": [ "none" ], "dependencies": [ - "SQLiteDB@0.1.0-a" + "SQLiteDB@0.1.0-a", + "libpdfjs@2.6.347-r", + "PDFLib@1.17.1" ], "locale": {}, "locales": { diff --git a/Docify/ts/main.ts b/Docify/ts/main.ts index d468020..8c5f007 100644 --- a/Docify/ts/main.ts +++ b/Docify/ts/main.ts @@ -1,5 +1,7 @@ namespace OS { export namespace application { + declare var pdfjsLib; + declare var PDFLib; export class Docify extends BaseApplication { private catview: GUI.tag.ListViewTag; @@ -108,7 +110,8 @@ namespace OS { main() { if (!this.setting.printer) { this.setting.printer = ""; } - + pdfjsLib.GlobalWorkerOptions.workerSrc = "pkg://libpdfjs/pdf.worker.js".asFileHandle().getlink(); + 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; @@ -288,12 +291,13 @@ namespace OS { const timestamp = Math.floor(Date.now() / 1000); data.ctime = timestamp; data.mtime = timestamp; - const r = await this.exec("merge_files", data); - if(r.error) + const r = await this.merge_files(data); + data.file = r.path; + /*if(r.error) { throw new Error(r.error.toString()); } - data.file = r.result; + data.file = r.result;*/ this.docdb.cache = data; const d = await this.docdb.write(undefined); if(d.error) @@ -326,12 +330,16 @@ namespace OS { { throw new Error(r.error.toString()); } - r = await this.exec("deletedoc", {file: item.data.file}); - if(r.error) - { - throw new Error(r.error.toString()); + // delete file + try { + await item.data.file.asFileHandle().remove(); + const thumb = await this.get_thumb_path(item.data.file); + await thumb.asFileHandle().remove(); + } + catch(e) + { + console.log(e); } - this.notify(r.result.toString()); this.update_doclist(item.data.cid); return this.clear_preview(); } @@ -362,22 +370,40 @@ namespace OS { 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) + if(data.file.includes(item.data.file) && data.file.length == 1) { - throw new Error(d.error); + // nothing changes + data.file = item.data.file; } + else + { + if(!data.file.includes(item.data.file)) + { + // remove old file + try { + console.log("remove old file", item.data.file); + await item.data.file.asFileHandle().remove(); + const thumb = await this.get_thumb_path(item.data.file); + await thumb.asFileHandle().remove(); + } + catch(e) + { + console.log(e); + } + } + // merge all PDF file + const merged_file = await this.merge_files(data); + data.file = merged_file.path; + } + data.mtime = Math.floor(Date.now() / 1000); const handle = item.data.$vfs; - handle.cache = d.result; - d = await handle.write(undefined); + handle.cache = data; + const d = await handle.write(undefined); if(d.error) { throw new Error(d.error); } - if (d.result) { this.toast(d.result); } + this.toast(__("Document updated")); this.update_doclist(catiem.data.id); return this.clear_preview(); } @@ -389,6 +415,90 @@ namespace OS { return this.initialize(); } + private async get_thumb_path(filepath: string| API.VFS.BaseFileHandle) + { + const path = filepath.asFileHandle().path; + let thumb_name = await this.sha1(path.replace(this.setting.docpath,"")); + return `${this.setting.docpath}/cache/${thumb_name}.png`; + } + + private async merge_files(data) { + const paths: string[] = data.file; + const cat = data.cid.toFixed(1).toString(); + const dir = `${this.setting.docpath}/${cat}`.asFileHandle(); + try{ + await dir.onready(); + } + catch(_) + { + const ret = await dir.parent().mk(cat); + if(ret.error) + { + throw new Error(ret.error.toString()); + } + await dir.onready(); + } + const des_file = `${dir.path}/${new Date(Date.now()).getTime().toString()}.pdf`.asFileHandle(); + // concat the file + const pdfdoc = await PDFLib.PDFDocument.create(); + let pages = []; + for(const path of paths) + { + const arr = await path.asFileHandle().read("binary"); + const doc = await PDFLib.PDFDocument.load(arr, { ignoreEncryption: true }); + const copiedpages = await pdfdoc.copyPages(doc, doc.getPageIndices()); + pages = pages.concat(copiedpages); + } + for (let i = 0; i < pages.length; i++) { + await pdfdoc.insertPage(i, pages[i]); + } + const buffer = await pdfdoc.save(); + des_file.cache = new Blob([buffer]); + const ret = await des_file.write("binary"); + if(ret.error) + { + throw new Error(ret.error.toString()); + } + // move thumb file + let src_tfile = await this.get_thumb_path(paths[0]); + const dest_tfile = await this.get_thumb_path(des_file); + try { + console.log("Move", src_tfile, "to", dest_tfile); + const ret = await src_tfile.asFileHandle().move(dest_tfile); + if(ret.error) + { + console.log(ret.error); + } + } + catch(e) + { + console.log(e); + } + // remove other file and thumb file + for(const path of paths) + { + try{ + src_tfile = await this.get_thumb_path(path); + console.log("'Remove file", path, src_tfile); + let ret = await path.asFileHandle().remove(); + if(ret.error) + { + console.log(ret); + } + ret = await src_tfile.asFileHandle().remove(); + if(ret.error) + { + console.log(ret); + } + } + catch(e) + { + console.log(e); + } + } + return des_file; + } + private async update_doclist(cid: any) { try { @@ -399,7 +509,6 @@ namespace OS { 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); @@ -420,14 +529,72 @@ namespace OS { this.docpreview.getContext('2d').clearRect(0,0,this.docpreview.width,this.docpreview.height); return this.docgrid.rows = []; } + + private async sha1(str) { + const enc = new TextEncoder(); + const hash = await crypto.subtle.digest('SHA-1', enc.encode(str)); + return Array.from(new Uint8Array(hash)) + .map(v => (v.toString(16) as any).padStart(2, '0')) + .join(''); + } + private async genthumb(path: string) + { + /** try to search if the thumb file exists, + * if it does not exist, generate it using + * pdfjs library and an hidden canvas + */ + const tpath = await this.get_thumb_path(path); + + const file = tpath.asFileHandle(); + try { + await file.onready(); + } + catch(e) + { + // generate thumb file + //data = await file.read("binary"); + console.log("Try to generate thumb file for", path); + const canvas = this.find("tmp-canvas") as HTMLCanvasElement; + const context = canvas.getContext('2d'); + const pdf = await pdfjsLib.getDocument(path.asFileHandle().getlink()).promise; + + const page = await pdf.getPage(1); + + const viewport = page.getViewport({ scale: 0.33}); + // Support HiDPI-screens. + const outputScale = window.devicePixelRatio || 1; + + canvas.width = Math.floor(viewport.width * outputScale); + canvas.height = Math.floor(viewport.height * outputScale); + canvas.style.width = Math.floor(viewport.width) + "px"; + canvas.style.height = Math.floor(viewport.height) + "px"; + + const transform = outputScale !== 1 + ? [outputScale, 0, 0, outputScale, 0, 0] + : null; + + const renderContext = { + canvasContext: context, + transform: transform, + viewport: viewport + }; + await page.render(renderContext).promise; + const url = canvas.toDataURL('image/png'); + file.cache = url; + const ret = await file.write("base64"); + if(ret.error) + { + throw new Error(ret.error.toString()); + } + await file.onready(); + } + return file; + } + 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 file = await this.genthumb(path); const data = await file.read("binary"); const img = new Image(); //($ me.view).append img @@ -435,7 +602,6 @@ namespace OS { 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); }; @@ -492,18 +658,6 @@ namespace OS { } } - 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 [ { @@ -538,6 +692,10 @@ namespace OS { } } } - Docify.dependencies = ["pkg://SQLiteDB/libsqlite.js"]; + Docify.dependencies = [ + "pkg://SQLiteDB/libsqlite.js", + "pkg://libpdfjs/pdf.js", + "pkg://PDFLib/main.js" + ]; } } \ No newline at end of file diff --git a/MarkOn/build/release/MarkOn.zip b/MarkOn/build/release/MarkOn.zip index ebd4f2ee704ab2828877c4617c127fd80fb4405e..ab65e85b2feefa08e3d60eb8685fed130314cd4c 100644 GIT binary patch delta 290 zcmeAd>KEb-@MdP=Vqjq4V3@n$_T)Q^f0%*v=G#o%tlUTv6M4%);uG6vgQ&@>jB9uq znM4>68fS7y*8@#qC`e4sPE1eL%PP*#3-Cr!6E?de(flI|1H)Gy1_pMJVmSB@WaTDi z<^i>#Yf@u79u@+WjsRi~xCRhIlntsWxfrZ#vK$8o*mas5(lY%($skup7hhMs+!Qo3 pCns=7tLg$>P@J5RnwzSZQIeYz;LQru!N9-@grbZL3{Sug1OPGvLc9O~ delta 278 zcmeAd>KEb-@MdP=Vqjq4U|`NTK3R#aoEb#VVVe!6t=QLaBgs$X{R0x-%)`jds>R48 z!T{G9rp9(WECgsy1lTMffdnSkbBI|1^@XX$hb}A!N=yV|P9y~k3{^m0kgKDMud7~e zN`NSdJV=AbDFtCE*vxe7ER1gMM$#pLshlLa`Wz`oJt hkXAg$#K4f7n3<=SRUF{W$_7%(3WTCSeNWgyJOEMNF!ule diff --git a/packages.json b/packages.json index 4ecbeaa..9b8722c 100644 --- a/packages.json +++ b/packages.json @@ -69,6 +69,16 @@ "dependencies": ["Antunnel@0.2.0-b"], "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/2.0.x/AntunnelPlugins/build/release/AntunnelPlugins.zip" }, + { + "pkgname": "AntunnelTestClient", + "name": "AntunnelTestClient", + "description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/2.0.x/AntunnelTestClient/README.md", + "category": "Development", + "author": "Dany LE", + "version": "0.1.0-a", + "dependencies": ["Antunnel@0.2.1-b"], + "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/2.0.x/AntunnelTestClient/build/release/AntunnelTestClient.zip" + }, { "pkgname": "Archive", "name": "Archive", @@ -145,8 +155,8 @@ "description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/2.0.x/Docify/README.md", "category": "Office", "author": "Dany LE", - "version": "0.1.0-b", - "dependencies": ["SQLiteDB@0.1.0-a"], + "version": "0.1.1-b", + "dependencies": ["SQLiteDB@0.1.0-a","libpdfjs@2.6.347-r","PDFLib@1.17.1"], "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/2.0.x/Docify/build/release/Docify.zip" }, { diff --git a/release.lua b/release.lua index ac06adb..4e22418 100644 --- a/release.lua +++ b/release.lua @@ -41,7 +41,7 @@ end local packages = {} -for i,v in ipairs(r) do +for i,v in pairs(r) do if v.type == "dir" then local ar_file = v.path.."/build/release/"..v.filename..".zip" local meta_file = v.path.."/package.json" @@ -74,6 +74,12 @@ for i,v in ipairs(r) do download = release_url..v.filename..".zip" } table.insert(packages, pkg) + --else + -- if not ulib.exists(ar_file) then + -- output("AR file not found "..ar_file) + -- else + -- output("Meta file not found "..meta_file) + -- end end end end diff --git a/release/Docify.md b/release/Docify.md index 666b1ca..91d3e5b 100644 --- a/release/Docify.md +++ b/release/Docify.md @@ -2,6 +2,7 @@ Simple PDF document manager ## Change logs +- v0.1.1-b: move PDF merge and document thumbnail generation to client side, remove server side lua script - 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 diff --git a/release/Docify.zip b/release/Docify.zip index 0a74a3b01206f196d06a0d7c99c434c6fbd0c5c7..53bd72915ffd9222468b63fc563105994ad7ebd8 100644 GIT binary patch literal 6993 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 Wb)8;oM|mZGB`7wXnOj- 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 diff --git a/release/MarkOn.zip b/release/MarkOn.zip index ebd4f2ee704ab2828877c4617c127fd80fb4405e..ab65e85b2feefa08e3d60eb8685fed130314cd4c 100644 GIT binary patch delta 290 zcmeAd>KEb-@MdP=Vqjq4V3@n$_T)Q^f0%*v=G#o%tlUTv6M4%);uG6vgQ&@>jB9uq znM4>68fS7y*8@#qC`e4sPE1eL%PP*#3-Cr!6E?de(flI|1H)Gy1_pMJVmSB@WaTDi z<^i>#Yf@u79u@+WjsRi~xCRhIlntsWxfrZ#vK$8o*mas5(lY%($skup7hhMs+!Qo3 pCns=7tLg$>P@J5RnwzSZQIeYz;LQru!N9-@grbZL3{Sug1OPGvLc9O~ delta 278 zcmeAd>KEb-@MdP=Vqjq4U|`NTK3R#aoEb#VVVe!6t=QLaBgs$X{R0x-%)`jds>R48 z!T{G9rp9(WECgsy1lTMffdnSkbBI|1^@XX$hb}A!N=yV|P9y~k3{^m0kgKDMud7~e zN`NSdJV=AbDFtCE*vxe7ER1gMM$#pLshlLa`Wz`oJt hkXAg$#K4f7n3<=SRUF{W$_7%(3WTCSeNWgyJOEMNF!ule diff --git a/release/libjpeg.md b/release/libjpeg.md new file mode 100644 index 0000000..0d94227 --- /dev/null +++ b/release/libjpeg.md @@ -0,0 +1,4 @@ +# libjpeg +Simple JPEG/DCT data decoder in JavaScript. Also this project includes JPEG 2000 and JBIG2 decoders. + +Github page: [https://github.com/notmasteryet/jpgjs](https://github.com/notmasteryet/jpgjs) \ No newline at end of file diff --git a/release/libjpeg.zip b/release/libjpeg.zip new file mode 100644 index 0000000000000000000000000000000000000000..171840346bc81bf9b186cec009110d840db49ab9 GIT binary patch literal 195489 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