mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-23 00:04:06 +00:00
Merge branch 'master' of https://github.com/jagenjo/litegraph.js
This commit is contained in:
@@ -1,12 +1,18 @@
|
||||
{
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 5
|
||||
},
|
||||
module.exports = {
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
"es2021": true,
|
||||
"node": true,
|
||||
"jest/globals": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"overrides": [
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": ["jest"],
|
||||
"globals": {
|
||||
"gl": true,
|
||||
"GL": true,
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@ node_modules/*
|
||||
npm-debug.log
|
||||
temp/
|
||||
temp/*
|
||||
coverage/
|
||||
|
||||
# Editors
|
||||
/.vscode/*
|
||||
|
||||
@@ -176,6 +176,7 @@ You can write any feedback to javi.agenjo@gmail.com
|
||||
|
||||
## Contributors
|
||||
|
||||
- atlasan
|
||||
- kriffe
|
||||
- rappestad
|
||||
- InventivetalentDev
|
||||
|
||||
@@ -5,13 +5,30 @@ LiteGraph.node_images_path = "../nodes_data/";
|
||||
var editor = new LiteGraph.Editor("main",{miniwindow:false});
|
||||
window.graphcanvas = editor.graphcanvas;
|
||||
window.graph = editor.graph;
|
||||
window.addEventListener("resize", function() { editor.graphcanvas.resize(); } );
|
||||
updateEditorHiPPICanvas();
|
||||
window.addEventListener("resize", function() {
|
||||
editor.graphcanvas.resize();
|
||||
updateEditorHiPPICanvas();
|
||||
} );
|
||||
//window.addEventListener("keydown", editor.graphcanvas.processKey.bind(editor.graphcanvas) );
|
||||
window.onbeforeunload = function(){
|
||||
var data = JSON.stringify( graph.serialize() );
|
||||
localStorage.setItem("litegraphg demo backup", data );
|
||||
}
|
||||
|
||||
function updateEditorHiPPICanvas() {
|
||||
const ratio = window.devicePixelRatio;
|
||||
if(ratio == 1) { return }
|
||||
const rect = editor.canvas.parentNode.getBoundingClientRect();
|
||||
const { width, height } = rect;
|
||||
editor.canvas.width = width * ratio;
|
||||
editor.canvas.height = height * ratio;
|
||||
editor.canvas.style.width = width + "px";
|
||||
editor.canvas.style.height = height + "px";
|
||||
editor.canvas.getContext("2d").scale(ratio, ratio);
|
||||
return editor.canvas;
|
||||
}
|
||||
|
||||
//enable scripting
|
||||
LiteGraph.allow_scripts = true;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ LiteGraph.slot_types_out = []; // slot types OUT*/
|
||||
|
||||
LiteGraph.alt_drag_do_clone_nodes = true; // [true!] very handy; ALT click to clone and drag the new node
|
||||
LiteGraph.do_add_triggers_slots = true; // [true!] will create and connect event slots when using action/events connections; !WILL CHANGE node mode when using onTrigger (enable mode colors); onExecuted does not need this
|
||||
LiteGraph.allow_multi_output_for_events = false; // [false!] being events; it is strongly reccomended to use them sequentually; one by one
|
||||
LiteGraph.allow_multi_output_for_events = false; // [false!] being events; it is strongly reccomended to use them sequentially; one by one
|
||||
LiteGraph.middle_click_slot_add_default_node = true; //[true!] allows to create and connect a ndoe clicking with the third button (wheel)
|
||||
LiteGraph.release_link_on_empty_shows_menu = true; //[true!] dragging a link to empty space will open a menu, add from list, search or defaults
|
||||
LiteGraph.pointerevents_method = "mouse"; // "mouse"|"pointer" use mouse for retrocompatibility issues? (none found @ now)
|
||||
@@ -25,7 +25,7 @@ LiteGraph.slot_types_out = []; // slot types OUT*/
|
||||
|
||||
LiteGraph.alt_drag_do_clone_nodes = true; // [true!] very handy; ALT click to clone and drag the new node
|
||||
LiteGraph.do_add_triggers_slots = true; // [true!] will create and connect event slots when using action/events connections; !WILL CHANGE node mode when using onTrigger (enable mode colors); onExecuted does not need this
|
||||
LiteGraph.allow_multi_output_for_events = false; // [false!] being events; it is strongly reccomended to use them sequentually; one by one
|
||||
LiteGraph.allow_multi_output_for_events = false; // [false!] being events; it is strongly reccomended to use them sequentially; one by one
|
||||
LiteGraph.middle_click_slot_add_default_node = true; //[true!] allows to create and connect a ndoe clicking with the third button (wheel)
|
||||
LiteGraph.release_link_on_empty_shows_menu = true; //[true!] dragging a link to empty space will open a menu, add from list, search or defaults
|
||||
LiteGraph.pointerevents_method = "pointer"; // "mouse"|"pointer" use mouse for retrocompatibility issues? (none found @ now)
|
||||
195
jest.config.js
Normal file
195
jest.config.js
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* For a detailed explanation regarding each configuration property, visit:
|
||||
* https://jestjs.io/docs/configuration
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// All imported modules in your tests should be mocked automatically
|
||||
// automock: false,
|
||||
|
||||
// Stop running tests after `n` failures
|
||||
// bail: 0,
|
||||
|
||||
// The directory where Jest should store its cached dependency information
|
||||
// cacheDirectory: "/tmp/jest_rs",
|
||||
|
||||
// Automatically clear mock calls, instances, contexts and results before every test
|
||||
// clearMocks: false,
|
||||
|
||||
// Indicates whether the coverage information should be collected while executing the test
|
||||
collectCoverage: true,
|
||||
|
||||
// An array of glob patterns indicating a set of files for which coverage information should be collected
|
||||
// collectCoverageFrom: undefined,
|
||||
|
||||
// The directory where Jest should output its coverage files
|
||||
coverageDirectory: "coverage",
|
||||
|
||||
// An array of regexp pattern strings used to skip coverage collection
|
||||
// coveragePathIgnorePatterns: [
|
||||
// "/node_modules/"
|
||||
// ],
|
||||
|
||||
// Indicates which provider should be used to instrument code for coverage
|
||||
// coverageProvider: "babel",
|
||||
|
||||
// A list of reporter names that Jest uses when writing coverage reports
|
||||
// coverageReporters: [
|
||||
// "json",
|
||||
// "text",
|
||||
// "lcov",
|
||||
// "clover"
|
||||
// ],
|
||||
|
||||
// An object that configures minimum threshold enforcement for coverage results
|
||||
// coverageThreshold: undefined,
|
||||
|
||||
// A path to a custom dependency extractor
|
||||
// dependencyExtractor: undefined,
|
||||
|
||||
// Make calling deprecated APIs throw helpful error messages
|
||||
// errorOnDeprecated: false,
|
||||
|
||||
// The default configuration for fake timers
|
||||
// fakeTimers: {
|
||||
// "enableGlobally": false
|
||||
// },
|
||||
|
||||
// Force coverage collection from ignored files using an array of glob patterns
|
||||
// forceCoverageMatch: [],
|
||||
|
||||
// A path to a module which exports an async function that is triggered once before all test suites
|
||||
// globalSetup: undefined,
|
||||
|
||||
// A path to a module which exports an async function that is triggered once after all test suites
|
||||
// globalTeardown: undefined,
|
||||
|
||||
// A set of global variables that need to be available in all test environments
|
||||
// globals: {},
|
||||
|
||||
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
|
||||
// maxWorkers: "50%",
|
||||
|
||||
// An array of directory names to be searched recursively up from the requiring module's location
|
||||
// moduleDirectories: [
|
||||
// "node_modules"
|
||||
// ],
|
||||
|
||||
// An array of file extensions your modules use
|
||||
// moduleFileExtensions: [
|
||||
// "js",
|
||||
// "mjs",
|
||||
// "cjs",
|
||||
// "jsx",
|
||||
// "ts",
|
||||
// "tsx",
|
||||
// "json",
|
||||
// "node"
|
||||
// ],
|
||||
|
||||
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
|
||||
// moduleNameMapper: {},
|
||||
|
||||
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
|
||||
// modulePathIgnorePatterns: [],
|
||||
|
||||
// Activates notifications for test results
|
||||
// notify: false,
|
||||
|
||||
// An enum that specifies notification mode. Requires { notify: true }
|
||||
// notifyMode: "failure-change",
|
||||
|
||||
// A preset that is used as a base for Jest's configuration
|
||||
// preset: undefined,
|
||||
|
||||
// Run tests from one or more projects
|
||||
// projects: undefined,
|
||||
|
||||
// Use this configuration option to add custom reporters to Jest
|
||||
// reporters: undefined,
|
||||
|
||||
// Automatically reset mock state before every test
|
||||
// resetMocks: false,
|
||||
|
||||
// Reset the module registry before running each individual test
|
||||
// resetModules: false,
|
||||
|
||||
// A path to a custom resolver
|
||||
// resolver: undefined,
|
||||
|
||||
// Automatically restore mock state and implementation before every test
|
||||
// restoreMocks: false,
|
||||
|
||||
// The root directory that Jest should scan for tests and modules within
|
||||
// rootDir: undefined,
|
||||
|
||||
// A list of paths to directories that Jest should use to search for files in
|
||||
// roots: [
|
||||
// "<rootDir>"
|
||||
// ],
|
||||
|
||||
// Allows you to use a custom runner instead of Jest's default test runner
|
||||
// runner: "jest-runner",
|
||||
|
||||
// The paths to modules that run some code to configure or set up the testing environment before each test
|
||||
// setupFiles: [],
|
||||
|
||||
// A list of paths to modules that run some code to configure or set up the testing framework before each test
|
||||
// setupFilesAfterEnv: [],
|
||||
|
||||
// The number of seconds after which a test is considered as slow and reported as such in the results.
|
||||
// slowTestThreshold: 5,
|
||||
|
||||
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
|
||||
// snapshotSerializers: [],
|
||||
|
||||
// The test environment that will be used for testing
|
||||
// testEnvironment: "jest-environment-node",
|
||||
|
||||
// Options that will be passed to the testEnvironment
|
||||
// testEnvironmentOptions: {},
|
||||
|
||||
// Adds a location field to test results
|
||||
// testLocationInResults: false,
|
||||
|
||||
// The glob patterns Jest uses to detect test files
|
||||
// testMatch: [
|
||||
// "**/__tests__/**/*.[jt]s?(x)",
|
||||
// "**/?(*.)+(spec|test).[tj]s?(x)"
|
||||
// ],
|
||||
|
||||
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
|
||||
// testPathIgnorePatterns: [
|
||||
// "/node_modules/"
|
||||
// ],
|
||||
|
||||
// The regexp pattern or array of patterns that Jest uses to detect test files
|
||||
// testRegex: [],
|
||||
|
||||
// This option allows the use of a custom results processor
|
||||
// testResultsProcessor: undefined,
|
||||
|
||||
// This option allows use of a custom test runner
|
||||
// testRunner: "jest-circus/runner",
|
||||
|
||||
// A map from regular expressions to paths to transformers
|
||||
// transform: undefined,
|
||||
|
||||
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
|
||||
// transformIgnorePatterns: [
|
||||
// "/node_modules/",
|
||||
// "\\.pnp\\.[^\\/]+$"
|
||||
// ],
|
||||
|
||||
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
|
||||
// unmockedModulePathPatterns: undefined,
|
||||
|
||||
// Indicates whether each individual test should be reported during the run
|
||||
// verbose: undefined,
|
||||
|
||||
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
|
||||
// watchPathIgnorePatterns: [],
|
||||
|
||||
// Whether to use watchman for file crawling
|
||||
// watchman: true,
|
||||
};
|
||||
11008
package-lock.json
generated
Normal file
11008
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,8 @@
|
||||
"prebuild": "rimraf build",
|
||||
"build": "grunt build",
|
||||
"start": "nodemon utils/server.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"test": "jest",
|
||||
"test:allVersions": "./utils/test.sh",
|
||||
"prettier": "npx prettier --write src/**/*.* css/**/*.*",
|
||||
"lint": "npx eslint src",
|
||||
"lint:fix": "npx eslint --fix src"
|
||||
@@ -33,12 +34,16 @@
|
||||
},
|
||||
"homepage": "https://github.com/jagenjo/litegraph.js#readme",
|
||||
"devDependencies": {
|
||||
"@types/jest": "^28.1.3",
|
||||
"eslint": "^8.37.0 ",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"express": "^4.17.1",
|
||||
"google-closure-compiler": "^20171112.0.0",
|
||||
"grunt": "^1.1.0",
|
||||
"grunt-cli": "^1.2.0",
|
||||
"grunt-closure-tools": "^1.0.0",
|
||||
"grunt-contrib-concat": "^1.0.1",
|
||||
"jest": "^28.1.3",
|
||||
"nodemon": "^1.19.4",
|
||||
"rimraf": "^2.7.1"
|
||||
}
|
||||
|
||||
2
src/litegraph.d.ts
vendored
2
src/litegraph.d.ts
vendored
@@ -1142,6 +1142,8 @@ export declare class LGraphCanvas {
|
||||
allow_interaction: boolean;
|
||||
/** allows to change a connection with having to redo it again */
|
||||
allow_reconnect_links: boolean;
|
||||
/** allow selecting multi nodes without pressing extra keys */
|
||||
multi_select: boolean;
|
||||
/** No effect */
|
||||
allow_searchbox: boolean;
|
||||
always_render_background: boolean;
|
||||
|
||||
313
src/litegraph.js
313
src/litegraph.js
@@ -124,14 +124,14 @@
|
||||
registered_slot_out_types: {}, // slot types for nodeclass
|
||||
slot_types_in: [], // slot types IN
|
||||
slot_types_out: [], // slot types OUT
|
||||
slot_types_default_in: [], // specify for each IN slot type a(/many) deafult node(s), use single string, array, or object (with node, title, parameters, ..) like for search
|
||||
slot_types_default_out: [], // specify for each OUT slot type a(/many) deafult node(s), use single string, array, or object (with node, title, parameters, ..) like for search
|
||||
slot_types_default_in: [], // specify for each IN slot type a(/many) default node(s), use single string, array, or object (with node, title, parameters, ..) like for search
|
||||
slot_types_default_out: [], // specify for each OUT slot type a(/many) default node(s), use single string, array, or object (with node, title, parameters, ..) like for search
|
||||
|
||||
alt_drag_do_clone_nodes: false, // [true!] very handy, ALT click to clone and drag the new node
|
||||
|
||||
do_add_triggers_slots: false, // [true!] will create and connect event slots when using action/events connections, !WILL CHANGE node mode when using onTrigger (enable mode colors), onExecuted does not need this
|
||||
|
||||
allow_multi_output_for_events: true, // [false!] being events, it is strongly reccomended to use them sequentually, one by one
|
||||
allow_multi_output_for_events: true, // [false!] being events, it is strongly reccomended to use them sequentially, one by one
|
||||
|
||||
middle_click_slot_add_default_node: false, //[true!] allows to create and connect a ndoe clicking with the third button (wheel)
|
||||
|
||||
@@ -157,80 +157,67 @@
|
||||
console.log("Node registered: " + type);
|
||||
}
|
||||
|
||||
var categories = type.split("/");
|
||||
var classname = base_class.name;
|
||||
const classname = base_class.name;
|
||||
|
||||
var pos = type.lastIndexOf("/");
|
||||
base_class.category = type.substr(0, pos);
|
||||
const pos = type.lastIndexOf("/");
|
||||
base_class.category = type.substring(0, pos);
|
||||
|
||||
if (!base_class.title) {
|
||||
base_class.title = classname;
|
||||
}
|
||||
//info.name = name.substr(pos+1,name.length - pos);
|
||||
|
||||
//extend class
|
||||
if (base_class.prototype) {
|
||||
//is a class
|
||||
for (var i in LGraphNode.prototype) {
|
||||
if (!base_class.prototype[i]) {
|
||||
base_class.prototype[i] = LGraphNode.prototype[i];
|
||||
}
|
||||
for (var i in LGraphNode.prototype) {
|
||||
if (!base_class.prototype[i]) {
|
||||
base_class.prototype[i] = LGraphNode.prototype[i];
|
||||
}
|
||||
}
|
||||
|
||||
var prev = this.registered_node_types[type];
|
||||
if(prev)
|
||||
console.log("replacing node type: " + type);
|
||||
else
|
||||
{
|
||||
if( !Object.hasOwnProperty( base_class.prototype, "shape") )
|
||||
Object.defineProperty(base_class.prototype, "shape", {
|
||||
set: function(v) {
|
||||
switch (v) {
|
||||
case "default":
|
||||
delete this._shape;
|
||||
break;
|
||||
case "box":
|
||||
this._shape = LiteGraph.BOX_SHAPE;
|
||||
break;
|
||||
case "round":
|
||||
this._shape = LiteGraph.ROUND_SHAPE;
|
||||
break;
|
||||
case "circle":
|
||||
this._shape = LiteGraph.CIRCLE_SHAPE;
|
||||
break;
|
||||
case "card":
|
||||
this._shape = LiteGraph.CARD_SHAPE;
|
||||
break;
|
||||
default:
|
||||
this._shape = v;
|
||||
}
|
||||
},
|
||||
get: function(v) {
|
||||
return this._shape;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
const prev = this.registered_node_types[type];
|
||||
if(prev) {
|
||||
console.log("replacing node type: " + type);
|
||||
}
|
||||
if( !Object.prototype.hasOwnProperty.call( base_class.prototype, "shape") ) {
|
||||
Object.defineProperty(base_class.prototype, "shape", {
|
||||
set: function(v) {
|
||||
switch (v) {
|
||||
case "default":
|
||||
delete this._shape;
|
||||
break;
|
||||
case "box":
|
||||
this._shape = LiteGraph.BOX_SHAPE;
|
||||
break;
|
||||
case "round":
|
||||
this._shape = LiteGraph.ROUND_SHAPE;
|
||||
break;
|
||||
case "circle":
|
||||
this._shape = LiteGraph.CIRCLE_SHAPE;
|
||||
break;
|
||||
case "card":
|
||||
this._shape = LiteGraph.CARD_SHAPE;
|
||||
break;
|
||||
default:
|
||||
this._shape = v;
|
||||
}
|
||||
},
|
||||
get: function() {
|
||||
return this._shape;
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
});
|
||||
|
||||
|
||||
//warnings
|
||||
if (base_class.prototype.onPropertyChange) {
|
||||
console.warn(
|
||||
"LiteGraph node class " +
|
||||
type +
|
||||
" has onPropertyChange method, it must be called onPropertyChanged with d at the end"
|
||||
);
|
||||
}
|
||||
|
||||
//used to know which nodes create when dragging files to the canvas
|
||||
if (base_class.supported_extensions) {
|
||||
for (var i in base_class.supported_extensions) {
|
||||
var ext = base_class.supported_extensions[i];
|
||||
if(ext && ext.constructor === String)
|
||||
this.node_types_by_file_extension[ ext.toLowerCase() ] = base_class;
|
||||
}
|
||||
}
|
||||
}
|
||||
//used to know which nodes to create when dragging files to the canvas
|
||||
if (base_class.supported_extensions) {
|
||||
for (let i in base_class.supported_extensions) {
|
||||
const ext = base_class.supported_extensions[i];
|
||||
if(ext && ext.constructor === String) {
|
||||
this.node_types_by_file_extension[ ext.toLowerCase() ] = base_class;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.registered_node_types[type] = base_class;
|
||||
if (base_class.constructor.name) {
|
||||
@@ -251,19 +238,11 @@
|
||||
" has onPropertyChange method, it must be called onPropertyChanged with d at the end"
|
||||
);
|
||||
}
|
||||
|
||||
//used to know which nodes create when dragging files to the canvas
|
||||
if (base_class.supported_extensions) {
|
||||
for (var i=0; i < base_class.supported_extensions.length; i++) {
|
||||
var ext = base_class.supported_extensions[i];
|
||||
if(ext && ext.constructor === String)
|
||||
this.node_types_by_file_extension[ ext.toLowerCase() ] = base_class;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO one would want to know input and ouput :: this would allow trought registerNodeAndSlotType to get all the slots types
|
||||
//console.debug("Registering "+type);
|
||||
if (this.auto_load_slot_types) nodeTmp = new base_class(base_class.title || "tmpnode");
|
||||
// TODO one would want to know input and ouput :: this would allow through registerNodeAndSlotType to get all the slots types
|
||||
if (this.auto_load_slot_types) {
|
||||
new base_class(base_class.title || "tmpnode");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -272,13 +251,18 @@
|
||||
* @param {String|Object} type name of the node or the node constructor itself
|
||||
*/
|
||||
unregisterNodeType: function(type) {
|
||||
var base_class = type.constructor === String ? this.registered_node_types[type] : type;
|
||||
if(!base_class)
|
||||
throw("node type not found: " + type );
|
||||
delete this.registered_node_types[base_class.type];
|
||||
if(base_class.constructor.name)
|
||||
delete this.Nodes[base_class.constructor.name];
|
||||
},
|
||||
const base_class =
|
||||
type.constructor === String
|
||||
? this.registered_node_types[type]
|
||||
: type;
|
||||
if (!base_class) {
|
||||
throw "node type not found: " + type;
|
||||
}
|
||||
delete this.registered_node_types[base_class.type];
|
||||
if (base_class.constructor.name) {
|
||||
delete this.Nodes[base_class.constructor.name];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Save a slot type and his node
|
||||
@@ -286,38 +270,49 @@
|
||||
* @param {String|Object} type name of the node or the node constructor itself
|
||||
* @param {String} slot_type name of the slot type (variable type), eg. string, number, array, boolean, ..
|
||||
*/
|
||||
registerNodeAndSlotType: function(type,slot_type,out){
|
||||
registerNodeAndSlotType: function(type, slot_type, out){
|
||||
out = out || false;
|
||||
var base_class = type.constructor === String && this.registered_node_types[type] !== "anonymous" ? this.registered_node_types[type] : type;
|
||||
|
||||
var sCN = base_class.constructor.type;
|
||||
|
||||
if (typeof slot_type == "string"){
|
||||
var aTypes = slot_type.split(",");
|
||||
}else if (slot_type == this.EVENT || slot_type == this.ACTION){
|
||||
var aTypes = ["_event_"];
|
||||
}else{
|
||||
var aTypes = ["*"];
|
||||
const base_class =
|
||||
type.constructor === String &&
|
||||
this.registered_node_types[type] !== "anonymous"
|
||||
? this.registered_node_types[type]
|
||||
: type;
|
||||
|
||||
const class_type = base_class.constructor.type;
|
||||
|
||||
let allTypes = [];
|
||||
if (typeof slot_type === "string") {
|
||||
allTypes = slot_type.split(",");
|
||||
} else if (slot_type == this.EVENT || slot_type == this.ACTION) {
|
||||
allTypes = ["_event_"];
|
||||
} else {
|
||||
allTypes = ["*"];
|
||||
}
|
||||
|
||||
for (var i = 0; i < aTypes.length; ++i) {
|
||||
var sT = aTypes[i]; //.toLowerCase();
|
||||
if (sT === ""){
|
||||
sT = "*";
|
||||
for (let i = 0; i < allTypes.length; ++i) {
|
||||
let slotType = allTypes[i];
|
||||
if (slotType === "") {
|
||||
slotType = "*";
|
||||
}
|
||||
var registerTo = out ? "registered_slot_out_types" : "registered_slot_in_types";
|
||||
if (typeof this[registerTo][sT] == "undefined") this[registerTo][sT] = {nodes: []};
|
||||
this[registerTo][sT].nodes.push(sCN);
|
||||
|
||||
const registerTo = out
|
||||
? "registered_slot_out_types"
|
||||
: "registered_slot_in_types";
|
||||
if (this[registerTo][slotType] === undefined) {
|
||||
this[registerTo][slotType] = { nodes: [] };
|
||||
}
|
||||
if (!this[registerTo][slotType].nodes.includes(class_type)) {
|
||||
this[registerTo][slotType].nodes.push(class_type);
|
||||
}
|
||||
|
||||
// check if is a new type
|
||||
if (!out){
|
||||
if (!this.slot_types_in.includes(sT.toLowerCase())){
|
||||
this.slot_types_in.push(sT.toLowerCase());
|
||||
if (!out) {
|
||||
if (!this.slot_types_in.includes(slotType.toLowerCase())) {
|
||||
this.slot_types_in.push(slotType.toLowerCase());
|
||||
this.slot_types_in.sort();
|
||||
}
|
||||
}else{
|
||||
if (!this.slot_types_out.includes(sT.toLowerCase())){
|
||||
this.slot_types_out.push(sT.toLowerCase());
|
||||
} else {
|
||||
if (!this.slot_types_out.includes(slotType.toLowerCase())) {
|
||||
this.slot_types_out.push(slotType.toLowerCase());
|
||||
this.slot_types_out.sort();
|
||||
}
|
||||
}
|
||||
@@ -1262,35 +1257,35 @@
|
||||
LGraph.prototype.arrange = function (margin, layout) {
|
||||
margin = margin || 100;
|
||||
|
||||
var nodes = this.computeExecutionOrder(false, true);
|
||||
var columns = [];
|
||||
for (var i = 0; i < nodes.length; ++i) {
|
||||
var node = nodes[i];
|
||||
var col = node._level || 1;
|
||||
const nodes = this.computeExecutionOrder(false, true);
|
||||
const columns = [];
|
||||
for (let i = 0; i < nodes.length; ++i) {
|
||||
const node = nodes[i];
|
||||
const col = node._level || 1;
|
||||
if (!columns[col]) {
|
||||
columns[col] = [];
|
||||
}
|
||||
columns[col].push(node);
|
||||
}
|
||||
|
||||
var x = margin;
|
||||
let x = margin;
|
||||
|
||||
for (var i = 0; i < columns.length; ++i) {
|
||||
var column = columns[i];
|
||||
for (let i = 0; i < columns.length; ++i) {
|
||||
const column = columns[i];
|
||||
if (!column) {
|
||||
continue;
|
||||
}
|
||||
var max_size = 100;
|
||||
var y = margin + LiteGraph.NODE_TITLE_HEIGHT;
|
||||
for (var j = 0; j < column.length; ++j) {
|
||||
var node = column[j];
|
||||
let max_size = 100;
|
||||
let y = margin + LiteGraph.NODE_TITLE_HEIGHT;
|
||||
for (let j = 0; j < column.length; ++j) {
|
||||
const node = column[j];
|
||||
node.pos[0] = (layout == LiteGraph.VERTICAL_LAYOUT) ? y : x;
|
||||
node.pos[1] = (layout == LiteGraph.VERTICAL_LAYOUT) ? x : y;
|
||||
var max_size_index = (layout == LiteGraph.VERTICAL_LAYOUT) ? 1 : 0;
|
||||
const max_size_index = (layout == LiteGraph.VERTICAL_LAYOUT) ? 1 : 0;
|
||||
if (node.size[max_size_index] > max_size) {
|
||||
max_size = node.size[max_size_index];
|
||||
}
|
||||
var node_size_index = (layout == LiteGraph.VERTICAL_LAYOUT) ? 0 : 1;
|
||||
const node_size_index = (layout == LiteGraph.VERTICAL_LAYOUT) ? 0 : 1;
|
||||
y += node.size[node_size_index] + margin + LiteGraph.NODE_TITLE_HEIGHT;
|
||||
}
|
||||
x += max_size + margin;
|
||||
@@ -5211,6 +5206,7 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
this.allow_dragcanvas = true;
|
||||
this.allow_dragnodes = true;
|
||||
this.allow_interaction = true; //allow to control widgets, buttons, collapse, etc
|
||||
this.multi_select = false; //allow selecting multi nodes without pressing extra keys
|
||||
this.allow_searchbox = true;
|
||||
this.allow_reconnect_links = true; //allows to change a connection with having to redo it again
|
||||
this.align_to_grid = false; //snap to grid
|
||||
@@ -5436,7 +5432,7 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
};
|
||||
|
||||
/**
|
||||
* returns the visualy active graph (in case there are more in the stack)
|
||||
* returns the visually active graph (in case there are more in the stack)
|
||||
* @method getCurrentGraph
|
||||
* @return {LGraph} the active graph
|
||||
*/
|
||||
@@ -6061,9 +6057,13 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
this.graph.beforeChange();
|
||||
this.node_dragged = node;
|
||||
}
|
||||
if (!this.selected_nodes[node.id]) {
|
||||
this.processNodeSelected(node, e);
|
||||
}
|
||||
this.processNodeSelected(node, e);
|
||||
} else { // double-click
|
||||
/**
|
||||
* Don't call the function if the block is already selected.
|
||||
* Otherwise, it could cause the block to be unselected while its panel is open.
|
||||
*/
|
||||
if (!node.is_selected) this.processNodeSelected(node, e);
|
||||
}
|
||||
|
||||
this.dirty_canvas = true;
|
||||
@@ -6475,6 +6475,10 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
var n = this.selected_nodes[i];
|
||||
n.pos[0] += delta[0] / this.ds.scale;
|
||||
n.pos[1] += delta[1] / this.ds.scale;
|
||||
if (!n.is_selected) this.processNodeSelected(n, e); /*
|
||||
* Don't call the function if the block is already selected.
|
||||
* Otherwise, it could cause the block to be unselected while dragging.
|
||||
*/
|
||||
}
|
||||
|
||||
this.dirty_canvas = true;
|
||||
@@ -7004,9 +7008,9 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
}
|
||||
}
|
||||
|
||||
if (e.code == "KeyV" && (e.metaKey || e.ctrlKey) && !e.shiftKey) {
|
||||
if (e.code == "KeyV" && (e.metaKey || e.ctrlKey)) {
|
||||
//paste
|
||||
this.pasteFromClipboard();
|
||||
this.pasteFromClipboard(e.shiftKey);
|
||||
}
|
||||
|
||||
//delete or backspace
|
||||
@@ -7091,15 +7095,15 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
var target_node = this.graph.getNodeById(
|
||||
link_info.origin_id
|
||||
);
|
||||
if (!target_node || !this.selected_nodes[target_node.id]) {
|
||||
//improve this by allowing connections to non-selected nodes
|
||||
if (!target_node) {
|
||||
continue;
|
||||
} //not selected
|
||||
}
|
||||
clipboard_info.links.push([
|
||||
target_node._relative_id,
|
||||
link_info.origin_slot, //j,
|
||||
node._relative_id,
|
||||
link_info.target_slot
|
||||
link_info.target_slot,
|
||||
target_node.id
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -7110,7 +7114,7 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
);
|
||||
};
|
||||
|
||||
LGraphCanvas.prototype.pasteFromClipboard = function() {
|
||||
LGraphCanvas.prototype.pasteFromClipboard = function(isConnectUnselected = false) {
|
||||
var data = localStorage.getItem("litegrapheditor_clipboard");
|
||||
if (!data) {
|
||||
return;
|
||||
@@ -7159,7 +7163,16 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
//create links
|
||||
for (var i = 0; i < clipboard_info.links.length; ++i) {
|
||||
var link_info = clipboard_info.links[i];
|
||||
var origin_node = nodes[link_info[0]];
|
||||
var origin_node;
|
||||
var origin_node_relative_id = link_info[0];
|
||||
if (origin_node_relative_id != null) {
|
||||
origin_node = nodes[origin_node_relative_id];
|
||||
} else if (isConnectUnselected) {
|
||||
var origin_node_id = link_info[4];
|
||||
if (origin_node_id) {
|
||||
origin_node = this.graph.getNodeById(origin_node_id);
|
||||
}
|
||||
}
|
||||
var target_node = nodes[link_info[2]];
|
||||
if( origin_node && target_node )
|
||||
origin_node.connect(link_info[1], target_node, link_info[3]);
|
||||
@@ -7288,7 +7301,7 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
};
|
||||
|
||||
LGraphCanvas.prototype.processNodeSelected = function(node, e) {
|
||||
this.selectNode(node, e && (e.shiftKey||e.ctrlKey));
|
||||
this.selectNode(node, e && (e.shiftKey || e.ctrlKey || this.multi_select));
|
||||
if (this.onNodeSelected) {
|
||||
this.onNodeSelected(node);
|
||||
}
|
||||
@@ -7324,6 +7337,7 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
for (var i in nodes) {
|
||||
var node = nodes[i];
|
||||
if (node.is_selected) {
|
||||
this.deselectNode(node);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -9743,13 +9757,17 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
ctx.fillRect(margin, y, widget_width - margin * 2, H);
|
||||
var range = w.options.max - w.options.min;
|
||||
var nvalue = (w.value - w.options.min) / range;
|
||||
ctx.fillStyle = active_widget == w ? "#89A" : "#678";
|
||||
if(nvalue < 0.0) nvalue = 0.0;
|
||||
if(nvalue > 1.0) nvalue = 1.0;
|
||||
ctx.fillStyle = w.options.hasOwnProperty("slider_color") ? w.options.slider_color : (active_widget == w ? "#89A" : "#678");
|
||||
ctx.fillRect(margin, y, nvalue * (widget_width - margin * 2), H);
|
||||
if(show_text && !w.disabled)
|
||||
ctx.strokeRect(margin, y, widget_width - margin * 2, H);
|
||||
if (w.marker) {
|
||||
var marker_nvalue = (w.marker - w.options.min) / range;
|
||||
ctx.fillStyle = "#AA9";
|
||||
if(marker_nvalue < 0.0) marker_nvalue = 0.0;
|
||||
if(marker_nvalue > 1.0) marker_nvalue = 1.0;
|
||||
ctx.fillStyle = w.options.hasOwnProperty("marker_color") ? w.options.marker_color : "#AA9";
|
||||
ctx.fillRect( margin + marker_nvalue * (widget_width - margin * 2), y, 2, H );
|
||||
}
|
||||
if (show_text) {
|
||||
@@ -9916,6 +9934,7 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
case "slider":
|
||||
var range = w.options.max - w.options.min;
|
||||
var nvalue = Math.clamp((x - 15) / (widget_width - 30), 0, 1);
|
||||
if(w.options.read_only) break;
|
||||
w.value = w.options.min + (w.options.max - w.options.min) * nvalue;
|
||||
if (w.callback) {
|
||||
setTimeout(function() {
|
||||
@@ -9996,6 +10015,12 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
var delta = x < 40 ? -1 : x > widget_width - 40 ? 1 : 0;
|
||||
if (event.click_time < 200 && delta == 0) {
|
||||
this.prompt("Value",w.value,function(v) {
|
||||
// check if v is a valid equation or a number
|
||||
if (/^[0-9+\-*/()\s]+$/.test(v)) {
|
||||
try {//solve the equation if possible
|
||||
v = eval(v);
|
||||
} catch (e) { }
|
||||
}
|
||||
this.value = Number(v);
|
||||
inner_value_change(this, this.value);
|
||||
}.bind(w),
|
||||
@@ -10024,7 +10049,6 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
case "text":
|
||||
if (event.type == LiteGraph.pointerevents_method+"down") {
|
||||
this.prompt("Value",w.value,function(v) {
|
||||
this.value = v;
|
||||
inner_value_change(this, v);
|
||||
}.bind(w),
|
||||
event,w.options ? w.options.multiline : false );
|
||||
@@ -10049,6 +10073,9 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
}//end for
|
||||
|
||||
function inner_value_change(widget, value) {
|
||||
if(widget.type == "number"){
|
||||
value = Number(value);
|
||||
}
|
||||
widget.value = value;
|
||||
if ( widget.options && widget.options.property && node.properties[widget.options.property] !== undefined ) {
|
||||
node.setProperty( widget.options.property, value );
|
||||
@@ -11167,7 +11194,7 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
LGraphCanvas.search_limit = -1;
|
||||
LGraphCanvas.prototype.showSearchBox = function(event, options) {
|
||||
// proposed defaults
|
||||
def_options = { slot_from: null
|
||||
var def_options = { slot_from: null
|
||||
,node_from: null
|
||||
,node_to: null
|
||||
,do_type_filter: LiteGraph.search_filter_enabled // TODO check for registered_slot_[in/out]_types not empty // this will be checked for functionality enabled : filter on slot type, in and out
|
||||
@@ -11865,7 +11892,7 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
|
||||
// TODO refactor, theer are different dialog, some uses createDialog, some dont
|
||||
LGraphCanvas.prototype.createDialog = function(html, options) {
|
||||
def_options = { checkForInput: false, closeOnLeave: true, closeOnLeave_checkModified: true };
|
||||
var def_options = { checkForInput: false, closeOnLeave: true, closeOnLeave_checkModified: true };
|
||||
options = Object.assign(def_options, options || {});
|
||||
|
||||
var dialog = document.createElement("div");
|
||||
@@ -12288,7 +12315,7 @@ LGraphNode.prototype.executeAction = function(action)
|
||||
var ref_window = this.getCanvasWindow();
|
||||
var that = this;
|
||||
var graphcanvas = this;
|
||||
panel = this.createPanel(node.title || "",{
|
||||
var panel = this.createPanel(node.title || "",{
|
||||
closable: true
|
||||
,window: ref_window
|
||||
,onOpen: function(){
|
||||
|
||||
226
src/litegraph.test.js
Normal file
226
src/litegraph.test.js
Normal file
@@ -0,0 +1,226 @@
|
||||
describe("register node types", () => {
|
||||
let lg;
|
||||
let Sum;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
lg = require("./litegraph");
|
||||
Sum = function Sum() {
|
||||
this.addInput("a", "number");
|
||||
this.addInput("b", "number");
|
||||
this.addOutput("sum", "number");
|
||||
};
|
||||
Sum.prototype.onExecute = function (a, b) {
|
||||
this.setOutputData(0, a + b);
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
test("normal case", () => {
|
||||
lg.LiteGraph.registerNodeType("math/sum", Sum);
|
||||
|
||||
let node = lg.LiteGraph.registered_node_types["math/sum"];
|
||||
expect(node).toBeTruthy();
|
||||
expect(node.type).toBe("math/sum");
|
||||
expect(node.title).toBe("Sum");
|
||||
expect(node.category).toBe("math");
|
||||
expect(node.prototype.configure).toBe(
|
||||
lg.LGraphNode.prototype.configure
|
||||
);
|
||||
});
|
||||
|
||||
test("callback triggers", () => {
|
||||
const consoleSpy = jest
|
||||
.spyOn(console, "log")
|
||||
.mockImplementation(() => {});
|
||||
|
||||
lg.LiteGraph.onNodeTypeRegistered = jest.fn();
|
||||
lg.LiteGraph.onNodeTypeReplaced = jest.fn();
|
||||
lg.LiteGraph.registerNodeType("math/sum", Sum);
|
||||
expect(lg.LiteGraph.onNodeTypeRegistered).toHaveBeenCalled();
|
||||
expect(lg.LiteGraph.onNodeTypeReplaced).not.toHaveBeenCalled();
|
||||
lg.LiteGraph.registerNodeType("math/sum", Sum);
|
||||
expect(lg.LiteGraph.onNodeTypeReplaced).toHaveBeenCalled();
|
||||
expect(consoleSpy).toHaveBeenCalledWith(
|
||||
expect.stringMatching("replacing node type")
|
||||
);
|
||||
expect(consoleSpy).toHaveBeenCalledWith(
|
||||
expect.stringMatching("math/sum")
|
||||
);
|
||||
});
|
||||
|
||||
test("node with title", () => {
|
||||
Sum.title = "The sum title";
|
||||
lg.LiteGraph.registerNodeType("math/sum", Sum);
|
||||
let node = lg.LiteGraph.registered_node_types["math/sum"];
|
||||
expect(node.title).toBe("The sum title");
|
||||
expect(node.title).not.toBe(node.name);
|
||||
});
|
||||
|
||||
test("handle error simple object", () => {
|
||||
expect(() =>
|
||||
lg.LiteGraph.registerNodeType("math/sum", { simple: "type" })
|
||||
).toThrow("Cannot register a simple object");
|
||||
});
|
||||
|
||||
test("check shape mapping", () => {
|
||||
lg.LiteGraph.registerNodeType("math/sum", Sum);
|
||||
|
||||
const node_type = lg.LiteGraph.registered_node_types["math/sum"];
|
||||
expect(new node_type().shape).toBe(undefined);
|
||||
node_type.prototype.shape = "default";
|
||||
expect(new node_type().shape).toBe(undefined);
|
||||
node_type.prototype.shape = "box";
|
||||
expect(new node_type().shape).toBe(lg.LiteGraph.BOX_SHAPE);
|
||||
node_type.prototype.shape = "round";
|
||||
expect(new node_type().shape).toBe(lg.LiteGraph.ROUND_SHAPE);
|
||||
node_type.prototype.shape = "circle";
|
||||
expect(new node_type().shape).toBe(lg.LiteGraph.CIRCLE_SHAPE);
|
||||
node_type.prototype.shape = "card";
|
||||
expect(new node_type().shape).toBe(lg.LiteGraph.CARD_SHAPE);
|
||||
node_type.prototype.shape = "custom_shape";
|
||||
expect(new node_type().shape).toBe("custom_shape");
|
||||
|
||||
// Check that also works for replaced node types
|
||||
jest.spyOn(console, "log").mockImplementation(() => {});
|
||||
function NewCalcSum(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
lg.LiteGraph.registerNodeType("math/sum", NewCalcSum);
|
||||
const new_node_type = lg.LiteGraph.registered_node_types["math/sum"];
|
||||
new_node_type.prototype.shape = "box";
|
||||
expect(new new_node_type().shape).toBe(lg.LiteGraph.BOX_SHAPE);
|
||||
});
|
||||
|
||||
test("onPropertyChanged warning", () => {
|
||||
const consoleSpy = jest
|
||||
.spyOn(console, "warn")
|
||||
.mockImplementation(() => {});
|
||||
|
||||
Sum.prototype.onPropertyChange = true;
|
||||
lg.LiteGraph.registerNodeType("math/sum", Sum);
|
||||
expect(consoleSpy).toBeCalledTimes(1);
|
||||
expect(consoleSpy).toBeCalledWith(
|
||||
expect.stringContaining("has onPropertyChange method")
|
||||
);
|
||||
expect(consoleSpy).toBeCalledWith(expect.stringContaining("math/sum"));
|
||||
});
|
||||
|
||||
test("registering supported file extensions", () => {
|
||||
expect(lg.LiteGraph.node_types_by_file_extension).toEqual({});
|
||||
|
||||
// Create two node types with calc_times overriding .pdf
|
||||
Sum.supported_extensions = ["PDF", "exe", null];
|
||||
function Times() {
|
||||
this.addInput("a", "number");
|
||||
this.addInput("b", "number");
|
||||
this.addOutput("times", "number");
|
||||
}
|
||||
Times.prototype.onExecute = function (a, b) {
|
||||
this.setOutputData(0, a * b);
|
||||
};
|
||||
Times.supported_extensions = ["pdf", "jpg"];
|
||||
lg.LiteGraph.registerNodeType("math/sum", Sum);
|
||||
lg.LiteGraph.registerNodeType("math/times", Times);
|
||||
|
||||
expect(
|
||||
Object.keys(lg.LiteGraph.node_types_by_file_extension).length
|
||||
).toBe(3);
|
||||
expect(lg.LiteGraph.node_types_by_file_extension).toHaveProperty("pdf");
|
||||
expect(lg.LiteGraph.node_types_by_file_extension).toHaveProperty("exe");
|
||||
expect(lg.LiteGraph.node_types_by_file_extension).toHaveProperty("jpg");
|
||||
|
||||
expect(lg.LiteGraph.node_types_by_file_extension.exe).toBe(Sum);
|
||||
expect(lg.LiteGraph.node_types_by_file_extension.pdf).toBe(Times);
|
||||
expect(lg.LiteGraph.node_types_by_file_extension.jpg).toBe(Times);
|
||||
});
|
||||
|
||||
test("register in/out slot types", () => {
|
||||
expect(lg.LiteGraph.registered_slot_in_types).toEqual({});
|
||||
expect(lg.LiteGraph.registered_slot_out_types).toEqual({});
|
||||
|
||||
// Test slot type registration with first type
|
||||
lg.LiteGraph.auto_load_slot_types = true;
|
||||
lg.LiteGraph.registerNodeType("math/sum", Sum);
|
||||
expect(lg.LiteGraph.registered_slot_in_types).toEqual({
|
||||
number: { nodes: ["math/sum"] },
|
||||
});
|
||||
expect(lg.LiteGraph.registered_slot_out_types).toEqual({
|
||||
number: { nodes: ["math/sum"] },
|
||||
});
|
||||
|
||||
// Test slot type registration with second type
|
||||
function ToInt() {
|
||||
this.addInput("string", "string");
|
||||
this.addOutput("number", "number");
|
||||
};
|
||||
ToInt.prototype.onExecute = function (str) {
|
||||
this.setOutputData(0, Number(str));
|
||||
};
|
||||
lg.LiteGraph.registerNodeType("basic/to_int", ToInt);
|
||||
expect(lg.LiteGraph.registered_slot_in_types).toEqual({
|
||||
number: { nodes: ["math/sum"] },
|
||||
string: { nodes: ["basic/to_int"] },
|
||||
});
|
||||
expect(lg.LiteGraph.registered_slot_out_types).toEqual({
|
||||
number: { nodes: ["math/sum", "basic/to_int"] },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("unregister node types", () => {
|
||||
let lg;
|
||||
let Sum;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
lg = require("./litegraph");
|
||||
Sum = function Sum() {
|
||||
this.addInput("a", "number");
|
||||
this.addInput("b", "number");
|
||||
this.addOutput("sum", "number");
|
||||
};
|
||||
Sum.prototype.onExecute = function (a, b) {
|
||||
this.setOutputData(0, a + b);
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
test("remove by name", () => {
|
||||
lg.LiteGraph.registerNodeType("math/sum", Sum);
|
||||
expect(lg.LiteGraph.registered_node_types["math/sum"]).toBeTruthy();
|
||||
|
||||
lg.LiteGraph.unregisterNodeType("math/sum");
|
||||
expect(lg.LiteGraph.registered_node_types["math/sum"]).toBeFalsy();
|
||||
});
|
||||
|
||||
test("remove by object", () => {
|
||||
lg.LiteGraph.registerNodeType("math/sum", Sum);
|
||||
expect(lg.LiteGraph.registered_node_types["math/sum"]).toBeTruthy();
|
||||
|
||||
lg.LiteGraph.unregisterNodeType(Sum);
|
||||
expect(lg.LiteGraph.registered_node_types["math/sum"]).toBeFalsy();
|
||||
});
|
||||
|
||||
test("try removing with wrong name", () => {
|
||||
expect(() => lg.LiteGraph.unregisterNodeType("missing/type")).toThrow(
|
||||
"node type not found: missing/type"
|
||||
);
|
||||
});
|
||||
|
||||
test("no constructor name", () => {
|
||||
function BlankNode() {}
|
||||
BlankNode.constructor = {}
|
||||
lg.LiteGraph.registerNodeType("blank/node", BlankNode);
|
||||
expect(lg.LiteGraph.registered_node_types["blank/node"]).toBeTruthy()
|
||||
|
||||
lg.LiteGraph.unregisterNodeType("blank/node");
|
||||
expect(lg.LiteGraph.registered_node_types["blank/node"]).toBeFalsy();
|
||||
})
|
||||
});
|
||||
@@ -363,7 +363,7 @@
|
||||
return -1;
|
||||
if(l == 1)
|
||||
return 0;
|
||||
//dichotimic search
|
||||
//dichotomic search
|
||||
while (imax >= imin)
|
||||
{
|
||||
imid = ((imax + imin)*0.5)|0;
|
||||
|
||||
@@ -5338,7 +5338,7 @@ void main(void){\n\
|
||||
}
|
||||
gl.finish2D();
|
||||
});
|
||||
else //rendering to offscren canvas and uploading to texture
|
||||
else //rendering to offscreen canvas and uploading to texture
|
||||
{
|
||||
if(properties.clear)
|
||||
ctx.clearRect(0,0,canvas.width,canvas.height);
|
||||
|
||||
@@ -93,10 +93,10 @@
|
||||
logicAnd.title = "AND";
|
||||
logicAnd.desc = "Return true if all inputs are true";
|
||||
logicAnd.prototype.onExecute = function() {
|
||||
ret = true;
|
||||
for (inX in this.inputs){
|
||||
var ret = true;
|
||||
for (var inX in this.inputs){
|
||||
if (!this.getInputData(inX)){
|
||||
ret = false;
|
||||
var ret = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -119,8 +119,8 @@
|
||||
logicOr.title = "OR";
|
||||
logicOr.desc = "Return true if at least one input is true";
|
||||
logicOr.prototype.onExecute = function() {
|
||||
ret = false;
|
||||
for (inX in this.inputs){
|
||||
var ret = false;
|
||||
for (var inX in this.inputs){
|
||||
if (this.getInputData(inX)){
|
||||
ret = true;
|
||||
break;
|
||||
@@ -159,9 +159,9 @@
|
||||
logicCompare.title = "bool == bool";
|
||||
logicCompare.desc = "Compare for logical equality";
|
||||
logicCompare.prototype.onExecute = function() {
|
||||
last = null;
|
||||
ret = true;
|
||||
for (inX in this.inputs){
|
||||
var last = null;
|
||||
var ret = true;
|
||||
for (var inX in this.inputs){
|
||||
if (last === null) last = this.getInputData(inX);
|
||||
else
|
||||
if (last != this.getInputData(inX)){
|
||||
|
||||
16
utils/test.sh
Executable file
16
utils/test.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
|
||||
|
||||
export NVM_DIR=$HOME/.nvm
|
||||
source "$NVM_DIR/nvm.sh"
|
||||
|
||||
# This are versions 12, 14, 16, 18
|
||||
NODE_VERSIONS=("lts/erbium" "lts/fermium" "lts/gallium" "lts/hydrogen")
|
||||
|
||||
for NODE_VERSION in "${NODE_VERSIONS[@]}"; do
|
||||
nvm install "$NODE_VERSION"
|
||||
nvm exec "$NODE_VERSION" npm install
|
||||
nvm exec "$NODE_VERSION" npm test
|
||||
done
|
||||
Reference in New Issue
Block a user