From d20db3e0fb583ca44859ae545055c11d2c91c5c9 Mon Sep 17 00:00:00 2001 From: lxsang Date: Sat, 6 Jun 2020 18:41:00 +0200 Subject: [PATCH] add archive manager --- Archive/README.md | 13 ++ Archive/assets/scheme.html | 17 ++ Archive/build/debug/README.md | 13 ++ Archive/build/debug/main.css | 20 +++ Archive/build/debug/main.js | 1 + Archive/build/debug/package.json | 15 ++ Archive/build/debug/scheme.html | 17 ++ Archive/build/release/Archive.zip | Bin 0 -> 8946 bytes Archive/coffees/main.coffee | 275 ++++++++++++++++++++++++++++++ Archive/css/main.css | 19 +++ Archive/package.json | 15 ++ Archive/project.json | 8 + packages.json | 9 + 13 files changed, 422 insertions(+) create mode 100644 Archive/README.md create mode 100644 Archive/assets/scheme.html create mode 100644 Archive/build/debug/README.md create mode 100644 Archive/build/debug/main.css create mode 100644 Archive/build/debug/main.js create mode 100644 Archive/build/debug/package.json create mode 100644 Archive/build/debug/scheme.html create mode 100644 Archive/build/release/Archive.zip create mode 100644 Archive/coffees/main.coffee create mode 100644 Archive/css/main.css create mode 100644 Archive/package.json create mode 100644 Archive/project.json diff --git a/Archive/README.md b/Archive/README.md new file mode 100644 index 0000000..173cdc8 --- /dev/null +++ b/Archive/README.md @@ -0,0 +1,13 @@ +# Archive + +Small application for zip file manager + +## Features +* Open, create zip file Archive +* Add/remove file/folder to archive +* Extract zip file content + +## Changle log + +### v0.0.1-a +* First release \ No newline at end of file diff --git a/Archive/assets/scheme.html b/Archive/assets/scheme.html new file mode 100644 index 0000000..ebd3753 --- /dev/null +++ b/Archive/assets/scheme.html @@ -0,0 +1,17 @@ + + + +
+ +
+
+ + +
+
+ +
+
+
+
+
\ No newline at end of file diff --git a/Archive/build/debug/README.md b/Archive/build/debug/README.md new file mode 100644 index 0000000..173cdc8 --- /dev/null +++ b/Archive/build/debug/README.md @@ -0,0 +1,13 @@ +# Archive + +Small application for zip file manager + +## Features +* Open, create zip file Archive +* Add/remove file/folder to archive +* Extract zip file content + +## Changle log + +### v0.0.1-a +* First release \ No newline at end of file diff --git a/Archive/build/debug/main.css b/Archive/build/debug/main.css new file mode 100644 index 0000000..feaf261 --- /dev/null +++ b/Archive/build/debug/main.css @@ -0,0 +1,20 @@ + +afx-app-window[data-id="Archive"] afx-tree-view .afx-tree-view-folder-close:before{ + content: "\f07b"; + font-family: "FontAwesome"; + color:#76D2F9; + font-size: 16px; +} +afx-app-window[data-id="Archive"] afx-tree-view .afx-tree-view-folder-open:before{ + content: "\f07c"; + font-family: "FontAwesome"; + color:#76D2F9; + font-size: 16px; +} +afx-app-window[data-id="Archive"] afx-tree-view .afx-tree-view-item:before{ + content: "\f016"; + font-family: "FontAwesome"; + font-size: 16px; + font-style: normal; + font-weight: normal; +} diff --git a/Archive/build/debug/main.js b/Archive/build/debug/main.js new file mode 100644 index 0000000..25943ad --- /dev/null +++ b/Archive/build/debug/main.js @@ -0,0 +1 @@ +(function(){var t;(t=class extends this.OS.application.BaseApplication{constructor(t){super("Archive",t),this.currfile="Untitled".asFileHandle(),this.args&&this.args.length>0&&this.args[0].path&&(this.currfile=t[0].path.asFileHandle())}main(){return this.btadd=this.find("btaradd"),this.btdel=this.find("btardel"),this.btxtract=this.find("btarxtract"),this.filetree=this.find("filetree"),this.zip=void 0,this.bindKey("ALT-N",()=>this.fileMenuHandle("new")),this.bindKey("ALT-O",()=>this.fileMenuHandle("open")),this.bindKey("CTRL-S",()=>this.fileMenuHandle("save")),this.bindKey("ALT-S",()=>this.fileMenuHandle("saveas")),this.btxtract.onbtclick=t=>{var e,i;return(e=this.filetree.selectedItem)?(i=e.data,this.openDialog("FileDialog",{title:__("Select a folder"),mimes:["dir"]}).then(t=>this.xtract(i,t.file.path).then(()=>this.notify(__("extract successful: {0}",i.path))).catch(t=>this.error(t.toString(),t))).catch(t=>this.error(t.toString(),t))):this.notify(__("Please select file/folder to extract"))},this.btadd.onbtclick=t=>this.actionAdd(),this.btdel.onbtclick=t=>this.actionDel(),this.filetree.contextmenuHandle=(t,e)=>{var i,r;if(i=this.filetree.selectedItem)return r=[{text:"__(Delete)",onmenuselect:()=>this.actionDel()},{text:"__(Info)",onmenuselect:()=>this.actionInfo()}],"dir"===i.data.type&&r.unshift({text:"__(Add)",onmenuselect:()=>this.actionAdd()}),e.items=r,e.show(t)},this.openar(this.currfile)}actionAdd(){var t,e;return(t=this.filetree.selectedItem)&&"dir"===t.data.type?(e=t.data,this.openDialog("FileDialog",{title:__("Select a file/folder")}).then(t=>this.addToZip(t.file,`${e.path}/${t.file.path.asFileHandle().basename}`).then(()=>(this.currfile.dirty=!0,this.refreshTreeFile())).catch(t=>this.error(t.toString(),t))).catch(t=>this.error(t.toString(),t))):this.notify(__("Please select a destination folder"))}actionDel(){var t,e;return(t=this.filetree.selectedItem)?(e=t.data).root?this.notify(__("You cannot delete the root node")):this.ask({title:"__(Delete)",text:__("Do you really want to delete: {0}?",e.text)}).then(t=>{if(t)return this.zip.remove(e.path.trimBy("/")),this.currfile.dirty=!0,this.refreshTreeFile()}).catch(t=>this.error(t.toString(),t)):this.notify(__("Please select a destination folder"))}actionInfo(){var t,e,i;return(t=this.filetree.selectedItem)?(e=t.data.path.trimBy("/"),"dir"===t.data.type&&(e+="/"),(i=this.zip.files[e])?this.openDialog("InfoDialog",{title:"About: "+i.name,name:i.name,date:i.date,dir:i.dir,dataBinary:i._dataBinary,size:i._data.uncompressedSize}):this.notify(__("Cannot get entry meta data"))):this.notify(__("Please select a file/folder"))}openar(t){return this.zip=void 0,"Untitled"===t.filename?(this.zip=new JSZip,this.currfile=t,this.refreshTreeFile()):t.read("binary").then(e=>JSZip.loadAsync(e).then(e=>(this.zip=e,this.currfile=t,this.refreshTreeFile())).catch(t=>this.error(__("Wrong zip format: {0}",t.toString()),t))).catch(e=>this.error(__("Unable to read archive: {0}",t.path),e))}refreshTreeFile(){var t,e,i,r,n;if(this.zip){for(t in r={text:this.currfile.filename.trimRight(".zip"),type:"dir",path:"",open:!0,root:!0,nodes:[]},i=this.zip.files)n=i[t],e=this.putFileInTree(t.split("/"),r),n.dir||(e.type="file",delete e.nodes);return this.filetree.data=r}}putFileInTree(t,e){var i,r,n,a;return i=function(){var t,i,r,n;for(n=[],t=0,i=(r=e.nodes).length;t"file"===t.type?this.zip.file(t.path.trimBy("/")).async("uint8array").then(n=>{var a;return(a=`${e}/${t.text}`.asFileHandle()).cache=new Blob([n],{type:"octet/stream"}),a.write().then((function(){return i()})).catch((function(t){return r(__e(t))}))}).catch((function(t){return r(__e(t))})):e.asFileHandle().mk(t.text).then(()=>{var n,a;return n=function(){var e,i,r,n;for(n=[],e=0,i=(r=t.nodes).length;e{var n;return 0===t.length?i():(n=t.shift(),this.xtract(n,e).then(()=>this.xtractall(t,e).then((function(){return i()})).catch((function(t){return r(__e(t))}))).catch((function(t){return r(__e(t))})))})}addToZip(t,e){return new Promise((i,r)=>"dir"===t.type?t.path.asFileHandle().read().then(t=>t.error?r(__e(this.throwe(t.error))):this.addFilesTozip(t.result,e).then((function(){return i()})).catch(t=>r(__e(t)))):t.path.asFileHandle().read("binary").then(t=>(this.zip.file(e.trimBy("/"),t,{binary:!0}),i())).catch((function(t){return i(__e(t))})))}addFilesTozip(t,e){return new Promise((i,r)=>{var n;return 0===t.length?i():(n=t.shift(),this.addToZip(n,`${e}/${n.path.asFileHandle().basename}`).then(()=>this.addFilesTozip(t,e).then((function(){return i()})).catch((function(t){return r(__e(t))}))).catch((function(t){return r(__e(t))})))})}saveZipAs(){return this.openDialog("FileDialog",{title:__("Save as"),file:this.currfile}).then(t=>{var e;return e=t.file.path.asFileHandle(),"file"===t.file.type&&(e=e.parent()),this.currfile.setPath(`${e.path}/${t.name}`),this.write()})}write(){if(this.zip&&"Untitled"!==this.currfile.path)return this.zip.generateAsync({type:"base64"}).then(t=>this.currfile.setCache("data:application/zip;base64,"+t).write("base64").then(()=>(this.currfile.dirty=!1,this.refreshTreeFile(),this.notify(__("zip file saved in {0}",this.currfile.path)))).catch(t=>this.error(__("Unable to save zip file: {0}",this.currfile.path))))}fileMenuHandle(t){switch(t){case"open":return this.openDialog("FileDialog",{title:__("Select a zip file"),mimes:["application/zip"]}).then(t=>this.openar(t.file.path.asFileHandle())).catch(t=>this.error(t.toString(),t));case"save":return"Untitled"!==this.currfile.path?this.write():this.saveZipAs();case"saveas":return this.saveZipAs()}}menu(){return[{text:"__(File)",nodes:[{text:"__(New)",id:"new",shortcut:"A-N"},{text:"__(Open)",id:"open",shortcut:"A-O"},{text:"__(Save)",id:"save",shortcut:"C-S"},{text:"__(Save as)",id:"saveas",shortcut:"A-S"}],onchildselect:t=>this.fileMenuHandle(t.data.item.data.id)}]}cleanup(t){if(this.currfile.dirty)return t.preventDefault(),this.ask({title:"__(Quit)",text:"__(Zip file has been modified. Quit without saving?)"}).then(t=>{if(t)return this.currfile.dirty=!1,this.quit()})}}).dependencies=["os://scripts/jszip.min.js"],this.OS.register("Archive",t)}).call(this); \ No newline at end of file diff --git a/Archive/build/debug/package.json b/Archive/build/debug/package.json new file mode 100644 index 0000000..3c8e497 --- /dev/null +++ b/Archive/build/debug/package.json @@ -0,0 +1,15 @@ +{ + "app":"Archive", + "name":"Archive", + "pkgname": "Archive", + "description":"Create of extract zip archive", + "info":{ + "author": "Xuan Sang LE", + "email": "mrsang@lxsang.me" + }, + "version":"0.0.1-a", + "category":"Other", + "iconclass":"fa fa-archive", + "mimes":["application/zip"], + "locale": {} +} \ No newline at end of file diff --git a/Archive/build/debug/scheme.html b/Archive/build/debug/scheme.html new file mode 100644 index 0000000..ebd3753 --- /dev/null +++ b/Archive/build/debug/scheme.html @@ -0,0 +1,17 @@ + + + +
+ +
+
+ + +
+
+ +
+
+
+
+
\ No newline at end of file diff --git a/Archive/build/release/Archive.zip b/Archive/build/release/Archive.zip new file mode 100644 index 0000000000000000000000000000000000000000..285a967c7d381e17b5bb2c8fe34d740f98556abb GIT binary patch literal 8946 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 literal 0 HcmV?d00001 diff --git a/Archive/coffees/main.coffee b/Archive/coffees/main.coffee new file mode 100644 index 0000000..9ea987b --- /dev/null +++ b/Archive/coffees/main.coffee @@ -0,0 +1,275 @@ +class Archive extends this.OS.application.BaseApplication + constructor: ( args ) -> + super "Archive", args + @currfile = "Untitled".asFileHandle() + if @args and @args.length > 0 and @args[0].path + @currfile = args[0].path.asFileHandle() + + main: () -> + @btadd = @find "btaradd" + @btdel = @find "btardel" + @btxtract = @find "btarxtract" + @filetree = @find "filetree" + @zip = undefined + @bindKey "ALT-N", () => @fileMenuHandle "new" + @bindKey "ALT-O", () => @fileMenuHandle "open" + @bindKey "CTRL-S", () => @fileMenuHandle "save" + @bindKey "ALT-S", () => @fileMenuHandle "saveas" + + @btxtract.onbtclick = (e) => + item = @filetree.selectedItem + return @notify __("Please select file/folder to extract") unless item + treedata = item.data + @openDialog "FileDialog", { title: __("Select a folder"), mimes: ["dir"] } + .then (d) => + @xtract(treedata, d.file.path) + .then () => @notify __("extract successful: {0}", treedata.path) + .catch (e) => @error e.toString(), e + .catch (e) => @error e.toString(), e + + + @btadd.onbtclick = (e) => @actionAdd() + + @btdel.onbtclick = (e) => @actionDel() + + @filetree.contextmenuHandle = (e, m) => + item = @filetree.selectedItem + return unless item + mdata = [ + { text: "__(Delete)", onmenuselect: () => @actionDel()}, + { text: "__(Info)", onmenuselect: () => @actionInfo()} + ] + if item.data.type is "dir" + mdata.unshift { text: "__(Add)", onmenuselect: () => @actionAdd() } + + + m.items = mdata + m.show(e) + + @openar(@currfile) + + actionAdd: () -> + item = @filetree.selectedItem + return @notify __("Please select a destination folder") unless item and item.data.type is "dir" + treedata = item.data + @openDialog "FileDialog", { title: __("Select a file/folder") } + .then (d) => + @addToZip d.file, "#{treedata.path}/#{d.file.path.asFileHandle().basename}" + .then () => + @currfile.dirty = true + @refreshTreeFile() + .catch (e) => @error e.toString(), e + .catch (e) => @error e.toString(), e + + actionDel: () -> + item = @filetree.selectedItem + return @notify __("Please select a destination folder") unless item + treedata = item.data + return @notify __("You cannot delete the root node") if treedata.root + + @ask {title: "__(Delete)", text: __("Do you really want to delete: {0}?", treedata.text) } + .then (d) => + return unless d + @zip.remove(treedata.path.trimBy("/")) + @currfile.dirty = true + @refreshTreeFile() + .catch (e) => @error e.toString(), e + + actionInfo: () -> + item = @filetree.selectedItem + return @notify __("Please select a file/folder") unless item + key = item.data.path.trimBy("/") + key = "#{key}/" if item.data.type is "dir" + meta = @zip.files[key] + return @notify __("Cannot get entry meta data") unless meta + @openDialog "InfoDialog", { + title: "About: #{meta.name}", + name: meta.name, + date: meta.date, + dir: meta.dir, + dataBinary: meta._dataBinary, + size: meta._data.uncompressedSize + } + + openar: (file) -> + @zip = undefined + if file.filename is "Untitled" + @zip = new JSZip() + @currfile = file + @refreshTreeFile() + else + # open the file and refresh filetree + file.read("binary") + .then (data) => + JSZip.loadAsync(data) + .then (zip) => + @zip = zip + @currfile = file + @refreshTreeFile() + .catch (e) => + @error __("Wrong zip format: {0}", e.toString()), e + .catch (e) => + @error __("Unable to read archive: {0}", file.path), e + + refreshTreeFile: () -> + return unless @zip + treedata = { + text: @currfile.filename.trimRight(".zip"), + type: "dir" + path: "", + open: true, + root: true, + nodes: [] + } + + for k,v of @zip.files + leaf = @putFileInTree k.split("/"), treedata + if not v.dir + leaf.type = "file" + delete leaf.nodes + @filetree.data = treedata + + putFileInTree: (patharr, treedata) -> + names = (v.text for v in treedata.nodes) + rep = patharr.shift() + return treedata unless rep + if names.includes rep + @putFileInTree patharr, treedata.nodes[names.indexOf rep] + else + subtree = { + text: rep, + path: "#{treedata.path}/#{rep}", + type: "dir", + nodes: [] + } + treedata.nodes.push subtree + return @putFileInTree patharr, subtree + + + xtract: (treedata, to) -> + new Promise (resolve, reject) => + if treedata.type is "file" + @zip.file(treedata.path.trimBy("/")) + .async("uint8array") + .then (data) => + fp = "#{to}/#{treedata.text}".asFileHandle() + fp.cache = new Blob([data], { type: "octet/stream" }) + fp.write() + .then () -> resolve() + .catch (e) -> reject __e e + .catch (e) -> reject __e e + else + #make the dir before extract + to.asFileHandle().mk treedata.text + .then () => + nodes = (v for v in treedata.nodes) + @xtractall nodes, "#{to}/#{treedata.text}" + .then -> resolve() + .catch (e) -> reject __e e + .catch (e) -> reject __e e + + xtractall: (list, to) -> + new Promise (resolve, reject) => + return resolve() if list.length is 0 + el = list.shift() + @xtract el, to + .then () => + @xtractall list, to + .then () -> resolve() + .catch (e) -> reject __e e + .catch (e) -> reject __e e + + addToZip: (file, to) -> + new Promise (resolve, reject) => + if file.type is "dir" + file.path.asFileHandle().read().then (data) => + return reject __e @throwe data.error if data.error + @addFilesTozip data.result, to + .then () -> resolve() + .catch (e) => reject __e e + else + file.path.asFileHandle() + .read("binary") + .then (data) => + @zip.file(to.trimBy("/"), data, { binary: true }) + resolve() + .catch (e) -> resolve __e e + + addFilesTozip: (list, to) -> + new Promise (resolve, reject) => + return resolve() if list.length is 0 + el = list.shift() + @addToZip el, "#{to}/#{el.path.asFileHandle().basename}" + .then () => + @addFilesTozip list, to + .then () -> resolve() + .catch (e) -> reject __e e + .catch (e) -> reject __e e + + saveZipAs: () -> + @openDialog("FileDialog", { + title: __("Save as"), + file: @currfile + }).then (f) => + d = f.file.path.asFileHandle() + d = d.parent() if f.file.type is "file" + @currfile.setPath "#{d.path}/#{f.name}" + @write() + + write: () -> + return unless @zip and @currfile.path isnt "Untitled" + @zip .generateAsync({ type: "base64" }) + .then (data) => + @currfile + .setCache( + "data:application/zip;base64," + data + ) + .write("base64") + .then () => + @currfile.dirty = false + @refreshTreeFile() + @notify __("zip file saved in {0}", @currfile.path) + .catch (e) => @error __("Unable to save zip file: {0}", @currfile.path) + + fileMenuHandle:(id) -> + switch id + when "open" + @openDialog "FileDialog", { title: __("Select a zip file"), mimes: ["application/zip"] } + .then (d) => + @openar(d.file.path.asFileHandle()) + .catch (e) => @error e.toString(), e + when "save" + return @write() if @currfile.path isnt "Untitled" + @saveZipAs() + + when "saveas" + @saveZipAs() + + menu: () -> + [ + { + text: "__(File)", + nodes: [ + { text: "__(New)", id:"new", shortcut: "A-N" }, + { text: "__(Open)", id:"open", shortcut: "A-O"}, + { text: "__(Save)", id:"save", shortcut: "C-S"}, + { text: "__(Save as)", id:"saveas", shortcut: "A-S"} + ], + onchildselect: (e) => @fileMenuHandle e.data.item.data.id + } + ] + + cleanup: (e) -> + return unless @currfile.dirty + e.preventDefault() + @ask { title: "__(Quit)", text: "__(Zip file has been modified. Quit without saving?)" } + .then (d) => + return unless d + @currfile.dirty = false + @quit() + +Archive.dependencies = [ + "os://scripts/jszip.min.js" +] + +this.OS.register "Archive", Archive \ No newline at end of file diff --git a/Archive/css/main.css b/Archive/css/main.css new file mode 100644 index 0000000..9fd300e --- /dev/null +++ b/Archive/css/main.css @@ -0,0 +1,19 @@ +afx-app-window[data-id="Archive"] afx-tree-view .afx-tree-view-folder-close:before{ + content: "\f07b"; + font-family: "FontAwesome"; + color:#76D2F9; + font-size: 16px; +} +afx-app-window[data-id="Archive"] afx-tree-view .afx-tree-view-folder-open:before{ + content: "\f07c"; + font-family: "FontAwesome"; + color:#76D2F9; + font-size: 16px; +} +afx-app-window[data-id="Archive"] afx-tree-view .afx-tree-view-item:before{ + content: "\f016"; + font-family: "FontAwesome"; + font-size: 16px; + font-style: normal; + font-weight: normal; +} diff --git a/Archive/package.json b/Archive/package.json new file mode 100644 index 0000000..3c8e497 --- /dev/null +++ b/Archive/package.json @@ -0,0 +1,15 @@ +{ + "app":"Archive", + "name":"Archive", + "pkgname": "Archive", + "description":"Create of extract zip archive", + "info":{ + "author": "Xuan Sang LE", + "email": "mrsang@lxsang.me" + }, + "version":"0.0.1-a", + "category":"Other", + "iconclass":"fa fa-archive", + "mimes":["application/zip"], + "locale": {} +} \ No newline at end of file diff --git a/Archive/project.json b/Archive/project.json new file mode 100644 index 0000000..6264e0e --- /dev/null +++ b/Archive/project.json @@ -0,0 +1,8 @@ +{ + "name": "Archive", + "root": "home://workspace/antosdk-apps/Archive", + "css": ["css/main.css"], + "javascripts": [], + "coffees": ["coffees/main.coffee"], + "copies": ["assets/scheme.html", "package.json", "README.md"] +} \ No newline at end of file diff --git a/packages.json b/packages.json index 0ff1705..90d8df8 100644 --- a/packages.json +++ b/packages.json @@ -17,6 +17,15 @@ "version": "0.0.6-a", "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/ActivityMonitor/build/release/ActivityMonitor.zip" }, + { + "pkgname": "Archive", + "name": "Archive", + "description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/Archive/README.md", + "category": "Other", + "author": "Xuan Sang LE", + "version": "0.0.1-a", + "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/Archive/build/release/Archive.zip" + }, { "pkgname": "Blogger", "name": "Blogging application",