Delete obsolete code

Signed-off-by: Andrey Shovkoplyas <motor4ik@gmail.com>
This commit is contained in:
janherich 2018-07-23 14:14:06 +02:00 committed by Andrey Shovkoplyas
parent c5771f3168
commit 9b990a8038
No known key found for this signature in database
GPG Key ID: EAAB7C8622D860A4
15 changed files with 13 additions and 3057 deletions

View File

@ -1,525 +0,0 @@
var jsSuggestionContainerStyle = {
backgroundColor: "white"
};
var jsSubContainerStyle = {
paddingTop: 9,
borderBottomWidth: 1,
borderBottomColor: "#0000001f"
};
function jsSuggestionSubContainerStyle(isLast) {
var borderBottomWidth = (isLast ? 0 : 1);
return {
paddingTop: 14,
paddingBottom: 14,
paddingRight: 14,
marginLeft: 14,
borderBottomWidth: borderBottomWidth,
borderBottomColor: "#e8ebec"
};
}
var jsValueStyle = {
fontSize: 15,
fontFamily: "font",
color: "#000000de"
};
var jsBoldValueStyle = {
fontSize: 15,
fontFamily: "font",
color: "#000000de",
fontWeight: "bold"
};
var jsDescriptionStyle = {
marginTop: 2,
fontSize: 14,
fontFamily: "font",
color: "#838c93de"
};
if (!String.prototype.startsWith) {
String.prototype.startsWith = function (searchString, position) {
position = position || 0;
return this.substr(position, searchString.length) === searchString;
};
}
function matchSubString(array, string) {
var matched = [];
for (var i = 0; i < array.length; i++) {
var item = array[i];
if (item.toLowerCase().startsWith(string.toLowerCase())) {
matched.push(item);
}
}
return matched;
}
function cleanCode(code) {
// remove comments
var commentsRegex = /\/\*.+?\*\/|\/\/.*/g;
code = code.replace(commentsRegex, "");
// replace string literals
var literalsRegex = /\"(?:\\\\\"|[^\"])*?\"/g;
code = code.replace(literalsRegex, '""');
var literalsRegex = /\'(?:\\\\\'|[^\'])*?\'/g;
code = code.replace(literalsRegex, '""');
return code
}
function createObjectSuggestion(name, docInfo, code, parameterNumber) {
var title = name;
if (docInfo.args) {
title += "(";
for (var i = 0; i < docInfo.args.length; i++) {
var argument = docInfo.args[i];
var argumentText = (i > 0 ? ", " : "") + (parameterNumber === i ? "*" + argument.name + "*" : argument.name);
if (argument.optional) {
argumentText = "[" + argumentText + "]";
}
title += argumentText;
}
title += ")";
}
if (!docInfo.desc) {
name += ".";
} else if (docInfo.args) {
name += "(";
if (docInfo.args.length == 0) {
name += ")";
}
}
var suggestion = {
title: title,
desc: docInfo.desc
};
if (code != null) {
suggestion.pressValue = code + name;
}
return suggestion;
}
var lastMessage = null;
function getLastForm(code) {
var codeLength = code.length;
var form = '';
var level = 0;
var index = codeLength - 1;
while (index >= 0) {
var char = code[index];
if (level == 0 && index != 0 && (char == '(' || char == ',')) {
break;
}
if (char == ')') {
level--;
}
if (char == '(') {
level++;
}
form = char + form;
index--;
}
return form;
}
function getLastLevel(code) {
var codeLength = code.length;
var form = '';
var index = codeLength - 1;
var nested = false;
var level = 0;
while (index >= 0) {
var char = code[index];
if (char == ')') {
level--;
// A single unbalanced ')' shouldn't set nested to true.
if (level > 0) {
nested = true;
}
}
if (char == '(') {
level++;
if (level == 0) {
nested = false;
}
if (level <= 0) {
form = "argument" + form;
index--;
continue;
}
}
if ((level == 1 && char == ',') || level == 2) {
break;
}
if (!nested || level > 0) {
form = char + form;
}
index--;
}
if (form.indexOf("(") < 0 && form != ",") {
var parts = form.split(',');
form = parts[parts.length - 1];
}
return form;
}
function getPartialSuggestions(doc, fullCode, code) {
var suggestions = [];
var functionParts = code.split("(");
var objectParts = code.split(/[^a-zA-Z_0-9\$\-\u00C0-\u1FFF\u2C00-\uD7FF\w]+/);
var index = 0;
var suggestedFunction = '';
while (index < objectParts.length) {
var part = objectParts[index];
if (part != "desc" && part != "args" && doc[part] != null) {
doc = doc[part];
suggestedFunction += part + '.';
index++;
} else {
break;
}
}
suggestedFunction = suggestedFunction.substring(0, suggestedFunction.length - 1)
if (functionParts.length == 1) {
// object suggestions
if (index > objectParts.length - 1) {
var suggestion = objectParts[objectParts.length - 1];
suggestions.push(createObjectSuggestion(suggestion, doc, fullCode.substring(0, fullCode.length - suggestion.length)));
} else if (index === objectParts.length - 1) {
var lastPart = objectParts[index];
var keys = Object.keys(doc);
var matches = matchSubString(keys, lastPart);
for (var i = 0; i < matches.length; i++) {
var suggestion = matches[i];
if (suggestion == "desc" || suggestion == "args") {
continue;
}
var docInfo = doc[suggestion];
if (docInfo != null) {
suggestions.push(createObjectSuggestion(suggestion, docInfo, fullCode.substring(0, fullCode.length - lastPart.length)));
}
}
}
} else if (functionParts.length == 2) {
// parameter suggestions
var parameters = functionParts[1].split(",");
if (doc.args && parameters.length <= doc.args.length && parameters[parameters.length - 1].indexOf(")") < 0) {
var paramInfo = doc.args[parameters.length - 1];
var docInfo = doc;
docInfo.desc = paramInfo.name + ": " + paramInfo.desc;
suggestions.push(createObjectSuggestion(suggestedFunction, docInfo, null, parameters.length - 1));
}
}
//console.debug(suggestions);
return suggestions;
}
function getJsSuggestions(code, context) {
var suggestions = [];
var doc = DOC_MAP;
// TODO: what's /c / doing there ???
//console.debug(code);
var previousMessage = localStorage.getItem("previousMessage");
if (!code || code == "" || code == "c ") {
code = "";
//console.debug("Last message: " + context.data);
if (previousMessage != null) {
suggestions.push({
title: 'Last command used:',
desc: previousMessage,
pressValue: previousMessage
});
}
var keys = Object.keys(doc);
for (var i = 0; i < keys.length; i++) {
var suggestion = keys[i];
var docInfo = doc[suggestion];
if (docInfo != null) {
suggestions.push(createObjectSuggestion(suggestion, docInfo, ""));
}
}
} else {
// TODO: what's /c / doing there ???
if (code.startsWith("c ")) {
code = code.substring(2);
}
if (previousMessage != null &&
(typeof previousMessage === 'string' || previousMessage instanceof String) &&
previousMessage.startsWith(code)) {
suggestions.unshift({
title: 'Last command used:',
desc: previousMessage,
pressValue: previousMessage
});
}
var originalCode = code;
code = cleanCode(code);
var levelCode = getLastLevel(code);
var code = getLastForm(levelCode);
if (levelCode != code) {
suggestions = getPartialSuggestions(doc, originalCode, levelCode);
}
//console.debug("Final code: " + code);
//console.debug("Level code: " + levelCode);
suggestions = suggestions.concat(getPartialSuggestions(doc, originalCode, code));
}
return suggestions;
}
function createMarkupText(text) {
var parts = [];
var index = 0;
var currentText = '';
var isBold = false;
while (index < text.length) {
var char = text[index];
if (char == '*') {
if (currentText != '') {
parts.push(
status.components.text(
{style: isBold ? jsBoldValueStyle : jsValueStyle},
currentText
)
);
currentText = '';
}
isBold = !isBold;
} else {
currentText += char;
}
index++;
}
if (currentText != '') {
parts.push(
status.components.text(
{style: isBold ? jsBoldValueStyle : jsValueStyle},
currentText
)
);
}
//console.debug(parts);
return parts;
}
function jsSuggestions(params, context) {
var suggestions = getJsSuggestions(params.code, context);
var sugestionsMarkup = [];
for (var i = 0; i < suggestions.length; i++) {
var suggestion = suggestions[i];
if (suggestion.title.indexOf('*') >= 0) {
suggestion.title = createMarkupText(suggestion.title);
}
var suggestionMarkup = status.components.view(jsSuggestionContainerStyle,
[status.components.view(jsSuggestionSubContainerStyle(i == suggestions.length - 1),
[
status.components.text({style: jsValueStyle},
suggestion.title),
status.components.text({style: jsDescriptionStyle},
suggestion.desc)
])]);
if (suggestion.pressValue) {
suggestionMarkup = status.components.touchable({
onPress: status.components.dispatch([status.events.SET_VALUE, suggestion.pressValue])
},
suggestionMarkup
);
}
sugestionsMarkup.push(suggestionMarkup);
}
if (sugestionsMarkup.length > 0) {
return {markup: status.components.view({}, sugestionsMarkup)};
} else {
return {markup: null};
}
}
function jsHandler(params, context) {
var result = {
err: null,
data: null,
messages: []
};
messages = [];
try {
result["text-message"] = String(JSON.stringify(eval(params.code)));
localStorage.setItem("previousMessage", params.code);
} catch (e) {
result.err = e;
}
result.messages = messages;
return result;
}
var suggestionsContainerStyle = {
keyboardShouldPersistTaps: "always",
backgroundColor: "white",
flexGrow: 1,
bounces: false
}
var suggestionContainerStyle = {
backgroundColor: "white"
};
function suggestionSubContainerStyle(isTwoLineEntry, isLast) {
var height = (isTwoLineEntry ? 64 : 48);
var borderBottomWidth = (isLast ? 0 : 1);
return {
paddingTop: 14,
paddingBottom: 14,
paddingRight: 14,
marginLeft: 14,
height: height,
borderBottomWidth: borderBottomWidth,
borderBottomColor: "#e8ebec"
};
}
var valueStyle = {
fontSize: 15,
fontFamily: "font",
color: "#000000de"
};
var descriptionStyle = {
marginTop: 2,
fontSize: 13,
fontFamily: "font",
color: "#838c93de"
};
function startsWith(str1, str2) {
// String.startsWith(...) doesn't work in otto
return str1.lastIndexOf(str2, 0) == 0 && str1 != str2;
}
var ropstenNetworkId = 3;
var rinkebyNetworkId = 4;
var ropstenFaucets = [
{
name: "Status Testnet Faucet",
url: "http://51.15.45.169:3001",
}
];
var rinkebyFaucets = [
{
name: "Status Rinkeby Faucet",
url: "http://51.15.60.23:3001",
}
];
function getFaucets(networkId) {
if (networkId == ropstenNetworkId) {
return ropstenFaucets;
} else if (networkId == rinkebyNetworkId) {
return rinkebyFaucets;
} else {
return [];
}
}
var faucets = getFaucets(status.ethereumNetworkId);
function faucetSuggestions(params) {
var subContainerStyle = suggestionSubContainerStyle(true, false);
var suggestions = faucets.map(function (entry, index) {
return status.components.touchable(
{onPress: status.components.dispatch([status.events.SET_COMMAND_ARGUMENT, [0, entry.url, true]])},
status.components.view(
suggestionContainerStyle,
[status.components.view(
(index == faucets.length - 1 ? suggestionSubContainerStyle(true, true) : subContainerStyle),
[
status.components.text(
{style: valueStyle},
entry.name
),
status.components.text(
{style: descriptionStyle},
entry.url
)
]
)]
)
);
});
return {markup: status.components.view({}, suggestions)};
}
var faucetCommandConfig ={
name: "faucet",
title: I18n.t('faucet_title'),
description: I18n.t('faucet_description'),
color: "#7099e6",
scope: ["personal-chats", "registered", "dapps"],
params: [{
name: "url",
type: status.types.TEXT,
suggestions: faucetSuggestions,
placeholder: I18n.t('faucet_placeholder')
}],
preview: function (params) {
return {
markup: status.components.text(
{},
params.url
)
};
},
shortPreview: function (params) {
return {
markup: status.components.chatPreviewText(
{},
I18n.t('faucet_title') + ": " + params.url
)
};
},
validator: function (params, context) {
var f = faucets.map(function (entry) {
return entry.url;
});
if (f.indexOf(params.url) == -1) {
var error = status.components.validationMessage(
I18n.t('faucet_incorrect_title'),
I18n.t('faucet_incorrect_description')
);
return {markup: error};
}
}
}
;
if (faucets.length > 0) {
status.command(faucetCommandConfig);
}
status.addListener("on-message-input-change", function (params, context) {
return jsSuggestions({code: params.message}, context);
});
status.addListener("on-message-send", function (params, context) {
return jsHandler({code: params.message}, context);
});

View File

@ -1,42 +0,0 @@
// Run this in a node REPL
// .load test.js
// Load dependencies
.load web3_metadata.js
.load bot.js
// A map from current input text to suggestion titles
var suggestionTests = {
",": [],
")": [],
"(": [],
"a)": [],
// Expected?
// "a,": [],
// "a(": [],
"c": ["console"],
"console.": ["log(text)"]
};
// Mock localStorage, necessary for suggestions functions in bot.js
var STORE = {};
var localStorage = function() {};
localStorage.getItem = function(k) { return STORE[k]; };
localStorage.setItem = function(k, v) { STORE[k] = v; };
var checkSuggestion = function(input) {
var suggestions = getJsSuggestions(input, {});
var titles = suggestions.map(function(suggestion) {
return suggestion.title;
});
var expectedTitles = suggestionTests[input];
var iseq = JSON.stringify(titles) == JSON.stringify(expectedTitles);
console.log("CHECK", input, " ", iseq);
if (!iseq) {
console.log("EXPECTED", expectedTitles);
console.log("ACTUAL", titles);
}
};
// Run tests
Object.keys(suggestionTests).forEach(checkSuggestion);

View File

@ -1,417 +0,0 @@
I18n.translations = {
en: {
password_description: 'Password',
password_placeholder: 'Type your password',
password_placeholder2: 'Confirm',
password_error: 'Password should be not less then 6 symbols.',
password_error1: 'Password confirmation doesn\'t match password.',
password_validation_title: 'Password',
faucet_incorrect_title: 'Incorrect faucet',
faucet_incorrect_description: 'Please, select a one from the list',
debug_mode_title: 'Debug mode',
debug_mode_description: 'Starts/stops a debug mode',
faucet_title: 'Faucet',
faucet_description: 'Get some ETH',
faucet_placeholder: 'Faucet URL'
}
/*
,
ru: {
password_description: 'Пароль',
password_placeholder: 'Введите свой пароль',
password_placeholder2: 'Повторно введите пароль для подтверждения',
password_error: 'Пароль должен содержать не менее 6 символов',
password_error1: 'Подтверждение пароля не совпадает с паролем',
password_validation_title: 'Пароль'
},
af: {
password_description: 'Wagwoord',
password_placeholder: 'Tik jou wagwoord in',
password_placeholder2: 'Tik asseblief weer jou wagwoord in om te bevestig',
password_error: 'Wagwoord mag nie minder as 6 simbole wees nie.',
password_error1: 'Wagwoordbevestiging is nie dieselfde as wagwoord nie.',
password_validation_title: 'Wagwoord'
},
ar: {
password_description: 'كلمة المرور',
password_placeholder: 'اكتب كلمة المرور الخاصة بك',
password_placeholder2: 'الرجاء إعادة إدخال كلمة المرور للتأكيد',
password_error: 'ينبغي أن لا تقل كلمة المرور عن 6 رموز.',
password_error1: 'لا يتوافق تأكيد كلمة المرور مع كلمة المرور.',
password_validation_title: 'كلمة المرور'
},
'zh-hant': {
password_description: '密碼',
password_placeholder: '鍵入你的密碼',
password_placeholder2: '重新鍵入你的密碼',
password_error: '密碼不得短於6個字符。',
password_error1: '確認密碼與鍵入的密碼不一致。',
password_validation_title: '密碼',
faucet_incorrect_title: '不正確的水龍頭',
faucet_incorrect_description: '請從列表中選擇一個',
debug_mode_title: '調試模式',
debug_mode_description: '開始/停止調試模式',
faucet_title: '水龍頭',
faucet_description: '獲取一些以太幣',
faucet_placeholder: '水龍頭網址'
},
'zh-hant-tw': {
password_description: '密碼',
password_placeholder: '輸入密碼',
password_placeholder2: '請重新輸入密碼以確認',
password_error: '密碼應不少於6個字符。',
password_error1: '密碼確認資訊與密碼不匹配。',
password_validation_title: '密碼',
faucet_incorrect_title: '不正確的水龍頭',
faucet_incorrect_description: '請從列表中選擇一個',
debug_mode_title: '除錯模式',
debug_mode_description: '開始/停止除錯模式',
faucet_title: '水龍頭',
faucet_description: '獲取一些以太幣',
faucet_placeholder: '水龍頭網址'
},
'zh-hant-sg': {
password_description: '密碼',
password_placeholder: '輸入密碼',
password_placeholder2: '請重新輸入密碼以確認',
password_error: '密碼應不少於6個字符。',
password_error1: '密碼確認資訊與密碼不匹配。',
password_validation_title: '密碼',
faucet_incorrect_title: '不正確的水龍頭',
faucet_incorrect_description: '請從列表中選擇一個',
debug_mode_title: '除錯模式',
debug_mode_description: '開始/停止除錯模式',
faucet_title: '水龍頭',
faucet_description: '獲取一些以太幣',
faucet_placeholder: '水龍頭網址'
},
'zh-hant-hk': {
password_description: '密碼',
password_placeholder: '輸入密碼',
password_placeholder2: '請重新輸入密碼以確認',
password_error: '密碼應不少於6個字符。',
password_error1: '密碼確認信息與密碼不匹配。',
password_validation_title: '密碼',
faucet_incorrect_title: '不正確的水龍頭',
faucet_incorrect_description: '請從列表中選擇一個',
debug_mode_title: '調試模式',
debug_mode_description: '開始/停止調試模式',
faucet_title: '水龍頭',
faucet_description: '獲取一些以太幣',
faucet_placeholder: '水龍頭網址'
},
'zh-hans': {
password_description: '密码',
password_placeholder: '输入密码',
password_placeholder2: '请重新输入密码以确认',
password_error: '密码应不少于6个字符。',
password_error1: '密码确认信息与密码不匹配。',
password_validation_title: '密码',
faucet_incorrect_title: '不正确的水龙头',
faucet_incorrect_description: '请从列表中选择一个',
debug_mode_title: '调试模式',
debug_mode_description: '开始/停止调试模式',
faucet_title: '水龙头',
faucet_description: '获取一些以太币',
faucet_placeholder: '水龙头网址'
},
'zh-yue': {
password_description: '密碼',
password_placeholder: '輸入密碼',
password_placeholder2: '請重新輸入密碼確認',
password_error: '密碼不能短於6個字符.',
password_error1: '確認密碼與輸入密碼不符.',
password_validation_title: '密碼',
faucet_incorrect_title: '不正確的水龍頭',
faucet_incorrect_description: '請從列表中選擇一個',
debug_mode_title: '調試模式',
debug_mode_description: '開始/停止調試模式',
faucet_title: '水龍頭',
faucet_description: '獲取一些以太幣',
faucet_placeholder: '水龍頭網址'
},
'zh-wuu': {
password_description: '密码',
password_placeholder: '输入密码',
password_placeholder2: '请重新输入密码确认',
password_error: '密码应不小于6个字符。',
password_error1: '密码确认不匹配。',
password_validation_title: '密码',
faucet_incorrect_title: '不正確的水龍頭',
faucet_incorrect_description: '請從列表中選擇一個',
debug_mode_title: '調試模式',
debug_mode_description: '開始/停止調試模式',
faucet_title: '水龍頭',
faucet_description: '獲取一些以太幣',
faucet_placeholder: '水龍頭網址'
},
nl: {
password_description: 'Wachtwoord',
password_placeholder: 'Typ je wachtwoord',
password_placeholder2: 'Voer je wachtwoord opnieuw in om te bevestigen',
password_error: 'Wachtwoord moet minstens 6 tekens hebben.',
password_error1: 'Wachtwoordbevestiging komt niet overeen met wachtwoord.',
password_validation_title: 'Wachtwoord'
},
fr: {
password_description: 'Mot de passe',
password_placeholder: 'Tapez votre mot de passe',
password_placeholder2: 'Veuillez retapez votre mot de passe pour le confirmer',
password_error: 'Le mot de passe doit contenir 6 symboles au minimum.',
password_error1: 'Le mot de passe de confirmation ne correspond pas au mot de passe.',
password_validation_title: 'Mot de passe'
},
de: {
password_description: 'Passwort',
password_placeholder: 'Geben Sie Ihr Passwort ein',
password_placeholder2: 'Bitte geben Sie das Passwort zur Bestätigung erneut ein',
password_error: 'Das Passwort sollte nicht weniger als 6 Stellen beinhalten',
password_error1: 'Die Passwortbestätigung stimmt nicht mit dem Passwort überein',
password_validation_title: 'Passwort',
},
hi: {
password_description: 'पासवर्ड',
password_placeholder: 'अपना पासवर्ड टाइप करें',
password_placeholder2: 'पुष्टि करने के लिए फिर से पासवर्ड दर्ज करें',
password_error: 'पासवर्ड 6 प्रतीकों से कम का नहीं होना चाहिए।',
password_error1: 'पासवर्ड पुष्टि पासवर्ड मेल नहीं खाता है।',
password_validation_title: 'पासवर्ड'
},
hu: {
password_description: 'Jelszó',
password_placeholder: 'Add meg a jelszavad',
password_placeholder2: 'A megerősítéshez kérjük, add meg újra a jelszavad',
password_error: 'A jelszó nem lehet hosszabb 6 szimbólumnál.',
password_error1: 'A megerősített jelszó nem egyezik a jelszóval.',
password_validation_title: 'Jelszó'
},
it: {
password_description: 'Password',
password_placeholder: 'Digita la tua password',
password_placeholder2: 'Reinserisci la password per confermare',
password_error: 'La password deve contenere almeno 6 caratteri.',
password_error1: 'Conferma password\ la password non corrisponde.',
password_validation_title: 'Password'
},
ja: {
password_description: 'パスワード',
password_placeholder: 'パスワードを入力してください',
password_placeholder2: '確認のためにパスワードを再入力してください',
password_error: 'パスワードは6文字以上にしてください。',
password_error1: 'パスワードが一致しません。',
password_validation_title: 'パスワード',
faucet_incorrect_title: 'フォーセットが違います',
faucet_incorrect_description: '一覧の中から一つだけ選択してください',
debug_mode_title: 'デバッグモード',
debug_mode_description: 'デバッグモードを開始/停止します',
faucet_title: 'フォーセット',
faucet_description: 'ETHを取得する',
faucet_placeholder: 'フォーセットURL'
},
ko: {
password_description: '비밀번호',
password_placeholder: '비밀번호를 입력하세요',
password_placeholder2: '확인을 위해 비밀번호를 다시 입력해 주세요',
password_error: '비밀번호는 6자 이상이어야 합니다.',
password_error1: '확인용 비밀번호가 원래 비밀번호와 일치하지 않습니다.',
password_validation_title: '비밀번호'
},
pl: {
password_description: 'Hasło',
password_placeholder: 'Wpisz swoje hasło',
password_placeholder2: 'Wprowadź ponownie hasło, aby potwierdzić',
password_error: 'Hasło powinno zawierać co najmniej 6 symboli.',
password_error1: 'Wprowadzone i potwierdzone hasła nie są takie same.',
password_validation_title: 'Hasło'
},
'pt-br': {
password_description: 'Senha',
password_placeholder: 'Digite sua senha',
password_placeholder2: 'Por favor, digite a senha novamente para confirmar',
password_error: 'A senha deve ter no mínimo 6 símbolos.',
password_error1: 'A confirmação da senha é diferente da senha.',
password_validation_title: 'Senha'
},
'pt-pt': {
password_description: 'Palavra-passe',
password_placeholder: 'Digite a sua palavra-passe',
password_placeholder2: 'Por favor, volte a digitar a palavra-passe para confirmar',
password_error: 'A palavra-passe não deve ter menos de 6 símbolos.',
password_error1: 'A confirmação da palavra-passe não coincide com a palavra-passe.',
password_validation_title: 'Palavra-passe'
},
ro: {
password_description: 'Parolă',
password_placeholder: 'Tastează parola',
password_placeholder2: 'Te rugăm să re-introduci parola pentru a confirma',
password_error: 'Parola trebuie să aibă cel puțin 6 simboluri.',
password_error1: 'Parola confirmată nu este aceeași cu parola introdusă.',
password_validation_title: 'Parolă'
},
sl: {
password_description: 'Geslo',
password_placeholder: 'Vnesi svoje geslo',
password_placeholder2: 'Prosimo, ponovno vnesi geslo za potrditev',
password_error: 'Geslo mora vsebovati vsaj 6 simbolov.',
password_error1: 'Potrditev gesla se ne ujema z geslom.',
password_validation_title: 'Geslo'
},
es: {
password_description: 'Contraseña',
password_placeholder: 'Escribe tu contraseña',
password_placeholder2: 'Por favor, vuelve a escribir la contraseña para confirmar',
password_error: 'La contraseña no debe ser inferior a 6 símbolos.',
password_error1: 'La confirmación de contraseña no coincide con la contraseña.',
password_validation_title: 'Contraseña'
},
'es-ar': {
password_description: 'Contraseña',
password_placeholder: 'Ingresa tu contraseña',
password_placeholder2: 'Ingresa tu contraseña para confirmar',
password_error: 'Las contraseñas deben contener no menos de 6 símbolos.',
password_error1: 'La confirmación de la contraseña no coincide con la contraseña.',
password_validation_title: 'Contraseña'
},
sw: {
password_description: 'Nenosiri',
password_placeholder: 'Andika nenosiri lako',
password_placeholder2: 'Tafadhali ingiza tena nenosiri kuthibitisha',
password_error: 'Nenosiri lisiwe chini ya alama 6.',
password_error1: 'Uthibitisho wa nenosiri haulingani na nenosiri.',
password_validation_title: 'Nenosiri'
},
sv: {
password_description: 'Lösenord',
password_placeholder: 'Skriv ditt lösenord',
password_placeholder2: 'Var god ange ditt lösenord igen för att bekräfta',
password_error: 'Lösenordet bör inte vara mindre än 6 symboler.',
password_error1: 'Lösenordsbekräftelsen matcharinte lösenordet.',
password_validation_title: 'Lösenord'
},
'fr-ch': {
password_description: 'Mot de passe',
password_placeholder: 'Tapez votre mot de passe',
password_placeholder2: 'Veuillez saisir à nouveau le mot de passe pour confirmer',
password_error: 'Le mot de passe doit avoir au moins 6 caractères.',
password_error1: 'La confirmation du mot de passe ne correspond pas au premier mot de passe.',
password_validation_title: 'Mot de passe'
},
'de-ch': {
password_description: 'Passwort',
password_placeholder: 'Gib dein Passwort ein',
password_placeholder2: 'Bitte gib das Passwort zur Bestätigung erneut ein',
password_error: 'Passwort sollte nicht kleiner als 6 Symbole sein.',
password_error1: 'Passwort Bestätigung stimmt mit Passwort nicht überein.',
password_validation_title: 'Passwort'
},
'it-ch': {
password_description: 'Password',
password_placeholder: 'Digita la tua password',
password_placeholder2: 'Inserisci nuovamente la password per confermare',
password_error: 'La password non può contenere meno di 6 caratteri.',
password_error1: 'La password di conferma non corrisponde alla password.',
password_validation_title: 'Password'
},
th: {
password_description: 'รหัสผ่าน',
password_placeholder: 'พิมพ์รหัสผ่านของคุณ',
password_placeholder2: 'โปรดกรอกรหัสผ่านอีกครั้งเพื่อยืนยัน',
password_error: 'รหัสผ่านควรมีสัญลักษณ์ไม่น้อยกว่า 6 ตัว',
password_error1: 'การยืนยันรหัสผ่านไม่ตรงกับรหัสผ่าน',
password_validation_title: 'รหัสผ่าน'
},
tr: {
password_description: 'Şifre',
password_placeholder: 'Şifrenizi girin',
password_placeholder2: 'Onaylamak için lütfen parolanızı yeniden girin',
password_error: 'Şifre 6 simgeden daha kısa olmamalıdır.',
password_error1: 'Şifre onayı, şifre ile eşleşmiyor.',
password_validation_title: 'Şifre'
},
uk: {
password_description: 'Пароль',
password_placeholder: 'Введіть свій пароль',
password_placeholder2: 'Будь ласка, введіть пароль ще раз для підтвердження',
password_error: 'Пароль повинен бути не менше 6 символів.',
password_error1: 'Підтвердження паролю не співпадає з паролем.',
password_validation_title: 'Пароль'
},
ur: {
password_description: 'پاسورڈ',
password_placeholder: 'اپنا پاسورڈ لکھیں',
password_placeholder2: 'برائے مہربانی تصدیق کے لیے اپنا پاسورڈ دوبارہ لکھیں',
password_error: 'پاسورڈ 6 اعداد سے چھوٹا نہیں ہونا چاہیے۔',
password_error1: 'تصدیقی پاسورڈ پاسورڈ سے مماثل نہیں',
password_validation_title: 'پاسورڈ'
},
vi: {
password_description: 'Mật khẩu',
password_placeholder: 'Gõ mật khẩu của bạn',
password_placeholder2: 'Vui lòng nhập lại mật khẩu để xác nhận',
password_error: 'Mật khẩu không được ít hơn 6 ký tự.',
password_error1: 'Xác nhận mật khẩu không khớp với mật khẩu.',
password_validation_title: 'Mật khẩu'
} */
};

View File

@ -1,587 +0,0 @@
var WEB3_UNIT = [
'kwei/ada',
'mwei/babbage',
'gwei/shannon',
'szabo',
'finney',
'ether',
'kether/grand/einstein',
'mether',
'gether',
'tether'
];
// because web3 doesn't provide params or docs
var DOC_MAP = {
console: {
log : {
desc: 'Outputs a message to chat context.',
args: [{
name: 'text',
type: 'String',
desc: 'message to output to chat context'
}]
}
},
web3: {
// setProvider : ['provider'], // TODO
version: {
api: {
desc: 'The ethereum js api version.'
},
node: {
desc: 'The client/node version.'
},
network: {
desc: 'The network protocol version.'
},
ethereum: {
desc: 'The ethereum protocol version.'
},
whisper: {
desc: 'The whisper protocol version.'
},
},
isConnected: {
desc: 'Check if a connection to a node exists.',
args: []
},
currentProvider: {
desc: 'Will contain the current provider, if one is set. This can be used to check if mist etc. set already a provider.'
},
reset: {
desc: 'Should be called to reset state of web3. Resets everything except manager. Uninstalls all filters. Stops polling.',
args: [{
name: 'keepIsSyncing',
type: 'Boolean',
desc: 'If true it will uninstall all filters, but will keep the web3.eth.isSyncing() polls'
}]
},
sha3: {
desc: 'Returns the Keccak-256 SHA3 of the given data.',
args: [{
name: 'string',
type: 'String',
desc: 'The string to hash using the Keccak-256 SHA3 algorithm'
}, {
name: 'options',
type: 'Object',
optional: true,
desc: 'Set encoding to hex if the string to hash is encoded in hex. A leading 0x will be automatically ignored.'
}]
},
toHex: {
desc: 'Converts any value into HEX',
args: [{
name: 'mixed',
type: 'String|Number|Object|Array|BigNumber',
desc: 'The value to parse to HEX. If its an object or array it will be JSON.stringify first. If its a BigNumber it will make it the HEX value of a number.'
}]
},
toAscii: {
desc: 'Converts a HEX string into a ASCII string.',
args: [{
name: 'hexString',
type: 'String',
desc: 'A HEX string to be converted to ascii.'
}]
},
fromAscii: {
desc: 'Converts any ASCII string to a HEX string.',
args: [{
name: 'string',
type: 'String',
desc: 'An ASCII string to be converted to HEX.'
}, {
name: 'padding',
type: 'Number',
desc: 'The number of bytes the returned HEX string should have. '
}]
},
toDecimal: {
desc: 'Converts a HEX string to its number representation.',
args: [{
name: 'hexString',
type: 'String',
desc: 'An HEX string to be converted to a number.'
}]
},
fromDecimal: {
desc: 'Converts a number or number string to its HEX representation.',
args: [{
name: 'number',
type: 'Number',
desc: 'A number to be converted to a HEX string.'
}]
},
fromWei: {
desc: 'Converts a number of wei into an ethereum unit',
args: [{
name: 'number',
type: 'Number|String|BigNumber',
desc: 'A number or BigNumber instance.'
}, {
name: 'unit',
type: 'string',
desc: 'One of the ether units'
}]
},
toWei: {
desc: 'Converts an ethereum unit into wei',
args: [{
name: 'number',
type: 'Number|String|BigNumber',
desc: 'A number or BigNumber instance.'
}, {
name: 'unit',
type: 'string',
desc: 'One of the ether units'
}]
},
toBigNumber: {
desc: 'Converts a given number into a BigNumber instance',
args: [{
name: 'numberOrHexString',
type: 'Number|String',
desc: 'A number, number string or HEX string of a number.'
}]
},
net: {
listening: {
desc: 'Is node actively listening for network connections?'
},
peerCount: {
desc: 'Returns the number of connected peers'
}
},
isAddress: {
desc: '',
args: [{
name: '',
type: 'string',
desc: 'hex string'
}], // TODO not in docs
},
eth: {
defaultAccount: {
desc: 'The currently set default address'
},
defaultBlock: {
desc: 'The default block number to use when querying a state.'
},
syncing: {
desc: 'Returns the either a sync object, when the node is syncing or false.'
},
isSyncing: {
desc: 'This convenience function calls the callback everytime a sync starts, updates and stops.',
args: [{
name: 'callback',
type: 'Function',
desc: 'The callback will be fired with true when the syncing starts and with false when it stopped. While syncing it will return the syncing object: {startingBlock, currentBlock, highestBlock}'
}]
},
coinbase: {
desc: 'Returns the coinbase address were the mining rewards go to.'
},
mining: {
desc: 'Says whether the node is mining or not.'
},
hashrate: {
desc: 'Returns the number of hashes per second that the node is mining with.'
},
gasPrice: {
desc: 'Returns the current gas price. The gas price is determined by the x latest blocks median gas price'
},
accounts: {
desc: 'Returns a list of accounts the node controls'
},
blockNumber: {
desc: 'Returns the current block number'
},
getBalance: {
desc: 'Get the balance of an address at a given block.',
args: [{
name: 'addressHexString',
type: 'String',
desc: 'The address to get the balance of'
}, {
name: 'defaultBlock',
type: 'Number|String',
optional: true,
desc: 'If you pass this parameter it will not use the default block set with web3.eth.defaultBlock.'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'If you pass a callback the HTTP request is made asynchronous.'
}]
},
getStorageAt: {
desc: 'Get the storage at a specific position of an address.',
args: [{
name: 'addressHexString',
type: 'String',
desc: 'The address to get the storage from.'
}, {
name: 'position',
type: 'Number',
desc: 'The index position of the storage.'
}, {
name: 'defaultBlock',
type: 'Number|String',
optional: true,
desc: 'If you pass this parameter it will not use the default block set with web3.eth.defaultBlock.'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'If you pass a callback the HTTP request is made asynchronous.'
}]
},
getCode: {
desc: 'Get the code at a specific address.',
args: [{
name: 'addressHexString',
type: 'String',
desc: 'The address to get the code from.'
}, {
name: 'defaultBlock',
type: 'Number|String',
optional: true,
desc: 'If you pass this parameter it will not use the default block set with web3.eth.defaultBlock.'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'If you pass a callback the HTTP request is made asynchronous.'
}]
},
getBlock: {
desc: 'Returns a block matching the block number or block hash.',
args: [{
name: 'blockHashOrBlockNumber',
type: 'String|Number',
desc: 'The block number or hash. Or the string "earliest", "latest" or "pending"'
}, {
name: 'returnTransactionObjects',
type: 'Boolean',
optional: true,
desc: '(default false) If true, the returned block will contain all transactions as objects, if false it will only contains the transaction hashes.'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'If you pass a callback the HTTP request is made asynchronous.'
}]
},
getBlockTransactionCount: {
desc: 'Returns the number of transaction in a given block.',
args: [{
name: 'hashStringOrBlockNumber',
type: 'String|Number',
desc: 'The block number or hash. Or the string "earliest", "latest" or "pending"'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'If you pass a callback the HTTP request is made asynchronous.'
}]
},
getUncle: {
desc: 'Returns a blocks uncle by a given uncle index position',
args: [{
name: 'blockHashStringOrNumber',
type: 'String|Number',
desc: 'The block number or hash. Or the string "earliest", "latest" or "pending"'
}, {
name: 'uncleNumber',
type: 'Number',
desc: 'The index position of the uncle.'
}, {
name: 'returnTransactionObjects',
type: 'Boolean',
desc: '(default false) If true, the returned block will contain all transactions as objects, if false it will only contains the transaction hashes.'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'If you pass a callback the HTTP request is made asynchronous.'
}]
},
getBlockUncleCount: {
desc: '', // TODO missing from docs
},
getTransaction: {
desc: 'Returns a transaction matching the given transaction hash.',
args: [{
name: 'transactionHash',
type: 'String',
desc: 'The transaction hash.'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'If you pass a callback the HTTP request is made asynchronous.'
}]
},
getTransactionFromBlock: {
desc: 'Returns a transaction based on a block hash or number and the transactions index position.',
args: [{
name: 'hashStringOrBlockNumber',
type: 'String|Number',
desc: 'The block number or hash. Or the string "earliest", "latest" or "pending"'
}, {
name: 'indexNumber',
type: 'Number',
desc: 'The transactions index position.'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'If you pass a callback the HTTP request is made asynchronous.'
}]
},
getTransactionReceipt: {
desc: 'Returns the receipt of a transaction by transaction hash.',
args: [{
name: 'hashString',
type: 'String',
desc: 'The transaction hash.'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'If you pass a callback the HTTP request is made asynchronous.'
}]
},
getTransactionCount: {
desc: 'Get the numbers of transactions sent from this address.',
args: [{
name: 'addressHexString',
type: 'String',
desc: 'The address to get the numbers of transactions from.'
}, {
name: 'defaultBlock',
type: 'String|Number',
desc: 'If you pass this parameter it will not use the default block set with web3.eth.defaultBlock.'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'If you pass a callback the HTTP request is made asynchronous.'
}]
},
sendTransaction: {
desc: 'Sends a transaction to the network.',
args: [{
name: 'transactionObject',
type: 'Object',
desc: 'The transaction object to send: {from[, to][, value][, gas][, gasPrice][, data][, nonce]}'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'If you pass a callback the HTTP request is made asynchronous.'
}]
},
sendRawTransaction: {
desc: 'Sends an already signed transaction.',
args: [{
name: 'signedTransactionData',
type: 'String',
desc: 'Signed transaction data in HEX format'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'If you pass a callback the HTTP request is made asynchronous.'
}]
},
sign: {
desc: 'Signs data from a specific account. This account needs to be unlocked.',
args: [{
name: 'address',
type: 'String',
desc: 'Address to sign with.'
}, {
name: 'dataToSign',
type: 'String',
desc: 'Data to sign.'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'If you pass a callback the HTTP request is made asynchronous.'
}]
},
call: {
desc: 'Executes a message call transaction, which is directly executed in the VM of the node, but never mined into the blockchain.',
args: [{
name: 'callObject',
type: 'String',
desc: 'Address to sign with.'
}, {
name: 'defaultBlock',
type: 'String',
optional: true,
desc: 'Data to sign.'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'If you pass a callback the HTTP request is made asynchronous.'
}]
},
estimateGas: {
desc: 'Executes a message call or transaction, which is directly executed in the VM of the node, but never mined into the blockchain and returns the amount of the gas used.',
args: [{
name: 'callObject',
type: 'Object',
desc: 'The transaction object to send: {[from][, to][, value][, gas][, gasPrice][, data][, nonce]}'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'If you pass a callback the HTTP request is made asynchronous.'
}]
},
filter: {
// TODO: add description
desc: '',
args: [{
name: 'options',
type: 'String|Object',
desc: 'The string "latest" or "pending" to watch for changes in the latest block or pending transactions respectively. Or a filter options object as follows: {fromBlock: Number|String, toBlock: Number|String, address: String, topics: StringArray}'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'Watch callback'
}]
},
// TODO filters
// watch : ['callback'],
// stopWatching : ['callback'],
contract: {
desc: 'Creates a contract object for a solidity contract, which can be used to initiate contracts on an address.',
args: [{
name: 'abiArray',
type: 'Array',
desc: 'ABI array with descriptions of functions and events of the contract.'
}]
},
getCompilers: {
desc: 'Gets a list of available compilers.',
args: [{
name: 'callback',
type: 'Function',
optional: true,
desc: 'If you pass a callback the HTTP request is made asynchronous.'
}]
},
compile: { // TODO we should auto hide these depending on output from getCompilers
lll: {
desc: 'Compiles LLL source code.',
args: [{
name: 'sourceString',
type: 'String',
desc: 'The LLL source code.'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'Watch callback'
}]
},
solidity: {
desc: 'Compiles solidity source code',
args: [{
name: 'sourceString',
type: 'String',
desc: 'The solidity source code.'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'Watch callback'
}],
},
serpent: {
desc: 'Compiles serpent source code',
args: [{
name: 'sourceString',
type: 'String',
desc: 'The serpent source code.'
}, {
name: 'callback',
type: 'Function',
optional: true,
desc: 'Watch callback'
}]
}
},
namereg: {
desc: 'Returns GlobalRegistrar object.'
}
},
db: {
putString: {
desc: 'Store a string in the local leveldb database.',
args: [{
name: 'db',
type: 'String',
desc: 'The database to store to.'
}, {
name: 'key',
type: 'String',
desc: 'The name of the store.'
}, {
name: 'value',
type: 'String',
desc: 'The string value to store.'
}]
},
getString: {
desc: 'Retrieve a string from the local leveldb database. (db, key)',
args: [{
name: 'db',
type: 'String',
desc: 'The database string name to retrieve from.'
}, {
name: 'key',
type: 'String',
desc: 'The name of the store.'
}]
},
putHex: {
desc: 'Store binary data in the local leveldb database. (db, key, value)',
args: [{
name: 'db',
type: 'String',
desc: 'The database to store to.'
}, {
name: 'key',
type: 'String',
desc: 'The name of the store.'
}, {
name: 'value',
type: 'String',
desc: 'The HEX string to store.'
}]
},
getHex: {
desc: 'Retrieve binary data from the local leveldb database. (db, key)',
args: [{
name: 'db',
type: 'String',
desc: 'The database string name to retrieve from.'
}, {
name: 'key',
type: 'String',
desc: 'The name of the store.'
}]
}
}
}
};

View File

@ -1,146 +0,0 @@
function round(n) {
return Math.round(n * 100) / 100;
}
function doubledValueLabel(params) {
var value = round(params.value);
return "sliderValue = " + value +
"; (2 * sliderValue) = " + (2 * value);
}
status.defineSubscription(
// the name of subscription and the name of the value in bot-db
// associated with this subscription
"doubledValue",
// the map of values on which subscription depends: keys are arbitrary names
// and values are db paths to another value
{value: ["sliderValue"]},
// the function which will be called as reaction on changes of values above,
// should be pure. Returned result will be associated with subscription in bot-db
doubledValueLabel
);
status.defineSubscription(
"roundedValue",
{value: ["sliderValue"]},
function (params) {
return round(params.value);
}
);
function demoSuggestions(params, context) {
var balance = parseFloat(web3.fromWei(web3.eth.getBalance(context.from), "ether"));
var defaultSliderValue = balance / 2;
var view = ["view", {},
["text", {}, "Balance " + balance + " ETH"],
["text", {}, ["subscribe", ["doubledValue"]]],
["slider", {
maximumValue: ["subscribe", ["balance"]],
value: defaultSliderValue,
minimumValue: 0,
onSlidingComplete: ["dispatch", ["set", "sliderValue"]],
step: 0.05
}],
['touchable',
{onPress: ['dispatch', ["set-value-from-db", "roundedValue"]]},
["view", {}, ["text", {}, "Set value"]]
],
["text", {style: {color: "red"}}, ["subscribe", ["validationText"]]]
];
status.setDefaultDb({
sliderValue: defaultSliderValue,
doubledValue: doubledValueLabel({value: defaultSliderValue})
});
var validationText = "";
if (typeof params !== 'undefined') {
if (isNaN(params.message)) {
validationText = "That's not a float number!";
} else if (parseFloat(params.message) > balance) {
validationText =
"Input value is too big!" +
" You have only " + balance + " ETH on your balance!";
}
}
status.updateDb({
balance: balance,
validationText: validationText
});
return {markup: view};
}
status.addListener("on-message-input-change", demoSuggestions);
status.addListener("on-message-send", function (params, context) {
var cnt = localStorage.getItem("cnt");
if (!cnt) {
cnt = 0;
}
cnt++;
localStorage.setItem("cnt", cnt);
if (isNaN(params.message)) {
return {"text-message": "Seems that you don't want to send money :(. cnt = " + cnt};
}
var balance = web3.eth.getBalance(context.from);
var value = parseFloat(params.message);
var weiValue = web3.toWei(value, "ether");
if (bn(weiValue).greaterThan(bn(balance))) {
return {"text-message": "No way man, you don't have enough money! :)"};
}
web3.eth.sendTransaction({
from: context.from,
to: context.from,
value: weiValue
}, function (error, hash) {
if (error) {
status.sendMessage("Something went wrong, try again :(");
status.showSuggestions(demoSuggestions(params, context).markup);
} else {
status.sendMessage("You are the hero, you sent " + value + " ETH to yourself!")
}
});
});
status.command({
name: "init-request",
description: "send-request",
color: "#a187d5",
sequentialParams: true,
params: [{
name: "address",
type: status.types.TEXT,
placeholder: "address"
}],
handler: function (params) {
return {
"text-message": {
type: "request",
content: {
command: "response",
params: {first: "123"},
text: "That's request's content! It works!"
}
}
};
}
});
status.response({
name: "response",
color: "#a187d5",
sequentialParams: true,
params: [{
name: "first",
type: status.types.TEXT,
placeholder: "first"
}],
handler: function (params) {
return {"text-message": "ok"};
}
});

View File

@ -1,305 +0,0 @@
// Send command/response
var assetSendParam = {
name: "asset",
type: status.types.TEXT,
suggestions: function (params) {
return {
markup: status.components.chooseAsset("asset", 0)
};
},
placeholder: I18n.t('currency_placeholder')
};
var recipientSendParam = {
name: "recipient",
type: status.types.TEXT,
suggestions: function (params) {
return {
title: I18n.t('send_title'),
markup: status.components.chooseContact(I18n.t('send_choose_recipient'), "recipient", 0)
};
}
};
function amountSendParam() {
return {
name: "amount",
type: status.types.NUMBER,
placeholder: I18n.t('amount_placeholder')
};
}
var paramsPersonalSend = [assetSendParam, amountSendParam()];
var paramsGroupSend = [recipientSendParam, amountSendParam()];
function validateSend(validateRecipient, params, context) {
var allowedAssets = context["allowed-assets"];
var asset = params["asset"];
if(!allowedAssets.hasOwnProperty(asset)){
return {
markup: status.components.validationMessage(
"Invalid asset",
"Unknown token - " + asset
)
};
}
if (!params["amount"]) {
return {
markup: status.components.validationMessage(
I18n.t('validation_title'),
I18n.t('validation_amount_specified')
)
};
}
var amount = params["amount"].replace(",", ".");
var amountSplitted = amount.split(".");
var decimals = allowedAssets[asset];
if (amountSplitted.length === 2 && amountSplitted[1].length > decimals) {
return {
markup: status.components.validationMessage(
I18n.t('validation_title'),
I18n.t('validation_amount_is_too_small') + decimals
)
};
}
if (isNaN(parseFloat(params.amount.replace(",", ".")))) {
return {
markup: status.components.validationMessage(
I18n.t('validation_title'),
I18n.t('validation_invalid_number')
)
};
}
try {
var val = web3.toWei(amount, "ether");
if (val < 0) {
throw new Error();
}
} catch (err) {
return {
markup: status.components.validationMessage(
I18n.t('validation_title'),
I18n.t('validation_invalid_number')
)
};
}
}
function handleSend(params, context) {
}
var personalSend = {
name: "send",
scope: ["global", "personal-chats", "registered", "humans"],
icon: "money_white",
color: "#5fc48d",
title: I18n.t('send_title'),
description: I18n.t('send_description'),
params: paramsPersonalSend,
validator: validateSend.bind(this, false),
handler: handleSend.bind(this),
asyncHandler: false
};
var groupSend = {
name: "send",
scope: ["global", "group-chats", "registered", "humans"],
icon: "money_white",
color: "#5fc48d",
title: I18n.t('send_title'),
description: I18n.t('send_description'),
params: paramsGroupSend,
validator: validateSend.bind(this, true),
handler: handleSend.bind(this),
asyncHandler: false
};
status.command(personalSend);
status.response(personalSend);
status.command(groupSend);
status.response(groupSend);
// Request command
var assetRequestParam = {
name: "asset",
type: status.types.TEXT,
suggestions: function (params) {
return {
markup: status.components.chooseAsset("asset", 0)
};
},
placeholder: I18n.t('currency_placeholder')
};
var recipientRequestParam = {
name: "recipient",
type: status.types.TEXT,
suggestions: function (params) {
return {
title: I18n.t('request_title'),
markup: status.components.chooseContact(I18n.t('send_choose_recipient'), "recipient", 0)
};
}
};
var amountRequestParam = {
name: "amount",
type: status.types.NUMBER,
placeholder: I18n.t('amount_placeholder')
};
var paramsPersonalRequest = [assetRequestParam, amountRequestParam];
var paramsGroupRequest = [recipientRequestParam, amountRequestParam];
function handlePersonalRequest(params, context) {
var val = params["amount"].replace(",", ".");
var network = context["network"];
var asset = params["asset"];
return {
event: "request",
request: {
command: "send",
params: {
network: network,
amount: val,
asset: asset
},
prefill: [asset, val]
}
};
}
function handleGroupRequest(params, context) {
var val = params["amount"].replace(",", ".");
var network = context["network"];
return {
event: "request",
request: {
command: "send",
params: {
recipient: context["current-account"]["name"],
network: network,
amount: val
},
prefill: [context["current-account"]["name"], val],
prefillBotDb: {
public: {
recipient: context["current-account"]
}
}
}
};
}
function validateRequest(validateRecipient, params, context) {
if (!params["bot-db"]) {
params["bot-db"] = {};
}
if (validateRecipient) {
if (!params["bot-db"]["public"] || !params["bot-db"]["public"]["recipient"] || !params["bot-db"]["public"]["recipient"]["address"]) {
return {
markup: status.components.validationMessage(
"Wrong address",
"Recipient address must be specified"
)
};
}
}
var allowedAssets = context["allowed-assets"];
var asset = params["asset"];
if(!allowedAssets.hasOwnProperty(asset)){
return {
markup: status.components.validationMessage(
"Invalid asset",
"Unknown token - " + asset
)
};
}
if (!params["amount"]) {
return {
markup: status.components.validationMessage(
I18n.t('validation_title'),
I18n.t('validation_amount_specified')
)
};
}
var amount = params.amount.replace(",", ".");
var amountSplitted = amount.split(".");
var decimals = allowedAssets[asset];
if (amountSplitted.length === 2 && amountSplitted[1].length > decimals) {
return {
markup: status.components.validationMessage(
I18n.t('validation_title'),
I18n.t('validation_amount_is_too_small') + decimals
)
};
}
if (isNaN(parseFloat(params.amount.replace(",", ".")))) {
return {
markup: status.components.validationMessage(
I18n.t('validation_title'),
I18n.t('validation_invalid_number')
)
};
}
try {
var val = web3.toWei(amount, "ether");
if (val < 0) {
throw new Error();
}
} catch (err) {
return {
markup: status.components.validationMessage(
I18n.t('validation_title'),
I18n.t('validation_invalid_number')
)
};
}
}
status.command({
name: "request",
scope: ["global", "personal-chats", "registered", "humans"],
icon: "money_white",
color: "#5fc48d",
title: I18n.t('request_title'),
description: I18n.t('request_description'),
params: paramsPersonalRequest,
handler: handlePersonalRequest,
validator: validateRequest.bind(null, false)
});
status.command({
name: "request",
scope: ["global", "group-chats", "registered", "humans"],
icon: "money_white",
color: "#5fc48d",
title: I18n.t('request_title'),
description: I18n.t('request_description'),
params: paramsGroupRequest,
handler: handleGroupRequest,
validator: validateRequest.bind(null, true)
});

View File

@ -1,490 +0,0 @@
I18n.translations = {
en: {
send_title: 'Send transaction',
send_description: 'Send a payment',
send_choose_recipient: 'Choose recipient',
send_specify_amount: 'Specify amount',
send_sending_to: 'to ',
currency_placeholder: 'Currency',
amount_placeholder: 'Amount',
eth: 'ETH',
request_title: 'Request ETH',
request_description: 'Request a payment',
request_requesting: 'Requesting ',
request_requesting_from: 'from ',
validation_internal_title: 'Internal error',
validation_balance: 'Could not fetch current balance',
validation_title: 'Amount',
validation_tx_title: 'Transaction',
validation_tx_failed: 'Transaction failed',
validation_amount_specified: 'Amount must be specified',
validation_invalid_number: 'Amount is not valid number',
validation_amount_is_too_small: 'Max number of decimals is ',
validation_insufficient_amount: 'Insufficient funds for gas * price + value (balance '
}
/*
,
ru: {
send_title: 'Отправить транзакцию',
send_description: 'Отправить платеж',
request_title: 'Запросить ETH',
request_description: 'Запросить платеж',
request_requesting: 'Запрос ',
validation_title: 'Сумма',
validation_amount_specified: 'Необходимо указать сумму',
validation_invalid_number: 'Сумма не является действительным числом',
validation_amount_is_too_small: 'Сумма излишне точная. Минимальная единица, которую можно отправить — 1 Wei (1x10^-18 ETH)',
validation_insufficient_amount: 'Недостаточно ETH на балансе ('
},
af: {
send_title: 'Stuur ETH',
send_description: 'Stuur \'n betaling',
request_title: 'Versoek ETH',
request_description: 'Versoek \'n betaling',
request_requesting: 'Besig met versoek ',
validation_title: 'Bedrag',
validation_amount_specified: 'Bedrag moet gespesifiseer word',
validation_invalid_number: 'Bedrag is nie \'n geldige syfer nie',
validation_insufficient_amount: 'Nie genoeg ETH in rekening nie ('
},
ar: {
send_title: 'إرسال ETH',
send_description: 'إرسال مدفوعات',
request_title: 'طلب ETH',
request_description: 'طلب مدفوعات',
request_requesting: 'مُطَالَبَة ',
validation_title: 'المبلغ',
validation_amount_specified: 'يجب تحديد المبلغ',
validation_invalid_number: 'المبلغ المحدد غير صحيح',
validation_insufficient_amount: 'لا يوجد ETH كافي بالحساب ('
},
'zh-hant': {
send_title: '發送 ETH',
send_description: '付款',
request_title: '請求 ETH',
request_description: '要求付款',
request_requesting: '正在請求 ',
validation_title: '金額',
validation_amount_specified: '必須指定金額',
validation_invalid_number: '金額不是有效數字',
validation_insufficient_amount: 'ETH 餘額不足 ('
},
'zh-hant-tw': {
send_title: '傳送 ETH',
send_description: '付款',
request_title: '請求 ETH',
request_description: '要求付款',
request_requesting: '正在請求 ',
validation_title: '金額',
validation_amount_specified: '必須指定金額',
validation_invalid_number: '金額不是有效數字',
validation_insufficient_amount: 'ETH 餘額不足 ('
},
'zh-hant-sg': {
send_title: '傳送 ETH',
send_description: '付款',
request_title: '請求 ETH',
request_description: '要求付款',
request_requesting: '正在請求 ',
validation_title: '金額',
validation_amount_specified: '必須指定金額',
validation_invalid_number: '金額不是有效數字',
validation_insufficient_amount: 'ETH 餘額不足 ('
},
'zh-hant-hk': {
send_title: '發送 ETH',
send_description: '付款',
request_title: '請求 ETH',
request_description: '要求付款',
request_requesting: '正在請求 ',
validation_title: '金額',
validation_amount_specified: '必須指定金額',
validation_invalid_number: '金額不是有效數字',
validation_insufficient_amount: 'ETH 餘額不足 ('
},
'zh-hans': {
send_title: '发送 ETH',
send_description: '付款',
request_title: '请求 ETH',
request_description: '要求付款',
request_requesting: '正在请求 ',
validation_title: '金额',
validation_amount_specified: '必须指定金额',
validation_invalid_number: '金额不是有效数字',
validation_insufficient_amount: 'ETH 余额不足 ('
},
'zh-yue': {
send_title: '發送 ETH',
send_description: '發送付款',
request_title: '請求 ETH',
request_description: '請求付款',
request_requesting: '請求中 ',
validation_title: '金額',
validation_amount_specified: '必須指定金額',
validation_invalid_number: '指定金額並非有效數字',
validation_insufficient_amount: '沒有足夠 ETH 餘額 ('
},
'zh-wuu': {
send_title: '发送 ETH',
send_description: '发送付款',
request_title: '请求 ETH',
request_description: '请求付款',
request_requesting: '请求中 ',
validation_title: '金额',
validation_amount_specified: '金额必须明确',
validation_invalid_number: '金额不是一个有效数字',
validation_insufficient_amount: 'ETH 余额不足 ('
},
nl: {
send_title: 'Stuur ETH',
send_description: 'Stuur een betaling',
request_title: 'Vraag ETH aan',
request_description: 'Vraag om een betaling',
request_requesting: 'Wordt aangevraagd ',
validation_title: 'Bedrag',
validation_amount_specified: 'Bedrag moet worden opgegeven',
validation_invalid_number: 'Bedrag is geen geldig nummer',
validation_insufficient_amount: 'Niet genoeg ETH op saldo ('
},
fr: {
send_title: 'Envoyer l\'ETH',
send_description: 'Envoyer un paiement',
request_title: 'Demander l\'ETH',
request_description: 'Demander un paiement',
request_requesting: 'Demande en cours: ',
validation_title: 'Montant',
validation_amount_specified: 'Le montant doit être spécifié',
validation_invalid_number: 'Le montant n\'est pas un nombre valide',
validation_insufficient_amount: 'Pas assez d\'ETH sur le solde ('
},
de: {
send_title: 'ETH abschicken',
send_description: 'Zahlung senden',
request_title: 'ETH anfragen',
request_description: 'Zahlung anfragen',
request_requesting: 'Anfrage: ',
validation_title: 'Betrag',
validation_amount_specified: 'Betrag muss angegeben werden',
validation_invalid_number: 'Betrag ist keine gültige Zahl',
validation_insufficient_amount: 'Nicht genügend ETH auf dem Konto ('
},
hi: {
send_title: 'ETH भेजें',
send_description: 'भुगतान भेजें',
request_title: 'ETH का अनुरोध करें',
request_description: 'भुगतान का अनुरोध करें',
request_requesting: 'अनुरोध किया जा रहा है ',
validation_title: 'राशि',
validation_amount_specified: 'राशि निर्दिष्ट की जानी चाहिए',
validation_invalid_number: 'राशि वैध संख्या नहीं है',
validation_insufficient_amount: 'बैलेंस पर पर्याप्त ETH नहीं है ('
},
hu: {
send_title: 'ETH küldése',
send_description: 'Kifizetés küldése',
request_title: 'ETH igénylése',
request_description: 'Fizetés igénylése',
request_requesting: 'Igénylés ',
validation_title: 'Összeg',
validation_amount_specified: 'Az összeget meg kell határozni',
validation_invalid_number: 'Az összeg nem egy elfogadott szám',
validation_insufficient_amount: 'Nincs elég ETH a számlán ('
},
it: {
send_title: 'Invia ETH',
send_description: 'Invia un pagamento',
request_title: 'Richiedi ETH',
request_description: 'Richiedi un pagamento',
request_requesting: 'Richiesta in corso: ',
validation_title: 'Ammontare',
validation_amount_specified: 'L\'ammontare deve essere specificato',
validation_invalid_number: 'L\'ammontare non è un numero valido',
validation_insufficient_amount: 'ETH insufficiente sul bilancio ('
},
ja: {
send_title: 'ETHを送信',
send_description: '支払いを送信',
request_title: 'ETHをリクエスト',
request_description: '支払いをリクエスト',
request_requesting: 'リクエスト中 ',
validation_title: '金額',
validation_amount_specified: '金額を特定する必要があります',
validation_invalid_number: '金額は有効な数字ではありません',
validation_insufficient_amount: '残高に十分なETHがありません('
},
ko: {
send_title: 'ETH 보내기',
send_description: '지불금 보내기',
request_title: 'ETH 요청',
request_description: '지불금 요청',
request_requesting: '요청 중 ',
validation_title: '금액',
validation_amount_specified: '금액을 지정해야 합니다',
validation_invalid_number: '금액이 유효한 숫자가 아닙니다',
validation_insufficient_amount: 'ETH 잔고가 부족합니다 ('
},
pl: {
send_title: 'Wyślij ETH',
send_description: 'Wyślij płatność',
request_title: 'Poproś o ETH',
request_description: 'Poproś o płatność',
request_requesting: 'Przesyłanie prośby ',
validation_title: 'Kwota',
validation_amount_specified: 'Należy określić kwotę',
validation_invalid_number: 'Kwota nie jest prawidłową liczbą',
validation_insufficient_amount: 'Brak wystarczającej liczby ETH na koncie ('
},
'pt-br': {
send_title: 'Enviar ETH',
send_description: 'Enviar um pagamento',
request_title: 'Solicitar ETH',
request_description: 'Solicitar um pagamento',
request_requesting: 'Solicitando ',
validation_title: 'Quantia',
validation_amount_specified: 'É necessário especificar a quantia',
validation_invalid_number: 'A quantia não é um número válido',
validation_insufficient_amount: 'ETH insuficiente no saldo ('
},
'pt-pt': {
send_title: 'Enviar ETH',
send_description: 'Enviar um pagamento',
request_title: 'Solicitar ETH',
request_description: 'Solicitar um pagamento',
request_requesting: 'A solicitar ',
validation_title: 'Montante',
validation_amount_specified: 'O montante deve ser especificado',
validation_invalid_number: 'O montante não é um número válido',
validation_insufficient_amount: 'Não há ETH suficiente no saldo ('
},
ro: {
send_title: 'Trimite ETH',
send_description: 'Trimite o plată',
request_title: 'Solicită ETH',
request_description: 'Solicită o plată',
request_requesting: 'Se solicită ',
validation_title: 'Sumă',
validation_amount_specified: 'Trebuie menționată o sumă',
validation_invalid_number: 'Suma nu are forma unui număr valid',
validation_insufficient_amount: 'Sold ETH insuficient ('
},
sl: {
send_title: 'Pošlji ETH',
send_description: 'Pošlji plačilo',
request_title: 'Zahtevaj ETH',
request_description: 'Zahtevaj plačilo',
request_requesting: 'Zahtevam ',
validation_title: 'Vsota',
validation_amount_specified: 'Vsota mora biti izrecno navedena',
validation_invalid_number: 'Vsota ni veljavna številka',
validation_insufficient_amount: 'Stanje ETH na računu je prenizko ('
},
es: {
send_title: 'Enviar ETH ',
send_description: 'Enviar un pago',
request_title: 'Solicitar ETH',
request_description: 'Solicitar un pago',
request_requesting: 'Solicitando ',
validation_title: 'Cantidad',
validation_amount_specified: 'Hay que especificar la cantidad',
validation_invalid_number: 'La cantidad no es un número válido',
validation_insufficient_amount: 'No hay suficiente ETH en conjunto ('
},
'es-ar': {
send_title: 'Enviar ETH',
send_description: 'Enviar un pago',
request_title: 'Solicitar ETH',
request_description: 'Solicitar un pago',
request_requesting: 'Solicitando ',
validation_title: 'Monto',
validation_amount_specified: 'Debes especificar el monto',
validation_invalid_number: 'El monto no es un número válido',
validation_insufficient_amount: 'No tienes suficiente ETH en tu saldo ('
},
sw: {
send_title: 'Tuma ETH',
send_description: 'Tuma malipo',
request_title: 'Omba ETH',
request_description: 'Omba malipo',
request_requesting: 'Kuomba ',
validation_title: 'Kiasi',
validation_amount_specified: 'Kiasi lazima kifafanuliwe',
validation_invalid_number: 'Kiasi si nambari halali',
validation_insufficient_amount: 'ETH haitoshi kwenye salio ('
},
sv: {
send_title: 'Skicka ETH',
send_description: 'Skicka en betalning',
request_title: 'Begär ETH',
request_description: 'Begär en betalning',
request_requesting: 'Begär ',
validation_title: 'Belopp',
validation_amount_specified: 'Beloppet måste anges',
validation_invalid_number: 'Beloppet är inte ett giltigt nummer',
validation_insufficient_amount: 'Inte tillräcklig ETH på balansen ('
},
'fr-ch': {
send_title: 'Envoyer des ETH',
send_description: 'Envoyer un paiement',
request_title: 'Demander des ETH',
request_description: 'Demander un paiement',
request_requesting: 'Demande ',
validation_title: 'Montant',
validation_amount_specified: 'Le montant doit être spécifié',
validation_invalid_number: 'Le montant n\'est pas un nombre valable',
validation_insufficient_amount: 'Pas assez d\'ETH sur le solde ('
},
'de-ch': {
send_title: 'Sende ETH',
send_description: 'Sende eine Zahlung',
request_title: 'Fordere ETH an',
request_description: 'Eine Zahlung anfordern',
request_requesting: 'Anfordern ',
validation_title: 'Betrag',
validation_amount_specified: 'Der Betrag muss angegeben werden',
validation_invalid_number: 'Der Betrag ist nicht gültig',
validation_insufficient_amount: 'Nicht genug ETH vorhanden ('
},
'it-ch': {
send_title: 'Invia ETH',
send_description: 'Invia un pagamento',
request_title: 'Richiedi ETH',
request_description: 'Richiedi un pagamento',
request_requesting: 'Richiesta in corso: ',
validation_title: 'Importo',
validation_amount_specified: 'Specificare l\'importo',
validation_invalid_number: 'Importo inserito non valido',
validation_insufficient_amount: 'Saldo ETH non sufficiente ('
},
th: {
send_title: 'ส่ง ETH',
send_description: 'ส่งการชำระเงิน',
request_title: 'ร้องขอ ETH',
request_description: 'ร้องขอการชำระเงิน',
request_requesting: 'กำลังร้องขอ ',
validation_title: 'จำนวน',
validation_amount_specified: 'จำเป็นต้องระบุจำนวน',
validation_invalid_number: 'จำนวนไม่ใช่หมายเลขที่ถูกต้อง',
validation_insufficient_amount: 'มี ETH ไม่เพียงพอในยอดคงเหลือ ('
},
tr: {
send_title: 'ETH gönder',
send_description: 'Bir ödeme gönder',
request_title: 'ETH iste',
request_description: 'Bir ödeme iste',
request_requesting: 'İsteniyor ',
validation_title: 'Miktar',
validation_amount_specified: 'Miktar belirtilmelidir',
validation_invalid_number: 'Miktar geçerli bir sayı değil',
validation_insufficient_amount: 'Yeterli ETH bakiyesi yok ('
},
uk: {
send_title: 'Надіслати ETH',
send_description: 'Надіслати платіж',
request_title: 'Запит ETH',
request_description: 'Запит платежу',
request_requesting: 'Запит ',
validation_title: 'Сума',
validation_amount_specified: 'Сума повинна бути вказана',
validation_invalid_number: 'Сума не дійсне число',
validation_insufficient_amount: 'Не вистачає ETH на балансі ('
},
ur: {
send_title: 'ETH بھیجیں',
send_description: 'ادائیگی کریں',
request_title: 'ETH کی درخواست دیں',
request_description: 'ادائیگی کی درخواست دیں',
request_requesting: 'درخواست کی جارہی ہے ',
validation_title: 'رقم',
validation_amount_specified: 'رقم درج کی جانی چاہیے۔ ',
validation_invalid_number: 'رقیم درست ہندسے نہیں ہیں',
validation_insufficient_amount: 'ETH میں کافی بیلنس نہیں ہے ('
},
vi: {
send_title: 'Gửi ETH',
send_description: 'Gửi một khoản thanh toán',
request_title: 'Yêu cầu ETH',
request_description: 'Yêu cầu một khoản thanh toán',
request_requesting: 'Đang yêu cầu ',
validation_title: 'Số tiền',
validation_amount_specified: 'Số tiền phải được xác định',
validation_invalid_number: 'Số tiền không phải là một số hợp lệ',
validation_insufficient_amount: 'Không đủ ETH trong số dư ('
}
*/
};

View File

@ -1,389 +0,0 @@
var _status_catalog = {
commands: {},
responses: {},
functions: {},
subscriptions: {}
},
status = {};
// This is default 'common sense' scope for commands/response which don't
// define any.
// We want the command/response to apply for 1-1 chats with registered user,
// as most of the bot developers will expect the sole registered user (for
// things like sending, etc.) and it will be non global, available only
// for that particular bot (that's what "dapps" in scope)
var defaultScope = ["personal-chats", "registered", "dapps"];
function scopeToBitMask(scope) {
// this function transforms scopes array to a single integer by generating a bit mask
return ((scope.indexOf("global") > -1) ? 1 : 0) |
((scope.indexOf("personal-chats") > -1) ? 2 : 0) |
((scope.indexOf("group-chats") > -1) ? 4 : 0) |
((scope.indexOf("anonymous") > -1) ? 8 : 0) |
((scope.indexOf("registered") > -1) ? 16 : 0) |
((scope.indexOf("dapps") > -1) ? 32 : 0) |
((scope.indexOf("humans") > -1) ? 64 : 0) |
((scope.indexOf("public-chats") > -1) ? 128 : 0);
}
function Command() {
}
function Response() {
}
Command.prototype.addToCatalog = function () {
_status_catalog.commands[[this.name, this["scope-bitmask"]]] = this;
};
Command.prototype.param = function (parameter) {
this.params.push(parameter);
return this;
};
Command.prototype.create = function (com) {
this.name = com.name;
this.title = com.title;
this.description = com.description;
this.handler = com.handler;
this["has-handler"] = com.handler !== null;
this["async-handler"] = (com.handler != null) && com.asyncHandler;
this.validator = com.validator;
this.color = com.color;
this.icon = com.icon;
this.params = com.params || [];
this.preview = com.preview;
this["short-preview"] = com.shortPreview;
this.fullscreen = com.fullscreen;
this.actions = com.actions;
this.request = com.request;
this["execute-immediately?"] = com.executeImmediately;
this["sequential-params"] = com.sequentialParams;
this["hide-send-button"] = com.hideSendButton;
// scopes
this.scope = com.scope || defaultScope;
this["scope-bitmask"] = scopeToBitMask(this["scope"]);
this.addToCatalog();
return this;
};
Response.prototype = Object.create(Command.prototype);
Response.prototype.addToCatalog = function () {
_status_catalog.responses[[this.name, this["scope-bitmask"]]] = this;
};
Response.prototype.onReceiveResponse = function (handler) {
this.onReceive = handler;
};
var context = {};
function addContext(key, value) {
context[status.message_id][key] = value;
}
function getContext(key) {
return context[status.message_id][key];
}
function call(pathStr, paramsStr) {
var params = JSON.parse(paramsStr),
path = JSON.parse(pathStr),
fn, callResult, message_id;
if (typeof params.context !== "undefined" &&
typeof params.context["message-id"] !== "undefined") {
message_id = params.context["message-id"];
} else {
message_id = null;
}
context[message_id] = {};
status.message_id = message_id;
fn = path.reduce(function (catalog, name) {
if (catalog && catalog[name]) {
return catalog[name];
}
},
_status_catalog
);
if (!fn) {
return null;
}
context.messages = [];
callResult = fn(params.parameters, params.context);
result = {
returned: callResult,
context: context[message_id],
messages: context.messages
};
return JSON.stringify(result);
}
function view(options, elements) {
return ['view', options].concat(elements);
}
function text(options, s) {
s = Array.isArray(s) ? s : [s];
return ['text', options].concat(s);
}
function chatPreviewText(options, s) {
return ['chat-preview-text', options, s];
}
function textInput(options) {
return ['text-input', options];
}
function image(options) {
return ['image', options];
}
function qrCode(options) {
return ['qr-code', options];
}
function linking(options) {
return ['linking', options];
}
function slider(options) {
return ['slider', options];
}
function image(options) {
return ['image', options];
}
function touchable(options, element) {
return ['touchable', options, element];
}
function activityIndicator(options) {
return ['activity-indicator', options];
}
function scrollView(options, elements) {
return ['scroll-view', options].concat(elements);
}
function subscribe(path) {
return ['subscribe', path];
}
function dispatch(path) {
return ['dispatch', path];
}
function webView(url) {
return ['web-view', {
source: {
uri: url
},
javaScriptEnabled: true
}];
}
function bridgedWebView(url) {
return ['bridged-web-view', {
url: url
}];
}
function validationMessage(titleText, descriptionText) {
return ['validation-message', {
title: titleText,
description: descriptionText
}];
}
function chooseContact(titleText, botDbKey, argumentIndex) {
return ['choose-contact', {
title: titleText,
"bot-db-key": botDbKey,
index: argumentIndex
}];
}
function chooseAsset(botDbKey, argumentIndex) {
return ['choose-asset', {
"bot-db-key": botDbKey,
index: argumentIndex
}];
}
function separator() {
return ['separator'];
}
var status = {
command: function (h) {
var command = new Command();
return command.create(h);
},
response: function (h) {
var response = new Response();
return response.create(h);
},
addListener: function (name, fn) {
_status_catalog.functions[name] = fn;
},
localizeNumber: function (num, del, sep) {
return I18n.toNumber(
num.replace(",", "."),
{
precision: 10,
strip_insignificant_zeros: true,
delimiter: del,
separator: sep
});
},
types: {
TEXT: 'text',
NUMBER: 'number',
PASSWORD: 'password'
},
events: {
SET_VALUE: 'set-value',
SET_COMMAND_ARGUMENT: 'set-command-argument',
UPDATE_DB: 'set',
SET_COMMAND_ARGUMENT_FROM_DB: 'set-command-argument-from-db',
SET_VALUE_FROM_DB: 'set-value-from-db',
FOCUS_INPUT: 'focus-input'
},
actions: {
WEB_VIEW_BACK: 'web-view-back',
WEB_VIEW_FORWARD: 'web-view-forward',
FULLSCREEN: 'fullscreen',
CUSTOM: 'custom',
},
components: {
view: view,
text: text,
chatPreviewText: chatPreviewText,
textInput: textInput,
slider: slider,
image: image,
qrCode: qrCode,
linking: linking,
slider: slider,
touchable: touchable,
activityIndicator: activityIndicator,
scrollView: scrollView,
webView: webView,
validationMessage: validationMessage,
bridgedWebView: bridgedWebView,
chooseAsset: chooseAsset,
chooseContact: chooseContact,
subscribe: subscribe,
dispatch: dispatch,
separator: separator
},
showSuggestions: function (view) {
status.sendSignal("show-suggestions", view);
},
setDefaultDb: function (db) {
addContext("default-db", db);
},
updateDb: function (db) {
addContext("update-db", db)
},
sendMessage: function (message) {
if(typeof message !== "string") {
message = JSON.stringify(message);
}
status.sendSignal("send-message", message);
},
addLogMessage: function (type, message) {
var message = {
type: type,
message: JSON.stringify(message)
};
var logMessages = getContext("log-messages");
if (!logMessages) {
logMessages = [];
}
logMessages.push(message);
addContext("log-messages", logMessages);
},
defineSubscription: function (name, subscriptions, handler) {
_status_catalog.subscriptions[name] = {
subscriptions: subscriptions,
handler: handler
};
},
sendSignal: function (eventName, data) {
var event = {
event: eventName,
data: data
};
statusSignals.sendSignal(JSON.stringify(event));
}
};
function calculateSubscription(parameters, context) {
var subscriptionConfig = _status_catalog.subscriptions[parameters.name];
if (!subscriptionConfig) {
return;
}
return subscriptionConfig.handler(parameters.subscriptions);
}
status.addListener("subscription", calculateSubscription);
console = (function (old) {
return {
log: function (text) {
old.log(text);
status.addLogMessage('log', text);
},
debug: function (text) {
old.debug(text);
status.addLogMessage('debug', text);
},
info: function (text) {
old.info(text);
status.addLogMessage('info', text);
},
warn: function (text) {
old.warn(text);
status.addLogMessage('warn', text);
},
error: function (text) {
old.error(text);
status.addLogMessage('error', text);
}
};
}(console));
var localStorage = {};
localStorage.setItem = function(key, value) {
if(value === null) {
delete localStorageData[key];
} else {
localStorageData[key] = value;
}
status.sendSignal("local-storage", JSON.stringify(localStorageData));
};
localStorage.getItem = function (key) {
if (typeof localStorageData[key] === "undefined") {
return null;
}
return localStorageData[key];
};

View File

@ -1,8 +1,8 @@
(ns status-im.core
(:require [status-im.utils.error-handler :as error-handler]
(:require [re-frame.core :as re-frame]
[status-im.utils.error-handler :as error-handler]
[status-im.ui.components.react :as react]
[reagent.core :as reagent]
[status-im.native-module.core :as status]
status-im.transport.impl.receive
[taoensso.timbre :as log]
[status-im.utils.config :as config]
@ -15,7 +15,7 @@
(defn init [app-root]
(log/set-level! config/log-level)
(error-handler/register-exception-handler!)
(status/init-jail)
(re-frame/dispatch [:initialize-keychain])
(when config/testfairy-enabled?
(.begin js-dependencies/testfairy config/testfairy-token))
(.registerComponent react/app-registry "StatusIm" #(reagent/reactify-component app-root)))

View File

@ -19,9 +19,6 @@
(log/debug :callback name args)
(apply callback args)))
(defn init-jail []
(module-interface/-init-jail rns-module))
(defn move-to-internal-storage [callback]
(module-interface/-move-to-internal-storage rns-module callback))
@ -49,15 +46,6 @@
(defn discard-sign-request [id]
(module-interface/-discard-sign-request rns-module id))
(defn parse-jail [chat-id file callback]
(module-interface/-parse-jail rns-module chat-id file callback))
(defn call-jail [params]
(module-interface/-call-jail rns-module params))
(defn call-function! [params]
(module-interface/-call-function! rns-module params))
(defn set-soft-input-mode [mode]
(module-interface/-set-soft-input-mode rns-module mode))

View File

@ -5,7 +5,6 @@
[re-frame.core :refer [dispatch] :as re-frame]
[taoensso.timbre :as log]
[cljs.core.async :as async :refer [<!]]
[status-im.utils.js-resources :as js-res]
[status-im.utils.platform :as p]
[status-im.utils.types :as types]
[status-im.utils.transducers :as transducers]
@ -51,18 +50,6 @@
(when (exists? (.-NativeModules rn-dependencies/react-native))
(.-Status (.-NativeModules rn-dependencies/react-native))))
(defn init-jail []
(when status
(call-module
(fn []
(let [init-js (string/join [js-res/status-js
"I18n.locale = '"
rn-dependencies/i18n.locale
"'; "
js-res/web3])]
(.initJail status init-js #(do (re-frame/dispatch [:initialize-keychain])
(log/debug "JavaScriptCore jail initialized"))))))))
(defonce listener-initialized (atom false))
(when-not @listener-initialized
@ -138,86 +125,6 @@
(defn- append-catalog-init [js]
(str js "\n" "var catalog = JSON.stringify(_status_catalog); catalog;"))
(defn parse-jail [bot-id file callback]
(when status
(call-module #(.parseJail status
bot-id
(append-catalog-init file)
callback))))
(defn execute-call [{:keys [jail-id path params callback]}]
(when status
(call-module
#(do
(log/debug :call-jail :jail-id jail-id)
(log/debug :call-jail :path path)
;; this debug message can contain sensitive info
#_(log/debug :call-jail :params params)
(let [params' (update params :context assoc
:debug js/goog.DEBUG
:locale rn-dependencies/i18n.locale)
cb (fn [jail-result]
(let [result (-> jail-result
types/json->clj
(assoc :bot-id jail-id)
(update :result types/json->clj))]
(callback result)))]
(.callJail status jail-id (types/clj->json path) (types/clj->json params') cb))))))
;; We want the mainting (time) windowed queue of all calls to the jail
;; in order to de-duplicate certain type of calls made in rapid succession
;; where it's beneficial to only execute the last call of that type.
;;
;; The reason why is to improve performance and user feedback, for example
;; when making command argument suggestion lookups, everytime the command
;; input changes (so the user types/deletes a character), we need to fetch
;; new suggestions.
;; However the process of asynchronously fetching and displaying them
;; is unfortunately not instant, so without de-duplication, given that user
;; typed N characters in rapid succession, N percievable suggestion updates
;; will be performed after user already stopped typing, which gives
;; impression of slow, unresponsive UI.
;;
;; With de-duplication in some timeframe (set to 400ms currently), only
;; the last suggestion call for given jail-id jail-path combination is
;; made, and the UI feedback is much better + we save some unnecessary
;; calls to jail.
(def ^:private queue-flush-time 400)
(def ^:private call-queue (async/chan))
(def ^:private deduplicated-calls (async/chan))
(async-util/chunked-pipe! call-queue deduplicated-calls queue-flush-time)
(defn compare-calls
"Used as comparator deciding which calls should be de-duplicated.
Whenever we fetch suggestions, we only want to issue the last call
done in the `queue-flush-time` window, for all other calls, we have
de-duplicate based on call identity"
[{:keys [jail-id path] :as call}]
(if (= :suggestions (last path))
[jail-id path]
call))
(go-loop []
(doseq [call (sequence (transducers/last-distinct-by compare-calls) (<! deduplicated-calls))]
(execute-call call))
(recur))
(defn call-jail [call]
(async/put! call-queue call))
(defn call-function!
[{:keys [chat-id function callback] :as opts}]
(let [path [:functions function]
params (select-keys opts [:parameters :context])]
(call-jail
{:jail-id chat-id
:path path
:params params
:callback callback})))
(defn set-soft-input-mode [mode]
(when status
(call-module #(.setSoftInputMode status mode))))
@ -254,8 +161,7 @@
(defrecord ReactNativeStatus []
module/IReactNativeStatus
;; status-go calls
(-init-jail [this]
(init-jail))
(-init-jail [this])
(-start-node [this config]
(start-node config))
(-stop-node [this]
@ -272,12 +178,9 @@
(approve-sign-request-with-args id password gas gas-price callback))
(-discard-sign-request [this id]
(discard-sign-request id))
(-parse-jail [this chat-id file callback]
(parse-jail chat-id file callback))
(-call-jail [this params]
(call-jail params))
(-call-function! [this params]
(call-function! params))
(-parse-jail [this chat-id file callback])
(-call-jail [this params])
(-call-function! [this params])
(-call-web3 [this payload callback]
(call-web3 payload callback))
(-call-web3-private [this payload callback]

View File

@ -32,11 +32,6 @@
(fn [error sync]
(re-frame/dispatch [:update-sync-state error sync]))))))
(re-frame/reg-fx
::status-init-jail
(fn []
(status/init-jail)))
(defn- assert-correct-network
[{:keys [db]}]
;; Assure that node was started correctly

View File

@ -58,20 +58,6 @@
[status-im.utils.utils :as utils]
[taoensso.timbre :as log]))
;;;; Helper fns
(defn- call-jail-function
[{:keys [chat-id function callback-event-creator] :as opts}]
(let [path [:functions function]
params (select-keys opts [:parameters :context])]
(status/call-jail
{:jail-id chat-id
:path path
:params params
:callback (fn [jail-response]
(when-let [event (callback-event-creator jail-response)]
(re-frame/dispatch event)))})))
;;;; COFX
(re-frame/reg-cofx

View File

@ -10,24 +10,6 @@
(def default-contacts (json->clj (slurp "resources/default_contacts.json")))
(def transactor-js (slurp-bot :transactor))
(def console-js (slurp-bot :console "web3_metadata.js"))
(def demo-bot-js (slurp-bot :demo_bot))
(def resources
{:transactor-bot transactor-js
:console-bot console-js
:demo-bot demo-bot-js})
(defn get-resource [url]
(let [resource-name (keyword (subs url (count local-protocol)))]
(resources resource-name)))
(def status-js (str (slurp "resources/js/status.js")
(slurp "resources/js/i18n.js")))
(def webview-js (slurp "resources/js/webview.js"))
(def web3 (str "; if (typeof Web3 == 'undefined') {"
(slurp "node_modules/web3/dist/web3.min.js")

View File

@ -1,7 +1,6 @@
(ns status-im.test.utils.transducers
(:require [cljs.test :refer-macros [deftest is testing]]
[status-im.utils.transducers :as transducers]
[status-im.native-module.impl.module :as native-module]))
[status-im.utils.transducers :as transducers]))
(def ^:private preview-call-1
{:jail-id 1
@ -39,7 +38,11 @@
(deftest last-distinct-by-test
(testing "Elements are removed from input according to provided `compare-fn`,
when duplicate elements are removed, the last one stays"
(is (= (sequence (transducers/last-distinct-by native-module/compare-calls) jail-calls)
(is (= (sequence (transducers/last-distinct-by (fn [{:keys [jail-id path] :as call}]
(if (= :suggestions (last path))
[jail-id path]
call)))
jail-calls)
'({:jail-id 1
:path [:suggestions]
:params {:arg 2}}