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
HTML
<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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