diff --git a/TODO b/TODO new file mode 100644 index 0000000..09c95db --- /dev/null +++ b/TODO @@ -0,0 +1,3 @@ +VFS mountpoints object (selected) is changed between apps, which is not a good ideal +API handler readfile function return JSON object in reading JSON file, need to be text +Some error in event handle using observable \ No newline at end of file diff --git a/src/core/BaseApplication.coffee b/src/core/BaseApplication.coffee index de53f3c..f00fbd2 100644 --- a/src/core/BaseApplication.coffee +++ b/src/core/BaseApplication.coffee @@ -3,7 +3,6 @@ class BaseApplication extends this.OS.GUI.BaseModel super name, args _OS.setting.applications[@name] = {} if not _OS.setting.applications[@name] @setting = _OS.setting.applications[@name] - init: -> me = @ # first register some base event to the app diff --git a/src/core/BaseDialog.coffee b/src/core/BaseDialog.coffee index 3e8f121..8f7e744 100644 --- a/src/core/BaseDialog.coffee +++ b/src/core/BaseDialog.coffee @@ -179,7 +179,7 @@ class YesNoDialog extends BasicDialog }, { label: "No", onclick: (d) -> - d handler false if dhandler + d.handler false if d.handler d.quit() } ], @@ -234,4 +234,42 @@ class AboutDialog extends BaseDialog rows.push [ { value: k }, { value: v } ] for k, v of mt.info (@find "mygrid").set "rows", rows -this.OS.register "AboutDialog", AboutDialog \ No newline at end of file +this.OS.register "AboutDialog", AboutDialog + +class FileDiaLog extends BaseDialog + constructor: () -> + super "FileDiaLog" + + init: () -> + @render "resources/schemes/filedialog.html" + + main: () -> + fileview = @find "fileview" + location = @find "location" + me = @ + @scheme.set "apptitle", "#{@title}" + fileview.set "fetch", (e, f) -> + return unless e.child + e.child.path.asFileHandler().read (d) -> + return me.error "Resource not found #{e.child.path}" if d.error + f d.result + location.set "onlistselect", (e) -> + return unless e and e.data.path + e.data.path.asFileHandler().read (d) -> + if(d.error) + return me.error "Resource not found #{e.data.path}" + fileview.set "path", e.data.path + fileview.set "data", d.result + location.set "items", ( i for i in @systemsetting.VFS.mountpoints when i.type isnt "app" ) + location.set "selected", 0 unless location.get "selected" + (@find "bt-ok").set "onbtclick", (e) -> + f = fileview.get "selectedFile" + return unless f + return unless f.type is "file" or ( me.data and me.data.seldir ) + me.handler f if me.handler + me.quit() + + (@find "bt-cancel").set "onbtclick", (e) -> + me.quit() + +this.OS.register "FileDiaLog", FileDiaLog \ No newline at end of file diff --git a/src/core/BaseModel.coffee b/src/core/BaseModel.coffee index 63a063d..f07a4d6 100644 --- a/src/core/BaseModel.coffee +++ b/src/core/BaseModel.coffee @@ -3,6 +3,7 @@ class BaseModel @observable = riot.observable() @_api = self.OS.API @_gui = self.OS.GUI + @systemsetting = self.OS.setting me = @ @on "exit", () -> me.quit() @host = "#desktop" diff --git a/src/core/api.coffee b/src/core/api.coffee index 4900ee4..e6e835d 100644 --- a/src/core/api.coffee +++ b/src/core/api.coffee @@ -13,7 +13,7 @@ self.OS.API = url: p, contentType: 'application/json', data: JSON.stringify d, - dataType: 'json', + dataType: 'json', # data type need to be configurable success: null } #$.getJSON p, d @@ -89,7 +89,7 @@ self.OS.API = get: (p, c, f) -> q = _courrier.getMID() _API.loading q, p - $.get p + $.get p # TODO add return type setting support .done (data) -> _API.loaded q, p, "OK" c(data) diff --git a/src/core/core.coffee b/src/core/core.coffee index ea7aa4e..80f4f41 100644 --- a/src/core/core.coffee +++ b/src/core/core.coffee @@ -10,6 +10,7 @@ self.OS or= applications: {} desktop: {} appearance: {} + VFS: {} courrier: observable: riot.observable() quota: 0 diff --git a/src/core/gui.coffee b/src/core/gui.coffee index 19a7fc3..75a5296 100644 --- a/src/core/gui.coffee +++ b/src/core/gui.coffee @@ -61,16 +61,19 @@ self.OS.GUI = _courrier.osfail "Cannot read service script: #{srv} ", e, s appsByMime: (mime) -> - metas = ( a.meta for k, a of _OS.APP when a.type is 1) - mimes = ( m.mimes for m in metas ) + metas = ( a.meta for k, a of _OS.APP when a and a.type is 1) + mimes = ( m.mimes for m in metas when m) apps = [] # search app by mimes f = ( arr, idx ) -> - arr.filter (m, i) -> - if mime.match (new RegExp m, "g") - apps.push metas[idx] + try + arr.filter (m, i) -> + if mime.match (new RegExp m, "g") + apps.push metas[idx] + return false return false - return false + catch e + _courrier.osfail "Find app by mimes #{mime}", e, mime ( f m, i if m ) for m, i in mimes return apps @@ -265,6 +268,14 @@ self.OS.GUI = _OS.setting.applications = conf.applications if conf.applications _OS.setting.appearance = conf.appearance if conf.appearance _OS.setting.user = conf.user + _OS.setting.VFS = conf.VFS if conf.VFS + _OS.setting.VFS.mountpoints = [ #TODO: multi app try to write to this object, it neet to be cloned + { text: "Applications", path: 'app:///', iconclass: "fa fa-adn", type: "app" }, + { text: "Home", path: 'home:///', iconclass: "fa fa-home", type: "fs" }, + { text: "OS", path: 'os:///', iconclass: "fa fa-inbox", type: "fs" }, + { text: "Desktop", path: 'home:///.desktop', iconclass: "fa fa-desktop", type: "fs"}, + ] if not _OS.setting.VFS.mountpoints + _OS.setting.desktop.path = "home:///.desktop" unless _OS.setting.desktop.path _OS.setting.appearance.theme = "antos" unless _OS.setting.appearance.theme # load theme @@ -279,5 +290,5 @@ self.OS.GUI = # startup application here _courrier.observable.one "desktoploaded", () -> - _GUI.launch "DummyApp" - #_GUI.launch "NotePad" \ No newline at end of file + #_GUI.launch "DummyApp" + _GUI.launch "NotePad" \ No newline at end of file diff --git a/src/core/schemes/filedialog.html b/src/core/schemes/filedialog.html new file mode 100644 index 0000000..1d60918 --- /dev/null +++ b/src/core/schemes/filedialog.html @@ -0,0 +1,12 @@ + + + + + +
+ + +
+
+
+
\ No newline at end of file diff --git a/src/core/tags/afx-file-view.js b/src/core/tags/afx-file-view.js index 8b83d5a..64ecd6c 100644 --- a/src/core/tags/afx-file-view.js +++ b/src/core/tags/afx-file-view.js @@ -12,6 +12,7 @@ self.data = opts.data || [] self.path = opts.path || "home:///" self.onfileselect + self.onfileopen this.status = opts.status == undefined?true:opts.status this.selectedFile = undefined this.showhidden = opts.showhidden @@ -182,8 +183,11 @@ $(self.refs.stbar).html("Selected: " + e.data.filename + " (" + e.data.size + " bytes)") }) self.root.observable.on("filedbclick", function(e){ - if(e.id != self.rid || e.data.type == 'file' || !self.chdir) return - self.chdir(e.data.path) + if(e.id != self.rid ) return + if(e.data.type == "file" && self.onfileopen) + self.onfileopen(e.data) + else if(self.chdir) + self.chdir(e.data.path) }) calibre_size() self.root.observable.on("resize", function(e){ diff --git a/src/core/tags/afx-list-view.js b/src/core/tags/afx-list-view.js index 86cf04d..016dfd3 100644 --- a/src/core/tags/afx-list-view.js +++ b/src/core/tags/afx-list-view.js @@ -22,6 +22,7 @@ { if(k == "selected") { + console.log("selected", v) if(self.selidx != -1) self.items[self.selidx].selected =false if(self.items[v]) self.items[v].selected = true @@ -121,6 +122,7 @@ _autoselect(it,i) { if(!it.selected || it.selected == false) return false + //if(self.selidx == i) return false var data = { id:self.rid, data:it, @@ -133,9 +135,11 @@ $(self.refs.mlist).hide() $(self.refs.current).html(it.text) } + if(self.onlistselect) self.onlistselect(data) this.root.observable.trigger('listselect',data) + //console.log("list select") return true } _select(event) diff --git a/src/core/tags/afx-tab-container.js b/src/core/tags/afx-tab-container.js index c28267c..efc7624 100644 --- a/src/core/tags/afx-tab-container.js +++ b/src/core/tags/afx-tab-container.js @@ -4,6 +4,7 @@ var self = this this.closable = opts.closable || false self.root.observable = opts.observable || riot.observable() + self.ontabselect = opts.ontabselect get_observable(){ return self.root.observable } @@ -12,6 +13,9 @@ return self.refs.list.root.get(k) } + self.root.update = function(){ + self.update() + } self.on("mount", function(){ self.refs.list.root.observable = self.root.observable @@ -19,7 +23,10 @@ console.log("list select") })*/ self.refs.list.root.set ("onlistselect",function (e) { + //console.log("tab is seleced") self.root.observable.trigger("tabselect", e) + if(self.ontabselect) + self.ontabselect(e) }) }) @@ -31,6 +38,8 @@ { self.closable = v } + else if(k == "ontabselect") + self.ontabselect = v else { if(k == "items") @@ -56,5 +65,6 @@ { self.refs.list.root.remove(e,u) } + \ No newline at end of file diff --git a/src/packages/Files/main.coffee b/src/packages/Files/main.coffee index beecb0f..bff1737 100644 --- a/src/packages/Files/main.coffee +++ b/src/packages/Files/main.coffee @@ -16,10 +16,12 @@ class Files extends this.OS.GUI.BaseApplication m.set "items", [ me.mnFile(), me.mnEdit() ] m.show(e) #@on "fileselect", (d) -> console.log d - @on "filedbclick", (e) -> - return unless e.data - return if e.data.type is "dir" - me._gui.openWith e.data + @view.set "onfileopen", (e) -> + return unless e + return if e.type is "dir" + #console.log e + me._gui.openWith e + @favo.set "onlistselect", (e) -> me.chdir e.data.path ($ @find "btback").click () -> @@ -34,23 +36,18 @@ class Files extends this.OS.GUI.BaseApplication @view.set "chdir", (p) -> me.chdir p @view.set "fetch", (e, f) -> return unless e.child - me._api.handler.scandir e.child.path, - (d) -> f d.result - , (e, s) -> me.error "Cannot fetch child dir #{e.child.path}" + e.child.path.asFileHandler().read (d) -> + return me.error "Resource not found #{e.child.path}" if d.error + f d.result - @setting.favorite = [ - { text: "Applications", path: 'app:///', iconclass: "fa fa-adn" }, - { text: "Home", path: 'home:///', iconclass: "fa fa-home" }, - { text: "OS", path: 'os:///', iconclass: "fa fa-inbox" }, - { text: "Desktop", path: 'home:///.desktop', iconclass: "fa fa-desktop" }, - ] if not @setting.favorite @setting.sidebar = true if @setting.sidebar is undefined @setting.nav = true if @setting.nav is undefined @setting.showhidden = false if @setting.showhidden is undefined - el.selected = false for el, i in @setting.favorite + mntpoints = @systemsetting.VFS.mountpoints + el.selected = false for el, i in mntpoints - @favo.set "items", @setting.favorite + @favo.set "items", mntpoints #@favo.set "selected", -1 @applySetting() @chdir null diff --git a/src/packages/NotePad/main.coffee b/src/packages/NotePad/main.coffee index f3d1238..f70c638 100644 --- a/src/packages/NotePad/main.coffee +++ b/src/packages/NotePad/main.coffee @@ -9,7 +9,7 @@ class NotePad extends this.OS.GUI.BaseApplication @fileview = @find "fileview" div = @find "datarea" ace.require "ace/ext/language_tools" - @currfile = if @args and @args.length > 0 then @args[0].asFileHandler() else undefined + @currfile = if @args and @args.length > 0 then @args[0].asFileHandler() else "Untitled".asFileHandler() @.editor = ace.edit div @.editor.setOptions { enableBasicAutocompletion: true, @@ -20,16 +20,19 @@ class NotePad extends this.OS.GUI.BaseApplication @.editor.completers.push { getCompletions: ( editor, session, pos, prefix, callback ) -> } @.editor.getSession().setUseWrapMode true - list = @find "modelist" + @mlist = @find "modelist" @modes = ace.require "ace/ext/modelist" ldata = [] - ldata.push { - text: m.name, - mode: m.mode, - selected: if m.mode is 'ace/mode/text' then true else false - } for m in @modes.modes - list.set "items", ldata - list.set "onlistselect", (e) -> + f = (m, i) -> + ldata.push { + text: m.name, + mode: m.mode, + selected: if m.mode is 'ace/mode/text' then true else false + } + m.idx = i + f(m, i) for m, i in @modes.modes + @mlist.set "items", ldata + @mlist.set "onlistselect", (e) -> me.editor.session.setMode e.data.mode themelist = @find "themelist" @@ -52,6 +55,15 @@ class NotePad extends this.OS.GUI.BaseApplication $(stat).html "Row #{c.row}, col #{c.column}, lines: #{l}" stup(0) @.editor.getSession().selection.on "changeCursor", (e) -> stup(e) + @editormux = false + @editor.on "input", () -> + if me.editormux + me.editormux = false + return false + if not me.currfile.dirty + me.currfile.dirty = true + me.currfile.text += "*" + me.tabarea.update() @on "resize", () -> me.editor.resize() @on "focus", () -> me.editor.focus() @@ -59,39 +71,89 @@ class NotePad extends this.OS.GUI.BaseApplication @fileview.set "chdir", (d) -> me.chdir d @fileview.set "fetch", (e, f) -> return unless e.child - me._api.handler.scandir e.child.path, - (d) -> f d.result - , (e, s) -> me.error "Cannot fetch child dir #{e.child.path}" - + e.child.path.asFileHandler().read (d) -> + return me.error "Resource not found #{e.child.path}" if d.error + f d.result + @fileview.set "onfileopen", (e) -> + me.open e.path.asFileHandler() @location.set "onlistselect", (e) -> me.chdir e.data.path - @location.set "items", [ - { text: "Home", path: 'home:///', iconclass: "fa fa-home", selected: true }, - { text: "OS", path: 'os:///', iconclass: "fa fa-inbox" }, - { text: "Desktop", path: 'home:///.desktop', iconclass: "fa fa-desktop" }, - ] - + @location.set "items", ( i for i in @systemsetting.VFS.mountpoints when i.type isnt "app" ) + @location.set "selected", 0 unless @location.get "selected" @tabarea = @find "tabarea" + @tabarea.set "ontabselect", (e) -> + me.selecteTab e.idx + @tabarea.set "onitemclose", (e) -> + it = e.item.item + return false unless it + return me.closeTab it unless it.dirty + me.openDialog "YesNoDialog", (d) -> + return me.closeTab it if d + me.editor.focus() + , "Close tab", { text: "Close without saving ?" } + return false #@tabarea.set "closable", true @open @currfile open: (file) -> #find table - @newtab "undefined".asFileHandler() unless file - return @newtab "undefined".asFileHandler() unless file + i = @findTabByFile file + return @tabarea.set "selected", i if i isnt -1 + return @newtab file if file.path.toString() is "Untitled" me = @ - file.read (d) -> - return unless d + file.read (_d) -> + d = if typeof _d is "string" then _d else JSON.stringify _d me.scheme.set "apptitle", file.basename - file.cache = d + file.cache = d or "" me.newtab file - newtab: (file) -> - file.text = if file.basename then file.basename else "undefined" - file.cache = "" unless file.cache + findTabByFile: (file) -> + lst = @tabarea.get "items" + its = ( i for d, i in lst when d.hash() is file.hash() ) + return -1 if its.length is 0 + return its[0] + + closeTab: (it) -> + @tabarea.remove it, false cnt = @tabarea.get "count" + if cnt is 0 + @open "Untitled".asFileHandler() + return false + @tabarea.set "selected", cnt - 1 + return false + + newtab: (file) -> + file.text = if file.basename then file.basename else file.path + file.cache = "" unless file.cache + file.um = new ace.UndoManager() + @currfile.selected = false + file.selected = true + #console.log cnt @tabarea.push file, true - @tabarea.set "selected", cnt + #@currfile = @file + #TODO: fix problem : @tabarea.set "selected", cnt + + selecteTab: (i) -> + #return if i is @tabarea.get "selidx" + file = (@tabarea.get "items")[i] + return unless file + #return if file is @currfile + if @currfile isnt file + @currfile.cache = @editor.getValue() + @currfile.cursor = @editor.selection.getCursor() + @currfile = file + + m = "ace/mode/text" + m = (@modes.getModeForPath file.path) if file.path.toString() isnt "Untitled" + @mlist.set "selected", m.idx + + @editormux = true @editor.setValue file.cache, -1 + @editor.session.setMode m.mode + @editor.session.setUndoManager file.um + if file.cursor + @editor.renderer.scrollCursorIntoView { row: file.cursor.row, column: file.cursor.column }, 0.5 + @editor.selection.moveTo file.cursor.row, file.cursor.column + @editor.focus() chdir: (p) -> me = @ @@ -104,14 +166,22 @@ class NotePad extends this.OS.GUI.BaseApplication , (e, s) -> me.error "Cannot chdir #{p}" - menu: ()-> + menu: () -> + me = @ menu = [{ text: "File", child: [ { text: "Open", dataid: "#{@name}-Open" }, { text: "Close", dataid: "#{@name}-Close" } - ] + ], + onmenuselect: (e) -> me.actionFile e }] menu + + actionFile: (e) -> + switch e.item.data.dataid + when "#{@name}-Open" + @openDialog "FileDiaLog", null, "Select file", { seldir: true } + NotePad.singleton = false this.OS.register "NotePad", NotePad \ No newline at end of file