|
|
- /**
- _enyo.Node_ is a control that creates structured trees based on Enyo's child
- component hierarchy format, e.g.:
-
- {kind: "Node", icon: "images/folder-open.png", content: "Tree",
- expandable: true, expanded: true, components: [
- {icon: "images/file.png", content: "Alpha"},
- {icon: "images/folder-open.png", content: "Bravo",
- expandable: true, expanded: false, components: [
- {icon: "images/file.png", content: "Bravo-Alpha"},
- {icon: "images/file.png", content: "Bravo-Bravo"},
- {icon: "images/file.png", content: "Bravo-Charlie"}
- ]
- }
- ]
- }
-
- The default kind of components within a node is itself _enyo.Node_, so only
- the top-level node of the tree needs to be explicitly defined as such.
-
- When an expandable tree node expands, an _onExpand_ event is sent; when it
- is tapped, a _nodeTap_ event is sent.
-
- When the optional property _onlyIconExpands_ is set to true, expandable
- nodes may only be opened by tapping the icon; tapping the content label
- will fire the _nodeTap_ event, but will not expand the node.
- */
-
- enyo.kind({
- name: "enyo.Node",
- published: {
- //* @public
- //* Whether or not the Node is expandable and has child branches
- expandable: false,
- //* Open/closed state of the current Node
- expanded: false,
- //* Path to image to be used as the icon for this Node
- icon: "",
- /**
- Optional flag that, when true, causes the Node to expand only when
- the icon is tapped; not when the contents are tapped
- */
- onlyIconExpands: false,
- //* @protected
- //* Adds or removes the Enyo-selected CSS class.
- selected: false
- },
- style: "padding: 0 0 0 16px;",
- content: "Node",
- defaultKind: "Node",
- classes: "enyo-node",
- components: [
- {name: "icon", kind: "Image", showing: false},
- {kind: "Control", name: "caption", Xtag: "span", style: "display: inline-block; padding: 4px;", allowHtml: true},
- {kind: "Control", name: "extra", tag: 'span', allowHtml: true}
- ],
- childClient: [
- {kind: "Control", name: "box", classes: "enyo-node-box", Xstyle: "border: 1px solid orange;", components: [
- {kind: "Control", name: "client", classes: "enyo-node-client", Xstyle: "border: 1px solid lightblue;"}
- ]}
- ],
- handlers: {
- ondblclick: "dblclick"
- },
- events: {
- //* @public
- //* Fired when the Node is tapped
- onNodeTap: "nodeTap",
- //* Fired when the Node is double-clicked
- onNodeDblClick: "nodeDblClick",
- /**
- Fired when the Node expands or contracts, as indicated by the
- 'expanded' property in the event data
- */
- onExpand: "nodeExpand",
- //* Fired when the Node is destroyed
- onDestroyed: "nodeDestroyed"
- },
- //
- //* @protected
- create: function() {
- this.inherited(arguments);
- //this.expandedChanged();
- //this.levelChanged();
- this.selectedChanged();
- this.iconChanged();
- },
- destroy: function() {
- this.doDestroyed();
- this.inherited(arguments);
- },
- initComponents: function() {
- // TODO: optimize to create the childClient on demand
- //this.hasChildren = this.components;
- if (this.expandable) {
- this.kindComponents = this.kindComponents.concat(this.childClient);
- }
- this.inherited(arguments);
- },
- //
- contentChanged: function() {
- //this.$.caption.setContent((this.expandable ? (this.expanded ? "-" : "+") : "") + this.content);
- this.$.caption.setContent(this.content);
- },
- iconChanged: function() {
- this.$.icon.setSrc(this.icon);
- this.$.icon.setShowing(Boolean(this.icon));
- },
- selectedChanged: function() {
- this.addRemoveClass("enyo-selected", this.selected);
- },
- rendered: function() {
- this.inherited(arguments);
- if (this.expandable && !this.expanded) {
- this.quickCollapse();
- }
- },
- //
- addNodes: function(inNodes) {
- this.destroyClientControls();
- for (var i=0, n; n=inNodes[i]; i++) {
- this.createComponent(n);
- }
- this.$.client.render();
- },
- addTextNodes: function(inNodes) {
- this.destroyClientControls();
- for (var i=0, n; n=inNodes[i]; i++) {
- this.createComponent({content: n});
- }
- this.$.client.render();
- },
- //
- tap: function(inSender, inEvent) {
- if(!this.onlyIconExpands) {
- this.toggleExpanded();
- this.doNodeTap();
- } else {
- if((inEvent.target==this.$.icon.hasNode())) {
- this.toggleExpanded();
- } else {
- this.doNodeTap();
- }
- }
- return true;
- },
- dblclick: function(inSender, inEvent) {
- this.doNodeDblClick();
- return true;
- },
- //
- toggleExpanded: function() {
- this.setExpanded(!this.expanded);
- },
- quickCollapse: function() {
- this.removeClass("enyo-animate");
- this.$.box.applyStyle("height", "0");
- var h = this.$.client.getBounds().height;
- this.$.client.setBounds({top: -h});
- },
- _expand: function() {
- this.addClass("enyo-animate");
- var h = this.$.client.getBounds().height;
- this.$.box.setBounds({height: h});
- this.$.client.setBounds({top: 0});
- setTimeout(enyo.bind(this, function() {
- // things may have happened in the interim, make sure
- // we only fix height if we are still expanded
- if (this.expanded) {
- this.removeClass("enyo-animate");
- this.$.box.applyStyle("height", "auto");
- }
- }), 225);
- },
- _collapse: function() {
- // disable transitions
- this.removeClass("enyo-animate");
- // fix the height of our box (rather than 'auto'), this
- // gives webkit something to lerp from
- var h = this.$.client.getBounds().height;
- this.$.box.setBounds({height: h});
- // yield the thead so DOM can make those changes (without transitions)
- setTimeout(enyo.bind(this, function() {
- // enable transitions
- this.addClass("enyo-animate");
- // shrink our box to 0
- this.$.box.applyStyle("height", "0");
- // slide the contents up
- this.$.client.setBounds({top: -h});
- }), 25);
- },
- expandedChanged: function(inOldExpanded) {
- if (!this.expandable) {
- this.expanded = false;
- } else {
- var event = {expanded: this.expanded};
- this.doExpand(event);
- if (!event.wait) {
- this.effectExpanded();
- }
- }
- },
- effectExpanded: function() {
- if (this.$.client) {
- if (!this.expanded) {
- this._collapse();
- } else {
- this._expand();
- }
- }
- //this.contentChanged();
- }/*,
- //
- //
- levelChanged: function() {
- this.applyStyle("padding-left", 16 + "px");
- },
- toggleChildren: function() {
- if (this.$.list) {
- this.$.list.setShowing(this.expanded);
- }
- },
- renderNodes: function(inNodes) {
- var list = this.createComponent({name: "list", container: this});
- for (var i=0, n; n=inNodes[i]; i++) {
- n.setLevel(this.level + 1);
- n.setContainer(list);
- n.render();
- }
- list.render();
- },
- //* @public
- addNodes: function(inNodes) {
- this.renderNodes(inNodes);
- this.toggleChildren();
- },
- removeNodes: function() {
- if (this.$.list) {
- this.$.list.destroy();
- }
- },
- hasVisibleChildren: function() {
- return this.expanded && this.$.list && this.$.list.controls.length > 0;
- },
- fetchParent: function() {
- return this.level > 0 && this.container.container;
- },
- fetchChildren: function() {
- return this.$.list && this.$.list.controls;
- },
- fetchFirstChild: function() {
- return this.$.list && this.$.list.controls[0];
- },
- fetchLastChild: function() {
- return this.$.list && this.$.list.controls[this.$.list.controls.length-1];
- },
- fetchPrevSibling: function() {
- var i = this.container.controls.indexOf(this);
- return this.level > 0 && this.container.controls[i-1];
- },
- fetchNextSibling: function() {
- var i = this.container.controls.indexOf(this);
- return this.level > 0 && this.container.controls[i+1];
- },
- getVisibleBounds: function() {
- return this.$.client.getBounds();
- }
- */
- });
|