UNPKG

node-red-contrib-chatbot

Version:

REDBot a Chat bot for a full featured chat bot for Telegram, Facebook Messenger and Slack. Almost no coding skills required

390 lines (372 loc) 15 kB
<script type="text/javascript"> var mountControl = function(container, param, defaultParam, callback) { container.empty(); switch(param.type) { case 'string': var suggestions = ''; var size = '100%' if (param.suggestions != null && param.suggestions.length !== 0) { suggestions = '<select value="' + (defaultParam != null ? defaultParam : '') + '" name="suggestions" autocomplete="disable" style="width: 18px;border: none;display: inline-block;">' + '<option value="">Select:</option>' + param.suggestions.map(function(suggestion) { return '<option value="' + suggestion + '">' + suggestion + '</option>'; }) + '</select>'; size = 'calc(100% - 18px)'; } container.append( '<div class="form-row" style="display:inline-block;margin-left:10px;">' + '<input type="text" value="' + (defaultParam != null ? defaultParam : '') + '" autocomplete="disable" style="width:' + size + ';" placeholder="' + (param.placeholder != null && param.placeholder != '' ? param.placeholder : '') + '">' + suggestions + '</div>' ); $('input', container) .keyup(function() { callback($(this).val()); }); $('select[name=suggestions]') .change(function(e) { $('input', container).val($(this).val()); callback($(this).val()); }); break; case 'boolean': container.append( '<div class="form-row" style="display:inline-block;margin-left:10px;">' + '<input type="radio" name="radio_' + param.name + '" value="true" style="width:20px;margin-top:-2px;"> Yes' + '<input type="radio" name="radio_' + param.name + '" value="false" style="width:20px;margin-top:-2px;margin-left:5px;"> No' + '</div>' ); $('input', container) .click(function() { callback($(this).attr('value') === 'true'); }); if (defaultParam === true || defaultParam === 'true') { $('input[type=radio][value=true]', container).attr('checked', true); } else if (defaultParam === false || defaultParam === 'false') { $('input[type=radio][value=false]', container).attr('checked', true); } break; case 'select': var options = ''; var idx = 0; for (idx = 0; idx < param.options.length; idx++) { options += '<option value="' + param.options[idx].value + '">' + param.options[idx].label + '</option>'; } container .append( '<div class="form-row" style="display:inline-block;margin-left:10px;">' + '<select autocomplete="disable" style="width:100%;" placeholder="' + (param.placeholder != null && param.placeholder != '' ? param.placeholder : '') + '">' + options + '</select>' + '</div>' ) $('select', container).val(defaultParam != null ? defaultParam : '') $('select', container) .change(function() { callback($(this).val()); }); // if no initial value specified, then use one from param type if (defaultParam == null && param.default != null) { callback(param.default); } break; } } var buildParam = function(row, platform, current) { var node = this; var params = node.availableParams[platform]; var idx = 0; var tooltip = null; var platformDefinition = null; for(idx = 0; idx < node.platforms.length; idx++) { if (node.platforms[idx].id === platform) { platformDefinition = node.platforms[idx]; } } var paramsOptions = ''; for(idx = 0; idx < params.length; idx++) { paramsOptions += '<option value="' + params[idx].name + '">' + params[idx].label + '</option>'; } row.empty() .append('<span class="platform" ' + 'style="font-size:10px;background-color:' + (platformDefinition != null && platformDefinition.color != null ? platformDefinition.color : '#bbbbbb') + ';padding: 2px 3px 2px 3px;border-radius:2px;text-transform:uppercase;color:#ffffff;margin-left:5px;"' + '>' + platform + '</span>') .append('<select class="param-name" name="transport" style="width:40%;margin-left:10px;">' + '<option value="">Select parameter</option>' + paramsOptions + '</select>') .append('<input class="value" type="hidden" name="" value="">') .append('<input class="type" type="hidden" name="type" value="">') .append('<span class="hint" style="margin-left:8px;display:inline-block;"><i class="fa fa-question-circle" style="color:#999999;"/></div>') .append('<div class="control" style="display:inline-block;height:34px;width:35%;">&nbsp;</div>'); $('.hint', row).hide(); $('select.param-name', row) .change(function() { var param = $(this).val(); var paramObj = null; for(idx = 0; idx < params.length; idx++) { if (params[idx].name === param) { paramObj = params[idx]; } } if (paramObj != null) { $('input[type=hidden].value', row).attr('name', param); $('input[type=hidden].value', row).attr('value', paramObj.default != null ? paramObj.default : null); $('input[type=hidden].type', row).attr('value', paramObj.type); mountControl( $('.control', row), paramObj, paramObj.default != null ? paramObj.default : null, function(value) { $('input[type=hidden].value', row).attr('value', value); } ); if (paramObj.description != null) { if (tooltip != null) { tooltip.dispose(); tooltip = null; } tooltip = new Tooltip($('.hint', row).get(0), { placement: 'right-start', title: paramObj.description, trigger: 'hover' }); $('.hint', row).show(); } else { $('.hint', row).hide(); if (tooltip != null) { tooltip.dispose(); tooltip = null; } } } }); if (current != null) { var paramObj = null; for(idx = 0; idx < params.length; idx++) { if (params[idx].name === current.name) { paramObj = params[idx]; } } $('input[type=hidden].type', row).attr('value', paramObj.type); $('input[type=hidden].value', row).attr('name', current.name); $('input[type=hidden].value', row).attr('value', current.value); $('select.param-name', row).val(current.name); mountControl( $('.control', row), paramObj, current.value, function(value) { $('input[type=hidden].value', row).attr('value', value); } ); if (paramObj.description != null) { if (tooltip != null) { tooltip.dispose(); tooltip = null; } tooltip = new Tooltip($('.hint', row).get(0), { placement: 'right-start', title: paramObj.description, trigger: 'hover' }); $('.hint', row).show(); } } } var buildParams = function() { var node = this; $("#node-input-params-container").css('min-height','250px').css('min-width','450px').editableList({ addButton: 'Add parameter', addItem: function (container, i, opt) { // build rule row var param = opt; var isEmpty = param.platform == null; // empty row var row = $('<div/>').appendTo(container); if (!isEmpty) { buildParam.call(node, row, param.platform, param); return; } else { // build transport options var transportOptions = '<option value="all">All</option>'; for(idx = 0; idx < node.platforms.length; idx++) { // only if some parameters if (node.availableParams[node.platforms[idx].id] != null) { transportOptions += '<option value="' + node.platforms[idx].id + '">' + (node.platforms[idx].name != null ? node.platforms[idx].name : node.platforms[idx].id) + '</option>'; } } row .append('<select class="transport" name="transport" style="width:40%;margin-left:10px;">' + '<option value="">Select transport</option>' + transportOptions + '</select>') $('select.transport', row) .change(function() { buildParam.call(node, row, $(this).val()); }); } }, removeItem: function(opt) { var rules = $('#node-input-params-container').editableList('items'); rules.each(function(i) { $(this).find('.node-input-rule-index').html(i + 1); }); }, sortItems: function() { var rules = $('#node-input-params-container').editableList('items'); rules.each(function(i) { $(this).find('.node-input-rule-index').html(i + 1); }); }, sortable: false, removable: true }); for (var i=0; i < node.params.length; i++) { var param = this.params[i]; $('#node-input-params-container').editableList('addItem', param); } }; $.RedBot.registerType('chatbot-params', { category: $.RedBot.config.name + ' Flow', color: '#FFCC66', defaults: { name: { value: '' }, params: { value: [], validate: function(params) { return $.RedBot.validate.params(params); } }, outputs: { value: 1 } }, inputs: 1, outputs: 1, paletteLabel: 'Params', icon: 'chatbot-params.png', label: function() { return this.name || 'Params' ; }, oneditsave: function() { var params = $('#node-input-params-container').editableList('items'); var node = this; node.params = []; params.each(function(i) { var paramRow = $(this); var platform = paramRow.find('.platform').text(); var name = paramRow.find('input[type=hidden].value').attr('name'); var value = paramRow.find('input[type=hidden].value').attr('value'); var type = paramRow.find('input[type=hidden].type').attr('value'); // do some conversion if (type === 'boolean') { value = value === 'true' || value === true; } node.params.push({ platform: platform, name: name, value: value }); }); }, oneditprepare: function() { var node = this; var nodeRedUrl = $.RedBot.getNodeRedUrl(); $.get(nodeRedUrl + 'redbot/globals') .done(function(response) { node.messageTypes = response.messageTypes; node.eventTypes = response.eventTypes; node.availableParams = response.params; $.RedBot.fetchPlatforms() .done(function(platforms) { node.platforms = platforms; buildParams.call(node); }); }); }, oneditresize: function() { var dialogForm = $('#dialog-form'); var rowName = $('.form-row-name', dialogForm); var rowLabel = $('.form-row-label', dialogForm); var height = dialogForm.height() - rowName.height() - rowLabel.height() - 30; $('#node-input-params-container').editableList('height', height); } }); </script> <script type="text/x-red" data-template-name="chatbot-params"> <div class="form-row form-row-name"> <label for="node-input-name"><i class="icon-tag"></i> Name</label> <input type="text" id="node-input-name" placeholder="Name"> </div> <div class="form-row form-row-label"> <label for="node-input-name" style="width:100%;">Add parameter to the chat flow:</label> </div> <div class="form-row node-input-params-container-row"> <ol id="node-input-params-container"></ol> </div> </script> <script type="text/x-red" data-help-name="chatbot-params"><p>The <code>Params node</code> is used to specify some platform related parameters or flag. For example in <strong>Telegram</strong> it’s possible to deliver a message silently while in <strong>Twilio</strong> it’s possible to specify the originator number (overriding the bot configuration).</p> <p>The text-like values of parameters also accepts chat contexts variables. For example in <strong>Telegram</strong> to modify the previous sent message instead of sending a new one, just add a parameter, select platform <strong>Telegram</strong> then select <em>“Modify message”</em> and then type <code>{{outboundMessageId}}</code></p> <p><img src="https://s3.us-west-2.amazonaws.com/secure.notion-static.com/159083b5-2efd-4d12-b603-51634fade887/modify-message.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45EIPT3X45%2F20230218%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20230218T124947Z&X-Amz-Expires=3600&X-Amz-Signature=df019690f0c7996e7abf979726b71e2a1ccf75d7ac8cfca354d2456cafcd9fba&X-Amz-SignedHeaders=host&x-id=GetObject" alt="Modify message"></p> <p>The same chat context value <code>{{outboundMessageId}}</code> can be used, for example, to delete a previous message.</p> <p>The same can obtained with in a upstream <code>Function node</code>:</p> <pre><code class="language-javascript">msg.params = [ { platform: &#39;telegram&#39;, name: &#39;modifyMessageId&#39;, value: &#39;{{outboundMessageId}}&#39; ]; return msg; </code></pre> <p>Available parameters for the <code>msg.payload</code></p> <table> <thead> <tr> <th>Name</th> <th>Type</th> <th>Description</th> </tr> </thead> <tbody><tr> <td>params</td> <td>array of [param]</td> <td>Array of parameters to send to the Sender node</td> </tr> </tbody></table> <p>The <em>param</em> object</p> <table> <thead> <tr> <th>Name</th> <th>Type</th> <th>Description</th> </tr> </thead> <tbody><tr> <td>platform</td> <td>string</td> <td>The specific platform (transport) this parameter is used for (<em>telegram</em>, <em>slack</em>, <em>facebook</em>, etc)</td> </tr> <tr> <td>name</td> <td>string</td> <td>The name of the parameter</td> </tr> <tr> <td>value</td> <td>any</td> <td>The value of the parameter</td> </tr> </tbody></table> <blockquote> <p>❗ The chat context <code>messageId</code> is deprecated, it was used ambiguously in previous versions to refer both the last inbound and outbound message. It’s replace by <code>outboundMessageId</code> (the id of the last message sent by the chatbot to the user) and <code>inboundMessageId</code> (the id of the last message received by the chatbot from the user).<br>For retro-compatibility <code>messageId</code> is still available. </p> </blockquote> </script>