From 9924c642c5a887d99c832ed1d61badc7f414da97 Mon Sep 17 00:00:00 2001 From: lxsang Date: Sun, 5 Apr 2020 22:51:31 +0200 Subject: [PATCH] add tree-view --- Makefile | 1 + src/core/tags/ListViewTag.coffee | 53 ++++--- src/core/tags/MenuTag.coffee | 109 +++++++------ src/core/tags/TreeViewTag.coffee | 181 ++++++++++++++++++++++ src/packages/ShowCase/coffees/main.coffee | 43 ++++- 5 files changed, 308 insertions(+), 79 deletions(-) create mode 100644 src/core/tags/TreeViewTag.coffee diff --git a/Makefile b/Makefile index f80c9d9..ca4da96 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,7 @@ coffees= src/core/core.coffee \ src/core/tags/MenuTag.coffee \ src/core/tags/GridView.coffee \ src/core/tags/TabBarTag.coffee \ + src/core/tags/TreeViewTag.coffee \ src/antos.coffee diff --git a/src/core/tags/ListViewTag.coffee b/src/core/tags/ListViewTag.coffee index 469f274..7a73348 100644 --- a/src/core/tags/ListViewTag.coffee +++ b/src/core/tags/ListViewTag.coffee @@ -11,10 +11,15 @@ class ListViewItemTag extends Ant.OS.GUI.BaseTag @setopt "index", 0 @setopt "closable", false @setopt "selected", false - -class SimpleListItemTag extends ListViewItemTag - constructor: (r, o) -> - super r, o + __closable__: (v) -> + if v then $(@refs.btcl).show() else $(@refs.btcl).hide() + + __selected__: (v) -> + $(@refs.item).removeClass() + return unless v + $(@refs.item).addClass "selected" + @get("onselect")({ item: @root }) + mount: () -> me = @ $(@refs.item).contextmenu (e) -> @@ -31,15 +36,19 @@ class SimpleListItemTag extends ListViewItemTag $(@refs.btcl).click (e) -> e.item = me.root me.get("onclose")(e) + layout: () -> + [{ + el: "li", ref: "item", children: [ + @itemlayout(), + { el: "i", class: "closable", ref: "btcl" } + ] + }] + + itemlayout: () -> - __closable__: (v) -> - if v then $(@refs.btcl).show() else $(@refs.btcl).hide() - - __selected__: (v) -> - $(@refs.item).removeClass() - return unless v - $(@refs.item).addClass "selected" - @get("onselect")({ item: @root }) +class SimpleListItemTag extends ListViewItemTag + constructor: (r, o) -> + super r, o __data__: (v) -> return unless v @@ -51,14 +60,8 @@ class SimpleListItemTag extends ListViewItemTag @set "selected", v.selected if v.selected @set "closable", v.closable if v.closable - layout: () -> - [{ - el: "li", ref: "item", children: [ - { el: "afx-label", ref: "label" }, - { el: "i", class: "closable", ref: "btcl" } - ] - }] - + itemlayout: () -> + { el: "afx-label", ref: "label" } class ListViewTag extends Ant.OS.GUI.BaseTag constructor: (r, o) -> @@ -104,11 +107,11 @@ class ListViewTag extends Ant.OS.GUI.BaseTag el[0] .set "data", item .set "oncontextmenu", (e) -> - me.iclick e + me.iclick e, true .set "ondbclick", (e) -> - me.idbclick e + me.idbclick e, false .set "onclick", (e) -> - me.iclick e + me.iclick e, false .set "onselect", (e) -> me.iselect e .set "onclose", (e) -> @@ -132,10 +135,10 @@ class ListViewTag extends Ant.OS.GUI.BaseTag for item in data @push item, false - iclick: (e) -> + iclick: (e, flag) -> return if not e.item list = @get("selectedItems") - if @multiselect() and list.includes(e.item) + if @multiselect() and list.includes(e.item) and not flag list.splice(list.indexOf(e.item), 1) return e.item.set "selected", false e.item.set "selected", true diff --git a/src/core/tags/MenuTag.coffee b/src/core/tags/MenuTag.coffee index 68c34ed..e316542 100644 --- a/src/core/tags/MenuTag.coffee +++ b/src/core/tags/MenuTag.coffee @@ -22,6 +22,57 @@ class MenuEntryTag extends Ant.OS.GUI.BaseTag is_root: () -> return if @get "parent" then false else true + + layout: () -> + [{ + el: "li", ref: "container", children: [ + { + el: "a", ref: "entry", children: @itemlayout() + }, + { el: "afx-menu", ref: "submenu" } + ] + }] + __children__: (v) -> + me = @ + $(@refs.container).removeClass("afx_submenu") + return $(@refs.submenu).hide() unless v and v.length > 0 + $(@refs.container).addClass("afx_submenu") + $(@refs.submenu) + .show() + .attr("style", "") + @refs.submenu.set "parent", @ + @refs.submenu.set "root", me.get("root") + @refs.submenu.set "items", v + if @is_root() + $(@refs.container).mouseleave (e) -> + $(me.refs.submenu).attr("style", "") + + mount: () -> + me = @ + @refs.switch.set "enable", false + $(@refs.entry).click (e) -> me.select e + + submenuoff: () -> + p = @get "parent" + return $(@refs.submenu).attr("style", "") unless p + p.submenuoff() + + select: (e) -> + me = @ + e.item = @root + evt = { id: @aid(), data: e } + e.preventDefault() + if @is_root() and @has_children() and not @get "context" + $(@refs.submenu).show() + else + @submenuoff() + @get("onmenuselect") evt + if @get("parent") + @get("parent").get("onchildselect") evt + if @get("root") + @get("root").get("onmenuitemselect") evt + + itemlayout: () -> class SimpleMenuEntryTag extends MenuEntryTag constructor: (r, o) -> @@ -75,31 +126,6 @@ class SimpleMenuEntryTag extends MenuEntryTag $(@refs.shortcut).show() $(@refs.shortcut).val v - __children__: (v) -> - me = @ - $(@refs.container).removeClass("afx_submenu") - return $(@refs.submenu).hide() unless v and v.length > 0 - $(@refs.container).addClass("afx_submenu") - $(@refs.submenu) - .show() - .attr("style", "") - @refs.submenu.set "parent", @ - @refs.submenu.set "root", me.get("root") - @refs.submenu.set "items", v - if @is_root() - $(@refs.container).mouseleave (e) -> - $(me.refs.submenu).attr("style", "") - - mount: () -> - me = @ - @refs.switch.set "enable", false - $(@refs.entry).click (e) -> me.select e - - submenuoff: () -> - p = @get "parent" - return $(@refs.submenu).attr("style", "") unless p - p.submenuoff() - reset_radio: () -> return unless @has_children() for v in @get "children" @@ -108,39 +134,20 @@ class SimpleMenuEntryTag extends MenuEntryTag select: (e) -> - me = @ - e.item = @root - evt = { id: @aid(), data: e } - e.preventDefault() - if @is_root() and @has_children() and not @get "context" - $(@refs.submenu).show() - else - @submenuoff() + super.select(e) if @get "switch" @set "checked", !@get "checked" else if @get "radio" p = @get "parent" p.reset_radio() if p @set "checked", !@get "checked" - @get("onmenuselect") evt - if @get("parent") - @get("parent").get("onchildselect") evt - if @get("root") - @get("root").get("onmenuitemselect") evt - layout: () -> - [{ - el: "li", ref: "container", children: [ - { - el: "a", ref: "entry", children: [ - { el: "afx-switch", ref: "switch" }, - { el: "afx-label", ref: "label" }, - { el: "span", class: "shortcut", ref: "shortcut" } - ] - }, - { el: "afx-menu", ref: "submenu" } - ] - }] + itemlayout: () -> + [ + { el: "afx-switch", ref: "switch" }, + { el: "afx-label", ref: "label" }, + { el: "span", class: "shortcut", ref: "shortcut" } + ] class MenuTag extends Ant.OS.GUI.BaseTag constructor: (r, o) -> diff --git a/src/core/tags/TreeViewTag.coffee b/src/core/tags/TreeViewTag.coffee new file mode 100644 index 0000000..d949445 --- /dev/null +++ b/src/core/tags/TreeViewTag.coffee @@ -0,0 +1,181 @@ +class TreeViewItemPrototype extends Ant.OS.GUI.BaseTag + constructor: (r, o) -> + super r, o + @setopt "data", undefined + @setopt "nodes", [] + @setopt "treeroot", undefined + @setopt "indent", 0 + @setopt "toggle", false + @setopt "fetch", undefined + @setopt "open", true + @setopt "itemindex", 0 + @setopt "selected", false + @setopt "treepath", @aid() + + __data__: (v) -> + return unless v + @set "nodes", v.nodes if v.nodes + + __selected__: (v) -> + return $(@refs.wrapper).addClass("afx_tree_item_selected") if v + $(@refs.wrapper).removeClass("afx_tree_item_selected") + + __open__: (v) -> + $(@refs.toggle) + .removeClass() + return unless @is_folder() + if(v) + $(@refs.childnodes).show() + else + $(@refs.childnodes).hide() + return $(@refs.toggle).addClass "afx-tree-view-folder-open" if v + $(@refs.toggle).addClass "afx-tree-view-folder-close" + + __itemindex__: (v) -> + return unless v + $(@refs.wrapper).addClass "afx_tree_item_odd" if v % 2 isnt 0 + + __indent__: (v) -> + return unless v + $(@refs.padding) + .css("display", "inline-block") + .css("height", "1px") + .css("padding", 0) + .css("margin", 0) + .css("background-color", "transparent") + .css("width", v * 15 + "px" ) + + is_folder: () -> + return @get("nodes") and @get("nodes").length > 0 + + + __nodes__: (nodes) -> + return unless @get("nodes") and @get("nodes").length > 0 + $(@refs.childnodes).empty() + $(@refs.wrapper).addClass("afx_folder_item") + root = @get("treeroot") + for v in nodes + el = $("").appendTo @refs.childnodes + el[0].uify undefined + el[0].set "treeroot", @get("treeroot") + el[0].set "indent", (@get("indent") + 1) + root.indexcounter++ + el[0].set "itemindex", root.indexcounter + el[0].set "treepath", "#{@get("treepath")}/#{el[0].aid()}" + el[0].set "data", v + + + mount: () -> + me = @ + super.mount() + $(@refs.container) + .css "padding", 0 + .css "margin", 0 + .css "white-space", "nowrap" + $(@refs.itemholder) + .css "display", "inline-block" + $(@refs.wrapper) + .click (e) -> + e.item = me.root + me.get("treeroot").itemclick e, false + $(@refs.wrapper) + .dblclick (e) -> + e.item = me.root + me.get("treeroot").itemclick e, true + + $(@refs.toggle) + .css "display", "inline-block" + .css "width", "15px" + .click (e) -> + me.set "open", not me.get("open") + e.preventDefault() + e.stopPropagation() + + + layout: () -> + [ { + el: "div", ref: "wrapper", children: [ + { + el: "ul", ref: "container", children: [ + { el: "li", ref: "padding" }, + { el: "li", ref: "toggle" } + { el: "li", ref: "itemholder", class: "itemname", children: @itemlayout() } + ] + } + ] }, + { + el: "ul", ref: "childnodes" + } + ] + + itemlayout: () -> + +class SimpleTreeViewItem extends TreeViewItemPrototype + constructor: (r, o) -> + super r, o + + + __data__: (v) -> + return unless v + super.__data__(v) + @refs.label.set "color", v.color if v.color + @refs.label.set "text", v.name if v.name + @refs.label.set "icon", v.icon if v.icon + @refs.label.set "iconclass", v.iconclass if v.iconclass + + itemlayout: () -> + [{ el: "afx-label", ref: "label" }] + + +class TreeViewTag extends Ant.OS.GUI.BaseTag + constructor: (r, o) -> + super r, o + @setopt "itemtag", "afx-tree-view-item" + @setopt "data", undefined + @setopt "treeroot", undefined + @setopt "parent", undefined + @setopt "indent", 0 + @setopt "open", true + @setopt "itemindex", 0 + @setopt "ontreeselect", () -> + @setopt "ontreedbclick", () -> + @setopt "selectedItem", undefined + @setopt "treepath", @aid() + @indexcounter = 0 + + __selectedItem__: (v) -> + return unless v + v.set "selected", true + + itemclick: (e, flag) -> + return unless e and e.item + return if e.item is @get("selectedItem") and not flag + @get("selectedItem").set "selected", false if @get("selectedItem") + @set "selectedItem", e.item + evt = { id: @aid(), data: e } + if flag + console.log "dblclick" + @get("ontreedbclick") evt + @observable.trigger "treedbclick", evt + else + @get("ontreeselect") evt + @observable.trigger "treeselect", evt + + is_root: () -> + return @get("treeroot") is undefined + + __data__: (v) -> + return unless v + $(@root).empty() + el = $("<#{@get "itemtag"}>").appendTo @root + el[0].uify undefined + el[0].set "treeroot", if @is_root() then @ else @get "treeroot" + el[0].set "indent", @get("indent") + el[0].set "itemindex", @get "itemindex" + el[0].set "treepath", @get("treepath") + el[0].set "data", v + el[0].set "open", @get("open") + +Ant.OS.GUI.define "afx-tree-view", TreeViewTag +Ant.OS.GUI.define "afx-tree-view-item-proto", TreeViewItemPrototype +Ant.OS.GUI.define "afx-tree-view-item", SimpleTreeViewItem \ No newline at end of file diff --git a/src/packages/ShowCase/coffees/main.coffee b/src/packages/ShowCase/coffees/main.coffee index a938abe..93d03e9 100644 --- a/src/packages/ShowCase/coffees/main.coffee +++ b/src/packages/ShowCase/coffees/main.coffee @@ -41,9 +41,8 @@ class ShowCase extends this.OS.GUI.BaseApplication -
box 2
-
box 2
-
+ + @@ -155,6 +154,44 @@ class ShowCase extends this.OS.GUI.BaseApplication [{ text: "text 7" }, { text: "text 8" }, { text: "text 9" }] ] + tdata = { + name: 'My Tree', + nodes: [ + { name: 'hello', iconclass:'fa fa-car'}, + { name: 'wat' }, + { + name: 'child folder', + nodes: [ + { + name: 'child folder', + nodes: [ + { name: 'hello' }, + { name: 'wat' } + ] + }, + { name: 'hello' }, + { name: 'wat' }, + { + name: 'child folder', + nodes: [ + { name: 'hello' }, + { name: 'wat' } + ] + } + ] + } + ] + } + + tree = $ "[data-id='tree']", scheme[0] + tree[0].set "data", tdata + tree[0].set "ontreeselect", (e) -> + console.log e.data.item.get "treepath" + tree[0].set "ontreedbclick", (e) -> + console.log "treedbclick", e + me.subwin.observable.on "treedbclick", (e) -> + console.log "observable treedbclick", e + mnFile: () -> #console.log file me = @