Mon 21 Jul 22:43:21 CEST 2025
This commit is contained in:
parent
cba0a144e5
commit
f3adfd7df3
308
js/term/widgets/node.js
Normal file
308
js/term/widgets/node.js
Normal file
|
@ -0,0 +1,308 @@
|
|||
/**
|
||||
** ==============================
|
||||
** O O O OOOO
|
||||
** O O O O O O
|
||||
** O O O O O O
|
||||
** OOOO OOOO O OOO OOOO
|
||||
** O O O O O O O
|
||||
** O O O O O O O
|
||||
** OOOO OOOO O O OOOO
|
||||
** ==============================
|
||||
** Dr. Stefan Bosse http://www.bsslab.de
|
||||
**
|
||||
** COPYRIGHT: THIS SOFTWARE, EXECUTABLE AND SOURCE CODE IS OWNED
|
||||
** BY THE AUTHOR(S).
|
||||
** THIS SOURCE CODE MAY NOT BE COPIED, EXTRACTED,
|
||||
** MODIFIED, OR OTHERWISE USED IN A CONTEXT
|
||||
** OUTSIDE OF THE SOFTWARE SYSTEM.
|
||||
**
|
||||
** $AUTHORS: Christopher Jeffrey and contributors, Stefan Bosse
|
||||
** $INITIAL: (C) 2013-2015, Christopher Jeffrey and contributors
|
||||
** $MODIFIED: sbosse (2017-2021).
|
||||
** $VERSION: 1.2.1
|
||||
**
|
||||
** $INFO:
|
||||
*
|
||||
* node.js - base abstract node for blessed
|
||||
*
|
||||
** $ENDOFINFO
|
||||
*/
|
||||
|
||||
/**
|
||||
* Modules
|
||||
*/
|
||||
var Comp = Require('com/compat');
|
||||
|
||||
var EventEmitter = Require('term/events').EventEmitter;
|
||||
|
||||
/**
|
||||
* Node
|
||||
*/
|
||||
|
||||
function Node(options) {
|
||||
var self = this;
|
||||
var Screen = Require('term/widgets/screen');
|
||||
|
||||
if (!instanceOf(this,Node)) {
|
||||
return new Node(options);
|
||||
}
|
||||
|
||||
EventEmitter.call(this);
|
||||
|
||||
options = options || {};
|
||||
this.options = options;
|
||||
|
||||
this.screen = this.screen || options.screen;
|
||||
|
||||
if (!this.screen) {
|
||||
if (this.type === 'screen') {
|
||||
this.screen = this;
|
||||
} else if (Screen.total === 1) {
|
||||
this.screen = Screen.global;
|
||||
} else if (options.parent) {
|
||||
this.screen = options.parent;
|
||||
while (this.screen && this.screen.type !== 'screen') {
|
||||
this.screen = this.screen.parent;
|
||||
}
|
||||
} else if (Screen.total) {
|
||||
// This _should_ work in most cases as long as the element is appended
|
||||
// synchronously after the screen's creation. Throw error if not.
|
||||
this.screen = Screen.instances[Screen.instances.length - 1];
|
||||
process.nextTick(function() {
|
||||
if (!self.parent) {
|
||||
throw new Error('Element (' + self.type + ')'
|
||||
+ ' was not appended synchronously after the'
|
||||
+ ' screen\'s creation. Please set a `parent`'
|
||||
+ ' or `screen` option in the element\'s constructor'
|
||||
+ ' if you are going to use multiple screens and'
|
||||
+ ' append the element later.');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
throw new Error('No active screen.');
|
||||
}
|
||||
}
|
||||
|
||||
this.parent = options.parent || null;
|
||||
this.children = [];
|
||||
this.$ = this._ = this.data = {};
|
||||
this.uid = Node.uid++;
|
||||
this.index = this.index != null ? this.index : -1;
|
||||
|
||||
if (this.type !== 'screen') {
|
||||
this.detached = true;
|
||||
}
|
||||
|
||||
if (this.parent) {
|
||||
this.parent.append(this);
|
||||
}
|
||||
|
||||
(options.children || []).forEach(this.append.bind(this));
|
||||
}
|
||||
|
||||
Node.uid = 0;
|
||||
|
||||
//Node.prototype.__proto__ = EventEmitter.prototype;
|
||||
inheritPrototype(Node,EventEmitter);
|
||||
|
||||
Node.prototype.type = 'node';
|
||||
|
||||
Node.prototype.insert = function(element, i) {
|
||||
var self = this;
|
||||
|
||||
if (element.screen && element.screen !== this.screen) {
|
||||
throw new Error('Cannot switch a node\'s screen.');
|
||||
}
|
||||
|
||||
element.detach();
|
||||
element.parent = this;
|
||||
element.screen = this.screen;
|
||||
|
||||
if (i === 0) {
|
||||
this.children.unshift(element);
|
||||
} else if (i === this.children.length) {
|
||||
this.children.push(element);
|
||||
} else {
|
||||
this.children.splice(i, 0, element);
|
||||
}
|
||||
|
||||
element.emit('reparent', this);
|
||||
this.emit('adopt', element);
|
||||
|
||||
(function emit(el) {
|
||||
var n = el.detached !== self.detached;
|
||||
el.detached = self.detached;
|
||||
if (n) el.emit('attach');
|
||||
el.children.forEach(emit);
|
||||
})(element);
|
||||
|
||||
if (!this.screen.focused) {
|
||||
this.screen.focused = element;
|
||||
}
|
||||
};
|
||||
|
||||
Node.prototype.prepend = function(element) {
|
||||
this.insert(element, 0);
|
||||
};
|
||||
|
||||
Node.prototype.append = function(element) {
|
||||
this.insert(element, this.children.length);
|
||||
};
|
||||
|
||||
Node.prototype.insertBefore = function(element, other) {
|
||||
var i = this.children.indexOf(other);
|
||||
if (~i) this.insert(element, i);
|
||||
};
|
||||
|
||||
Node.prototype.insertAfter = function(element, other) {
|
||||
var i = this.children.indexOf(other);
|
||||
if (~i) this.insert(element, i + 1);
|
||||
};
|
||||
|
||||
Node.prototype.remove = function(element) {
|
||||
if (element.parent !== this) return;
|
||||
|
||||
var i = this.children.indexOf(element);
|
||||
if (!~i) return;
|
||||
|
||||
element.clearPos();
|
||||
|
||||
element.parent = null;
|
||||
|
||||
this.children.splice(i, 1);
|
||||
|
||||
i = this.screen.clickable.indexOf(element);
|
||||
if (~i) this.screen.clickable.splice(i, 1);
|
||||
i = this.screen.keyable.indexOf(element);
|
||||
if (~i) this.screen.keyable.splice(i, 1);
|
||||
|
||||
element.emit('reparent', null);
|
||||
this.emit('remove', element);
|
||||
|
||||
(function emit(el) {
|
||||
var n = el.detached !== true;
|
||||
el.detached = true;
|
||||
if (n) el.emit('detach');
|
||||
el.children.forEach(emit);
|
||||
})(element);
|
||||
|
||||
if (this.screen.focused === element) {
|
||||
this.screen.rewindFocus();
|
||||
}
|
||||
};
|
||||
|
||||
Node.prototype.detach = function() {
|
||||
if (this.parent) this.parent.remove(this);
|
||||
};
|
||||
|
||||
Node.prototype.free = function() {
|
||||
return;
|
||||
};
|
||||
|
||||
Node.prototype.destroy = function() {
|
||||
this.detach();
|
||||
this.forDescendants(function(el) {
|
||||
el.free();
|
||||
el.destroyed = true;
|
||||
el.emit('destroy');
|
||||
}, this);
|
||||
};
|
||||
|
||||
Node.prototype.forDescendants = function(iter, s) {
|
||||
if (s) iter(this);
|
||||
this.children.forEach(function emit(el) {
|
||||
iter(el);
|
||||
el.children.forEach(emit);
|
||||
});
|
||||
};
|
||||
|
||||
Node.prototype.forAncestors = function(iter, s) {
|
||||
var el = this;
|
||||
if (s) iter(this);
|
||||
while (el = el.parent) {
|
||||
iter(el);
|
||||
}
|
||||
};
|
||||
|
||||
Node.prototype.collectDescendants = function(s) {
|
||||
var out = [];
|
||||
this.forDescendants(function(el) {
|
||||
out.push(el);
|
||||
}, s);
|
||||
return out;
|
||||
};
|
||||
|
||||
Node.prototype.collectAncestors = function(s) {
|
||||
var out = [];
|
||||
this.forAncestors(function(el) {
|
||||
out.push(el);
|
||||
}, s);
|
||||
return out;
|
||||
};
|
||||
|
||||
Node.prototype.emitDescendants = function() {
|
||||
var args = Array.prototype.slice(arguments)
|
||||
, iter;
|
||||
|
||||
if (typeof args[args.length - 1] === 'function') {
|
||||
iter = args.pop();
|
||||
}
|
||||
|
||||
return this.forDescendants(function(el) {
|
||||
if (iter) iter(el);
|
||||
el.emit.apply(el, args);
|
||||
}, true);
|
||||
};
|
||||
|
||||
Node.prototype.emitAncestors = function() {
|
||||
var args = Array.prototype.slice(arguments)
|
||||
, iter;
|
||||
|
||||
if (typeof args[args.length - 1] === 'function') {
|
||||
iter = args.pop();
|
||||
}
|
||||
|
||||
return this.forAncestors(function(el) {
|
||||
if (iter) iter(el);
|
||||
el.emit.apply(el, args);
|
||||
}, true);
|
||||
};
|
||||
|
||||
Node.prototype.hasDescendant = function(target) {
|
||||
return (function find(el) {
|
||||
for (var i = 0; i < el.children.length; i++) {
|
||||
if (el.children[i] === target) {
|
||||
return true;
|
||||
}
|
||||
if (find(el.children[i]) === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
})(this);
|
||||
};
|
||||
|
||||
Node.prototype.hasAncestor = function(target) {
|
||||
var el = this;
|
||||
while (el = el.parent) {
|
||||
if (el === target) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Node.prototype.get = function(name, value) {
|
||||
if (this.data.hasOwnProperty(name)) {
|
||||
return this.data[name];
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
Node.prototype.set = function(name, value) {
|
||||
return this.data[name] = value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose
|
||||
*/
|
||||
|
||||
module.exports = Node;
|
Loading…
Reference in New Issue
Block a user