From 15f1fb45ebbaec003340bd21210222914d5c5378 Mon Sep 17 00:00:00 2001 From: Xuan Sang LE Date: Thu, 25 Jan 2018 19:15:41 +0100 Subject: [PATCH] vfs (contd.) --- src/core/BaseDialog.coffee | 39 ++++++++- src/core/BaseModel.coffee | 3 +- src/core/api.coffee | 57 +++++++++++- src/core/gui.coffee | 1 - src/core/handlers/RemoteHandler.coffee | 22 ++++- src/core/vfs.coffee | 23 ++++- .../CoreServices/PushNotification.coffee | 2 +- src/packages/Files/main.coffee | 86 ++++++++++++++++--- 8 files changed, 212 insertions(+), 21 deletions(-) diff --git a/src/core/BaseDialog.coffee b/src/core/BaseDialog.coffee index 45bb6b0..9ee7357 100644 --- a/src/core/BaseDialog.coffee +++ b/src/core/BaseDialog.coffee @@ -40,11 +40,12 @@ this.OS.GUI.BaseDialog = BaseDialog } ### class BasicDialog extends BaseDialog - constructor: ( name, @conf ) -> + constructor: ( name, @conf, @title) -> super name init: () -> - html = " + @title = @name if not @title + html = " " html += "<#{@conf.tag} #{@conf.att} data-id = 'content'>" html += "
" @@ -70,6 +71,7 @@ class PromptDialog extends BasicDialog tag: "input", width: 200, height: 90, + att: "type = 'text'" resizable: false, buttons: [ { @@ -86,7 +88,8 @@ class PromptDialog extends BasicDialog } ], filldata: (d) -> - d.scheme.set "apptitle", d.data if d.data + return unless d.data + (d.find "content").value = d.data } this.OS.register "PromptDialog", PromptDialog @@ -156,10 +159,38 @@ class InfoDialog extends BasicDialog rows = [] rows.push [ { value: k }, { value: v } ] for k, v of d.data (d.find "content").set "rows", rows - d.scheme.set "apptitle", d.data.filename } this.OS.register "InfoDialog", InfoDialog + +class YesNoDialog extends BasicDialog + constructor: () -> + super "YesNoDialog", { + tag: "afx-label", + width: 300, + height: 100, + att:"style = 'padding:10px;'" + resizable: true, + buttons: [ + { + label: "Yes", onclick: (d) -> + d.handler true if d.handler + d.quit() + }, + { + label: "No", onclick: (d) -> + d handler false if dhandler + d.quit() + } + ], + filldata: (d) -> + return unless d.data + l = d.find "content" + for k, v of d.data + l.set k, v + } +this.OS.register "YesNoDialog", YesNoDialog + class AboutDialog extends BaseDialog constructor: () -> super "AboutDialog" diff --git a/src/core/BaseModel.coffee b/src/core/BaseModel.coffee index 1064906..0682858 100644 --- a/src/core/BaseModel.coffee +++ b/src/core/BaseModel.coffee @@ -31,7 +31,7 @@ class BaseModel subscribe: (e, f) -> _courrier.on e, f, @ - openDialog: (d, f, data) -> + openDialog: (d, f, title, data) -> if @dialog @dialog.show() return @@ -43,6 +43,7 @@ class BaseModel @dialog.handler = f @dialog.pid = @pid @dialog.data = data + @dialog.title = title @dialog.init() publish: (t, m) -> diff --git a/src/core/api.coffee b/src/core/api.coffee index b8f7bb0..9897c89 100644 --- a/src/core/api.coffee +++ b/src/core/api.coffee @@ -23,6 +23,61 @@ self.OS.API = .fail (e, s) -> _API.loaded q, p, "FAIL" f(e, s) + + blob: (p, c, f) -> + q = _courrier.getMID() + r = new XMLHttpRequest() + r.open "GET", p, true + r.responseType = "arraybuffer" + + r.onload = (e) -> + if @status is 200 and @readyState is 4 + c @response + _API.loaded q, p, "OK" + else + f e, @ + _API.loaded q, p, "FAIL" + + _API.loading q, p + r.send() + + upload: (p, d, c, f) -> + q = _courrier.getMID() + #insert a temporal file selector + o = ($ '').attr('type', 'file').css("display", "none") + o.change () -> + _API.loading q, p + formd = new FormData() + formd.append 'path', d + # TODO: only one file is selected at this time + formd.append 'upload', o[0].files[0] + + $.ajax { + url: p, + data: formd, + type: 'POST', + contentType: false, + processData: false, + } + .done (data) -> + _API.loaded q, p, "OK" + c(data) + .fail (e, s) -> + _API.loaded q, p, "FAIL" + f(e, s) + + o.click() + + saveblob: (name, b) -> + url = window.URL.createObjectURL b + o = ($ '') + .attr("href", url) + .attr("download", name) + .css("display", "none") + .appendTo("body") + o[0].click() + window.URL.revokeObjectURL(url) + o.remove() systemConfig: -> _API.request 'config', (result) -> @@ -54,7 +109,7 @@ self.OS.API = resource: (r, c, f) -> path = "resources/#{r}" _API.get path, c, f - + throwe: (n) -> err = undefined try diff --git a/src/core/gui.coffee b/src/core/gui.coffee index b9af0ab..cf267db 100644 --- a/src/core/gui.coffee +++ b/src/core/gui.coffee @@ -156,7 +156,6 @@ self.OS.GUI = username: ($ "#txtuser").val(), password: ($ "#txtpass").val() _API.handler.login data, (d) -> - console.log d if d.error then ($ "#login_error").html d.error else _GUI.startAntOS d.result , (e, s) -> alert "System fall: Cannot init login screen" diff --git a/src/core/handlers/RemoteHandler.coffee b/src/core/handlers/RemoteHandler.coffee index 5f7d550..1ac7d1f 100644 --- a/src/core/handlers/RemoteHandler.coffee +++ b/src/core/handlers/RemoteHandler.coffee @@ -16,7 +16,27 @@ self.OS.API.handler = readfile: (p, c) -> path = "lua-api/fs/get/" _API.get path + p, c, (e, s) -> - _courrier.osfail "Fail to read file: #{p}",e , s + _courrier.osfail "Fail to read file: #{p}", e, s + + move: (s, d, c) -> + path = "lua-api/fs/move" + _API.post path, { src: s, dest: d }, c, (e, s) -> + _courrier.osfail "Fail to move file: #{s} -> #{d}", e, s + + delete: (p , c) -> + path = "lua-api/fs/delete" + _API.post path, { path: p }, c, (e, s) -> + _courrier.osfail "Fail to delete: #{p}", e, s + + fileblob: (p, c) -> + path = "lua-api/fs/get/" + _API.blob path + p, c, (e, s) -> + _courrier.osfail "Fail to read file: #{p}", e, s + + upload: (d, c) -> + path = "lua-api/fs/upload" + _API.upload path, d, c, (e, s) -> + _courrier.osfail "Fail to upload file to: #{d}", e, s write: (p, d , c) -> path = "lua-api/fs/write" diff --git a/src/core/vfs.coffee b/src/core/vfs.coffee index e2a950d..cf71497 100644 --- a/src/core/vfs.coffee +++ b/src/core/vfs.coffee @@ -64,9 +64,17 @@ class BasicFileHandler me = @ @onready (() -> me.action "remove", null, f) + upload: (f) -> + me = @ + @onready (() -> me.action "upload", null, f) + + download: (f) -> + me = @ + @onready (() -> me.action "download", null, f) + move: (d, f) -> me = @ - @onready (() -> me action "move", d, f) + @onready (() -> me.action "move", d, f) execute: (f) -> me = @ @@ -93,6 +101,7 @@ class RemoteFileHandler extends self.OS.API.VFS.BasicFileHandler _API.handler.fileinfo @path, f action: (n, p, f) -> + me = @ switch n when "read" return _API.handler.scandir @path, f if @meta.type is "dir" @@ -103,6 +112,18 @@ class RemoteFileHandler extends self.OS.API.VFS.BasicFileHandler _API.handler.mkdir "#{@path}/#{p}", f when "write" _API.handler.write @path, p, f + when "upload" + return if @meta.type is "file" + _API.handler.upload @path, f + when "remove" + _API.handler.delete @path, f + when "download" + return if @meta.type is "dir" + _API.handler.fileblob @path, (d) -> + blob = new Blob [d], { type: "octet/stream" } + _API.saveblob me.basename, blob + when "move" + _API.handler.move @path, p, f else return _courrier.osfail "VFS unknown action: #{n}", (_API.throwe "OS.VFS"), n diff --git a/src/packages/CoreServices/PushNotification.coffee b/src/packages/CoreServices/PushNotification.coffee index fc7fc04..547b7bf 100644 --- a/src/packages/CoreServices/PushNotification.coffee +++ b/src/packages/CoreServices/PushNotification.coffee @@ -55,7 +55,7 @@ class PushNotification extends this.OS.GUI.BaseService pushout: (s, o, mfeed) -> d = { - text: "[#{s}] #{o.name} (#{o.id}): #{o.data.m} : #{o.data.e}", + text: "[#{s}] #{o.name} (#{o.id}): #{o.data.m}", icon: o.data.icon, iconclass: o.data.iconclass, closable: true } diff --git a/src/packages/Files/main.coffee b/src/packages/Files/main.coffee index 0668b0d..263bb4a 100644 --- a/src/packages/Files/main.coffee +++ b/src/packages/Files/main.coffee @@ -10,6 +10,7 @@ class Files extends this.OS.GUI.BaseApplication @navbar = @find "nav-bar" @currdir = undefined @favo = @find "favouri" + @clipboard = undefined @view.contextmenuHandler = (e, m) -> m.set "items", [ me.mnFile(), me.mnEdit() ] @@ -61,8 +62,8 @@ class Files extends this.OS.GUI.BaseApplication if(d.error) return me.error "Resource not found #{p}" me.currdir = dir - ($ me.navinput).val p - me.view.set "path", p + ($ me.navinput).val dir.path + me.view.set "path", dir.path me.view.set "data", d.result mnFile:() -> @@ -72,7 +73,10 @@ class Files extends this.OS.GUI.BaseApplication child: [ { text: "New file", dataid: "#{@name}-mkf" }, { text: "New folder", dataid: "#{@name}-mkdir" }, - { text: "Upload", dataid: "#{@name}-upload" } + { text: "Open with", dataid: "#{@name}-open" }, + { text: "Upload", dataid: "#{@name}-upload" }, + { text: "Download", dataid: "#{@name}-download" }, + { text: "Properties", dataid: "#{@name}-info" } ], onmenuselect: (e) -> me.actionFile e } mnEdit: () -> @@ -82,9 +86,9 @@ class Files extends this.OS.GUI.BaseApplication child: [ { text: "Rename", dataid: "#{@name}-mv" }, { text: "Delete", dataid: "#{@name}-rm" }, - { text: "Information", dataid: "#{@name}-info" }, - { text: "Open with", dataid: "#{@name}-open" }, - { text: "Download", dataid: "#{@name}-download" }, + { text: "Cut", dataid: "#{@name}-cut" }, + { text: "Copy", dataid: "#{@name}-copy" }, + { text: "Paste", dataid: "#{@name}-paste" } ], onmenuselect: (e) -> me.actionEdit e } menu: () -> @@ -138,30 +142,90 @@ class Files extends this.OS.GUI.BaseApplication #@toggleNav e.item.data.checked actionEdit: (e) -> + me = @ + file = @view.get "selectedFile" switch e.item.data.dataid - when "#{@name}-info" - file = @view.get "selectedFile" + when "#{@name}-mv" return unless file - @openDialog "InfoDialog", null, file + @openDialog "PromptDialog", + (d) -> + return if d is file.filename + file.path.asFileHandler() + .move "#{me.currdir.path}/#{d}", (r) -> + if r.result then me.chdir null else me.error "Fail to rename to #{d}: #{r.error}" + , "Rename", file.filename + + when "#{@name}-rm" + return unless file + @openDialog "YesNoDialog", + (d) -> + return unless d + file.path.asFileHandler() + .remove (r) -> + if r.result then me.chdir null else me.error "Fail to delete #{file.filename}: #{r.error}" + , "Delete" , + { iconclass: "fa fa-question-circle", text: "Do you really want to delete: #{file.filename} ?" } + + when "#{@name}-cut" + return unless file + @clipboard = + cut: true + file: file.path.asFileHandler() + @notify "File #{file.filename} cut" + + when "#{@name}-copy" + return unless file + @clipboard = + cut: false + file: file.path.asFileHandler() + @notify "File #{file.filename} copied" + + when "#{@name}-paste" + me = @ + return unless @clipboard + if @clipboard.cut + @clipboard.file # duplicate file check + .move "#{me.currdir.path}/#{@clipboard.file.basename}", (r) -> + me.clipboard = undefined + if r.result then me.chdir null else me.error "Fail to paste: #{r.error}" + else + @notify "Copy not yet implemented" + @clipboard = undefined else @_api.handler.setting() actionFile: (e) -> me = @ + file = @view.get "selectedFile" switch e.item.data.dataid + when "#{@name}-mkdir" @openDialog "PromptDialog", (d) -> me.currdir.mk d, (r) -> - if r.result then me.chdir null else me.error "Fail to create #{d}" + if r.result then me.chdir null else me.error "Fail to create #{d}: #{r.error}" , "New folder" + when "#{@name}-mkf" @openDialog "PromptDialog", (d) -> fp = "#{me.currdir.path}/#{d}".asFileHandler() fp.write "", (r) -> - if r.result then me.chdir null else me.error "Fail to create #{d}" + if r.result then me.chdir null else me.error "Fail to create #{d}: #{r.error}" , "New file" + + when "#{@name}-info" + return unless file + @openDialog "InfoDialog", null, file.filename, file + + when "#{@name}-upload" + me = @ + @currdir.upload (r) -> + if r.result then me.chdir null else me.error "Faile to upload to: #{d}: #{r.error}" + + when "#{@name}-download" + return unless file + file.path.asFileHandler().download ()-> else console.log e