@qooxdoo/framework
Version:
The JS Framework for Coders
140 lines (115 loc) • 3.97 kB
JavaScript
/* ************************************************************************
qooxdoo - the new era of web development
http://qooxdoo.org
Copyright:
2017 Cajus Pollmeier
License:
MIT: https://opensource.org/licenses/MIT
See the LICENSE file in the project's top-level directory for details.
Authors:
* Cajus Pollmeier
* Derrell Lipman
************************************************************************ */
/**
* Because of the virtual nature of the VirtualTree, and the fact that
* rendering occurs asynchronously, it is not a simple matter to bind a
* property in the model that will open or close branches in the
* tree. Instead, this controller listens to both the model and the tree, and
* synchronizes the openness of branches in the tree.
*
* To use this controller, simply instantiate it with the requisite
* constructor arguments.
*/
qx.Class.define("qx.ui.tree.core.OpenCloseController",
{
extend: qx.core.Object,
/**
* @param tree {qx.ui.tree.VirtualTree}
* The tree whose branch open or closed state is to be synchronized to a
* model property.
*
* @param rootModel {qx.data.Array}
* The tree root model wherein a property is to be synchronized to the
* tree branches' open or closed states
*/
construct: function(tree, rootModel)
{
var openProperty = tree.getOpenProperty();
this.base(arguments);
// Save the tree and initialize storage of listener IDs
this._tree = tree;
this._lids = [];
// Sync tree nodes
var sync = function(node) {
if (qx.Class.hasProperty(node.constructor, "children")) {
node.getChildren().forEach(sync);
}
if (qx.Class.hasProperty(node.constructor, openProperty)) {
if (node.get(openProperty)) {
tree.openNode(node);
}
else {
tree.closeNode(node);
}
}
}.bind(this);
sync(rootModel);
// Wire change listeners
var lid = tree.addListener("open", this._onOpen, this);
this._lids.push([tree, lid]);
lid = tree.addListener("close", this._onClose, this);
this._lids.push([tree, lid]);
lid = rootModel.addListener("changeBubble", this._onChangeBubble, this);
this._lids.push([rootModel, lid]);
},
members:
{
/** The tree which is synced to the model */
_tree: null,
/** Listener IDs that we manage */
_lids: null,
// event listener for "open" on the tree
_onOpen: function(ev)
{
ev.getData().set(this._tree.getOpenProperty(), true);
},
// event listener for "close" on the tree
_onClose: function(ev)
{
ev.getData().set(this._tree.getOpenProperty(), false);
},
// event listener for model changes
_onChangeBubble: function(ev)
{
var index;
var item;
var isOpen;
var bubble = ev.getData();
// Extract the index of the current item
index = bubble.name.replace(/.*\[([0-9]+)\]$/, "$1");
// Retrieve that indexed array item if it's an array; otherwise the item itself
item = bubble.item.getItem ? bubble.item.getItem(index) : bubble.item;
// If this item isn't being deleted and has an open property...
if (item && qx.Class.hasProperty(item.constructor, this._tree.getOpenProperty())) {
// ... then find out if this branch is open
isOpen = item.get(this._tree.getOpenProperty());
// Open or close the tree branch as necessary
if (isOpen && !this._tree.isNodeOpen(item)) {
this._tree.openNode(item);
}
else if (! isOpen && this._tree.isNodeOpen(item)) {
this._tree.closeNode(item);
}
}
// Rebuild the internal lookup table
this._tree.refresh();
}
},
destruct: function()
{
this._tree = null;
this._lids.forEach(function(data) {
data[0].removeListenerById(data[1]);
});
}
});