UNPKG

iobroker.sayit

Version:

Text to speech interface for ioBroker.

878 lines (813 loc) 38.5 kB
<html> <head> <!-- Materialze style --> <link rel="stylesheet" type="text/css" href="../../css/adapter.css"/> <link rel="stylesheet" type="text/css" href="../../lib/css/materialize.css"> <script type="text/javascript" src="../../lib/js/jquery-3.2.1.min.js"></script> <script type="text/javascript" src="../../socket.io/socket.io.js"></script> <script type="text/javascript" src="engines.js"></script> <script type="text/javascript" src="../../js/translate.js"></script> <script type="text/javascript" src="../../lib/js/materialize.js"></script> <script type="text/javascript" src="../../js/adapter-settings.js"></script> <script type="text/javascript" src="words.js"></script> <style> #drop_zone { border: 2px dashed #bbb; -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; padding: 25px; text-align: center; font-size: 20pt; font-weight: bold; font-family: 'Arial'; color: #bbb; width: 90%; height: 60px; } .error { border: 2px solid red; } </style> <script type="text/javascript"> var webServers = null; var gOnChange; function showHideSettings() { $('.variable').hide(); var type = $('#type').val(); for (var j = 0; j < sayitOptions[type].params.length; j++) { $('#tr_' + sayitOptions[type].params[j]).show(); } if (type === 'googleHome') { $('.announceValue').hide(); $('.announce').hide(); $('.system').hide(); $('.googleHome').show(); getIsAdapterAlive(function (isAlive) { if (isAlive || common.enabled) { $('#search').removeClass('disabled'); fillGoogleHome(); } }); } else { $('.googleHome').hide(); $('.announceValue').show(); $('.announce').show(); } $('.engine').hide(); var engine = $('#engine').val(); if (!sayitEngines[engine] || sayitOptions[type].params.indexOf('engine') === -1) { return; } for (var i = 0; i < sayitEngines[engine].params.length; i++) { $('#tr_' + sayitEngines[engine].params[i]).show(); } if (type !== 'system') { $('.system').hide(); } else { $('.system').show(); } if (!$('#announce').val()) { $('.announce').hide(); $('#play').addClass('disabled'); } else { $('.announce').show(); $('#play').removeClass('disabled'); } } function fillEngineParams() { var engine = $('#engine').val(); if (!sayitEngines[engine]) return; for (var i = 0; i < sayitEngines[engine].params.length; i++) { $('#tr_' + sayitEngines[engine].params[i]).show(); if (sayitEngines[engine][sayitEngines[engine].params[i]]) { var arr = sayitEngines[engine][sayitEngines[engine].params[i]]; var param = sayitEngines[engine].params[i]; var $val = $('#' + param); if (arr.length) { var val = $val.val(); var text = ''; $val.empty(); for (var p = 0; p < arr.length; p++) { $val.append('<option value="' + arr[p] + '">' + arr[p] + '</option>'); } $val.select(); if (val) { $val.val(val); } else { $val.val(arr[0]); } } else { $val.html(''); } } } } function fillSonosDevices(elem, current) { socket.emit('getObjectView', 'system', 'channel', {startkey: 'sonos.', endkey: 'sonos.\u9999'}, function (err, res) { if (!err && res) { for (var i = 0; i < res.rows.length; i++) { var name = res.rows[i].value && res.rows[i].value.common && res.rows[i].value.common.name; if (typeof name === 'object') { name = name.en; } $(elem).append('<option value="' + res.rows[i].id + '">' + res.rows[i].id.replace(/^sonos\.\d+\.root\./, '') + ' [' + name + ']</option>'); } } $(elem).val(current); $(elem).select(); }); } function fillHeosDevices(elem, current) { socket.emit('getObjectView', 'system', 'channel', {startkey: 'heos.', endkey: 'heos.\u9999'}, function (err, res) { if (!err && res) { for (var i = 0; i < res.rows.length; i++) { var name = res.rows[i].value && res.rows[i].value.common && res.rows[i].value.common.name; if (typeof name === 'object') { name = name.en; } if(res.rows[i].id.includes('.players.')){ $(elem).append('<option value="' + res.rows[i].id + '">' + res.rows[i].id.replace(/^heos\.\d+\.players\./, '') + ' [' + name + ']</option>'); } } } $(elem).val(current); $(elem).select(); }); } function fillMpdDevice(elem, current) { socket.emit('getObjectView', 'system', 'instance', {startkey: 'system.adapter.mpd.', endkey: 'system.adapter.mpd.\u9999'}, function (err, res) { if (!err && res) { for (var i = 0; i < res.rows.length; i++) { var n = res.rows[i].id.replace('system.adapter.', ''); $(elem).append('<option value="' + n + '">' + n + '</option>'); } } $(elem).val(current); $(elem).select(); }); } function fillChromecastDevices(elem, current) { socket.emit('getObjectView', 'system', 'device', {startkey: 'chromecast.', endkey: 'chromecast.\u9999'}, function (err, res) { if (!err && res) { for (var i = 0; i < res.rows.length; i++) { $(elem).append('<option value="' + res.rows[i].id + '">' + res.rows[i].id + '</option>'); } } $(elem).val(current); $(elem).select(); }); } function fillGoogleHome() { $('#search').addClass('disabled'); sendTo(null, 'browseChromecast', null, function (list) { var text = '<option value="">' + _('select') + '</option>'; if (list) { for (var i = 0; i < list.length; i++) { text += '<option value="' + list[i].ip + '">' + list[i].name + '[' + list[i].ip + ']</option>'; } $('#googleHome').html(text).prop('disabled', false).off('change').on('change', function () { $('#server').val($(this).val()).trigger('change'); }); } else { $('#googleHome').html('<option value="">' + _('error') + '</option>').prop('disabled', true); } $('#search').removeClass('disabled'); M.updateTextFields('#search'); $('#googleHome').select(); }); } function ip2hex(ip) { var octets = ip.split('.'); if (octets.length !== 4) { return 0; } var result = 0; for (var i = 0; i < octets.length; ++i) { var octet = parseInt(octets[i], 10); if (Number.isNaN(octet) || octet < 0 || octet > 255) { throw new Error("Each octet must be between 0 and 255"); } result |= octet << ((octets.length - i) * 8); } return result; } function checkWeb(elem, current) { var web = $('#web').val(); for (var i = 0; i < webServers.length; i++) { if (webServers[i].id === 'system.adapter.' + web) { if (webServers[i].value.native.auth) { showMessage(_('Cannot use web server with authentication'), null, 'info'); } if (webServers[i].value.native.bind === 'localhost' || webServers[i].value.native.bind === '127.0.0.1' || webServers[i].value.native.bind === '::1') { showMessage(_('Cannot use web server only on localhost'), null, 'info'); } if (webServers[i].value.native.bind === '0.0.0.0') { $('#tr_webServer').show(); var $webServer = $('#webServer'); $webServer.html(''); // read all ipv4 addresses of host socket.emit('getObject', 'system.host.' + webServers[i].value.common.host, function (err, obj) { var text = ''; if (!err && obj && obj.native) { for (var iface in obj.native.hardware.networkInterfaces) { if (obj.native.hardware.networkInterfaces.hasOwnProperty(iface)) { for (var i = 0; i < obj.native.hardware.networkInterfaces[iface].length; i++) { if (obj.native.hardware.networkInterfaces[iface][i].family === 'IPv4' && !obj.native.hardware.networkInterfaces[iface][i].internal) { text += '<option value="' + obj.native.hardware.networkInterfaces[iface][i].address + '" data-mask="' + obj.native.hardware.networkInterfaces[iface][i].netmask + '">[IPv4] ' + obj.native.hardware.networkInterfaces[iface][i].address + ' - ' + iface + '</option>'; } } } } } $webServer.html(text); current && $webServer.val(current); $webServer.select(); $webServer.off('change').on('change', function () { gOnChange(); var ip = $(this).val(); var netmask = $(this).find('option[value="' + ip + '"]').data('mask'); var server; var type = $('#type').val(); if (type === 'googleHome') { server = $('#server').val(); } else if (type === 'sonos') { server = $('#device').val().split('.')[3].replace('_', '.').replace('_', '.').replace('_', '.'); } else if (type === 'heos') { server = $('#heos_device').val().split('.')[3].replace('_', '.').replace('_', '.').replace('_', '.'); } else if (type === 'chromecast') { server = $('#cDevice').val(); } else if (type === 'mpd') { server = $('#mpd_device').val(); } if (server && ip && netmask && server.indexOf(':') === -1 && ip.indexOf(':') === -1) { ip = ip2hex(ip); netmask = ip2hex(netmask); server = ip2hex(server); if ((ip & netmask) !== (server & netmask)) { $webServer.addClass('error').attr('title', _('IP not accessible for server')); } else { $webServer.removeClass('error').attr('title', ''); } } else { $webServer.removeClass('error'); } }); }); } else if (webServers[i].value.native.bind === '::') { // read all ipv6 addresses of host socket.emit('getObject', 'system.host.' + webServers[i].value.common.host, function (err, obj) { if (!err && obj && obj.native) { for (var iface in obj.native.hardware.networkInterfaces) { if (obj.native.hardware.networkInterfaces.hasOwnProperty(iface)) { for (var i = 0; i < obj.native.hardware.networkInterfaces[iface].length; i++) { if (obj.native.hardware.networkInterfaces[iface][i].family === 'IPv6' && !obj.native.hardware.networkInterfaces[iface][i].internal) { $('#webServer').append('<option value="' + obj.native.hardware.networkInterfaces[iface][i].address + '">[IPv6] ' + obj.native.hardware.networkInterfaces[iface][i].address + ' - ' + iface + '</option>'); } } } } } current && $('#webServer').val(current); $('#webServer').select(); }); } else { $('#tr_webServer').hide(); } } } } function fillWebServices(elem, current, type, webServer) { socket.emit('getObjectView', 'system', 'instance', {startkey: 'system.adapter.web.', endkey: 'system.adapter.web.\u9999'}, function (err, res) { if (!err && res) { webServers = res.rows; for (var i = 0; i < res.rows.length; i++) { var n = res.rows[i].id.replace('system.adapter.', ''); var auth = res.rows[i].value.native.auth ? 'data-auth="true"' : ''; $(elem).append('<option value="' + n + '" ' + auth + '>' + n + '</option>'); } } $(elem).val(current); if ((type === 'sonos') || (type === 'heos') || (type === 'chromecast') || (type === 'googleHome') || (type === 'mpd') ) { checkWeb('#web', webServer); } $(elem).select(); }); } function uploadFile(file, callback) { var reader = new FileReader(); // Closure to capture the file information. reader.onload = function(e) { socket.emit('writeFile', 'sayit.' + instance, 'tts.userfiles/' + file.name, e.target.result, function () { callback && callback(file.name); }); }; // Read in the image file as a data URL. reader.readAsArrayBuffer(file); } function handleFileSelect(evt) { var files = evt.target.files; // FileList object $('#drop_indcator').hide(); // files is a FileList of File objects. List some properties. var count = 0; for (var i = 0, f; f = files[i]; i++) { if (f.size > 1024 * 1024) { showMessage(_('File %s is too big. Maximum 1MB', escape(f.name))); $('#files').val(''); return; } if (f.name === 'say.mp3') { showMessage(_('Name say.mp3 is reserved')); $('#files').val(''); return; } count++; uploadFile(f, function (name) { count--; if (!count) { // Read names of files for gong socket.emit('readDir', 'sayit.' + instance, 'tts.userfiles', function (err, dir) { var text = '<option value="">' + _('none') + '</option>'; if (dir) { for (var i = 0; i < dir.length; i++) { if (dir[i].isDir) continue; text += '<option value="' + dir[i].file + '">' + dir[i].file + '</option>'; } } $('#announce').html(text).val(name).trigger('change'); $('#announce').select(); $('#files').val(''); }); } }); } } function handleFileSelectDrop(evt) { $('#drop_indcator').hide(); evt.stopPropagation(); evt.preventDefault(); var files = evt.dataTransfer.files; // FileList object. // files is a FileList of File objects. List some properties. var output = []; for (var i = 0, f; f = files[i]; i++) { if (f.size > 1024 * 1024) { return showMessage(_('File %s is too big. Maximum 1MB', escape(f.name))); } console.log(escape(f.name)); } } function handleDragOver(evt) { evt.stopPropagation(); evt.preventDefault(); evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy. $('#drop_indcator').show(); } // the function loadSettings has to exist ... function load(settings, onChange) { if (!settings) return; if (!settings.player) { settings.player = 'mpg321'; } gOnChange = onChange; $('#play').on('click', function () { socket.emit('readFile', 'sayit.' + instance, 'tts.userfiles/' + $('#announce').val(), function (err, data) { if (typeof AudioContext !== 'undefined') { context = new AudioContext(); context.decodeAudioData(data, function(buffer) { //console.log(buffer); var source = context.createBufferSource(); // creates a sound source source.buffer = buffer; // tell the source which sound to play source.connect(context.destination); // connect the source to the context's destination (the speakers) source.start(0); }, function(err) { console.log(err); }); } }); }); var $t = $('#type'); for (name in sayitOptions) { if (sayitOptions.hasOwnProperty(name)) { $t.append('<option value="' + name + '">' + sayitOptions[name].name + '</option>'); } } $('#search').on('click', function () { fillGoogleHome(); }); getIsAdapterAlive(function (isAlive) { if (isAlive || common.enabled) { $('#search').removeClass('disabled'); if (settings.type === 'googleHome') { fillGoogleHome(); } } else { $('#search').addClass('disabled').attr('title', _('Adapter must be enabled')); } M.updateTextFields('#search'); }); var $e = $('#engine'); for (var name in sayitEngines) { if (sayitEngines.hasOwnProperty(name)) { $e.append('<option value="' + name + '">' + sayitEngines[name].name + '</option>'); } } for (var key in settings) { if (settings.hasOwnProperty(key)) { var $val = $('#' + key + '.value'); if ($val.attr('type') === 'checkbox') { $val.prop('checked', settings[key]); } else { $val.val(settings[key]); } } } $('.value').on('change', function () { var key = $(this).attr('id'); if (key === 'auth') { if ($('#auth').prop('checked')) { $('#secure').prop('checked', true); } } else if (key === 'type' || key === 'engine') { showHideSettings(); var type = $('#type').val(); if ((type === 'sonos') || (type === 'heos') || (type === 'chromecast') || (type === 'mpd') || (type === 'googleHome')) { checkWeb('#web'); $('#announce').val('').trigger('change'); M.updateTextFields('#search'); showHideSettings(); } else { showHideSettings(); } if (key === 'engine') {fillEngineParams();} } else if (key === 'announce') { showHideSettings(); if ($(this).val()) { socket.emit('readFile', 'sayit.' + instance, 'tts.userfiles/' + $('#announce').val(), function (err, data) { if (typeof AudioContext !== 'undefined') { context = new AudioContext(); context.decodeAudioData(data, function (buffer) { $('#annoDuration').val(Math.ceil(buffer.duration)); }, function (err) { console.log(err); }); } }); } } if (key === 'web') { checkWeb('#web'); } onChange(); }).keyup(function() { $(this).trigger('change'); }); if (!settings.engine) { settings.engine = systemLang; $('#engine').val(systemLang).trigger('change'); } if (!settings.instance) { settings.instance = 'FFFFFFFF'; $('#instance').val(settings.instance).trigger('change'); } fillEngineParams(); fillSonosDevices('#device', settings.device); fillHeosDevices('#heos_device', settings.device); fillChromecastDevices('#cDevice', settings.cDevice); fillWebServices('#web', settings.web, settings.type, settings.webServer); fillMpdDevice('#mpd_device', settings.mpd_device); if ((settings.type === 'sonos') || (settings.type === 'heos') || (settings.type === 'chromecast') || (settings.type === 'mpd') || (settings.type === 'googleHome')){ $('.announce').hide(); if (settings.announce) { $('#announce').val('').trigger('change'); } } // Read names of files for gong socket.emit('readDir', 'sayit.' + instance, 'tts.userfiles', null, function (err, dir) { var text = '<option value="">' + _('none') + '</option>'; if (dir) { for (var i = 0; i < dir.length; i++) { if (dir[i].isDir) continue; text += '<option value="' + dir[i].file + '">' + dir[i].file + '</option>'; } } $('#announce').html(text).val(settings.announce); $('#announce').select(); showHideSettings(); }); getAdapterInstances('cloud', function (list) { if (list) { var text = ''; for (var i = 0; i < list.length; i++) { var id = list[i]._id.substring('system.adapter.'.length); text += '<option value="' + id + '" ' + (id === settings.cloud ? 'selected' : '') + '>' + id + '</option>'; } text && $('#cloud').html(text); $('#cloud').select(); } }); $('#voice').val(settings.voice); var w = $('#engine').width(); $('#announce').css({width: w}); $('#type').css({width: w}); document.getElementById('files').addEventListener('change', handleFileSelect, false); showHideSettings(); if (!$('#announce').val()) { $('#play').addClass('disabled'); } if (typeof AudioContext === 'undefined') { $('#play').hide(); } var dropZone = document.getElementById('drop_zone'); if (dropZone) { dropZone.addEventListener('dragover', handleDragOver, false); dropZone.addEventListener('drop', handleFileSelect, false); /*dropZone.addEventListener('dragend', function () { $(this).css({background: 'white'}); console.log('dragend'); return false; }, false); dropZone.addEventListener('dragstart', function () { console.log('dragstart'); }, false); dropZone.addEventListener('dragleave', function () { $(this).css({background: 'white'}); }, false); dropZone.addEventListener('dragenter', function () { $(this).css({background: 'gray'}); }, false);*/ } onChange(false); } function save(callback) { var obj = {}; $('.value').each(function () { var $this = $(this); if ($this.attr('type') === 'checkbox') { obj[$this.attr('id')] = $this.prop('checked'); } else { obj[$this.attr('id')] = $this.val(); } }); if (obj.engine && sayitEngines[obj.engine].engine === 'yandex') { if (!obj.key) { showMessage(_('API Key is not set!')); return; } } else if (obj.engine && sayitEngines[obj.engine].engine === 'polly') { if (!obj.accessKey || !obj.secretKey) { showMessage(_('API Key is not set!')); return; } if (!obj.region) { showMessage(_('AWS Region is not set!')); return; } } if (obj.type === 'googleHome') { obj.cache = false; } callback(obj); } </script> </head> <body> <div class="m adapter-container" ondragover="return false" ondrop="return false"> <div class="row"> <div class="col s12"> <div class="row"> <div class="col s6"> <img src="sayit.png" class="logo"> </div> </div> <div class="row"> <div class="input-field col s6 m4"> <select class="value" id="type"></select> <label class="translate" for="type">Type:</label> </div> <div class="input-field col s6 m4" id="tr_engine" > <select class="value" id="engine"></select> <label class="translate" for="engine">Language:</label> </div> </div> <div class="row system"> <div class="input-field col s6 m4"> <select class="value" id="player" > <option value="mpg321">mpg321</option> <option value="omxplayer">omxplayer</option> <option value="mplayer">mplayer</option> </select> <label for="player"><span class="translate">Linux player:</span><span class="translate" style="padding-left: 10px; font-size: 10px">Ignore for non linux OS</span></label> </div> <div class="input-field col s6 m4 l2"> <input class="value" id="command"/> <label class="translate" for="command">System command:</label> </div> </div> <div class="row announceValue"> <div class="input-field col s6 m4"> <select class="value" id="announce"></select> <label class="translate" for="announce">Announce:</label> &nbsp;<a class="waves-effect waves-light btn translate" id="play">play</a> </div> <div class="file-field input-field col s6 m4"> <div class="btn"> <span class="translate">File</span> <input type="file" accept=".mp3,audio/*" id="files" name="files[]" multiple /> </div> <div class="file-path-wrapper"> <input class="file-path validate" type="text" /> </div> </div> </div> <div class="row announce"> <div class="input-field col s4 m4 l2"> <input class="value" id="annoTimeout" type="number" min="0" max="1000" /> <label class="translate" for="annoTimeout">Announce timeout (sec):</label> </div> <div class="input-field col s4 m4 l2"> <input class="value" id="annoDuration" type="number" min="0" max="99"/> <label class="translate" for="annoDuration">Announce length (sec):</label> </div> <div class="input-field col s4 m4 l2"> <input class="value" id="annoVolume" type="number" min="0" max="100"/> <label class="translate" for="annoVolume">Announce volume (%):</label> </div> </div> <div class="row"> </div> <div class="row variable"> <div class="input-field col s6 m4" id="tr_cache"> <input class="value" id="cache" type="checkbox" /> <label class="translate" for="cache">Cache:</label> </div> <div class="input-field col s6 m4" id="tr_cacheExpiryDays" > <input class="value" id="cacheExpiryDays" size="5" /> <label class="translate" for="cacheExpiryDays">Cache-Expiry:</label> </div> </div> <div id="tr_server" class="row variable"> <div class="input-field col s6 m4 l2"> <input class="value" id="server"/> <label class="translate" for="server">Server:</label> <select class="value googleHome" id="googleHome"> <option value="" class="translate">none</option> </select> <a class="waves-effect waves-light btn translate googleHome" style="font-size: 10px; margin-left: 10px;" id="search">Browse</a> </div> </div> <div id="tr_port" class="row variable"> <div class="input-field col s6 m4 l2"> <input class="value" id="port" size="5" maxlength="5"/> <label class="translate" for="port">Port:</label> </div> </div> <div class="row variable"> <div id="tr_user" class="input-field col s6 m4 l2"> <input class="value" id="user" /> <label class="translate" for="user">User:</label> </div> <div id="tr_pass" class="input-field col s6 m4 l2"> <input class="value" id="pass" /> <label class="translate" for="pass">Password:</label> </div> </div> <div id="tr_instance" class="row variable"> <div class="input-field col s6 m4 l2"> <label class="translate" for="instance">Browser instance:</label> <input class="value" id="instance" /> </div> </div> <div id="tr_device" class="row variable"> <div class="input-field col s6 l4"> <select class="value" id="device"> <option value="" class="translate">All</option> </select> <label class="translate" for="device">Device:</label> </div> </div> <div id="tr_heos_device" class="row variable"> <div class="input-field col s6 l4"> <select class="value" id="heos_device"> <option value="" class="translate">All</option> </select> <label class="translate" for="heos_device">Device:</label> </div> </div> <div id="tr_cDevice" class="row variable"> <div class="input-field col s6 l4"> <select class="value" id="cDevice"> <option value="" class="translate">All</option> </select> <label class="translate" for="cDevice">Device:</label> </div> </div> <div id="tr_mpd_device" class="row variable"> <div class="input-field col s6 l4"> <select class="value" id="mpd_device"> <option value="" class="translate">All</option> </select> <label class="translate" for="mpd_device">Device:</label> </div> </div> <div id="tr_web" class="row variable"> <div class="input-field col s6 l4"> <select class="value" id="web"></select> <label class="translate" for="web">Web instance:</label> </div> </div> <div id="tr_webServer" class="row variable"> <div class="input-field col s6 l4"> <select class="value" id="webServer"></select> <label class="translate" for="webServer">Web server IP:</label> </div> </div> <div id="tr_voice" class="row engine" > <div class="input-field col s6 m4 l2"> <select class="value" id="voice"></select> <label class="translate" for="voice">Voice:</label> </div> </div> <div id="tr_key" class="row engine" > <div class="input-field col s6 m4 l2"> <input class="value" id="key" type="text"/> <label class="translate" for="key">API Key:</label> </div> </div> <div id="tr_folderID" class="row engine" > <div class="input-field col s6 m4 l2"> <input class="value" id="folderID" type="text"/> <label class="translate" for="folderID">Folder ID:</label> </div> </div> <div id="tr_emotion" class="row engine" > <div class="input-field col s6 m4 l2"> <select class="value" id="emotion"></select> <label class="translate" for="emotion">Emotion:</label> </div> </div> <div id="tr_drunk" class="row engine" > <div class="input-field col s6 m4 l2"> <input type="checkbox" class="value" id="drunk"/> <label class="translate" for="drunk">Drunk:</label> </div> </div> <div id="tr_ill" class="row engine" > <div class="input-field col s6 m4 l2"> <input type="checkbox" class="value" id="ill"/> <label class="translate" for="ill">Ill:</label> </div> </div> <div id="tr_robot" class="row engine" > <div class="input-field col s6 m4 l2"> <input type="checkbox" class="value" id="robot"/> <label class="translate" for="robot">Robot:</label> </div> </div> <div id="tr_accessKey" class="row engine" > <div class="input-field col s6 m4 l2"> <label class="translate" for="accessKey">Access Key:</label> <input class="value" id="accessKey" type="text"/> </div> </div> <div id="tr_secretKey" class="row engine" > <div class="input-field col s6 m4 l2"> <label class="translate" for="secretKey">Secret Key:</label> <input class="value" id="secretKey" type="password"/> </div> </div> <div id="tr_region" class="row engine" > <div class="input-field col s6 m4 l2"> <input class="value" id="region" type="text"/> <label class="translate" for="region">AWS Region:</label> </div> </div> <div id="tr_cloud" class="row engine" > <div class="input-field col s6 m4 l2"> <select class="value" id="cloud"> <option value="" class="translate">Install first cloud adapter</option> </select> <label class="translate" for="cloud">Cloud instance:</label> </div> </div> </div> </div> <div id="drop_zone" style="display: none" class="translate">place here</div> </div> </body> </html>