Inline меню для telegram

Само меню находится в объекте «menu», где описываются элементы (кнопки). Скрипт автоматически генерирует структуру для отображения и управляющие команды для кнопок меню. При вызове меню в telegram, на кнопках отображаются актуальные состояния объектов, для каждого из булева состояния можно указать свою иконку (эмодзи), которая будет отображать на кнопке перед именем.

На этом сайте можно найти эмодзи на любой вкус, просто копируем нужный и вставляем скрипт.

Пример работы inline меню для telegram

Если меню не будет вызываться по команде, то попробуйте заменить строку callback(name[userid].firstName, cmd); на callback(name[userid].userName, cmd);

var sub = [], iter = 0;

//////////// Настройки ///////////
var options = {
    telegram:   'telegram.0',            // Инстанция драйвера
    backtext:   '🔙 Назад',              // Надпись на кнопке Назад
    closetext:  '❌ Закрыть',            // Надпись на кнопке Закрыть
    hometext:   '🏚 Главная',             // Надпись на кнопке Домой
    width:      3,                       // Максимальное количество столбцов с кнопками
    users_id:   [000000000, 111111111],  // id пользователей которые имеют доступ к меню
    menucall:   ['меню', '/command1'],   // Команда для вызова меню
    prefix:     'menu',                  // Префикс для отправляемых команд при нажатии на кнопку, можно не менять
    showHome:   true,                    // Показывать кнопку Домой
    showMsg:    true,                    // Показывать вплывающие сообщения
    debug:      false                    // Режим отладки, подробное логирование
};

/////////// МЕНЮ НАЧАЛО ////////////
var menu = {
    name: 'Главное меню',
    icon: '⚙️',
    submenu: [
        { // Сценарии
            name: 'Сценарии',
            icon: '⚙️',
            submenu: [
                {
                    name: 'ТВ',
                    state: 'javascript.0.Scenes.TV',
                    icons: {on: '📺', off: '✖️'},
                    submenu: []
                },
                {
                    name: 'Кино',
                    state: 'javascript.0.Scenes.Moves',
                    icons: {on: '📽', off: '✖️'},
                    submenu: []
                },
                {
                    name: 'Kodi',
                    state: 'javascript.0.Scenes.Kodi',
                    icons: {on: '🕹️', off: '✖️'},
                    submenu: []
                },
                {
                    name: 'Музыка Kodi',
                    state: 'javascript.0.Scenes.Music',
                    icons: {on: '🕹️🎵', off: '✖️'},
                    submenu: []
                },
                {
                    name: 'Спать',
                    state: 'javascript.0.Scenes.Sleep',
                    icons: {on: '🛌', off: '✖️'},
                    submenu: []
                },
                {
                    name: 'Уборка',
                    state: 'javascript.0.Scenes.Сleaning',
                    icons: {on: '🤦', off: '✖️'},
                    submenu: []
                },
                {
                    name: 'Оповещение',
                    state: 'javascript.0.Scenes.sayOff',
                    icons: {on: '🔇', off: '🔊'},
                    submenu: []
                },
                {
                    name: 'Отпуск',
                    state: 'javascript.0.Scenes.Otpusk',
                    icons: {on: '📅', off: '✖️'},
                    submenu: []
                }
                ]
        },
        { // Освещение
            name: 'Освещение',
            icon: '💡',
            submenu: [
                {
                    name: 'Зал',
                    icon: '💡',
                    submenu: [
                        {
                            name: 'Основной 1',
                            state: 'mqtt.0.myhome.lighting.GuestRoom_main',
                            icons: {on: '💡', off: '✖️'},
                            submenu: []
                        },
                        {
                            name: 'Основной 2',
                            state: 'mqtt.0.myhome.lighting.GuestRoom_main2',
                            icons: {on: '💡', off: '✖️'},
                            submenu: []
                        },
                        {
                            name: 'Глазки',
                            state: 'mqtt.0.myhome.lighting.GuestRoom_sec',
                            icons: {on: '💡', off: '✖️'},
                            submenu: []
                        }
                    ]
                },
                {
                    name: 'Кухня',
                    icon: '💡',
                    submenu: [
                        {
                            name: 'Основной',
                            state: 'mqtt.0.myhome.lighting.Kitchen_main',
                            icons: {on: '💡', off: '✖️'},
                            submenu: []
                        },
                        {
                            name: 'Глазки',
                            state: 'mqtt.0.myhome.lighting.Kitchen_sec',
                            icons: {on: '💡', off: '✖️'},
                            submenu: []
                        }
                    ]
                },
                {
                    name: 'Ванная',
                    icon: '🛀',
                    submenu: [
                        {
                            name: 'Основной',
                            state: 'mqtt.0.myhome.lighting.BathRoom_main',
                            icons: {on: '💡', off: '✖️'},
                            submenu: []
                        },
                        {
                            name: 'Зеркало',
                            state: 'mqtt.0.myhome.lighting.BathRoom_sec',
                            icons: {on: '💡', off: '✖️'},
                            submenu: []
                        }
                    ]
                },
                {
                    name: 'Коридор',
                    icon: '💡',
                    submenu: [
                        {
                            name: 'Основной',
                            state: 'mqtt.0.myhome.lighting.Hall_main',
                            icons: {on: '💡', off: '✖️'},
                            submenu: []
                        }
                    ]
                },
                {
                    name: 'Спальня',
                    icon: '💡',
                    submenu: [
                        {
                            name: 'Основной',
                            state: 'mqtt.0.myhome.lighting.BedRoom_main',
                            icons: {on: '💡', off: '✖️'},
                            submenu: []
                        },
                        {
                            name: 'Глазки',
                            state: 'mqtt.0.myhome.lighting.BedRoom_sec',
                            icons: {on: '💡', off: '✖️'},
                            submenu: []
                        }
                    ]
                },
            ]
        },
        { // Шторы
            name: 'Шторы',
            icon: '⚙️',
            submenu: [
                {
                    name: 'Кухня',
                    state: 'javascript.0.Rollet.Kitchen.Close',
                    icons: {on: '🌚', off: '🌞'},
                    submenu: []
                },
                {
                    name: 'Спальня',
                    state: 'javascript.0.Rollet.Bedroom.Close',
                    icons: {on: '🌚', off: '🌞'},
                    submenu: []
                }
            ]
        },
        { // Разное
            name: 'Разное',
            icon: '⚙️',
            submenu: [
                {
                    name: 'Компьютер',
                    state: 'javascript.0.GetAdmin.Power',
                    icons: {on: '🖥️', off: '✖️'}, 
                    submenu: []
                },
                {
                    name: 'Кондиционер',
                    state: 'haier.0.power',
                    icons: {on: '☑️', off: '✖️'},
                    submenu: []
                },
                {
                    name: 'Вода',
                    icon: '🚰',
                    submenu: [
                        {
                            name: 'Открыть',
                            state: 'mqtt.0.myhome.Aquastoroj.ButtonOpen',
                            icons: {on: '🔄', off: '⏺'},
                            submenu: []
                        },
                        {
                            name: ' ',
                            state: 'mqtt.0.myhome.Aquastoroj.open',
                            icons: {on: 'Открыто', off: 'Закрыто'},
                            submenu: []
                        },
                        {
                            name: 'Закрыть',
                            state: 'mqtt.0.myhome.Aquastoroj.ButtonClose',
                            icons: {on: '🔄', off: '⏺'},
                            submenu: []
                        }
                    ]
                }
            ]
        },
        { // Информация
            name: 'Информация',
            icon: 'ℹ️',
            submenu: [
                {
                    name: 'Температура',
                    state: Temperature,
                    icon: '🌡',
                    submenu: []
                },
                {
                    name: 'Влажность',
                    state: Humidity, // А можно вызвать функцию вот так
                    icon: '💦',
                    submenu: []
                }
            ]
        },
    ]
};
/////////// МЕНЮ КОНЕЦ ////////////

/////////// ПОЛЬЗОВАТЕЛЬСКИЕ ФУНКЦИИ НАЧАЛО /////////////
function Humidity(){
    var text = '';
    text += '- Влажность в спальне: ' + getState('mqtt.0.myhome.Bedroom.Humidity_room').val + '%';
    text += '\r\n- Влажность на кухне: ' + getState('mqtt.0.myhome.Kitchen.Humidity_room').val + '%';
    return text;
}

function Temperature(){
    var text = '';
    text += '- Температура в спальне: ' + getState('mqtt.0.myhome.Bedroom.Temp_room').val + '';
    text += '\r\n- Температура на кухне: ' + getState('mqtt.0.myhome.Kitchen.Temp_room').val + '';
    return text;
}
/////////// ПОЛЬЗОВАТЕЛЬСКИЕ ФУНКЦИИ КОНЕЦ /////////////


////////////////////////////////////////////////////////////////
////////////////////////// МАГИЯ ///////////////////////////////
////////////////////////////////////////////////////////////////
function setCommand(state, user){
    var timer;
    logs('ОТПРАВЛЯЕМ КОММАНДУ ' + state);
    if(typeof state !== 'function'){
        logs('ОБЬЕКТ = ' + JSON.stringify(getObject(state)));
        var obj = getObject(state);
        var role = obj.common.role;
        var type = obj.common.type;
        clearTimeout(timer);
        timer = setTimeout(function() {
            showMsg('Ошибка! нет ответа', user);
            sub = sub.slice(0, sub.length-1);
            show(user, sub);
        }, 4000); 

    } else {
        show(user, sub);
    }
    if(type === 'boolean'){
        setState(state, !getState(state).val, function cb(){
            clearTimeout(timer);
            sub = sub.slice(0, sub.length-1);
            showMsg('Успешно!', user);
            show(user, sub);
            logs('СОСТОЯНИЕ = ' + getState(state).val);
        });
    } else {
        logs('НЕ ВЕРНЫЙ ТИП ОБЬЕКТА');
        showMsg('Не верный тип обьекта', user);
    }
}

function show(user, num, state){  /*** show ***/
    logs('ВЫЗОВ ФУНКЦИИ show(user, num)');
    getMenu(state, function cb(keyboard){
        logs('КОЛБЭК в show - function cb(keyboard)');
        logs('keyboard = ' + JSON.stringify(keyboard));
        if(sub.length > 0){
            keyboard.buttons = splitMenu(keyboard.buttons);
            if(options.showHome){
                keyboard.buttons.push([{ text: options.backtext, callback_data: 'back' }, { text: options.hometext, callback_data: 'home' }, { text: options.closetext, callback_data: 'close' }]);
            } else {
                keyboard.buttons.push([{ text: options.backtext, callback_data: 'back' }, { text: options.closetext, callback_data: 'close' }]);
            }
            logs('keyboard.buttons = ' + JSON.stringify(keyboard.buttons));
            if(typeof keyboard.state === "function"){
                keyboard.menutext += '\r\n' + keyboard.state();
            }
            logs('keyboard 2 = ' + JSON.stringify(keyboard));
            sendTo(options.telegram, {
                user: user,
                text: keyboard.menutext,
                editMessageText: {
                    options: {
                        chat_id: getState(options.telegram + ".communicate.requestChatId").val, 
                        message_id: getState(options.telegram + ".communicate.requestMessageId").val,
                        reply_markup: {
                            inline_keyboard: keyboard.buttons,
                        }
                    }
                }
            });
        } else {
            close(user);
            keyboard.buttons = splitMenu(keyboard.buttons);
            keyboard.buttons.push([{ text: options.closetext, callback_data: 'close' }]);
            logs('keyboard 4 ' + JSON.stringify(keyboard));
            sendTo(options.telegram, {
                user: user,
                text: keyboard.menutext,
                    reply_markup: {
                        inline_keyboard: keyboard.buttons,
                    }
            }); 
        }
    });
}

function getMenu(state, cb){ /*** getMenu ***/
    logs('ВЫЗОВ ФУНКЦИИ getMenu(cb)');
    var keyboard_ = {
        menutext: (menu.icon ? menu.icon + ' ':'') + UnUnique(menu.name),
        state: '',
        buttons: []
    };
    var SubArr = sub.concat([]);
    logs('menu.submenu = ' + menu.submenu[2].submenu[1].state); 
    getObj(menu.submenu, SubArr, keyboard_, function callback(SubMenuObj, keyboard, isfunc){
        logs('КОЛБЭК в getMenu - function callback(SubMenuObj, keyboard)');
        for (var i = 0; i < SubMenuObj.length; i++) {
            var icon;
            if(SubMenuObj[i].state && typeof SubMenuObj[i].state !== 'function' && getState(SubMenuObj[i].state).val){
                icon = SubMenuObj[i].icons.on;
            } else if (SubMenuObj[i].state && typeof SubMenuObj[i].state !== 'function'){
                icon = SubMenuObj[i].icons.off;
            } else {
                icon = SubMenuObj[i].icon;
            }
            logs('** SubMenuObj[i] = ' + JSON.stringify(SubMenuObj[i]));
            keyboard.buttons.push({
                text: icon + ' ' + UnUnique(SubMenuObj[i].name),
                callback_data: options.prefix + SubMenuObj[i].name
            });
        }
        cb(keyboard);
    });
}

function getObj(SubMenuObj, SubArr, keyboard, cb){  /*** getObj ***/
    logs('ВЫЗОВ ФУНКЦИИ getObj(obj, num, keyboard, cb)');
    var n;
    logs('SubArr.length = ' + SubArr.length);
    if(SubArr.length > 0){
        keyboard.menutext += ' > ' + (SubMenuObj[SubArr[0]].icon ? SubMenuObj[SubArr[0]].icon + ' ':'') + UnUnique(SubMenuObj[SubArr[0]].name);
        n = SubArr.shift();
        if(typeof SubMenuObj[n].state == 'function'){
            keyboard.state = SubMenuObj[n].state;
        }
        getObj(SubMenuObj[n].submenu, SubArr, keyboard, cb);
    } else {
        logs('****** getObj SubArr = ' + JSON.stringify(SubMenuObj[n]));
        cb(SubMenuObj, keyboard);
    }
}

function getSub(cmd, arr, cb){   /*** getSub ***/
    logs('ВЫЗОВ ФУНКЦИИ getSub(cmd, arr, cb)');
    cmd = cmd.replace(options.prefix, '');
    sub = [];
    arr = arr.submenu;
    logs('Определяем sub для команды = ' + cmd);
    if(arr.length > 0){
        for (var i = 0; i < arr.length; i++) {
            logs('i=' + i + ', i1=' + i1 + ', i2=' + i2);
            if(cmd === arr[i].name.toLowerCase()){
                sub[0] = i;
                if(arr[i].submenu.length == 0){
                    return cb(sub, arr[i].state);
                } else {
                    return cb(sub, false);
                }
            }
            var arr1 = arr[i].submenu;
            if(arr1.length > 0){
                for (var i1 = 0; i1 < arr1.length; i1++) {
                    logs('i=' + i + ', i1=' + i1 + ', i2=' + i2);
                    if(cmd === arr1[i1].name.toLowerCase()){
                        sub[0] = i;
                        sub[1] = i1;
                        if(arr1[i1].submenu.length == 0){
                            return cb(sub, arr1[i1].state);
                        } else {
                            return cb(sub, false);
                        }
                    }
                    var arr2 = arr1[i1].submenu;
                    if(arr2.length > 0){
                        for (var i2 = 0; i2 < arr2.length; i2++) {
                            logs('i=' + i + ', i1=' + i1 + ', i2=' + i2);
                            if(cmd === arr2[i2].name.toLowerCase()){
                                sub[0] = i;
                                sub[1] = i1;
                                sub[2] = i2;
                                if(arr2[i2].submenu.length == 0){
                                    return cb(sub, arr2[i2].state);
                                } else {
                                    return cb(sub, false);
                                }
                            }
                        }
                    } 
                }
            }
        }
    }
}

function callback(user, cmd){
    if(~options.menucall.indexOf(cmd)){
        sub = [];
        show(user, sub);
    } else {
        if(cmd === 'close'){
            sub = [];
            close(user);
        } else if(cmd === 'back'){
            if(sub.length !== 0){
                sub = sub.slice(0, sub.length-1);
            }
            show(user, sub);
        } else if(cmd === 'home'){
            sub = [];
            show(user, sub);
        } else {
            getSub(cmd, menu, function cb(sub, state){
                logs('КОЛБЭК в callback - function cb(sub, state)');
                logs('state = ' + state);
                if(!state || typeof state === 'function'){
                    show(user, sub, state);
                } else {
                    setCommand(state, user);
                }
            });
        }
    }
}

function close(user){
    sendTo(options.telegram, {
        user: user,
        deleteMessage: {
            options: {
                chat_id: getState(options.telegram + ".communicate.requestChatId").val, 
                message_id: getState(options.telegram + ".communicate.requestMessageId").val,
            }
        }
    });
}

on({id: options.telegram + '.communicate.request', change: 'any'}, function (obj) {
    var cmd = (obj.state.val.substring(obj.state.val.indexOf(']')+1)).toLowerCase(); 
    var userid = getState(options.telegram + ".communicate.requestChatId").val;
    if (userid){
        var name = getState(options.telegram + ".communicate.users").val;
        try {
            name = JSON.parse(name);
        } catch (err) {
            logs("Ошибка парсинга - " + JSON.stringify(err));
        }
        if (~options.users_id.indexOf(userid)){
            logs('Пользователь - ' + name[userid].firstName + ' с id - ' + userid + '; Отправленная команда - ' + cmd);
            callback(name[userid].firstName, cmd);
        }  else {
            log('Доступ запрещен. Пользователя - ' + name[userid] + ' с id - ' + userid + ' нет в списке доверенных.' );
        }
    }
});

function splitMenu(arr){
    var i, j, tmp = [];
    for (i = 0, j = arr.length; i < j; i += options.width) {
        tmp.push(arr.slice(i, i + options.width));
    }
    return tmp;
}

function showMsg(text, user, showAlert){
    if(options.showMsg){
        sendTo(options.telegram, {
            user: user,
            answerCallbackQuery: {
                text: text,
                showAlert: showAlert ? true:false
            }
        });
    }
}

function UniqueNames(obj){
    if(obj.name){
        obj.name = Rand(obj.name);
    }
    if(obj.submenu.length > 0){
        for(var i = 0; i < obj.submenu.length; i++){
            if(obj.submenu[i].name){
                obj.submenu[i].name = Rand(obj.submenu[i].name);
            }
            if(obj.submenu[i].submenu.length > 0){
                for(var i1 = 0; i1 < obj.submenu[i].submenu.length; i1++){
                    if(obj.submenu[i].submenu[i1].name){
                        obj.submenu[i].submenu[i1].name = Rand(obj.submenu[i].submenu[i1].name);
                    }
                    if(obj.submenu[i].submenu[i1].submenu.length > 0){
                        for(var i2 = 0; i2 < obj.submenu[i].submenu[i1].submenu.length; i2++){
                            if(obj.submenu[i].submenu[i1].submenu[i2].name){
                                obj.submenu[i].submenu[i1].submenu[i2].name = Rand(obj.submenu[i].submenu[i1].submenu[i2].name);
                            }
                        }
                    }
                }
            }
        }
    }
    logs(obj);
    menu = obj;
}

function Rand(val){
    val = iter + val;
    iter++;
    return val;
}

function UnUnique(name){
    return name.replace(/^\d+/, '');
}

UniqueNames(menu);

function logs(txt){
    if(options.debug){
        log(txt);
    }
}
Подписаться
Уведомлять
guest

3 комментариев
Старые вначале
Новые вначале По голосам
Межтекстовые Отзывы
Посмотреть все комментарии
Артём
Артём
3 лет назад

Жесть! Но прикольно! А можно побольше статей о жаваскрипт\логике\таймерах и т.д.?

Иван
Иван
1 год назад

Блин а нет реализации к примеру долгого выполнения функции которая выполняется при нажатии кнопки ? и как передать параметры в функцию… тоже не разобрался.

3
0
Поделиться своими мыслямиx