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

806 lines (754 loc) 844 kB
<script type="text/javascript"> $.fn.RB_setComboWithPlatformLabels = function(value) { var combo = $(this); $(this).val(value); var selected = $('option[value=' + value + ']', this); combo .attr('class') .split(' ') .forEach(function(className) { if (className.indexOf('platform-') !== -1) { combo.removeClass(className); } }); if (selected != null) { combo.addClass(selected.attr('class')); } }; $.fn.RB_comboWithPlatformLabels = function() { $(this) .change(function() { var combo = $(this); var selected = $('option[value=' + combo.val() + ']', this); combo .attr('class') .split(' ') .forEach(function(className) { if (className.indexOf('platform-') !== -1) { combo.removeClass(className); } }); if (selected != null) { combo.addClass(selected.attr('class')); } }); }; $.fn.RB_OptionsEditor = function(command, options) { var container = $(this); var defaultOptions = { label: 'Options', labelAdd: 'add' }; if (arguments.length === 1 && typeof arguments[0] === 'object') { options = $.extend({}, defaultOptions, arguments[0]); command = 'init'; } else if (arguments.length === 0) { command = 'init'; options = $.extend({}, defaultOptions); } else if (arguments.length === 1 && arguments[0] === 'value') { command = 'get_value'; } else if (arguments.length === 2 && arguments[0] === 'value') { command = 'set_value'; } var addRow = function(value, label) { var count = $('.option', container); $('<div class="option"/>').css('marginTop','5px') .append('<div style="display:inline-block;width:6%;" class="order">' + (count.length + 1) + '.</div>') .append($('<input style="width:35%" class="node-input-rule-type" type="text" name="value" placeholder="Value" value="' + value + '"/>')) .append($('<input style="width:48%;margin-left: 5%" class="node-input-rule-type" type="text" name="label" placeholder="Label" value="' + label + '"/>')) .append('<a href="#" class="btn-remove" style="width:5%;display:inline-block;"><i class="fa fa-times"></i></a>') .appendTo($('.options', container)); }; switch(command) { case 'init': container .addClass('rb-options-editor') .on('click', '.btn-remove', function() { $(this).parents('.option').remove(); $('.option', container).each(function(idx, item) { $('.order', item).html(idx + 1); }); }); $('<div class="control-description"/>') .html(options.label) .appendTo(container); $('<div class="options"/>') .appendTo(container); $('<div class="button"/>') .append('<a class="btn-add" href="#">' + options.labelAdd+ '</a>') .appendTo(container); $('a.btn-add', container) .click(function(e) { e.preventDefault(); addRow('', ''); }); break; case 'get_value': var values = []; $('.option', container).each(function(idx, item) { var value = $('input[name=value]', item).val(); var label = $('input[name=label]', item).val(); if (value === '' && label !== '') { value = label; } else if (value !== '' && label === '') { label = value; } if (value !== '' && label !== '') { values.push({ value: value, label: label }); } }); return values; case 'set_value': $('.options').empty(); $(arguments[1]).each(function(idx, option) { addRow(option.value, option.label); }); break; } return container; }; $.fn.RB_setElementData = function(obj, options) { options = options || {}; options.badges = options.badges !== false; var container = $(this); var select = $('select[name=type]', container).val(obj.type); var panel = $('.panel-' + obj.type, container).show(); var element = $.RedBot.elementTypes.findElement(obj.type); if (element != null && options.badges) { select.attr('class', element.className); } $('input[name="label"]', panel).val(obj.label); $('input[name="name"]', panel).val(obj.name); $('input[name="value"]', panel).val(obj.value); $('input[name="placeholder"]', panel).val(obj.placeholder); $('input[name="hint"]', panel).val(obj.hint); $('select[name="subtype"]', panel).val(obj.subtype); $('input[name="max_length"]', panel).val(obj.maxLength); $('input[name="min_length"]', panel).val(obj.minLength); $('input[name="optional"]', panel).attr('checked', obj.optional === true); $('.container-options', panel).RB_OptionsEditor('value', obj.options); return container; }; $.fn.RB_setButtonData = function(obj, options) { options = options || {}; options.badges = options.badges !== false; var container = $(this); var availablePlatforms = $.isArray(container.data('platforms')) ? container.data('platforms') : ['facebook', 'telegram']; var select = $('select[name=type]', container).val(obj.type); var panel = $('.panel-' + obj.type, container).show(); var button = $.RedBot.buttonTypes.findButton(obj.type); // update badges of select with intersection of available platforms and button compatibility if (button != null && options.badges) { $.RedBot.supportedBy($('.type-badges', container), $.RedBot.intersect(availablePlatforms, button.platforms)); //select.attr('class', $.RedBot.platformClass('select', $.RedBot.intersect(availablePlatforms, button.platforms))); } else { //select.attr('class', ''); $('.type-badges', container).empty(); } $('input[name=label]', panel).val(obj.label); $('input[name=url]', panel).val(obj.url); $('input[name=value]', panel).val(obj.value); $('input[name=number]', panel).val(obj.number); $('input[name=answer]', panel).val(obj.answer); $('input[name=alert]', panel).attr('checked', obj.alert === true); $('select[name=webview_height_ratio]', panel).val(obj.webViewHeightRatio); $('select[name=style]', panel).val(obj.style); $('input[name=messenger_extensions]').attr('checked', obj.extensions === true); return container; }; $.fn.RB_getElementData = function() { var container = $(this); var type = $('select[name="type"]', container); var panel = $('.panel-' + type.val(), container); var label = $('input[name="label"]', panel); var name = $('input[name="name"]', panel); var value = $('input[name="value"]', panel); var placeholder = $('input[name="placeholder"]', panel); var hint = $('input[name="hint"]', panel); var subtype = $('select[name="subtype"]', panel); var maxLength = $('input[name="max_length"]', panel); var minLength = $('input[name="min_length"]', panel); var optional = $('input[name="optional"]', panel); var options = $('.container-options', panel); var result = null; switch(type.val()) { case 'text': case 'textarea': result = { type: type.val(), label: label.val(), name: name.val(), value: value.val(), placeholder: placeholder.val(), hint: hint.val(), optional: optional.is(':checked') }; if (subtype.val() !== '') { result.subtype = subtype.val(); } if (!isNaN(parseInt(maxLength.val(), 10))) { result.maxLength = parseInt(maxLength.val(), 10); } if (!isNaN(parseInt(minLength.val(), 10))) { result.minLength = parseInt(minLength.val(), 10); } break; case 'select': result = { type: 'select', label: label.val(), name: name.val(), options: options.RB_OptionsEditor('value') }; break; } return result; }; $.fn.RB_getButtonData = function() { var container = $(this); var type = $('select[name="type"]', container); var panel = $('.panel-' + type.val(), container); var label = $('input[name="label"]', panel); var url = $('input[name="url"]', panel); var value = $('input[name="value"]', panel); var number = $('input[name="number"]', panel); var answer = $('input[name="answer"]', panel); var alert = $('input[name="alert"]', panel); var style = $('select[name="style"]', panel); var messengerExtensions = $('input[name="messenger_extensions"]', panel); var webViewHeight = $('select[name="webview_height_ratio"]', panel); var result = null; switch(type.val()) { case 'keyboardButton': result = { type: 'keyboardButton', label: label.val() }; break; case 'url': result = { type: 'url', label: label.val(), url: url.val(), webViewHeightRatio: webViewHeight.val(), extensions: messengerExtensions.is(':checked'), answer: answer.val(), alert: alert.is(':checked') }; break; case 'call': result = { type: 'call', label: label.val(), number: number.val() }; break; case 'postback': result = { type: 'postback', label: label.val(), value: value.val(), answer: answer.val(), alert: alert.is(':checked'), style: style.val() }; break; case 'dialog': result = { type: 'dialog', label: label.val(), value: value.val(), answer: answer.val(), alert: alert.is(':checked'), style: style.val() }; break; case 'quick-reply': result = { type: 'quick-reply', label: label.val(), value: value.val(), url: url.val() }; break; case 'newline': result = { type: 'newline' }; break; case 'location': result = { type: 'location' }; break; case 'share': result = { type: 'share' }; break; case 'logout': result = { type: 'logout' }; break; case 'login': result = { type: 'login', url: url.val() }; break; case 'phone': result = { type: 'phone' }; break; case 'email': result = { type: 'email' }; break; } return result; }; $.fn.RB_hasPlatform = function(platform, platforms) { platform = platform instanceof Array ? platform : [platform]; var hasMatch = false; for(var idx = 0; idx < platform.length; idx++) { if (platforms.indexOf(platform[idx]) !== -1) { hasMatch = true; } } return hasMatch ? $(this) : $(); }; $.fn.RB_mountButtonDialog = function(options) { options = options || {}; options.types = options.types != null ? options.types : ['url', 'postback', 'call', 'share', 'login', 'newline', 'logout', 'location', 'quick-reply', 'dialog', 'key', 'email', 'phone']; options.platforms = options.platforms != null ? options.platforms : ['facebook', 'telegram']; options.badges = options.badges !== false; var container = $(this); // store available platforms in the container container.data('platforms', options.platforms); var main = $('<div/>').appendTo(container); var cx = options.badges ? $.RedBot.platformClass : function() { return ''; }; var selectButtonType = $('<select name="type"/>', { style:"width:200px; margin-left: 5px; text-align: center;" }) .attr('placeholder', 'Select button type') .change(function() { var type = $(this).val(); $('.panel', container).hide(); $('.panel-' + type, container).show(); // find the right button var button = $.RedBot.buttonTypes.findButton(type); // store class only if badges should be shown if (button != null && options.badges) { //$(this).attr('class', cx('select', $.RedBot.intersect(options.platforms, button.platforms))); $.RedBot.supportedBy($('.type-badges', main), $.RedBot.intersect(options.platforms, button.platforms)); } else { //$(this).attr('class', ''); $('.type-badges', main).empty(); } }) .appendTo(main); $('<div class="type-badges" style="margin-left:5px;display:inline-block;"></div>').appendTo(main); selectButtonType.append($('<option value="">Select button type</option>')); $.RedBot.buttonTypes.forEach(function(button) { if (options.types.indexOf(button.type) !== -1 && $.RedBot.platforms(options.platforms, button.platforms)) { selectButtonType.append($('<option value="' + button.type + '">' + button.label + '</option>')); } }); var panelUrl = $('<div class="panel panel-url" style="display:none;"/>').appendTo(container); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="label" placeholder="Button label"/>')) .appendTo(panelUrl); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="url" placeholder="Button URL"/>')) .appendTo(panelUrl); $('<div/>').css('marginTop','5px') .RB_hasPlatform('telegram', options.platforms) .append('<input class="node-input-rule-type" type="text" name="answer" style="width:60%" placeholder="Button feedback"/>') .append('<div class="redbot-platforms telegram"/>') .append('<input type="checkbox" name="alert" value="on" style="width:auto;margin:0px 10px 5px 10px;"/>') .append('<span>With popup</span>') .append('<div class="redbot-platforms telegram"/>') .appendTo(panelUrl); $('<div/>').css('marginTop','5px') .RB_hasPlatform('facebook', options.platforms) .append('<select name="webview_height_ratio" style="width:60%">' + '<option value="tall">Tall</option>' + '<option value="compact">Compact</option>' + '<option value="full">Full</option>' + '</select>') .append('<div class="redbot-platforms facebook"/>') .append('<input type="checkbox" name="messenger_extensions" value="on" style="width: auto;margin:0px 10px 5px 10px;"/>') .append('<span>Extensions</span><div class="redbot-platforms facebook"/>') .appendTo(panelUrl); $(panelUrl).RB_Platforms(); var panelEmail = $('<div class="panel panel-email" style="display:none;"/>').appendTo(container); $('<div/>').css('marginTop','5px') .append($('<div class="redbot-form-hint">Send user email associated to the Facebook Messenger account</div>')) .appendTo(panelEmail); var panelPhone = $('<div class="panel panel-phone" style="display:none;"/>').appendTo(container); $('<div/>').css('marginTop','5px') .append($('<div class="redbot-form-hint">Send user phone number associated to the Facebook Messenger account</div>')) .appendTo(panelPhone); var panelPostback = $('<div class="panel panel-postback" style="display:none;"/>').appendTo(container); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="label" placeholder="Button label"/>')) .appendTo(panelPostback); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="value" placeholder="Postback value">')) .appendTo(panelPostback); var feedbackRow = $('<div/>').css('marginTop','5px') .RB_hasPlatform(['telegram', 'slack'], options.platforms) .append('<input class="node-input-rule-type" type="text" name="answer" style="width:60%;"placeholder="Button feedback (optional)"/>') .append('<div class="redbot-platforms telegram slack"/>'); $('<input type="checkbox" name="alert" value="on" style="width: auto;margin:0px 10px 5px 10px;"/>') .RB_hasPlatform(['telegram'], options.platforms) .appendTo(feedbackRow); $('<span>With popup</span><div class="redbot-platforms telegram"/>') .RB_hasPlatform(['telegram'], options.platforms) .appendTo(feedbackRow); feedbackRow.appendTo(panelPostback); $('<div/>').css('marginTop','5px') .RB_hasPlatform('slack', options.platforms) .append('<select name="style" style="width:70%">' + '<option value="">Select button style</option>' + '<option value="default">Default</option>' + '<option value="primary">Primary</option>' + '<option value="danger">Danger</option>' + '</select>') .append('<div class="redbot-platforms slack"/>') .appendTo(panelPostback); $(panelPostback).RB_Platforms(); var panelDialog = $('<div class="panel panel-dialog" style="display:none;"/>').appendTo(container); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="label" placeholder="Button label"/>')) .appendTo(panelDialog); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="value" placeholder="Dialog Id">')) .appendTo(panelDialog); $('<div/>').css('marginTop','5px') .RB_hasPlatform(['telegram', 'slack'], options.platforms) .append('<input class="node-input-rule-type" type="text" name="answer" placeholder="Button feedback (optional)"/>') .appendTo(panelDialog); $('<div/>').css('marginTop','5px') .append('<select name="style" style="width:70%">' + '<option value="">Select button style</option>' + '<option value="default">Default</option>' + '<option value="primary">Primary</option>' + '<option value="danger">Danger</option>' + '</select>') .appendTo(panelDialog); var panelQuickReply = $('<div class="panel panel-quick-reply" style="display:none;"/>').appendTo(container); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="label" placeholder="Button label"/>')) .appendTo(panelQuickReply); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="value" placeholder="Postback value">')) .appendTo(panelQuickReply); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="url" placeholder="Image URL"/>')) .appendTo(panelQuickReply); var panelCall = $('<div class="panel panel-call" style="display:none;"/>').appendTo(container); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="label" placeholder="Button label"/>')) .appendTo(panelCall); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="number" placeholder="Phone number"/>')) .appendTo(panelCall); var panelNewline = $('<div class="panel panel-newline" style="display:none;"/>').appendTo(container); $('<div/>').css('marginTop','5px') .html('This creates a new row of buttons') .appendTo(panelNewline); var panelKeyboardButton = $('<div class="panel panel-keyboardButton" style="display:none;"/>').appendTo(container); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="label" placeholder="Button label"/>')) .appendTo(panelKeyboardButton); $('<div class="panel panel-share" style="display:none;"/>').appendTo(container); $('<div class="panel panel-logout" style="display:none;"/>').appendTo(container); $('<div class="panel panel-location" style="display:none;"/>').appendTo(container); var panelLogin = $('<div class="panel panel-login" style="display:none;"/>').appendTo(container); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="url" placeholder="Authentication URL callback"/>')) .appendTo(panelLogin); return container; }; $.fn.RB_mountElementDialog = function(options) { options = options || {}; options.types = options.types != null ? options.types : ['text', 'textarea', 'select']; options.platforms = options.platforms != null ? options.platforms : ['slack']; options.badges = options.badges !== false; var container = $(this); var main = $('<div/>').appendTo(container); var cx = options.badges ? $.RedBot.platformClass : function() { return ''; }; var selectElementType = $('<select name="type"/>', {style:"width:200px; margin-left: 5px; text-align: center;"}) .attr('placeholder', 'Select element type') .change(function() { var type = $(this).val(); $('.panel', container).hide(); $('.panel-' + type, container).show(); // find the right button var button = $.RedBot.buttonTypes.findButton(type); // store class only if badges should be shown if (button != null && options.badges) { $(this).attr('class', button.className); } else { $(this).attr('class', ''); } }) .appendTo(main); selectElementType.append($('<option value="">Select element type</option>')); $.RedBot.elementTypes.forEach(function(button) { if (options.types.indexOf(button.type) !== -1 && $.RedBot.platforms(options.platforms, button.platforms)) { selectElementType.append($('<option value="' + button.type + '">' + button.label + '</option>')); } }); var panelText = $('<div class="panel panel-text" style="display:none;"/>').appendTo(container); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="label" placeholder="Label"/>')) .appendTo(panelText); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="name" placeholder="Name"/>')) .appendTo(panelText); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="value" placeholder="Initial value"/>')) .appendTo(panelText); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="placeholder" placeholder="Placeholder"/>')) .appendTo(panelText); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="hint" placeholder="Hint"/>')) .appendTo(panelText); $('<div/>').css('marginTop','5px') .append('<select name="subtype" class="' + cx('select', ['']) + '" style="width:60%">' + '<option value="">Select sub-type</option>' + '<option value="email">Email</option>' + '<option value="number">Number</option>' + '<option value="tel">Telephone</option>' + '<option value="url">URL</option>' + '</select>') .append('<input type="checkbox" name="optional" value="on" style="width: auto;margin:0px 10px 5px 10px;"/>') .append('<span>Optional</span>') .appendTo(panelText); $('<div/>').css('marginTop','5px') .append($('<input style="width:45%" class="node-input-rule-type" type="number" name="min_length" placeholder="Min Length"/>')) .append($('<input style="width:45%;margin-left: 10%" class="node-input-rule-type" type="number" name="max_length" placeholder="Max Length"/>')) .appendTo(panelText); var panelTextarea = $('<div class="panel panel-textarea" style="display:none;"/>').appendTo(container); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="label" placeholder="Label"/>')) .appendTo(panelTextarea); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="name" placeholder="Name"/>')) .appendTo(panelTextarea); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="value" placeholder="Initial value"/>')) .appendTo(panelTextarea); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="placeholder" placeholder="Placeholder"/>')) .appendTo(panelTextarea); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="hint" placeholder="Hint"/>')) .appendTo(panelTextarea); $('<div/>').css('marginTop','5px') .append('<select name="subtype" class="' + cx('select', ['']) + '" style="width:60%">' + '<option value="">Subtype</option>' + '<option value="email">Email</option>' + '<option value="number">Number</option>' + '<option value="tel">Telephone</option>' + '<option value="url">URL</option>' + '</select>') .append('<input type="checkbox" name="optional" value="on" style="width: auto;margin:0px 10px 5px 10px;"/>') .append('<span>Optional</span>') .appendTo(panelTextarea); var panelSelect = $('<div class="panel panel-select" style="display:none;"/>').appendTo(container); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="label" placeholder="Label"/>')) .appendTo(panelSelect); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="name" placeholder="Name"/>')) .appendTo(panelSelect); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="value" placeholder="Initial value"/>')) .appendTo(panelSelect); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="placeholder" placeholder="Placeholder"/>')) .appendTo(panelSelect); $('<div/>').css('marginTop','5px') .append($('<input style="width:100%" class="node-input-rule-type" type="text" name="hint" placeholder="Hint"/>')) .appendTo(panelSelect); $('<div/>').css('marginTop','5px') .append('<div class="container-options"/>') .appendTo(panelSelect); panelSelect.find('.container-options').RB_OptionsEditor({ label: 'Combo box options'}); }; $.RedBot.registerType('chatbot-inline-buttons', { category: $.RedBot.config.name, color: '#FFCC66', defaults: { name: { value: '' }, buttons: { value: [], validate: function(buttons) { if (buttons == null) { return true; // allow no buttons } var valid = true; var idx; for(idx = 0; idx < buttons.length; idx++) { if (!$.RedBot.validate.button(buttons[idx])) { valid = false; } } return valid; } }, message: { value: '' }, trackMessage: { value: false }, outputs: { value: 1 } }, inputs: 1, outputs: 1, outputLabels: function(index) { if (index === 0) { return 'to sender node'; } else { const button = this.buttons[index - 1]; if (button.type === 'postback') { if (button.label != null && button.label !== '') { return button.label + (button.value != null && button.value !== '' ? ' (' + button.value + ')' : ''); } else if (button.value != null && button.value !== '') { return button.value; } } return 'not used'; } }, paletteLabel: 'Buttons', icon: 'chatbot-inline-button.png', label: function() { return this.name || 'Buttons'; }, oneditsave: function() { var buttons = $("#node-input-buttons-container").editableList('items'); var node = this; node.buttons = []; var idx; for(idx = 0; idx < buttons.length; idx++) { node.buttons.push($(buttons[idx]).RB_getButtonData()); } // store outputs if ($('#node-input-trackMessage').is(':checked')) { node.outputs = node.buttons.length + 2; } else { node.outputs = 1; } }, oneditprepare: function() { var node = this; $('#node-input-buttons-container') .css('min-height','300px') .css('min-width','450px') .editableList({ addButton: 'Add button', addItem: function(container, i, item) { $(container).RB_mountButtonDialog({ types: ['url', 'postback', 'call', 'login', 'newline', 'logout', 'dialog'], platforms: ['facebook', 'telegram', 'slack', 'msteams'] }); $(container).RB_setButtonData(item); }, removable: true, sortable: true }); $.RedBot.fetchPlatforms() .done(function() { var buttons = node.buttons; var idx; for (idx = 0; idx < buttons.length; idx++) { $('#node-input-buttons-container').editableList('addItem', buttons[idx]); } }); }, oneditresize: function() { var dialogForm = $('#dialog-form'); var rowName = $('.form-row-name', dialogForm); var rowMessage = $('.form-row-message', dialogForm); var rowLabel = $('.form-row-label', dialogForm); var rowHint = $('.form-row-hint', dialogForm); var rowTrack = $('.form-row-track', dialogForm); var height = dialogForm.height() - rowTrack.height() - rowName.height() - rowMessage.height() - rowLabel.height() - rowHint.height() - 30; $('#node-input-buttons-container').editableList('height', height); } }); </script> <script type="text/x-red" data-template-name="chatbot-inline-buttons"> <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-message"> <label for="node-input-message"><i class="icon-envelope"></i> Message</label> <textarea id="node-input-message" placeholder="Message" style="width:93%;height:50px;"></textarea> <div style="max-width: 460px;font-size: 12px;color: #999999;line-height: 14px;clear:both;margin-top:5px;"> Supports handlebars-like variables for chat context like {{firstName}}, {{lastName}}, etc. and emoticons (:smile:, etc.) </div> </div> <div class="form-row form-row-label" style="margin-bottom:0;"> <label><i class="fa fa-list"></i> <span>Buttons</span></label> </div> <div class="form-row node-input-rule-container-row"> <ol id="node-input-buttons-container"></ol> </div> <div class="form-row form-row-track"> <label for="node-input-trackMessage">Track</label> <input type="checkbox" value="true" id="node-input-trackMessage" style="width:auto"> <span class="redbot-form-hint"> Track answers to these buttons here (will enable an output pin for each button) </span> </div> </script> <script type="text/x-red" data-help-name="chatbot-inline-buttons"><p>This node creates a message with one or more buttons in order to get a quick reaction from the users. </p> <p>Available buttons: </p> <ul> <li><p><strong>URL</strong>: Open a URL inside the client. Button feedbacks are available for Telegram and Messenger extensions in Facebook <em>[Telegram, Facebook, Viber]</em></p> </li> <li><p><strong>Postback</strong>: Allow the user to send a predefined message, the message will no be shown in the chat history. Button feedbacks are available for Telegram and Messenger extensions in Facebook <em>[Telegram, Facebook, Smooch, Viber]</em></p> </li> <li><p><strong>Phone call</strong>: Starts a phone call on mobile. <em>[Facebook]</em></p> </li> <li><p><strong>Log In</strong>: Starts the account linking flow. <em>[Facebook]</em></p> </li> <li><p><strong>Log Out</strong>: Starts the account unlinking flow. <em>[Facebook]</em></p> </li> <li><p><strong>New row</strong>: Telegram supports buttons layout with multiple row, this element just starts a new one. <em>[Telegram, Viber]</em></p> </li> </ul> <p>Platform exceptions: </p> <ul> <li><p><strong>Telegram</strong> supports a visual feedback, visible in the client, when a <code>Postback</code> or <code>URL</code> buttons is pressed</p> </li> <li><p><strong>Facebook</strong> supports some extra parameters in the <code>URL</code> button, like the size of the web view and <a href="https://developers.facebook.com/docs/messenger-platform/webview">messenger extensions</a> and a maximum od three buttons.</p> </li> </ul> <p>The tipical use of the buttons node is with the <em>Track</em> option of a <code>Sender node</code> and <a href="https://app.notion.com/p/4113636f565d4ff4af08bc61a644206b">Rules node</a> to capture the aswer</p> <p><img src="data:image/png;base64,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