Code Multiplexer Component
One thing I ran into was wanting to be able to use a single code component to handle multiple inputs and outputs. This would allow for a smaller footprint when designing flows and prevent duplication of code components.
I do not have the component fully fleshed out yet, missing the readme, and because I built this before the fix for #82 still suffers the initial issue. I think this would be a great component to add, or possibly even replace current code component.
<script total>
exports.name = 'Multiplexer';
exports.icon = 'fa fa-exchange-alt';
exports.author = 'Colton McInroy';
exports.version = '1';
exports.group = 'Common';
exports.config = { name: 'Label', inputs: [{ id: 'input', name: 'Input' }], outputs: [{ id: 'output', name: 'Output' }], code: '// instance {FlowStreamInstance};\n// $ {FlowStreamMessage};\n// vars {Object};\n// repo {Object};\n// data {String/Number/Boolean/Date/Buffer/Object};\n// $.send(\'output\', data); // or simply send(data); which uses the first output\n// $.destroy();\n// $.throw(err);\n\n// IMPORTANT: If you do not perform re-send, you need to destroy this message via $.destroy() method\n// IMPORTANT: methods $.send(), $.destroy() and $.throw() can be executed only once\n\n// $.send(\'output\', data);\n// $.destroy();\nif ($.input === \'input\') {\n $.send(\'output\', data);\n return;\n}' };
exports.inputs = [{ id: 'input', name: 'Input' }];
exports.outputs = [{ id: 'output', name: 'Output' }];
// exports.npm = ['npm_module_1', 'npm_module_2@version'];
// exports.meta = { readonly: false, singleton: false, hidden: false };
exports.make = function(instance, config) {
let fn;
// instance.main.variables {Object}
// instance.main.variables2 {Object}
// instance.save();
// instance.replace(str); // replaces {variable_name} for values from "variables" and "variables2"
// instance.status(obj, [refresh_delay_in_ms]);
instance.message = function($) {
// var data = $.data;
// $.send('output', data);
// or $.destroy();
if (fn) {
try {
// var send = data => $.send('output', data);
fn($.data, instance, $, $, F.require, $.send, $.repo, $.vars, $.data);
} catch (e) {
$.throw(e);
$.destroy();
}
}
};
instance.configure = function() {
if (!config.outputs.length || !config.inputs.length)
return;
// "config" is changed
instance.inputs = [];
instance.outputs = [];
config.inputs.forEach((input, i) => {
instance.inputs.push({ id: input.id || 'input' + (i + 1), name: input.name || 'Input #' + (i + 1) });
});
config.outputs.forEach((output, i) => {
instance.outputs.push({ id: output.id || 'output' + (i + 1), name: output.name || 'Output #' + (i + 1) });
});
instance.save();
try {
if (config.code) {
instance.status(1);
fn = new Function('value', 'instance', '$', 'message', 'require', 'send', 'repo', 'vars', 'data', config.code);
} else {
instance.status(0);
fn = null;
}
} catch (e) {
fn = null;
instance.throw('Code: ' + e.message);
}
};
instance.close = function() {
// this instance is closed
fn = null;
};
instance.variables = function(variables) {
// FlowStream variables are changed
};
instance.variables2 = function(variables) {
// Global variables are changed
};
instance.configure();
};
</script>
<readme>
Markdown readme
</readme>
<settings>
<div class="padding">
<div data---="input__?.name" class="m">Name</div>
<section class="switch-inputs m">
<label class="ui-input-label">Inputs</label>
<div class="switch-thead">
<div class="row">
<div class="col-md-1">#</div>
<div class="col-md-5">Input id</div>
<div class="col-md-5">Input name</div>
<div class="col-md-1">Action</div>
</div>
</div>
<ui-bind path="?.inputs" config="template:.switch-input -> data-index" clas="block">
<ui-component name="movable" path="?.inputs" config="selector:.dragme;exec:FUNC.switch_input_dragged">
<script type="text/html">
{{ foreach con in value }}
<div class="switch-input dragme" data-index="{{ $index }}" draggable="true">
<div class="row">
<div class="col-md-1">
{{ ($index + 1) }}.
</div>
<div class="col-md-5">
<ui-component name="input" path="?.inputs[{{ $index }}].id"></ui-component>
</div>
<div class="col-md-5">
<ui-component name="input" path="?.inputs[{{ $index }}].name"></ui-component>
</div>
<div class="col-md-1">
<i class="ti ti-trash red exec" data-exec="FUNC.switch_remove_input"></i>
</div>
</div>
</div>
{{ end }}
</script>
</ui-component>
</ui-bind>
<div class="help m">Each input corresponds to an output index. First input --> First output, etc.</div>
<button class="button-add exec" data-exec="FUNC.switch_add_input">ADD</button>
</section>
<section class="switch-outputs m">
<label class="ui-input-label">Outputs</label>
<div class="switch-thead">
<div class="row">
<div class="col-md-1">#</div>
<div class="col-md-5">Output id</div>
<div class="col-md-5">Output name</div>
<div class="col-md-1">Action</div>
</div>
</div>
<ui-bind path="?.outputs" config="template:.switch-output -> data-index" clas="block">
<ui-component name="movable" path="?.outputs" config="selector:.dragme;exec:FUNC.switch_output_dragged">
<script type="text/html">
{{ foreach con in value }}
<div class="switch-output dragme" data-index="{{ $index }}" draggable="true">
<div class="row">
<div class="col-md-1">
{{ ($index + 1) }}.
</div>
<div class="col-md-5">
<ui-component name="input" path="?.outputs[{{ $index }}].id"></ui-component>
</div>
<div class="col-md-5">
<ui-component name="input" path="?.outputs[{{ $index }}].name"></ui-component>
</div>
<div class="col-md-1">
<i class="ti ti-trash red exec" data-exec="FUNC.switch_remove_output"></i>
</div>
</div>
</div>
{{ end }}
</script>
</ui-component>
</ui-bind>
<div class="help m">Each output corresponds to an output index. First output --> First output, etc.</div>
<button class="button-add exec" data-exec="FUNC.switch_add_output">ADD</button>
</section>
<button class="button exec" style="width: 200px;" data-exec="FUNC.switch_readme"><i class="ti ti-info-circle blue"></i>Show configuration info</button>
<div class="ui-input-label">Code:</div>
<ui-component name="codemirror" path="?.code" config="type:javascript;minheight:200;parent:auto;margin:60;tabs:true;trim:true" class="m"></ui-component>
</div>
</settings>
<script>
FUNC.switch_readme = function() {
EXEC('flow/readme', flow.info.selected.component);
};
FUNC.switch_add_input = function(el) {
var scope = el.scope();
PUSH(scope.path + '.inputs', { operator: '==', type: 'string', value: '' });
};
FUNC.switch_remove_input = function(el) {
var path = el.scope().path;
var config = GET(path);
var index = el.closest('.switch-input').attrd('index');
config.inputs.splice(index, 1);
SET(path, config);
console.log(config);
};
FUNC.switch_input_dragged = function(list, dragged, target) {
dragged = $(dragged);
var dragged_index = dragged.attrd('index');
var target_index = $(target).attrd('index');
var path = dragged.scope().path;
var config = GET(path);
var dragged_item = config.inputs.splice(dragged_index, 1)[0];
config.inputs.splice(target_index, 0, dragged_item);
SET(path, config);
};
FUNC.switch_add_output = function(el) {
var scope = el.scope();
PUSH(scope.path + '.outputs', { });
};
FUNC.switch_remove_output = function(el) {
var path = el.scope().path;
var config = GET(path);
var index = el.closest('.switch-output').attrd('index');
config.outputs.splice(index, 1);
SET(path, config);
console.log(config);
};
FUNC.switch_output_dragged = function(list, dragged, target) {
dragged = $(dragged);
var dragged_index = dragged.attrd('index');
var target_index = $(target).attrd('index');
var path = dragged.scope().path;
var config = GET(path);
var dragged_item = config.outputs.splice(dragged_index, 1)[0];
config.outputs.splice(target_index, 0, dragged_item);
SET(path, config);
};
FUNC.switch_tooltip = function(el) {
var opt = {};
opt.element = el;
var id = el.attrd('id');
opt.html = REPO.switch_tooltips[id];
SETTER('tooltip', 'show', opt);
};
// Client-side script
// Optional, you can remove it
// A custom helper for the component instances
// The method below captures each instance of this component
TOUCH(function(exports, reinit) {
var name = exports.name + ' --> ' + exports.id;
console.log(name, 'initialized' + (reinit ? ' : UPDATE' : ''));
exports.settings = function(meta) {
// Triggered when the user opens settings
console.log(name, 'settings', meta);
};
exports.configure = function(config, isinit) {
// Triggered when the config is changed
console.log(name, 'configure', config);
var changes = exports.instance.changes;
if (changes && changes.newbie) {
const inputs = [];
for (const input of exports.instance.config.inputs) {
let i = inputs.length+1;
inputs.push({ id: input.id || 'input' + i, name: input.name || 'Input #' + i });
}
exports.instance.inputs = inputs;
const outputs = [];
for (const output of exports.instance.config.outputs) {
let i = outputs.length+1;
outputs.push({ id: output.id || 'output' + i, name: output.name || 'Output #' + i });
}
exports.instance.outputs = outputs;
UPD('flow.data');
}
};
exports.status = function(status, isinit) {
// Triggered when the status is changed
console.log(name, 'status', status);
};
exports.note = function(note, isinit) {
// Triggered when the note is changed
console.log(name, 'note', note);
};
exports.variables = function(variables) {
// Triggered when the variables are changed
console.log(name, 'variables', variables);
};
exports.variables2 = function(variables) {
// Triggered when the variables2 are changed
console.log(name, 'variables2', variables);
};
exports.close = function() {
// Triggered when the instance is closing due to some reasons
console.log(name, 'close');
};
});
</script>
<style>
.CLASS footer { padding: 10px; font-size: 12px; }
.button-add { height: 24px; font-size: 12px; border: 1px solid #E0E0E0; border-radius: var(--radius); color: #000; background-color: #f0f0f0; margin: 0; padding: 2px 10px; }
.button-add:hover { background-color: #F8F8F8; }
.button-add:active { background-color: #E0E0E0; }
.ui-dark .button-add { border-color: #404040; color: #FFF; background-color: #202020; }
.ui-dark .button-add:hover { background-color: #303030; }
.ui-dark .button-add:active { background-color: #404040; }
.switch-input-group { clear: both; height: 36px; }
.switch-input-group > ui-component:first-child .ui-input-control { border-right: none; border-bottom-right-radius: 0; border-top-right-radius: 0; width: 120px; float: left; background-color: #f0f0f0; }
.switch-input-group > ui-component:last-child .ui-input-control { border-bottom-left-radius: 0; border-top-left-radius: 0; float: left; width: calc(100% - 120px); }
.switch-input-group.wide > ui-component:first-child .ui-input-control { width: 200px; }
.switch-input-group.wide > ui-component:last-child .ui-input-control { width: calc(100% - 200px); }
.switch-inputs { border: 1px solid #e0e0e0; padding: 8px; border-radius: 3px; }
.switch-input { border: 1px solid #e0e0e0; border-radius: 3px; padding: 8px; margin-bottom:4px; }
.switch-input > .row > .col-md-1 { height: 36px; line-height: 36px; }
.switch-output-group { clear: both; height: 36px; }
.switch-output-group > ui-component:first-child .ui-output-control { border-right: none; border-bottom-right-radius: 0; border-top-right-radius: 0; width: 120px; float: left; background-color: #f0f0f0; }
.switch-output-group > ui-component:last-child .ui-output-control { border-bottom-left-radius: 0; border-top-left-radius: 0; float: left; width: calc(100% - 120px); }
.switch-output-group.wide > ui-component:first-child .ui-output-control { width: 200px; }
.switch-output-group.wide > ui-component:last-child .ui-output-control { width: calc(100% - 200px); }
.switch-outputs { border: 1px solid #e0e0e0; padding: 8px; border-radius: 3px; }
.switch-output { border: 1px solid #e0e0e0; border-radius: 3px; padding: 8px; margin-bottom:4px; }
.switch-output > .row > .col-md-1 { height: 36px; line-height: 36px; }
.switch-help { background-color: #e7e7ff; border-radius: 3px; padding: 4px; }
.switch-thead { padding: 8px; margin-bottom:4px; }
</style>
<body>
<header>
<i class="ICON"></i>NAME (<span data-bind="CONFIG.name__text"></span>)
</header>
</body>
@ColtonMcInroy Instead of using syntax highlighter here, please upload .html files only.
@ColtonMcInroy I can publish it to the main FlowStreamComponents repo if you agree, but please add readme information. Thank you!
Here is an updated version of this component with readme information provided. Multiplexer.zip
One thing I should mention, currently I used the "Switch" component to figure out how to handle creating the inputs/outputs. The drag/drop for re-ordering functionality in both the Switch component and this multiplexer component do not appear to work. I have not had time to look into it yet.