diff --git a/js/interface_common.js b/js/interface_common.js
index 87aaf80..664bcf3 100644
--- a/js/interface_common.js
+++ b/js/interface_common.js
@@ -16,7 +16,12 @@ var twister = {
tmpl: { // templates pointers are stored here
root: $('
') // templates should be detached from DOM and attached here; use extractTemplate()
},
- modal: {}
+ modal: {},
+ res: {}, // reses for various reqs are cached here
+ var: {
+ localAccounts: [],
+ updatesCheckClient: {}
+ }
};
var window_scrollY = 0;
var _watchHashChangeRelaxDontDoIt = window.location.hash === '' ? true : false;
@@ -55,6 +60,9 @@ function openModal(modal) {
modal.self = $('#templates ' + modal.classBase).clone(true)
.addClass(modal.classAdd);
+ if (modal.removeBlackout)
+ modal.self.find('.modal-blackout').remove();
+
if (modal.title)
modal.self.find('.modal-header h3').html(modal.title);
if (modal.content)
@@ -63,6 +71,16 @@ function openModal(modal) {
else
modal.content = modal.self.find('.modal-content');
+ if (modal.warn && modal.warn.name && modal.warn.text) {
+ var elem = twister.tmpl.modalComponentWarn.clone(true)
+ .attr('data-warn-name', modal.warn.name)
+ .toggle(!$.Options.get('skipWarn' + modal.warn.name))
+ ;
+ fillElemWithTxt(elem.find('.text'), modal.warn.text, {markout: 'apply'});
+ elem.find('.options .never-again + span').text(polyglot.t('do_not_show_it_again'));
+ elem.insertBefore(modal.content);
+ }
+
modal.self.appendTo('body').fadeIn('fast'); // FIXME maybe it's better to append it to some container inside body
if (modal.classBase === '.modal-wrapper') {
@@ -71,7 +89,9 @@ function openModal(modal) {
modal.drapper = $('
').appendTo(twister.html.detached); // here modal goes instead detaching
- modal.content.outerHeight(modal.self.height() - modal.self.find('.modal-header').outerHeight());
+ modal.content.outerHeight(modal.self.height() - modal.self.find('.modal-header').outerHeight()
+ - modal.self.find('.inline-warn').outerHeight()
+ * (modal.warn && !$.Options.get('skipWarn' + modal.warn.name) ? 1 : 0));
var windowHeight = $(window).height();
if (modal.self.outerHeight() > windowHeight) {
@@ -107,6 +127,9 @@ function closeModal(req, switchMode) {
else
this.remove(); // if it's minimized it will be removed with twister.modal[i].drapper
+ if (typeof twister.modal[i].onClose === 'function')
+ twister.modal[i].onClose(twister.modal[i].onCloseReq);
+
twister.modal[i].drapper.remove();
twister.modal[i] = undefined;
}
@@ -287,8 +310,9 @@ function confirmPopup(req) {
var modal = openModal({
classBase: '.prompt-wrapper',
- classAdd: 'confirm-popup',
+ classAdd: req.classAdd ? 'confirm-popup ' + req.classAdd : 'confirm-popup',
content: $('#confirm-popup-template').children().clone(true),
+ removeBlackout: !req.addBlackout,
title: req.txtTitle
});
@@ -343,6 +367,8 @@ function confirmPopup(req) {
btn.on('click', {cbFunc: req.cbClose, cbReq: req.cbCloseReq}, closePrompt);
}
}
+
+ return modal;
}
function alertPopup(req) {
@@ -359,7 +385,7 @@ function alertPopup(req) {
req.removeCancel = true;
}
- confirmPopup(req);
+ return confirmPopup(req);
}
function checkNetworkStatusAndAskRedirect(cbFunc, cbReq) {
@@ -377,6 +403,7 @@ function checkNetworkStatusAndAskRedirect(cbFunc, cbReq) {
}
function timeGmtToText(t) {
+ if (t == 0) return '-';
var d = new Date(0);
d.setUTCSeconds(t);
return d.toString().replace(/GMT.*/g, '');
@@ -400,6 +427,94 @@ function timeSincePost(t) {
return polyglot.t('time_ago', {time: expression});
}
+function openModalLogin() {
+ var modal = openModal({
+ classAdd: 'login-modal',
+ content: twister.tmpl.loginMC.clone(true),
+ title: polyglot.t('twister login')
+ });
+}
+
+function handleClickAccountLoginLogin(event) {
+ loginToAccount($(event.target).closest('.module').find('select.local-usernames').val());
+}
+
+function handleInputAccountCreateSetReq(event) {
+ var container = $(event.target).closest('.module');
+
+ container.find('.availability').text('');
+ $.MAL.enableButton(container.find('.check'));
+ $.MAL.disableButton(container.find('.create'));
+}
+
+function handleClickAccountCreateCheckReq(event) {
+ var container = $(event.target).closest('.module');
+ var peerAliasElem = container.find('.alias');
+ var peerAlias = peerAliasElem.val().toLowerCase();
+ var availField = container.find('.availability');
+
+ peerAliasElem.val(peerAlias);
+ $.MAL.disableButton(container.find('.check'));
+
+ if (!peerAlias.length)
+ return;
+ if (peerAlias.length > 16) {
+ availField.text(polyglot.t('Must be 16 characters or less.'));
+ return;
+ }
+
+ // check for non-alphabetic characters and space
+ if (peerAlias.search(/[^a-z0-9_]/) !== -1) {
+ availField.text(polyglot.t('Only alphanumeric and underscore allowed.'));
+ return;
+ }
+
+ availField.text(polyglot.t('Checking...'));
+
+ dumpPubkey(peerAlias,
+ function(req, ret) {
+ if (ret) {
+ req.container.find('.availability').text(polyglot.t('Not available'));
+ } else {
+ req.container.find('.availability').text(polyglot.t('Available'));
+ $.MAL.enableButton(req.container.find('.create'));
+ }
+ }, {container: container}
+ );
+}
+
+function handleClickAccountCreateCreate(event) {
+ var container = $(event.target).closest('.module');
+ var peerAlias = container.find('.alias').val().toLowerCase();
+
+ if (twister.var.localAccounts.indexOf(peerAlias) < 0) {
+ createAccount(peerAlias);
+ } else {
+ // user exists in wallet but transaction not sent
+ dumpPrivkey(peerAlias,
+ function (req, ret) {
+ $.MAL.processCreateAccount(req.peerAlias, ret);
+ }, {peerAlias: peerAlias}
+ );
+ }
+}
+
+function handleInputAccountImportSetReq(event) {
+ var container = $(event.target).closest('.module');
+
+ if (container.find('.secret-key').val().length === 52
+ && container.find('.alias').val().toLowerCase().length)
+ $.MAL.enableButton(container.find('.import'));
+ else
+ $.MAL.disableButton(container.find('.import'));
+}
+
+function handleClickAccountImportImport(event) {
+ var container = $(event.target).closest('.module');
+
+ importAccount(container.find('.alias').val().toLowerCase(), container.find('.secret-key').val())
+}
+
function openGroupProfileModalWithNameHandler(groupAlias) {
var modal = openModal({
classAdd: 'profile-modal',
@@ -449,6 +564,8 @@ function openUserProfileModalWithNameHandler(peerAlias) {
content.find('.tox-ctc').attr('title', polyglot.t('Copy to clipboard'));
content.find('.bitmessage-ctc').attr('title', polyglot.t('Copy to clipboard'));
+ content.find('.open-followers').on('mouseup', {route: '#followers?user=' + peerAlias}, routeOnClick);
+
var modal = openModal({
classAdd: 'profile-modal',
content: content,
@@ -475,37 +592,54 @@ function openHashtagModalFromSearchHandler(hashtag) {
title: '#' + hashtag
});
- setupQueryModalUpdating(modal.content.find('.postboard-posts'), hashtag, 'hashtag');
+ var req = queryStart(modal.content.find('.postboard-posts'), hashtag, 'hashtag');
+ modal.content.find('.postboard-news').on('click', {req: req}, handleClickDisplayPendingTwists);
}
-function setupQueryModalUpdating(postboard, query, resource) {
- var req = {
- postboard: postboard,
- query: query,
- resource: resource,
- id: query + '@' + resource
- };
-
- postboard.attr('data-request-id', req.id);
+function handleClickDisplayPendingTwists(event) {
+ if (!event || !event.data || !event.data.req)
+ return;
- requestQuery(req);
+ $(event.target).hide();
- // use extended timeout parameters on modal refresh (requires twister_core >= 0.9.14).
- // our first query above should be faster (with default timeoutArgs of twisterd),
- // then we may possibly collect more posts on our second try by waiting more.
- req.timeoutArgs = [10000, 2000, 3];
+ queryPendingDraw(event.data.req);
- postboard.attr('data-request-interval', setInterval(updateQueryModal, 5000, req)); // FIXME
+ if (typeof event.data.cbFunc === 'function')
+ event.data.cbFunc(event.data.cbReq);
}
-function updateQueryModal(req) {
- if (!isModalWithElemExists(req.postboard)) {
- clearInterval(req.postboard.attr('data-request-interval'));
- clearQueryProcessed(req.id);
+function openFavsModal(event) {
+ if (event && typeof event.stopPropagation === 'function') {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+
+ var userInfo = $(this).closest('[data-screen-name]');
+ var peerAlias = '';
+ if (userInfo.length)
+ peerAlias = userInfo.attr('data-screen-name');
+ else if (defaultScreenName)
+ peerAlias = defaultScreenName;
+ else {
+ alertPopup({
+ //txtTitle: polyglot.t(''), add some title (not 'error', please) or just KISS
+ txtMessage: polyglot.t('No favs here because you are not logged in.')
+ });
return;
}
- requestQuery(req);
+ window.location.hash = '#favs?user=' + peerAlias;
+}
+
+function openFavsModalHandler(peerAlias) {
+ var modal = openModal({
+ classAdd: 'hashtag-modal',
+ content: $('#hashtag-modal-template').children().clone(true),
+ title: polyglot.t('users_favs', {username: peerAlias})
+ });
+
+ var req = queryStart(modal.content.find('.postboard-posts'), peerAlias, 'fav');
+ modal.content.find('.postboard-news').on('click', {req: req}, handleClickDisplayPendingTwists);
}
function openMentionsModal(event) {
@@ -537,22 +671,22 @@ function openMentionsModalHandler(peerAlias) {
title: polyglot.t('users_mentions', {username: peerAlias})
});
- setupQueryModalUpdating(modal.content.find('.postboard-posts'), peerAlias, 'mention');
+ var req = queryStart(modal.content.find('.postboard-posts'), peerAlias, 'mention');
+ modal.content.find('.postboard-news')
+ .on('click',
+ {req: req, cbFunc: (peerAlias === defaultScreenName) ? resetMentionsCount : ''},
+ handleClickDisplayPendingTwists
+ )
+ ;
if (peerAlias === defaultScreenName) {
- // obtain already cached mention posts from twister_newmsgs.js
- processQuery({
- postboard: modal.content.find('.postboard-posts'),
- query: defaultScreenName,
- resource: 'mention',
- posts: getMentionsData()
- });
+ modal.content.on('scroll', handleMentionsModalScroll);
resetMentionsCount();
}
}
function openFollowersModal(peerAlias) {
- var followers, title, txtAlert;
+ var followers, title, warn;
if (!peerAlias || peerAlias === defaultScreenName) {
if (!defaultScreenName) {
@@ -565,22 +699,27 @@ function openFollowersModal(peerAlias) {
}
title = polyglot.t('Followers');
followers = twisterFollowingO.knownFollowers.slice();
- txtAlert = '* ' + polyglot.t('warn_followers_not_all');
+ warn = {
+ name: 'FollowersNotAll',
+ text: '* ' + polyglot.t('warn_followers_not_all')
+ };
} else {
title = polyglot.t('Followers_of', {alias: peerAlias});
followers = whoFollows(peerAlias);
- txtAlert = polyglot.t('warn_followers_not_all_of', {alias: peerAlias});
+ warn = {
+ name: 'FollowersNotAllOf',
+ text: polyglot.t('warn_followers_not_all_of', {alias: peerAlias})
+ };
}
var modal = openModal({
classAdd: 'followers-modal',
content: twister.tmpl.followersList.clone(true),
- title: title
+ title: title,
+ warn: warn
});
appendFollowersToElem(modal.content.find('ol'), followers);
-
- alertPopup({txtMessage: txtAlert});
}
function appendFollowersToElem(list, followers) {
@@ -658,6 +797,7 @@ function addPeerToFollowingList(list, peerAlias) {
.on('mouseup', {route: $.MAL.mentionsUrl(peerAlias)}, routeOnClick);
getAvatar(peerAlias, item.find('.mini-profile-photo'));
getFullname(peerAlias, item.find('.mini-profile-name'));
+ getStatusTime(peerAlias, item.find('.latest-activity .time'));
if (peerAlias === defaultScreenName)
item.find('.following-config').hide();
@@ -677,9 +817,6 @@ function addPeerToFollowingList(list, peerAlias) {
}
function fillWhoToFollowModal(list, hlist, start) {
- var itemTmp = $('#follow-suggestion-template').clone(true)
- .removeAttr('id');
-
for (var i = 0; i < followingUsers.length && list.length < start + 20; i++) {
if (typeof twisterFollowingO.followingsFollowings[followingUsers[i]] !== 'undefined') {
for (var j = 0; j < twisterFollowingO.followingsFollowings[followingUsers[i]].following.length && list.length < start + 25; j++) {
@@ -687,26 +824,11 @@ function fillWhoToFollowModal(list, hlist, start) {
if (followingUsers.indexOf(utf) < 0 && list.indexOf(utf) < 0) {
list.push(utf);
- var item = itemTmp.clone(true);
-
- item.find('.twister-user-info').attr('data-screen-name', utf);
- item.find('.twister-user-name').attr('href', $.MAL.userUrl(utf));
- item.find('.twister-by-user-name').attr('href', $.MAL.userUrl(followingUsers[i]));
- item.find('.twister-user-tag').text('@' + utf);
-
- getAvatar(utf, item.find('.twister-user-photo'));
- getFullname(utf, item.find('.twister-user-full'));
- getBioToElem(utf, item.find('.bio'));
- getFullname(followingUsers[i], item.find('.followed-by').text(followingUsers[i]));
-
- item.find('.twister-user-remove').remove();
-
- hlist.append(item);
+ processWhoToFollowSuggestion(hlist, utf, followingUsers[i]);
}
}
}
}
- itemTmp.remove();
if (i >= followingUsers.length - 1)
return false;
@@ -727,12 +849,60 @@ function openWhoToFollowModal() {
modal.content.on('scroll', function() {
if (modal.content.scrollTop() >= hlist.height() - modal.content.height() - 20) {
- if (!fillWhoToFollowModal(tmplist, hlist, tmplist.length))
+ if (!fillWhoToFollowModal(tmplist, modal.self, tmplist.length))
modal.content.off('scroll');
}
});
- fillWhoToFollowModal(tmplist, hlist, 0);
+ fillWhoToFollowModal(tmplist, modal.self, 0);
+}
+
+function openNewUsersModal() {
+ var modal = openModal({
+ classAdd: 'new-users-modal',
+ title: polyglot.t('New Users'),
+ onClose: function() {
+ NewUserSearch.isNewUserModalOpen = false;
+ }
+ });
+
+ var hlist = $('')
+ .appendTo(modal.content);
+ var count = 15;
+
+ modal.content.on('scroll', function() {
+ if (modal.content.scrollTop() >= hlist.height() - modal.content.height() - 20) {
+ if (newUsers.getLastNUsers(5, count, modal.self))
+ count += 5;
+ }
+ });
+
+ NewUserSearch.isNewUserModalOpen = true;
+ newUsers.getLastNUsers(15, 0, modal.self);
+}
+
+function openModalUriShortener()
+{
+ var modal = openModal({
+ classAdd: 'uri-shortener-modal',
+ content: twister.tmpl.uriShortenerMC.clone(true),
+ title: polyglot.t('URI_shortener')
+ });
+
+ modal.content.find('.uri-shortener-control .shorten-uri').text(polyglot.t('shorten_URI'));
+ modal.content.find('.uri-shortener-control .clear-cache').text(polyglot.t('clear_cache'));
+
+ var urisList = modal.content.find('.uris-list');
+ //var i = 0;
+ for (var short in twister.URIs) {
+ //i++;
+ var long = twister.URIs[short] instanceof Array ? twister.URIs[short][0] : twister.URIs[short];
+ var item = twister.tmpl.uriShortenerUrisListItem.clone(true);
+ item.find('.short').text(short);
+ item.find('.long').text(long).attr('href', long);
+ item.appendTo(urisList);
+ }
+ //i + URIs are cached
}
function newConversationModal(peerAlias, resource) {
@@ -796,14 +966,22 @@ function handleClickOpenProfileModal(event) {
}
function handleClickOpenConversation(event) {
- event.preventDefault();
- event.stopPropagation();
+ var elem = $(event.target).closest(event.data.feeder);
+ if (!elem.length) {
+ muteEvent(event, true);
+ return;
+ }
- var elem = $(event.target);
- var postData = elem.closest(event.data.feeder);
+ var post = {
+ writer: elem.attr('data-screen-name'),
+ id: elem.attr('data-id')
+ };
+ if (!post.writer || !post.id) {
+ muteEvent(event, true);
+ return;
+ }
- event.data.route = '#conversation?post=' + postData.attr('data-screen-name')
- + ':post' + postData.attr('data-id');
+ event.data.route = '#conversation?post=' + post.writer + ':post' + post.id;
routeOnClick(event);
}
@@ -828,8 +1006,8 @@ function openRequestShortURIForm(event) {
if (parseInt(twisterVersion) < 93500) {
alertPopup({
//txtTitle: polyglot.t(''), add some title (not 'error', please) or just KISS
- txtMessage: 'You can\'t shorten links because twister daemon is obsolete!\n'
- + 'Version 0.9.35 or higher is required. Please keep your twister up to date.'
+ txtMessage: 'You can\'t shorten links —\n'
+ + polyglot.t('daemon_is_obsolete', {versionReq: '0.9.35'})
});
return;
}
@@ -845,7 +1023,7 @@ function openRequestShortURIForm(event) {
function showURIPair(uriLong, uriShort) { // FIXME req
if (uriShort)
alertPopup({
- txtTitle: 'URI shortener',
+ txtTitle: polyglot.t('URI_shortener'),
txtMessage: uriLong + ' — `' + uriShort + '`'
});
else
@@ -854,7 +1032,7 @@ function showURIPair(uriLong, uriShort) { // FIXME req
function showURIShortenerErrorRPC(ret) {
alertPopup({
- txtTitle: 'URI shortener',
+ txtTitle: polyglot.t('URI_shortener'),
txtMessage: 'something went wrong. RPC error message:\n' + (ret && ret.message ? ret.message : ret)
});
}
@@ -909,12 +1087,28 @@ function fetchShortenedURI(req, attemptCount) {
function applyShortenedURI(short, uriAndMimetype) {
var long = (uriAndMimetype instanceof Array) ? uriAndMimetype[0] : uriAndMimetype;
var mimetype = (uriAndMimetype instanceof Array) ? uriAndMimetype[1] : undefined;
- var elems = getElem('.link-shortened[href="' + short + '"]')
+ var elems = getElem('.link-shortened[href="' + short + '"]');
+
+ if (isUriSuspicious(long)) {
+ elems.replaceWith(
+ '… ' + polyglot.t('busted_oh') + ' '
+ + polyglot.t('busted_avowal') + ': '
+ + long
+ .replace(/&(?!lt;|gt;)/g, '&')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''')
+ + ' … '
+ );
+ return;
+ }
+
+ elems
.attr('href', long)
.removeClass('link-shortened')
.off('click mouseup')
.on('click mouseup', muteEvent)
;
+
var cropped = (/*$.Options.cropLongURIs &&*/ long.length > 23) ? long.slice(0, 23) + '…' : undefined;
for (var i = 0; i < elems.length; i++) {
if (elems[i].text === short) // there may be some other text, possibly formatted, so we check it
@@ -952,7 +1146,7 @@ function applyShortenedURI(short, uriAndMimetype) {
previewContainer.append(startTorrentLink);
}
} else {
- var enableWebTorrentWarning = $('' +
+ var enableWebTorrentWarning = $('' +
polyglot.t('Enable WebTorrent support in options page to display this content') +
'');
previewContainer.append(enableWebTorrentWarning);
@@ -972,7 +1166,7 @@ function startTorrentDownloadAndPreview(torrentId, previewContainer, isMedia) {
function _startTorrentDownloadAndPreview(torrentId, previewContainer, isMedia) {
var torrent = WebTorrentClient.get(torrentId);
- if( torrent === null )
+ if( torrent === null )
torrent = WebTorrentClient.add(torrentId);
previewContainer.empty();
@@ -1003,7 +1197,7 @@ function webtorrentFilePreview(file, previewContainer, isMedia) {
// try guessing by filename extension
isMedia = /^[^?]+\.(?:jpe?g|gif|png|mp4|webm|mp3|ogg|wav|)$/i.test(file.name)
}
-
+
if (isMedia) {
var imagePreview = $('');
previewContainer.append(imagePreview);
@@ -1012,7 +1206,9 @@ function webtorrentFilePreview(file, previewContainer, isMedia) {
elem.pause();
}
});
- imagePreview.find("video").removeAttr("autoplay");
+ var $vid = imagePreview.find("video");
+ $vid.removeAttr("autoplay");
+ $vid.on('click mouseup', muteEvent);
} else {
file.getBlobURL(function (err, url) {
if (err) return console.error(err)
@@ -1039,6 +1235,9 @@ function routeOnClick(event) {
if (!event || !event.data || !event.data.route)
return;
+ if (event.button === 0 && window.getSelection().toString() !== '')
+ return;
+
event.stopPropagation();
event.preventDefault();
@@ -1100,7 +1299,7 @@ function loadModalFromHash() {
// FIXME rework hash scheme from '#following?user=twister' to something like '#/@twister/following'
if (hashdata[0] !== '#web+twister')
- hashdata = hashstring.match(/(hashtag|profile|mentions|directmessages|followers|following|conversation)\?(?:group|user|hashtag|post)=(.+)/);
+ hashdata = hashstring.match(/(hashtag|profile|mentions|directmessages|followers|following|conversation|favs)\?(?:group|user|hashtag|post)=(.+)/);
if (hashdata && hashdata[1] !== undefined && hashdata[2] !== undefined) {
if (hashdata[1] === 'profile')
@@ -1127,6 +1326,8 @@ function loadModalFromHash() {
splithashdata2 = hashdata[2].split(':');
openConversationModal(splithashdata2[0], splithashdata2[1]);
}
+ else if (hashdata[1] === 'favs')
+ openFavsModalHandler(hashdata[2]);
} else if (hashstring === '#directmessages')
openCommonDMsModal();
else if (hashstring === '#followers')
@@ -1139,8 +1340,14 @@ function loadModalFromHash() {
openGroupMessagesNewGroupModal();
else if (hashstring === '#groupmessages+joingroup')
openGroupMessagesJoinGroupModal();
+ else if (hashstring === '#/login')
+ openModalLogin();
else if (hashstring === '#whotofollow')
openWhoToFollowModal();
+ else if (hashstring === '#/uri-shortener')
+ openModalUriShortener();
+ else if (hashstring === '#newusers')
+ openNewUsersModal();
}
function initHashWatching() {
@@ -1213,6 +1420,49 @@ function reTwistPopup(event, post, textArea) {
replyArea.find('.post-submit').addClass('with-reference');
}
+function favPopup(event, post, textArea) {
+ event.stopPropagation();
+
+ if (!defaultScreenName) {
+ alertPopup({
+ txtMessage: polyglot.t('You have to log in to favorite messages.')
+ });
+ return;
+ }
+
+ if (typeof post === 'undefined')
+ post = $.evalJSON($(event.target).closest('.post-data').attr('data-userpost'));
+
+ var modal = openModal({
+ classBase: '.prompt-wrapper',
+ classAdd: 'fav-this',
+ title: polyglot.t('fav_this')
+ });
+
+ modal.content
+ .append(postToElem(post, ''))
+ .append($('#fav-modal-template').children().clone(true))
+ ;
+ /*
+ //TODO: favs can be also commented
+ var replyArea = modal.content.find('.post-area .post-area-new');
+ if (typeof textArea === 'undefined') {
+ textArea = replyArea.find('textarea');
+ var textAreaPostInline = modal.content.find('.post .post-area-new textarea');
+ $.each(['placeholder', 'data-reply-to'], function(i, attribute) {
+ textArea.attr(attribute, textAreaPostInline.attr(attribute));
+ });
+ } else {
+ replyArea.find('textarea').replaceWith(textArea);
+ if (textArea.val()) {
+ textArea.focus();
+ replyArea.addClass('open');
+ }
+ }
+ replyArea.find('.post-submit').addClass('with-reference');
+ */
+}
+
// Expande Área do Novo post
function replyInitPopup(e, post, textArea) {
var modal = openModal({
@@ -1426,7 +1676,7 @@ function postExpandFunction(e, postLi) {
var originalLi = $('', {class: 'module post original'}).appendTo(itemOl)
.append(originalPost);
- setPostImagePreview(postExpandedContent, originalPost.find('a[rel="nofollow"]'));
+ setPostImagePreview(postExpandedContent, originalPost.find('a[rel^="nofollow"]'));
postExpandedContent.slideDown('fast');
@@ -1724,7 +1974,7 @@ function replyTextUpdateRemaining(ta) {
return false;
}
});
- if (!disable && c >= 0 && c < $.Options.MaxPostEditorChars.val &&
+ if (!disable && c >= 0 && c < $.Options.MaxPostEditorChars.val &&
textArea.val() !== textArea.attr('data-reply-to')) {
remainingCount.removeClass('warn');
$.MAL.enableButton(buttonSend);
@@ -2265,6 +2515,17 @@ function retweetSubmit(event) {
closePrompt(prompt);
}
+function favSubmit(event) {
+ event.preventDefault();
+ event.stopPropagation();
+
+ var prompt = $(event.target).closest('.prompt-wrapper');
+ var priv = (event.target.className.indexOf('private') > -1);
+
+ newFavMsg(prompt.find('.post-data'), priv);
+ closePrompt(prompt);
+}
+
function changeStyle() {
var style, profile, menu;
var theme = $.Options.theme.val;
@@ -2335,9 +2596,86 @@ function replaceDashboards() {
}
function initInterfaceCommon() {
+ twister.tmpl.modalComponentWarn = extractTemplate('#template-inline-warn');
+ twister.tmpl.modalComponentWarn.find('.close').on('click',
+ function(event) {
+ var i = $(event.target).closest('.modal-wrapper').attr('data-modal-id');
+
+ if (!i || !twister.modal[i]) return;
+
+ var modal = twister.modal[i];
+
+ modal.self.find('.inline-warn').hide();
+
+ modal.content.outerHeight(modal.self.height() - modal.self.find('.modal-header').outerHeight());
+
+ var windowHeight = $(window).height();
+ if (modal.self.outerHeight() > windowHeight) {
+ modal.content.outerHeight(modal.content.outerHeight() - modal.self.outerHeight() + windowHeight);
+ modal.self.outerHeight(windowHeight);
+ modal.self.css('margin-top', - windowHeight / 2);
+ }
+ }
+ );
+ twister.tmpl.modalComponentWarn.find('.options .never-again').on('change',
+ function(event) {
+ $.Options.set('skipWarn' + $(event.target).closest('.inline-warn')
+ .attr('data-warn-name'), event.target.checked); // e.g. 'skipWarnFollowersNotAll'
+ }
+ );
twister.tmpl.commonDMsList = extractTemplate('#template-direct-messages-list');
+ twister.tmpl.uriShortenerMC = extractTemplate('#template-uri-shortener-modal-content');
+ twister.tmpl.uriShortenerMC
+ .find('.shorten-uri').on('click',
+ {cbFunc:
+ function (long, short) {
+ if (short) {
+ var urisList = getElem('.uri-shortener-modal .uris-list');
+ if (urisList.length) {
+ var item = urisList.find('.short:contains("' + short + '")').closest('li');
+ if (!item.length) {
+ item = twister.tmpl.uriShortenerUrisListItem.clone(true);
+ item.find('.short').text(short);
+ item.find('.long').text(long).attr('href', long);
+ item.appendTo(urisList);
+ }
+ urisList.children('.highlighted').removeClass('highlighted');
+ item.addClass('highlighted');
+ var mc = urisList.closest('.modal-content');
+ mc.scrollTop(item.offset().top - mc.offset().top + mc.scrollTop());
+ }
+ showURIPair(long, short);
+ } else
+ showURIShortenerErrorRPC(short);
+ }
+ },
+ function (event) {
+ muteEvent(event);
+ openRequestShortURIForm(event);
+ }
+ )
+ .siblings('.clear-cache').on('click',
+ function () {
+ confirmPopup({
+ txtMessage: polyglot.t('confirm_uri_shortener_clear_cache'),
+ cbConfirm: function () {
+ twister.URIs = {};
+ $.localStorage.set('twistaURIs', twister.URIs);
+ getElem('.uri-shortener-modal .uris-list').empty();
+ }
+ });
+ }
+ )
+ ;
+ twister.tmpl.uriShortenerUrisListItem = extractTemplate('#template-uri-shortener-uris-list-item')
+ .on('click', function (event) {
+ var elem = $(event.target);
+ elem.closest('.uris-list').children('.highlighted').removeClass('highlighted');
+ elem.addClass('highlighted');
+ })
+ ;
- $('.modal-close, .modal-blackout').not('.prompt-close').on('click', closeModal);
+ getElem('.modal-wrapper .modal-close, .modal-wrapper .modal-blackout').on('click', closeModal);
$('.minimize-modal').on('click', function (event) {
minimizeModal($(event.target).closest('.modal-wrapper'));
@@ -2347,18 +2685,19 @@ function initInterfaceCommon() {
$('.prompt-close').on('click', closePrompt);
- $('button.follow').on('click', clickFollow);
+ getElem('button.follow', true).on('click', clickFollow);
$('.following-config-method-buttons .public-following').on('click', function(event) {
setFollowingMethod(event);
closePrompt(event);
});
- $('.open-followers').on('mouseup', {route: '#followers'}, routeOnClick);
+ $('.module.mini-profile .open-followers').on('mouseup', {route: '#followers'}, routeOnClick);
$('.post-text').on('click', 'a', muteEvent);
$('.post-reply').on('click', postReplyClick);
$('.post-propagate').on('click', reTwistPopup);
+ $('.post-favorite').on('click', favPopup);
$('.userMenu-config').clickoutside(closeThis.bind($('.config-menu')));
$('.userMenu-config-dropdown').on('click', dropDownMenu);
$('#post-template.module.post').on('click', function(event) {
@@ -2378,6 +2717,8 @@ function initInterfaceCommon() {
;
$('.post-submit').on('click', postSubmit);
$('.modal-propagate').on('click', retweetSubmit);
+ $('.modal-fav-public').on('click', favSubmit);
+ $('.modal-fav-private').on('click', favSubmit);
$('.expanded-content .show-more').on('mouseup',
{feeder: '.module.post.original.open .module.post.original .post-data'}, handleClickOpenConversation)
.on('click', muteEvent) // to prevent post collapsing
@@ -2393,11 +2734,11 @@ function initInterfaceCommon() {
//$('.open-following-modal').on('click', openFollowingModal);
$('.userMenu-connections a').on('click', openMentionsModal);
$('.mentions-from-user').on('click', openMentionsModal);
+ $('.userMenu-favs a').on('click', openFavsModal);
+ $('.favs-from-user').on('click', openFavsModal);
- $('#hashtag-modal-template .postboard-news').on('click', function () {
- $(this).hide();
- displayQueryPending($('.hashtag-modal .postboard-posts'));
- });
+ getElem('.latest-activity', true).on('mouseup',
+ {feeder: '.latest-activity'}, handleClickOpenConversation);
replaceDashboards();
$(window).resize(replaceDashboards);
@@ -2438,7 +2779,14 @@ function initInterfaceCommon() {
$('.tox-ctc').on('click', promptCopyAttrData);
$('.bitmessage-ctc').on('click', promptCopyAttrData);
- $('.uri-shortener').on('click', openRequestShortURIForm); // FIXME implement Uri Shortener Center with links library etc
+ $('.uri-shortener').on('mouseup', {route: '#/uri-shortener'}, routeOnClick);
+
+ $('.updates-check-client').text(polyglot.t('updates_check_client'))
+ .on('mouseup', function (event) {
+ muteEvent(event);
+ checkUpdatesClient(true);
+ }
+ );
$('.post-area-new textarea')
.on('focus',
@@ -2494,18 +2842,6 @@ function inputEnterActivator(event) {
.attr('disabled', elemEvent.val().trim() === '');
}
-function importSecretKeypress(event) { // FIXME rename
- var elemModule = $(event.target).closest('.module');
- var elemEnter = elemModule.find('.import-secret-key');
- var secretKey = elemModule.find('.secret-key-import').val();
- var peerAlias = elemModule.find('.username-import').val().toLowerCase();
-
- if (secretKey.length === 52 && peerAlias.length)
- $.MAL.enableButton(elemEnter);
- else
- $.MAL.disableButton(elemEnter);
-}
-
function pasteToTextarea(ta, p) {
if (!ta || typeof ta.val !== 'function') return;
@@ -2563,10 +2899,21 @@ $(document).ready(function () {
if ($.localStorage.isSet('twistaURIs'))
twister.URIs = $.localStorage.get('twistaURIs');
twister.html.blanka.appendTo('body').hide();
+ twister.tmpl.loginMC = extractTemplate('#template-login-modal');
+ twister.tmpl.loginMC.find('.login').on('click', handleClickAccountLoginLogin);
+ var module = twister.tmpl.loginMC.closest('.create-account');
+ module.find('.alias').on('input', handleInputAccountCreateSetReq);
+ module.find('.check').on('click', handleClickAccountCreateCheckReq);
+ module.find('.create').on('click', handleClickAccountCreateCreate);
+ module = twister.tmpl.loginMC.closest('.import-account');
+ module.find('.secret-key').on('input', handleInputAccountImportSetReq);
+ module.find('.alias').on('input', handleInputAccountImportSetReq);
+ module.find('.import').on('click', handleClickAccountImportImport);
twister.tmpl.followersList = extractTemplate('#template-followers-list');
twister.tmpl.followersPeer = extractTemplate('#template-followers-peer');
twister.tmpl.followingList = extractTemplate('#template-following-list');
twister.tmpl.followingPeer = extractTemplate('#template-following-peer');
+ twister.tmpl.whoTofollowPeer = extractTemplate('#template-whotofollow-peer');
twister.tmpl.commonDMsListItem = extractTemplate('#template-direct-messages-list-item')
.on('mouseup', function (event) {
event.data = {route:
@@ -2620,9 +2967,7 @@ $(document).ready(function () {
var path = window.location.pathname;
var page = path.split("/").pop();
- if (page.indexOf("login.html") === 0) {
- initInterfaceLogin();
- } else if (page.indexOf("network.html") === 0) {
+ if (page.indexOf('network.html') === 0) {
initInterfaceNetwork();
} else if (page.indexOf('options.html') === 0) {
initInterfaceCommon();
diff --git a/js/interface_home.js b/js/interface_home.js
index e59ad6e..4e31144 100644
--- a/js/interface_home.js
+++ b/js/interface_home.js
@@ -49,8 +49,7 @@ var InterfaceFunctions = function() {
//$("span.screen-name").text('@' + user);
var $miniProfile = $(".mini-profile");
if (!defaultScreenName) {
- $(".userMenu-profile > a").text(polyglot.t("Login"));
- $(".userMenu-profile > a").attr("href","login.html");
+ $('.userMenu-profile > a').attr('href', '#/login').text(polyglot.t('Login'));
$(".post-area-new > textarea").attr("placeholder",polyglot.t("You have to log in to post messages."));
$(".post-area-new > textarea").attr("disabled","true");
$miniProfile.find(".mini-profile-name").text("guest");
@@ -100,6 +99,11 @@ var InterfaceFunctions = function() {
else
killInterfaceModule('who-to-follow');
+ if ($.Options.NewUsers.val === 'enable')
+ initNewUsers();
+ else
+ killInterfaceModule('new-users');
+
if ($.Options.TwistdayReminder.val === 'enable')
initTwistdayReminder();
else
@@ -113,7 +117,7 @@ var InterfaceFunctions = function() {
if ($.Options.WebTorrent.val === 'enable')
initWebTorrent();
}
-}
+};
function initTopTrends() {
var $tt = initInterfaceModule('toptrends');
@@ -200,6 +204,30 @@ function refreshWhoToFollow() {
}
}
+function initNewUsers() {
+ var nus = initInterfaceModule('new-users');
+
+ newUsers = NewUserSearch();
+ if (nus.length) {
+ var nusRefresh = nus.find('.refresh-users');
+ nusRefresh.on('click', refreshNewUsers);
+ setTimeout(function() {nusRefresh.click();}, 100);
+ }
+}
+
+function refreshNewUsers() {
+ var module = $('.module.new-users');
+ var list = module.find('.follow-suggestions');
+
+ if (list.length) {
+ list.empty().hide();
+ module.find('.refresh-users').hide();
+ module.find('.loading-roller').show();
+
+ newUsers.getLastNUsers(3, 0, module, true);
+ }
+}
+
function initTwistdayReminder() {
var $module = initInterfaceModule('twistday-reminder');
@@ -268,7 +296,9 @@ function refreshTwistdayReminder() {
});
for (var i = 0; i < posts.length; i++) {
- if (followingUsers.indexOf(posts[i].userpost.n) > -1) {
+ if (followingUsers.indexOf(posts[i].userpost.n) > -1
+ && posts[i].userpost.height !== posts[i].userpost.k) // to filter possible promoted twists which may appear suddenly (shame on you Miguel!)
+ {
d.setTime(0);
d.setUTCSeconds(posts[i].userpost.time);
if (d.getMonth() === curMonth && d.getDate() === curDate) {
@@ -333,7 +363,7 @@ function initWebTorrent() {
console.log("onget:", torrentId, err, data)
if (err || data === null) {
// error reading blob, just add torrentId
- console.log("WebTorrent auto-download: " + torrentId +
+ console.log("WebTorrent auto-download: " + torrentId +
" (previously seeded as: " + twister.torrentIds[torrentId] + ")" );
WebTorrentClient.add(torrentId);
} else {
diff --git a/js/interface_localization.js b/js/interface_localization.js
index 9911d10..abf858c 100644
--- a/js/interface_localization.js
+++ b/js/interface_localization.js
@@ -45,6 +45,8 @@ if(preferredLanguage == "en"){
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"btn_ok": "Okay",
"Cancel": "Cancel",
+ 'cant_get_requested_resourse': 'Can\'t get resourse at %{link}\n status: %{status}.',
+ "clear_cache": "Clear cache",
"Confirm": "Confirm",
"сonfirm_group_leaving_header": "Confirm group leaving",
"сonfirm_group_leaving_body": "Are you sure want to leave %{alias} group?",
@@ -54,12 +56,14 @@ if(preferredLanguage == "en"){
"Do you want to check [Network Status page](%{page}) instead?",
"confirm_terminate_daemon": "Are you sure you want to exit the daemon?\nThe Twister client will stop working.",
"confirm_unfollow_@": "Are you sure you want to unfollow @%{alias}?",
+ "confirm_uri_shortener_clear_cache": "Are you sure you want to clear browser cache of shortened URIs?",
"Change user": "Change user",
"Checking...": "Checking...", // checking if username is available
"Collapse": "Collapse", // smaller view of a post
"Configure block generation": "Configure block generation",
"Connections:": "Connections: ", // to network
"Connection lost.": "Connection lost.",
+ "daemon_is_obsolete": "twister daemon is obsolete, version %{versionReq} or higher is required",
"days": "%{smart_count} day |||| %{smart_count} days",
"Detailed information": "Detailed information",
"DHT network down.": "DHT network down.",
@@ -67,11 +71,16 @@ if(preferredLanguage == "en"){
"Group Messages": "Group Messages",
"Group Messages — New Group Creation": "Group Messages — New Group Creation",
"Group Messages — Join Group": "Group Messages — Join Group",
+ "group_key_cant_import": "Can\'t import DM group key",
+ "group_key_is_invalid_perhaps": "perhaps the key is invalid",
+ "group_key_was_imported": "Key for DM group %{alias} was imported.\n"
+ + "Its messages will be fetched soon.",
"direct_messages_with": "Direct messages with %{username}",
"Disable": "Disable",
"display_mentions": "Display mentions",
"Display retransmissions": "Display retransmissions",
"DNS to obtain list of peers:": "DNS to obtain list of peers:",
+ "do_not_show_it_again": "don't show it again",
"downloading_block_chain": "Downloading block chain, please wait before continuing (block chain is %{days} days old).",
"download_posts_status": "Downloaded %{portion} posts", // Downloaded 10/30 posts
"Enable": "Enable",
@@ -175,6 +184,7 @@ if(preferredLanguage == "en"){
+ "Note: shortening an URL will produce an 'empty' twist on your behalf containing the full URL.\n"
+ "This special twist is not displayed by twister clients, but your twist counter will increase.",
"shorten_URI_its_public_is_it_ok": "Your link will be public available! Are you OK with that?",
+ "URI_shortener": "URI Shortener",
"The File APIs are not fully supported in this browser.": "The File APIs are not fully supported in this browser.",
"time_ago": "%{time} ago", // 5 minutes ago
"Time of the last block:": "Time of the last block: ",
@@ -182,7 +192,24 @@ if(preferredLanguage == "en"){
"Unfollow": "Unfollow",
"Update": "Update",
"Auto updating": "Automatic updating",
+ 'updates_are_available': 'Updates are available',
+ 'updates_not_available': 'No updates are available',
+ 'updates_check_client': 'Check for client\'s updates',
+ 'updates_repo_overview': 'Currently we are on the branch %{branch} of %{repo} at the commit\n %{commit} of %{date}\n'
+ + 'but HEAD of its source is already at the commit\n %{commitUpstream} of %{dateUpstream}.',
+ 'updates_checkout_diff': 'Checkout [the diff on GitHub](%{link}) to learn what is changed.',
+ 'updates_checkout_diff_nfmt': 'Checkout the diff on GitHub to learn what is changed:\n %{link}',
+ 'updates_upstream_isnt_changed': 'A corresponding branch of the source repository seems to have not changed.',
"Updating status...": "Updating status...", // status of block chain
+ 'new_account_briefing': 'A new account was created and it is being propagated to the network. '
+ + 'Please do not close this window, this might take a few minutes.\n\n'
+ + 'Your secret key is: *%{secretKey}*\n\n'
+ + 'It is highly recommended that you take this time to save your secret key. '
+ + 'Print it, do a screenshot, use the camera in your phone or write it down to a piece of paper.\n\n'
+ + 'The secret key will be needed to use this account from different computers. '
+ + 'If you ever lose your secret key your account will be locked forever '
+ + '(note: ~this is alpha software and it may crash, causing loss of data~).\n\n'
+ + 'Just wait. The OK button will be shown faster you can say ~decentralization~.',
"user_not_yet_accepted": "Other peers have not yet accepted this new user.\n" +
"Unfortunately it is not possible to save profile\n" +
"or send any posts in this state.\n\n" +
@@ -358,6 +385,14 @@ if(preferredLanguage == "en"){
"IP Overhead Upload:": "IP Overhead Upload:",
"Payload Download:": "Payload Download:",
"Payload Upload:": "Payload Upload:",
+ "No favs here because you are not logged in." : "No favs here because you are not logged in.",
+ "users_favs": "Favorites of @%{username}",
+ "Favorites": "Favorites",
+ "You have to log in to favorite messages.": "You have to log in to favorite messages.",
+ "fav_this": "Is it for you only?",
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
if(preferredLanguage == "es"){
@@ -379,6 +414,8 @@ if(preferredLanguage == "es"){
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"btn_ok": "Okay",
"Cancel": "Cancelar",
+ 'cant_get_requested_resourse': 'Can\'t get resourse at %{link}\n status: %{status}.',
+ "clear_cache": "Clear cache",
"Confirm": "Confirm",
"сonfirm_group_leaving_header": "Confirm group leaving",
"сonfirm_group_leaving_body": "Are you sure want to leave %{alias} group?",
@@ -388,12 +425,14 @@ if(preferredLanguage == "es"){
"¿Quieres comprobar la [página de estado de la red](%{page}) en su lugar?",
"confirm_terminate_daemon": "Are you sure you want to exit the daemon?\nThe Twister client will stop working.",
"confirm_unfollow_@": "Are you sure you want to unfollow @%{alias}?",
+ "confirm_uri_shortener_clear_cache": "Are you sure you want to clear browser cache of shortened URIs?",
"Change user": "Cambiar de usuario",
"Checking...": "Comprobando ...", // checking if username is available
"Collapse": "Colapsar", // smaller view of a post
"Configure block generation": "Configure la generación de bloques",
"Connections:": "Conexiones: ", // to network
"Connection lost.": "Conexión perdida.",
+ "daemon_is_obsolete": "twister daemon is obsolete, version %{versionReq} or higher is required",
"days": "%{smart_count} día |||| %{smart_count} días",
"Detailed information": "Información detallada",
"DHT network down.": "Red DHT caida.",
@@ -401,11 +440,16 @@ if(preferredLanguage == "es"){
"Group Messages": "Group Messages",
"Group Messages — New Group Creation": "Group Messages — New Group Creation",
"Group Messages — Join Group": "Group Messages — Join Group",
+ "group_key_cant_import": "Can\'t import DM group key",
+ "group_key_is_invalid_perhaps": "perhaps the key is invalid",
+ "group_key_was_imported": "Key for DM group %{alias} was imported.\n"
+ + "Its messages will be fetched soon.",
"direct_messages_with": "Mensajes directos con %{username}",
"Disable": "Inhabilitar",
"display_mentions": "Visualización de menciones",
"Display retransmissions": "Visualización de retransmisiones",
"DNS to obtain list of peers:": "DNS para obtener la lista de los pares:",
+ "do_not_show_it_again": "don't show it again",
"downloading_block_chain": "Descarga de la cadena de bloques, por favor espere antes de continuar (la cadena de bloques esta %{days} días).",
"download_posts_status": "Post %{portion} descargados", // Downloaded 10/30 posts
"Enable": "Permitir",
@@ -509,6 +553,7 @@ if(preferredLanguage == "es"){
+ "Note: shortening an URL will produce an 'empty' twist on your behalf containing the full URL.\n"
+ "This special twist is not displayed by twister clients, but your twist counter will increase.",
"shorten_URI_its_public_is_it_ok": "Your link will be public available! Are you OK with that?",
+ "URI_shortener": "URI Shortener",
"The File APIs are not fully supported in this browser.": "Las API de archivos no son totalmente compatibles con este navegador.",
"time_ago": "hace %{time}", // 5 minutes ago
"Time of the last block:": "Hora del último bloque: ",
@@ -516,7 +561,24 @@ if(preferredLanguage == "es"){
"Unfollow": "Dejar de seguir",
"Update": "Actualizar",
"Auto updating": "Auto updating",
+ 'updates_are_available': 'Updates are available',
+ 'updates_not_available': 'No updates are available',
+ 'updates_check_client': 'Check for client\'s updates',
+ 'updates_repo_overview': 'Currently we are on the branch %{branch} of %{repo} at the commit\n %{commit} of %{date}\n'
+ + 'but HEAD of its source is already at the commit\n %{commitUpstream} of %{dateUpstream}.',
+ 'updates_checkout_diff': 'Checkout [the diff on GitHub](%{link}) to learn what is changed.',
+ 'updates_checkout_diff_nfmt': 'Checkout the diff on GitHub to learn what is changed:\n %{link}',
+ 'updates_upstream_isnt_changed': 'A corresponding branch of the source repository seems to have not changed.',
"Updating status...": "Actualización del estado ...", // status of block chain
+ 'new_account_briefing': 'A new account was created and it is being propagated to the network. '
+ + 'Please do not close this window, this might take a few minutes.\n\n'
+ + 'Your secret key is: *%{secretKey}*\n\n'
+ + 'It is highly recommended that you take this time to save your secret key. '
+ + 'Print it, do a screenshot, use the camera in your phone or write it down to a piece of paper.\n\n'
+ + 'The secret key will be needed to use this account from different computers. '
+ + 'If you ever lose your secret key your account will be locked forever '
+ + '(note: ~this is alpha software and it may crash, causing loss of data~).\n\n'
+ + 'Just wait. The OK button will be shown faster you can say ~decentralization~.',
"user_not_yet_accepted": "Otros pares no han aceptado este nuevo usuario.\n" +
"Por desgracia, no es posible guardar el perfil\n" +
"o enviar ningún mensaje en este estado.\n\n" +
@@ -675,6 +737,27 @@ if(preferredLanguage == "es"){
"Sound": "Sonido",
"Users": "Usuarios",
"Direct Message's copy to self": "Direct Message's copy to self",
+ "Traffic information": "Traffic information",
+ "DHT Torrents:": "DHT Torrents:",
+ "Peers:": "Peers:",
+ "Peer List Size:": "Peer List Size:",
+ "Active Requests:": "Active Requests:",
+ "Download:": "Download:",
+ "Upload:": "Upload:",
+ "DHT Download:": "DHT Download:",
+ "DHT Upload:": "DHT Upload:",
+ "IP Overhead Download:": "IP Overhead Download:",
+ "IP Overhead Upload:": "IP Overhead Upload:",
+ "Payload Download:": "Payload Download:",
+ "Payload Upload:": "Payload Upload:",
+ "No favs here because you are not logged in." : "No favs here because you are not logged in.",
+ "users_favs": "Favorites of @%{username}",
+ "Favorites": "Favorites",
+ "You have to log in to favorite messages.": "You have to log in to favorite messages.",
+ "fav_this": "Is it for you only?",
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -697,6 +780,8 @@ if(preferredLanguage == "uk"){
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"btn_ok": "Okay",
"Cancel": "Відміна",
+ 'cant_get_requested_resourse': 'Can\'t get resourse at %{link}\n status: %{status}.',
+ "clear_cache": "Clear cache",
"Confirm": "Confirm",
"сonfirm_group_leaving_header": "Confirm group leaving",
"сonfirm_group_leaving_body": "Are you sure want to leave %{alias} group?",
@@ -706,12 +791,14 @@ if(preferredLanguage == "uk"){
"Чи бажаєте ви перевірити [сторінку зі статусом мережі](%{page})?",
"confirm_terminate_daemon": "Ви впевнені, що бажаєте завершити роботу?\nКлієнт Twister буде зупинено допоки ви не запустите його знову.",
"confirm_unfollow_@": "Are you sure you want to unfollow @%{alias}?",
+ "confirm_uri_shortener_clear_cache": "Are you sure you want to clear browser cache of shortened URIs?",
"Change user": "Змінити користувача",
"Checking...": "Перевірка...", // checking if username is available
"Collapse": "Згорнути", // smaller view of a post
"Configure block generation": "Налаштувати генерацію блоку",
"Connections:": "З’єднання: ", // to network
"Connection lost.": "З’єднання втрачено.",
+ "daemon_is_obsolete": "twister daemon is obsolete, version %{versionReq} or higher is required",
"days": "%{smart_count} день |||| %{smart_count} днів",
"Detailed information": "Детальна інформація",
"DHT network down.": "Мережа DHT недоступна.",
@@ -719,11 +806,16 @@ if(preferredLanguage == "uk"){
"Group Messages": "Group Messages",
"Group Messages — New Group Creation": "Group Messages — New Group Creation",
"Group Messages — Join Group": "Group Messages — Join Group",
+ "group_key_cant_import": "Can\'t import DM group key",
+ "group_key_is_invalid_perhaps": "perhaps the key is invalid",
+ "group_key_was_imported": "Key for DM group %{alias} was imported.\n"
+ + "Its messages will be fetched soon.",
"direct_messages_with": "Direct messages with %{username}",
"Disable": "Вимкнено",
"display_mentions": "Показати сповіщення",
"Display retransmissions": "Показати пересилання",
"DNS to obtain list of peers:": "DNS для отримання пірів:",
+ "do_not_show_it_again": "don't show it again",
"dns address": "адреса DNS",
"downloading_block_chain": "Завантаження ланцюга блоків, будь ласка, зачекайте перед продовженням (ланцюг блоків віком %{days} днів).",
"download_posts_status": "Завантажено %{portion} твістів", // Downloaded 10/30 posts
@@ -828,6 +920,7 @@ if(preferredLanguage == "uk"){
+ "Note: shortening an URL will produce an 'empty' twist on your behalf containing the full URL.\n"
+ "This special twist is not displayed by twister clients, but your twist counter will increase.",
"shorten_URI_its_public_is_it_ok": "Your link will be public available! Are you OK with that?",
+ "URI_shortener": "URI Shortener",
"The File APIs are not fully supported in this browser.": "File APIs не повністю підтримується браузером.",
"time_ago": "%{time} тому", // 5 minutes ago
"Time of the last block:": "Час останнього блоку: ",
@@ -835,7 +928,24 @@ if(preferredLanguage == "uk"){
"Unfollow": "Відписатись",
"Update": "Оновити",
"Auto updating": "Автоматичне оновлення",
+ 'updates_are_available': 'Updates are available',
+ 'updates_not_available': 'No updates are available',
+ 'updates_check_client': 'Check for client\'s updates',
+ 'updates_repo_overview': 'Currently we are on the branch %{branch} of %{repo} at the commit\n %{commit} of %{date}\n'
+ + 'but HEAD of its source is already at the commit\n %{commitUpstream} of %{dateUpstream}.',
+ 'updates_checkout_diff': 'Checkout [the diff on GitHub](%{link}) to learn what is changed.',
+ 'updates_checkout_diff_nfmt': 'Checkout the diff on GitHub to learn what is changed:\n %{link}',
+ 'updates_upstream_isnt_changed': 'A corresponding branch of the source repository seems to have not changed.',
"Updating status...": "Оновлення статусу...", // status of block chain
+ 'new_account_briefing': 'A new account was created and it is being propagated to the network. '
+ + 'Please do not close this window, this might take a few minutes.\n\n'
+ + 'Your secret key is: *%{secretKey}*\n\n'
+ + 'It is highly recommended that you take this time to save your secret key. '
+ + 'Print it, do a screenshot, use the camera in your phone or write it down to a piece of paper.\n\n'
+ + 'The secret key will be needed to use this account from different computers. '
+ + 'If you ever lose your secret key your account will be locked forever '
+ + '(note: ~this is alpha software and it may crash, causing loss of data~).\n\n'
+ + 'Just wait. The OK button will be shown faster you can say ~decentralization~.',
"user_not_yet_accepted": "Триває підтвердження нового користувача.\n" +
"У цей час не можна редагувати профіль та надсилати повідомлення.\n\n" +
"Будь ласка, зачекайте декілька хвилин.\n" +
@@ -992,6 +1102,26 @@ if(preferredLanguage == "uk"){
"Direct Message's copy to self": "Повідомлення скопійовано самому собі",
"Traffic information": "Статистика трафіку",
"Direct messages with": "Співбесіда з",
+ "DHT Torrents:": "DHT Torrents:",
+ "Peers:": "Peers:",
+ "Peer List Size:": "Peer List Size:",
+ "Active Requests:": "Active Requests:",
+ "Download:": "Download:",
+ "Upload:": "Upload:",
+ "DHT Download:": "DHT Download:",
+ "DHT Upload:": "DHT Upload:",
+ "IP Overhead Download:": "IP Overhead Download:",
+ "IP Overhead Upload:": "IP Overhead Upload:",
+ "Payload Download:": "Payload Download:",
+ "Payload Upload:": "Payload Upload:",
+ "No favs here because you are not logged in." : "No favs here because you are not logged in.",
+ "users_favs": "Favorites of @%{username}",
+ "Favorites": "Favorites",
+ "You have to log in to favorite messages.": "You have to log in to favorite messages.",
+ "fav_this": "Is it for you only?",
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -1014,6 +1144,8 @@ if(preferredLanguage == "zh-CN"){
"busted_avowal": "系统检测到此用户试图在这里注入恶意代码",
"btn_ok": "Okay",
"Cancel": "取消",
+ 'cant_get_requested_resourse': 'Can\'t get resourse at %{link}\n status: %{status}.',
+ "clear_cache": "Clear cache",
"Confirm": "Confirm",
"сonfirm_group_leaving_header": "Confirm group leaving",
"сonfirm_group_leaving_body": "Are you sure want to leave %{alias} group?",
@@ -1023,12 +1155,14 @@ if(preferredLanguage == "zh-CN"){
"你要跳转到[网络状态页](%{page})吗?",
"confirm_terminate_daemon": "你确定要退出后台进程?\nTwister 客户端将停止工作。",
"confirm_unfollow_@": "Are you sure you want to unfollow @%{alias}?",
+ "confirm_uri_shortener_clear_cache": "Are you sure you want to clear browser cache of shortened URIs?",
"Change user": "切换用户",
"Checking...": "检查中...", // checking if username is available
"Collapse": "折叠", // smaller view of a post
"Configure block generation": "配置区块生成器",
"Connections:": "连接数:", // to network
"Connection lost.": "连接中断。",
+ "daemon_is_obsolete": "twister daemon is obsolete, version %{versionReq} or higher is required",
"days": "%{smart_count} 天",
"Detailed information": "详细信息",
"DHT network down.": "DHT网络中断。",
@@ -1036,11 +1170,16 @@ if(preferredLanguage == "zh-CN"){
"Group Messages": "Group Messages",
"Group Messages — New Group Creation": "Group Messages — New Group Creation",
"Group Messages — Join Group": "Group Messages — Join Group",
+ "group_key_cant_import": "Can\'t import DM group key",
+ "group_key_is_invalid_perhaps": "perhaps the key is invalid",
+ "group_key_was_imported": "Key for DM group %{alias} was imported.\n"
+ + "Its messages will be fetched soon.",
"direct_messages_with": "Direct messages with %{username}",
"Disable": "关闭",
"display_mentions": "显示",
"Display retransmissions": "显示转发",
"DNS to obtain list of peers:": "用DNS获取节点列表:",
+ "do_not_show_it_again": "don't show it again",
"downloading_block_chain": "区块链下载中,请等待下载完成(区块链仍落后 %{days} 天)。",
"download_posts_status": "已下载 %{portion} 推文", // Downloaded 10/30 posts
"Enable": "开启",
@@ -1144,6 +1283,7 @@ if(preferredLanguage == "zh-CN"){
+ "Note: shortening an URL will produce an 'empty' twist on your behalf containing the full URL.\n"
+ "This special twist is not displayed by twister clients, but your twist counter will increase.",
"shorten_URI_its_public_is_it_ok": "Your link will be public available! Are you OK with that?",
+ "URI_shortener": "URI Shortener",
"The File APIs are not fully supported in this browser.": "这个浏览器不能完全支持 File API。",
"time_ago": "%{time} 之前", // 5 minutes ago
"Time of the last block:": "最新区块的时间:",
@@ -1151,7 +1291,24 @@ if(preferredLanguage == "zh-CN"){
"Unfollow": "取消关注",
"Update": "更新",
"Auto updating": "自动更新",
+ 'updates_are_available': 'Updates are available',
+ 'updates_not_available': 'No updates are available',
+ 'updates_check_client': 'Check for client\'s updates',
+ 'updates_repo_overview': 'Currently we are on the branch %{branch} of %{repo} at the commit\n %{commit} of %{date}\n'
+ + 'but HEAD of its source is already at the commit\n %{commitUpstream} of %{dateUpstream}.',
+ 'updates_checkout_diff': 'Checkout [the diff on GitHub](%{link}) to learn what is changed.',
+ 'updates_checkout_diff_nfmt': 'Checkout the diff on GitHub to learn what is changed:\n %{link}',
+ 'updates_upstream_isnt_changed': 'A corresponding branch of the source repository seems to have not changed.',
"Updating status...": "状态更新中...", // status of block chain
+ 'new_account_briefing': 'A new account was created and it is being propagated to the network. '
+ + 'Please do not close this window, this might take a few minutes.\n\n'
+ + 'Your secret key is: *%{secretKey}*\n\n'
+ + 'It is highly recommended that you take this time to save your secret key. '
+ + 'Print it, do a screenshot, use the camera in your phone or write it down to a piece of paper.\n\n'
+ + 'The secret key will be needed to use this account from different computers. '
+ + 'If you ever lose your secret key your account will be locked forever '
+ + '(note: ~this is alpha software and it may crash, causing loss of data~).\n\n'
+ + 'Just wait. The OK button will be shown faster you can say ~decentralization~.',
"user_not_yet_accepted": "其他节点还没有接受这个新用户。\n" +
"很抱歉,现在你还不能保存你的个人简介\n" +
"或发送新的推文。\n\n" +
@@ -1326,6 +1483,14 @@ if(preferredLanguage == "zh-CN"){
"IP Overhead Upload:": "IP层开销上传:",
"Payload Download:": "有效载荷下载:",
"Payload Upload:": "有效载荷上传:",
+ "No favs here because you are not logged in." : "No favs here because you are not logged in.",
+ "users_favs": "Favorites of @%{username}",
+ "Favorites": "Favorites",
+ "You have to log in to favorite messages.": "You have to log in to favorite messages.",
+ "fav_this": "Is it for you only?",
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -1348,6 +1513,8 @@ if(preferredLanguage == "nl"){
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"btn_ok": "Okay",
"Cancel": "Annuleren",
+ 'cant_get_requested_resourse': 'Can\'t get resourse at %{link}\n status: %{status}.',
+ "clear_cache": "Clear cache",
"Confirm": "Confirm",
"сonfirm_group_leaving_header": "Confirm group leaving",
"сonfirm_group_leaving_body": "Are you sure want to leave %{alias} group?",
@@ -1357,12 +1524,14 @@ if(preferredLanguage == "nl"){
"Do you want to check [Network Status page](%{page}) instead?",
"confirm_terminate_daemon": "Are you sure you want to exit the daemon?\nThe Twister client will stop working.",
"confirm_unfollow_@": "Are you sure you want to unfollow @%{alias}?",
+ "confirm_uri_shortener_clear_cache": "Are you sure you want to clear browser cache of shortened URIs?",
"Change user": "Gebruiker wijzigen",
"Checking...": "Controleren...", // checking if username is available
"Collapse": "Uitklappen", // smaller view of a post
"Configure block generation": "Block productie configureren",
"Connections:": "Connecties: ", // to network
"Connection lost.": "Verbinding kwijt.",
+ "daemon_is_obsolete": "twister daemon is obsolete, version %{versionReq} or higher is required",
"days": "%{smart_count} dag |||| %{smart_count} dagen",
"Detailed information": "Gedetailleerde informatie",
"DHT network down.": "DHT netwerk down.",
@@ -1370,11 +1539,16 @@ if(preferredLanguage == "nl"){
"Group Messages": "Group Messages",
"Group Messages — New Group Creation": "Group Messages — New Group Creation",
"Group Messages — Join Group": "Group Messages — Join Group",
+ "group_key_cant_import": "Can\'t import DM group key",
+ "group_key_is_invalid_perhaps": "perhaps the key is invalid",
+ "group_key_was_imported": "Key for DM group %{alias} was imported.\n"
+ + "Its messages will be fetched soon.",
"direct_messages_with": "Direct messages with %{username}",
"Disable": "Uitschakelen",
"display_mentions": "Toon vermeldingen",
"Display retransmissions": "Toon retransmissions",
"DNS to obtain list of peers:": "DNS om peers lijst op te halen:",
+ "do_not_show_it_again": "don't show it again",
"downloading_block_chain": "Bezig met downloaden block chain, wacht a.u.b. voordat je doorgaat (block chain is %{days} dagen oud).",
"download_posts_status": "%{portion} berichten gedownload", // Downloaded 10/30 posts
"Enable": "Activeren",
@@ -1478,6 +1652,7 @@ if(preferredLanguage == "nl"){
+ "Note: shortening an URL will produce an 'empty' twist on your behalf containing the full URL.\n"
+ "This special twist is not displayed by twister clients, but your twist counter will increase.",
"shorten_URI_its_public_is_it_ok": "Your link will be public available! Are you OK with that?",
+ "URI_shortener": "URI Shortener",
"The File APIs are not fully supported in this browser.": "The File APIs are not fully supported in this browser.",
"time_ago": "%{time} geleden", // 5 minutes ago
"Time of the last block:": "Tijd van de laatste block: ",
@@ -1485,7 +1660,24 @@ if(preferredLanguage == "nl"){
"Unfollow": "Ontvolgen",
"Update": "Update",
"Auto updating": "Auto updating",
+ 'updates_are_available': 'Updates are available',
+ 'updates_not_available': 'No updates are available',
+ 'updates_check_client': 'Check for client\'s updates',
+ 'updates_repo_overview': 'Currently we are on the branch %{branch} of %{repo} at the commit\n %{commit} of %{date}\n'
+ + 'but HEAD of its source is already at the commit\n %{commitUpstream} of %{dateUpstream}.',
+ 'updates_checkout_diff': 'Checkout [the diff on GitHub](%{link}) to learn what is changed.',
+ 'updates_checkout_diff_nfmt': 'Checkout the diff on GitHub to learn what is changed:\n %{link}',
+ 'updates_upstream_isnt_changed': 'A corresponding branch of the source repository seems to have not changed.',
"Updating status...": "Status aan het updaten...", // status of block chain
+ 'new_account_briefing': 'A new account was created and it is being propagated to the network. '
+ + 'Please do not close this window, this might take a few minutes.\n\n'
+ + 'Your secret key is: *%{secretKey}*\n\n'
+ + 'It is highly recommended that you take this time to save your secret key. '
+ + 'Print it, do a screenshot, use the camera in your phone or write it down to a piece of paper.\n\n'
+ + 'The secret key will be needed to use this account from different computers. '
+ + 'If you ever lose your secret key your account will be locked forever '
+ + '(note: ~this is alpha software and it may crash, causing loss of data~).\n\n'
+ + 'Just wait. The OK button will be shown faster you can say ~decentralization~.',
"user_not_yet_accepted": "Other peers have not yet accepted this new user.\n" +
"Unfortunately it is not possible to save profile\n" +
"or send any posts in this state.\n\n" +
@@ -1644,6 +1836,27 @@ if(preferredLanguage == "nl"){
"Sound": "Sound",
"Users": "Users",
"Direct Message's copy to self": "Direct Message's copy to self",
+ "Traffic information": "Traffic information",
+ "DHT Torrents:": "DHT Torrents:",
+ "Peers:": "Peers:",
+ "Peer List Size:": "Peer List Size:",
+ "Active Requests:": "Active Requests:",
+ "Download:": "Download:",
+ "Upload:": "Upload:",
+ "DHT Download:": "DHT Download:",
+ "DHT Upload:": "DHT Upload:",
+ "IP Overhead Download:": "IP Overhead Download:",
+ "IP Overhead Upload:": "IP Overhead Upload:",
+ "Payload Download:": "Payload Download:",
+ "Payload Upload:": "Payload Upload:",
+ "No favs here because you are not logged in." : "No favs here because you are not logged in.",
+ "users_favs": "Favorites of @%{username}",
+ "Favorites": "Favorites",
+ "You have to log in to favorite messages.": "You have to log in to favorite messages.",
+ "fav_this": "Is it for you only?",
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -1666,6 +1879,8 @@ if(preferredLanguage == "it"){
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"btn_ok": "Okay",
"Cancel": "Cancella",
+ 'cant_get_requested_resourse': 'Can\'t get resourse at %{link}\n status: %{status}.',
+ "clear_cache": "Clear cache",
"Confirm": "Confirm",
"сonfirm_group_leaving_header": "Confirm group leaving",
"сonfirm_group_leaving_body": "Are you sure want to leave %{alias} group?",
@@ -1675,12 +1890,14 @@ if(preferredLanguage == "it"){
"Vuoi controllare lo [stato della rete Twister](%{page}), invece?",
"confirm_terminate_daemon": "Are you sure you want to exit the daemon?\nThe Twister client will stop working.",
"confirm_unfollow_@": "Are you sure you want to unfollow @%{alias}?",
+ "confirm_uri_shortener_clear_cache": "Are you sure you want to clear browser cache of shortened URIs?",
"Change user": "Cambia utente",
"Checking...": "Controllo in corso...", // checking if username is available
"Collapse": "Chiudi", // smaller view of a post
"Configure block generation": "Configura generatore di blocchi",
"Connections:": "Connessioni: ", // to network
"Connection lost.": "Connessione interrotta.",
+ "daemon_is_obsolete": "twister daemon is obsolete, version %{versionReq} or higher is required",
"days": "%{smart_count} giorno |||| %{smart_count} giorni",
"Detailed information": "Informazioni dettagliate",
"DHT network down.": "DHT network inaccessibile.",
@@ -1688,11 +1905,16 @@ if(preferredLanguage == "it"){
"Group Messages": "Group Messages",
"Group Messages — New Group Creation": "Group Messages — New Group Creation",
"Group Messages — Join Group": "Group Messages — Join Group",
+ "group_key_cant_import": "Can\'t import DM group key",
+ "group_key_is_invalid_perhaps": "perhaps the key is invalid",
+ "group_key_was_imported": "Key for DM group %{alias} was imported.\n"
+ + "Its messages will be fetched soon.",
"direct_messages_with": "Messaggi Diretti come %{username}",
"Disable": "Disabilitato",
"display_mentions": "Mostra le menzioni",
"Display retransmissions": "Mostra Ripubblicazioni",
"DNS to obtain list of peers:": "DNS per la lista dei nodi:",
+ "do_not_show_it_again": "don't show it again",
"downloading_block_chain": "Scaricamento della catena di blocchi in corso, attendere prego (la catena risale a %{days} giorni fa).",
"download_posts_status": "Scaricati %{portion} messaggi", // Downloaded 10/30 posts
"Enable": "Attivato",
@@ -1796,6 +2018,7 @@ if(preferredLanguage == "it"){
+ "Note: shortening an URL will produce an 'empty' twist on your behalf containing the full URL.\n"
+ "This special twist is not displayed by twister clients, but your twist counter will increase.",
"shorten_URI_its_public_is_it_ok": "Your link will be public available! Are you OK with that?",
+ "URI_shortener": "URI Shortener",
"The File APIs are not fully supported in this browser.": "Le API File non sono interamente supportate da questo browser.",
"time_ago": "%{time} fa", // 5 minutes ago
"Time of the last block:": "Orario del blocco più recente: ",
@@ -1803,7 +2026,24 @@ if(preferredLanguage == "it"){
"Unfollow": "Smetti di seguire",
"Update": "Aggiorna",
"Auto updating": "Auto updating",
+ 'updates_are_available': 'Updates are available',
+ 'updates_not_available': 'No updates are available',
+ 'updates_check_client': 'Check for client\'s updates',
+ 'updates_repo_overview': 'Currently we are on the branch %{branch} of %{repo} at the commit\n %{commit} of %{date}\n'
+ + 'but HEAD of its source is already at the commit\n %{commitUpstream} of %{dateUpstream}.',
+ 'updates_checkout_diff': 'Checkout [the diff on GitHub](%{link}) to learn what is changed.',
+ 'updates_checkout_diff_nfmt': 'Checkout the diff on GitHub to learn what is changed:\n %{link}',
+ 'updates_upstream_isnt_changed': 'A corresponding branch of the source repository seems to have not changed.',
"Updating status...": "Aggiornamento in corso...", // status of block chain
+ 'new_account_briefing': 'A new account was created and it is being propagated to the network. '
+ + 'Please do not close this window, this might take a few minutes.\n\n'
+ + 'Your secret key is: *%{secretKey}*\n\n'
+ + 'It is highly recommended that you take this time to save your secret key. '
+ + 'Print it, do a screenshot, use the camera in your phone or write it down to a piece of paper.\n\n'
+ + 'The secret key will be needed to use this account from different computers. '
+ + 'If you ever lose your secret key your account will be locked forever '
+ + '(note: ~this is alpha software and it may crash, causing loss of data~).\n\n'
+ + 'Just wait. The OK button will be shown faster you can say ~decentralization~.',
"user_not_yet_accepted": "Gli altri nodi non hanno ancora accettato il nuovo utente.\n" +
"Al momento non puoi salvare il profilo o spedire messaggi.\n" +
"Attendi qualche minuto prima di continuare.\n\n" +
@@ -1960,6 +2200,27 @@ if(preferredLanguage == "it"){
"Sound": "Sound",
"Users": "Users",
"Direct Message's copy to self": "Direct Message's copy to self",
+ "Traffic information": "Traffic information",
+ "DHT Torrents:": "DHT Torrents:",
+ "Peers:": "Peers:",
+ "Peer List Size:": "Peer List Size:",
+ "Active Requests:": "Active Requests:",
+ "Download:": "Download:",
+ "Upload:": "Upload:",
+ "DHT Download:": "DHT Download:",
+ "DHT Upload:": "DHT Upload:",
+ "IP Overhead Download:": "IP Overhead Download:",
+ "IP Overhead Upload:": "IP Overhead Upload:",
+ "Payload Download:": "Payload Download:",
+ "Payload Upload:": "Payload Upload:",
+ "No favs here because you are not logged in." : "No favs here because you are not logged in.",
+ "users_favs": "Favorites of @%{username}",
+ "Favorites": "Favorites",
+ "You have to log in to favorite messages.": "You have to log in to favorite messages.",
+ "fav_this": "Is it for you only?",
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -1982,6 +2243,8 @@ if(preferredLanguage == "fr"){
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"btn_ok": "Okay",
"Cancel": "Annuler",
+ 'cant_get_requested_resourse': 'Can\'t get resourse at %{link}\n status: %{status}.',
+ "clear_cache": "Clear cache",
"Confirm": "Confirm",
"сonfirm_group_leaving_header": "Confirm group leaving",
"сonfirm_group_leaving_body": "Are you sure want to leave %{alias} group?",
@@ -1991,12 +2254,14 @@ if(preferredLanguage == "fr"){
"Voulez-vous consulter la [page d'état du réseau](%{page}) à la place?",
"confirm_terminate_daemon": "Are you sure you want to exit the daemon?\nThe Twister client will stop working.",
"confirm_unfollow_@": "Are you sure you want to unfollow @%{alias}?",
+ "confirm_uri_shortener_clear_cache": "Are you sure you want to clear browser cache of shortened URIs?",
"Change user": "Changer d'utilisateur",
"Checking...": "Vérification...", // checking if username is available
"Collapse": "Fermer", // smaller view of a post
"Configure block generation": "Configuration de la production de blocs",
"Connections:": "Connexions: ", // to network
"Connection lost.": "Connexion perdue.",
+ "daemon_is_obsolete": "twister daemon is obsolete, version %{versionReq} or higher is required",
"days": "%{smart_count} jour |||| %{smart_count} jours",
"Detailed information": "Informations détaillées",
"DHT network down.": "Panne du réseau DHT.",
@@ -2004,11 +2269,16 @@ if(preferredLanguage == "fr"){
"Group Messages": "Group Messages",
"Group Messages — New Group Creation": "Group Messages — New Group Creation",
"Group Messages — Join Group": "Group Messages — Join Group",
+ "group_key_cant_import": "Can\'t import DM group key",
+ "group_key_is_invalid_perhaps": "perhaps the key is invalid",
+ "group_key_was_imported": "Key for DM group %{alias} was imported.\n"
+ + "Its messages will be fetched soon.",
"direct_messages_with": "Messages privés avec %{username}",
"Disable": "Désactiver",
"display_mentions": "Afficher les mentions",
"Display retransmissions": "Afficher les retransmissions",
"DNS to obtain list of peers:": "DNS où obtenir une liste des pairs:",
+ "do_not_show_it_again": "don't show it again",
"downloading_block_chain": "Téléchargement de la chaîne de blocs, veuillez patienter avant de continuer (la chaîne de blocs a %{days} jours de retard).",
"download_posts_status": "%{portion} billets téléchargés", // Downloaded 10/30 posts
"Enable": "Activer",
@@ -2112,6 +2382,7 @@ if(preferredLanguage == "fr"){
+ "Note: shortening an URL will produce an 'empty' twist on your behalf containing the full URL.\n"
+ "This special twist is not displayed by twister clients, but your twist counter will increase.",
"shorten_URI_its_public_is_it_ok": "Your link will be public available! Are you OK with that?",
+ "URI_shortener": "URI Shortener",
"The File APIs are not fully supported in this browser.": "L'API de fichier n'est pas entièrement pris en charge dans votre navigateur.",
"time_ago": "Il y a %{time}", // 5 minutes ago
"Time of the last block:": "Heure du dernier bloc: ",
@@ -2119,7 +2390,24 @@ if(preferredLanguage == "fr"){
"Unfollow": "Se désabonner",
"Update": "Mettre à jour",
"Auto updating": "Mise à jour automatique",
+ 'updates_are_available': 'Updates are available',
+ 'updates_not_available': 'No updates are available',
+ 'updates_check_client': 'Check for client\'s updates',
+ 'updates_repo_overview': 'Currently we are on the branch %{branch} of %{repo} at the commit\n %{commit} of %{date}\n'
+ + 'but HEAD of its source is already at the commit\n %{commitUpstream} of %{dateUpstream}.',
+ 'updates_checkout_diff': 'Checkout [the diff on GitHub](%{link}) to learn what is changed.',
+ 'updates_checkout_diff_nfmt': 'Checkout the diff on GitHub to learn what is changed:\n %{link}',
+ 'updates_upstream_isnt_changed': 'A corresponding branch of the source repository seems to have not changed.',
"Updating status...": "Mise à jour du statut...", // status of block chain
+ 'new_account_briefing': 'A new account was created and it is being propagated to the network. '
+ + 'Please do not close this window, this might take a few minutes.\n\n'
+ + 'Your secret key is: *%{secretKey}*\n\n'
+ + 'It is highly recommended that you take this time to save your secret key. '
+ + 'Print it, do a screenshot, use the camera in your phone or write it down to a piece of paper.\n\n'
+ + 'The secret key will be needed to use this account from different computers. '
+ + 'If you ever lose your secret key your account will be locked forever '
+ + '(note: ~this is alpha software and it may crash, causing loss of data~).\n\n'
+ + 'Just wait. The OK button will be shown faster you can say ~decentralization~.',
"user_not_yet_accepted": "Les autres pairs n'ont pas encore accepté ce nouvel utilisateur.\n" +
"Malheureusement, il n'est pas possible d'enregistrer le profil\n" +
"ou envoyer des billets pour le moment.\n\n" +
@@ -2278,6 +2566,26 @@ if(preferredLanguage == "fr"){
"Sound": "Sound",
"Users": "Users",
"Direct Message's copy to self": "Direct Message's copy to self",
+ "Traffic information": "Traffic information",
+ "DHT Torrents:": "DHT Torrents:",
+ "Peers:": "Peers:",
+ "Peer List Size:": "Peer List Size:",
+ "Active Requests:": "Active Requests:",
+ "Download:": "Download:",
+ "Upload:": "Upload:",
+ "DHT Download:": "DHT Download:",
+ "DHT Upload:": "DHT Upload:",
+ "IP Overhead Download:": "IP Overhead Download:",
+ "IP Overhead Upload:": "IP Overhead Upload:",
+ "Payload Download:": "Payload Download:",
+ "Payload Upload:": "Payload Upload:",
+ "No favs here because you are not logged in." : "No favs here because you are not logged in.",
+ "users_favs": "Favorites of @%{username}",
+ "Favorites": "Favorites",
+ "You have to log in to favorite messages.": "You have to log in to favorite messages.",
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -2302,6 +2610,8 @@ if(preferredLanguage == "ru"){
"busted_avowal": "я пойман на попытке вставить этот подозрительный код здесь",
"btn_ok": "Лады́",
"Cancel": "Отмена",
+ 'cant_get_requested_resourse': 'Невозможно получить %{link}\n статус: %{status}.',
+ "clear_cache": "Очистить кэш",
"Confirm": "Несомненно",
"сonfirm_group_leaving_header": "Подтверждение ухода из группы",
"сonfirm_group_leaving_body": "Воистину покинуть группу %{alias}?",
@@ -2311,12 +2621,14 @@ if(preferredLanguage == "ru"){
"Не хотите перейти на [страницу настройки сети](%{page})?",
"confirm_terminate_daemon": "Вы уверены, что хотите выключить демон?\nTwister клиент перестанет работать.",
"confirm_unfollow_@": "Действительно отписаться от @%{alias}?",
+ "confirm_uri_shortener_clear_cache": "В самом деле очистить кэш сокращённых URI в браузере?",
"Change user": "Сменить пользователя",
"Checking...": "Проверка...",
"Collapse": "Свернуть",
"Configure block generation": "Настройка майнинга",
"Connections:": "Соединений: ",
"Connection lost.": "Соединение с сетью было потеряно.",
+ "daemon_is_obsolete": "твистер демон устарел, необходима версия %{versionReq} или выше",
"days": "%{smart_count} день |||| %{smart_count} дней",
"Detailed information": "Подробная информация",
"DHT network down.": "Недоступна DHT сеть.",
@@ -2324,11 +2636,16 @@ if(preferredLanguage == "ru"){
"Group Messages": "Групповые сообщения",
"Group Messages — New Group Creation": "Групповые сообщения — Создать новую группу",
"Group Messages — Join Group": "Групповые сообщения — Присоединиться к группе",
+ "group_key_cant_import": "невозможно импортировать ключ ЛС группы",
+ "group_key_is_invalid_perhaps": "возможно, неправильный ключ",
+ "group_key_was_imported": "Ключ для ЛС группы %{alias} импортирован.\n"
+ + "Её сообщения будут подгружены в скором времени.",
"direct_messages_with": "Личная переписка с %{username}",
"Disable": "Отключено",
"display_mentions": "Показать упоминания",
"Display retransmissions": "Показать репосты",
"DNS to obtain list of peers:": "DNS адрес для получения пиров:",
+ "do_not_show_it_again": "не показывать больше",
"downloading_block_chain": "Загрузка цепочки блоков, пожалуйста подождите, (Цепочка блоков устарела на %{days} дней).",
"download_posts_status": "Загружено %{portion} постов", // Downloaded 10/30 posts
"Enable": "Включено",
@@ -2432,6 +2749,7 @@ if(preferredLanguage == "ru"){
+ "Примечание: в результате сокращения URL получается 'пустой' твист, содержащий эту URL.\n"
+ "Этот особый твист не отображается клиентами твистера, но учитывается в числе твоих твистов.",
"shorten_URI_its_public_is_it_ok": "Ссылка будет общедоступной! Это приемлимо для тебя?",
+ "URI_shortener": "Сокращалка URI",
"The File APIs are not fully supported in this browser.": "File APIs не полностью поддерживается этим браузером.",
"time_ago": "%{time} назад", // 5 minutes ago
"Time of the last block:": "Время последнего блока: ",
@@ -2439,7 +2757,24 @@ if(preferredLanguage == "ru"){
"Unfollow": "Отписаться",
"Update": "Обновить",
"Auto updating": "Автоматическое обновление",
+ 'updates_are_available': 'Доступны обновления',
+ 'updates_not_available': 'Обновления не доступны',
+ 'updates_check_client': 'Проверить обновления клиента',
+ 'updates_repo_overview': 'Мы сейчас на ветке %{branch} в %{repo} на коммите\n %{commit} от %{date},\n'
+ + 'а вот HEAD её источника уже на коммите\n %{commitUpstream} от %{dateUpstream}.',
+ 'updates_checkout_diff': 'Смотри [сравнение на GitHub](%{link}), чтобы узнать каковы изменения.',
+ 'updates_checkout_diff_nfmt': 'Смотри сравнение на GitHub, чтобы узнать каковы изменения:\n %{link}',
+ 'updates_upstream_isnt_changed': 'Соответствующая ветка в исходном репозитории выглядит неизменённой.',
"Updating status...": "Обновление информации...", // status of block chain
+ 'new_account_briefing': 'Новая учётная запись создана и сейчас распространяется по сети. '
+ + 'Пожалуйста, не закрывай это окно: это может занять несколько минут.\n\n'
+ + 'Твой секретный ключ: *%{secretKey}*\n\n'
+ + 'Настоятельно рекомендуется провести время ожидания, сохраняя этот ключ. '
+ + 'Распечатай его, сделай скриншот, сфотографируй телефоном или перепиши на бумагу.\n\n'
+ + 'Секретный ключ будет необходим для использования на разных устройствах. '
+ + 'В случае его утери учётная запись окажется недосягаемой навсегда '
+ + '(заметь: ~это альфа-версия и возможны сбои, приводящие к утере данных~).\n\n'
+ + 'Подожди. Кнопка OK станет доступна быстрее, чем ты произнесёшь ~децентрализация~.',
"user_not_yet_accepted": "Другие участники сети еще не получили информацию о новом пользователе.\n" +
"К сожалению, сейчас вы не можете редактировать ваш профиль\n" +
"или отправлять сообщение.\n\n" +
@@ -2602,6 +2937,27 @@ if(preferredLanguage == "ru"){
"New post": "Новый пост",
"Search": "Поиск",
"Direct Msg": "ЛС",
+ "Traffic information": "Traffic information",
+ "DHT Torrents:": "DHT Torrents:",
+ "Peers:": "Peers:",
+ "Peer List Size:": "Peer List Size:",
+ "Active Requests:": "Active Requests:",
+ "Download:": "Download:",
+ "Upload:": "Upload:",
+ "DHT Download:": "DHT Download:",
+ "DHT Upload:": "DHT Upload:",
+ "IP Overhead Download:": "IP Overhead Download:",
+ "IP Overhead Upload:": "IP Overhead Upload:",
+ "Payload Download:": "Payload Download:",
+ "Payload Upload:": "Payload Upload:",
+ "No favs here because you are not logged in." : "No favs here because you are not logged in.",
+ "users_favs": "Favorites of @%{username}",
+ "Favorites": "Favorites",
+ "You have to log in to favorite messages.": "You have to log in to favorite messages.",
+ "fav_this": "Is it for you only?",
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -2624,6 +2980,8 @@ if(preferredLanguage == "de"){
"busted_avowal": "Ich bin ertappt, habe versucht, hier Schadcode einzugeben!",
"btn_ok": "Okay",
"Cancel": "Abbrechen",
+ 'cant_get_requested_resourse': 'Can\'t get resourse at %{link}\n status: %{status}.',
+ "clear_cache": "Clear cache",
"Confirm": "Confirm",
"сonfirm_group_leaving_header": "Confirm group leaving",
"сonfirm_group_leaving_body": "Are you sure want to leave %{alias} group?",
@@ -2633,12 +2991,14 @@ if(preferredLanguage == "de"){
"Möchtest du stattdessen den [Netzwerkstatus](%{page}) überprüfen?",
"confirm_terminate_daemon": "Are you sure you want to exit the daemon?\nThe Twister client will stop working.",
"confirm_unfollow_@": "Are you sure you want to unfollow @%{alias}?",
+ "confirm_uri_shortener_clear_cache": "Are you sure you want to clear browser cache of shortened URIs?",
"Change user": "Benutzer wechseln",
"Checking...": "Überprüfe...", // checking if username is available
"Collapse": "Einklappen", // smaller view of a post
"Configure block generation": "Block-Generierung einstellen",
"Connections:": "Verbindungen: ", // to network
"Connection lost.": "Verbindung verloren.",
+ "daemon_is_obsolete": "twister daemon is obsolete, version %{versionReq} or higher is required",
"days": "%{smart_count} Tag |||| %{smart_count} Tage",
"Detailed information": "Detaillierte Informationen",
"DHT network down.": "DHT-Netzwerk nicht verfügbar.",
@@ -2646,11 +3006,16 @@ if(preferredLanguage == "de"){
"Group Messages": "Gruppennachrichten",
"Group Messages — New Group Creation": "Gruppennachrichten — Neue Gruppe erstellen",
"Group Messages — Join Group": "Gruppennachrichten — Gruppe beitreten",
+ "group_key_cant_import": "Can\'t import DM group key",
+ "group_key_is_invalid_perhaps": "perhaps the key is invalid",
+ "group_key_was_imported": "Key for DM group %{alias} was imported.\n"
+ + "Its messages will be fetched soon.",
"direct_messages_with": "Direktnachrichten mit %{username}",
"Disable": "Deaktivieren",
"display_mentions": "Zeige Erwähnungen", // Ist das richtig? Ich weiß nicht, in welchem Zusammenhang das benutzt wird.
"Display retransmissions": "Weiterleitungen anzeigen",
"DNS to obtain list of peers:": "DNS um Peer-Liste abzurufen:",
+ "do_not_show_it_again": "don't show it again",
"dns address": "DNS-Adresse",
"downloading_block_chain": "Block-Chain wird heruntergeladen, bitte warten (Block-Chain ist %{days} Tage alt).",
"download_posts_status": "%{portion} Posts heruntergeladen", // Downloaded 10/30 posts
@@ -2702,7 +3067,7 @@ if(preferredLanguage == "de"){
"in postboard": "in der Timeline",
"in search result": "in den Suchergebnissen",
"in top trends": "in den Top Trends",
- "new_posts": "%{smart_count} neuer Post |||| %{smart_count} neue Posts",
+ "new_posts": "%{smart_count} neuer Post |||| %{smart_count} neue Posts", /* FIXME: duplicate */
"new_mentions": "%{smart_count} neue Erwähnung |||| %{smart_count} neue Erwähnungen",
"new_direct_messages": "%{smart_count} neue Direktnachricht |||| %{smart_count} neue Direktnachrichten",
"new_group_messages": "%{smart_count} neue Gruppen-Nachricht |||| %{smart_count} neue Gruppen-Nachrichten",
@@ -2755,6 +3120,7 @@ if(preferredLanguage == "de"){
+ "Note: shortening an URL will produce an 'empty' twist on your behalf containing the full URL.\n"
+ "This special twist is not displayed by twister clients, but your twist counter will increase.",
"shorten_URI_its_public_is_it_ok": "Your link will be public available! Are you OK with that?",
+ "URI_shortener": "URI Shortener",
"The File APIs are not fully supported in this browser.": "Die File-API's werden von diesem Browser nicht vollständig unterstützt.",
"time_ago": "vor %{time}", // 5 minutes ago
"Time of the last block:": "Zeit des letzten Blocks: ",
@@ -2762,7 +3128,24 @@ if(preferredLanguage == "de"){
"Unfollow": "Nicht mehr folgen",
"Update": "Aktualisieren",
"Auto updating": "Automatische Aktualisierung",
+ 'updates_are_available': 'Updates are available',
+ 'updates_not_available': 'No updates are available',
+ 'updates_check_client': 'Check for client\'s updates',
+ 'updates_repo_overview': 'Currently we are on the branch %{branch} of %{repo} at the commit\n %{commit} of %{date}\n'
+ + 'but HEAD of its source is already at the commit\n %{commitUpstream} of %{dateUpstream}.',
+ 'updates_checkout_diff': 'Checkout [the diff on GitHub](%{link}) to learn what is changed.',
+ 'updates_checkout_diff_nfmt': 'Checkout the diff on GitHub to learn what is changed:\n %{link}',
+ 'updates_upstream_isnt_changed': 'A corresponding branch of the source repository seems to have not changed.',
"Updating status...": "Status wird aktualisiert...", // status of block chain
+ 'new_account_briefing': 'A new account was created and it is being propagated to the network. '
+ + 'Please do not close this window, this might take a few minutes.\n\n'
+ + 'Your secret key is: *%{secretKey}*\n\n'
+ + 'It is highly recommended that you take this time to save your secret key. '
+ + 'Print it, do a screenshot, use the camera in your phone or write it down to a piece of paper.\n\n'
+ + 'The secret key will be needed to use this account from different computers. '
+ + 'If you ever lose your secret key your account will be locked forever '
+ + '(note: ~this is alpha software and it may crash, causing loss of data~).\n\n'
+ + 'Just wait. The OK button will be shown faster you can say ~decentralization~.',
"user_not_yet_accepted": "Andere Peers haben diesen Benutzter noch nicht akzeptiert.\n" +
"Leider ist es nicht möglich, das Profil zu speichern\n" +
"oder Nachrichten zu senden.\n\n" +
@@ -2813,7 +3196,7 @@ if(preferredLanguage == "de"){
"Options": "Einstellungen",
"Switch to Promoted posts": "Wechsle zu Promoted Nachrichten",
"Switch to Normal posts": "Switch to Normal posts",
- "new_posts": "%{smart_count} neue Nachricht |||| %{smart_count} neue Nachrichten",
+ "new_posts": "%{smart_count} neue Nachricht |||| %{smart_count} neue Nachrichten", /* FIXME: duplicate */
"Use language": "Sprache einstellen",
"Ignore": "Ignorieren",
"Ignore and clear out": "Ignore and clear out",
@@ -2922,6 +3305,27 @@ if(preferredLanguage == "de"){
"Sound": "Sound",
"Users": "Users",
"Direct Message's copy to self": "Kopie der Direktnachricht an mich selbst",
+ "Traffic information": "Traffic information",
+ "DHT Torrents:": "DHT Torrents:",
+ "Peers:": "Peers:",
+ "Peer List Size:": "Peer List Size:",
+ "Active Requests:": "Active Requests:",
+ "Download:": "Download:",
+ "Upload:": "Upload:",
+ "DHT Download:": "DHT Download:",
+ "DHT Upload:": "DHT Upload:",
+ "IP Overhead Download:": "IP Overhead Download:",
+ "IP Overhead Upload:": "IP Overhead Upload:",
+ "Payload Download:": "Payload Download:",
+ "Payload Upload:": "Payload Upload:",
+ "No favs here because you are not logged in." : "No favs here because you are not logged in.",
+ "users_favs": "Favorites of @%{username}",
+ "Favorites": "Favorites",
+ "You have to log in to favorite messages.": "You have to log in to favorite messages.",
+ "fav_this": "Is it for you only?",
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -2944,6 +3348,8 @@ if(preferredLanguage == "ja"){
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"btn_ok": "Okay",
"Cancel": "キャンセル",
+ 'cant_get_requested_resourse': 'Can\'t get resourse at %{link}\n status: %{status}.',
+ "clear_cache": "Clear cache",
"Confirm": "Confirm",
"сonfirm_group_leaving_header": "Confirm group leaving",
"сonfirm_group_leaving_body": "Are you sure want to leave %{alias} group?",
@@ -2953,12 +3359,14 @@ if(preferredLanguage == "ja"){
"[ネットワーク状態ペー](%{page})ジへ移動して確認しますか?",
"confirm_terminate_daemon": "Are you sure you want to exit the daemon?\nThe Twister client will stop working.",
"confirm_unfollow_@": "Are you sure you want to unfollow @%{alias}?",
+ "confirm_uri_shortener_clear_cache": "Are you sure you want to clear browser cache of shortened URIs?",
"Change user": "ユーザーを変更",
"Checking...": "チェック...", // checking if username is available
"Collapse": "閉じる", // smaller view of a post
"Configure block generation": "ブロック生成の設定",
"Connections:": "接続数: ", // to network
"Connection lost.": "切断されました。",
+ "daemon_is_obsolete": "twister daemon is obsolete, version %{versionReq} or higher is required",
"days": "%{smart_count}日 |||| %{smart_count}日",
"Detailed information": "詳細",
"DHT network down.": "DHTネットワークがダウンしています",
@@ -2966,11 +3374,16 @@ if(preferredLanguage == "ja"){
"Group Messages": "Group Messages",
"Group Messages — New Group Creation": "Group Messages — New Group Creation",
"Group Messages — Join Group": "Group Messages — Join Group",
+ "group_key_cant_import": "Can\'t import DM group key",
+ "group_key_is_invalid_perhaps": "perhaps the key is invalid",
+ "group_key_was_imported": "Key for DM group %{alias} was imported.\n"
+ + "Its messages will be fetched soon.",
"direct_messages_with": "Direct messages with %{username}",
"Disable": "停止",
"display_mentions": "メンションを表示する",
"Display retransmissions": "リトランスミットを表示する",
"DNS to obtain list of peers:": "ピア取得用のDNS:",
+ "do_not_show_it_again": "don't show it again",
"downloading_block_chain": "ブロックチェインをダウンロードしています。しばらくお待ちください。(ブロックチェーンは%{days}日送れています)",
"download_posts_status": "ダウンロード済みの投稿 %{portion}", // Downloaded 10/30 posts
"Enable": "有効",
@@ -3074,6 +3487,7 @@ if(preferredLanguage == "ja"){
+ "Note: shortening an URL will produce an 'empty' twist on your behalf containing the full URL.\n"
+ "This special twist is not displayed by twister clients, but your twist counter will increase.",
"shorten_URI_its_public_is_it_ok": "Your link will be public available! Are you OK with that?",
+ "URI_shortener": "URI Shortener",
"The File APIs are not fully supported in this browser.": "ご使用のブラウザーは完全にファイルAPIに対応していません。",
"time_ago": "%{time}前", // 5 minutes ago
"Time of the last block:": "最新ブロックの生成日時: ",
@@ -3081,7 +3495,24 @@ if(preferredLanguage == "ja"){
"Unfollow": "解除",
"Update": "アップデート",
"Auto updating": "Auto updating",
+ 'updates_are_available': 'Updates are available',
+ 'updates_not_available': 'No updates are available',
+ 'updates_check_client': 'Check for client\'s updates',
+ 'updates_repo_overview': 'Currently we are on the branch %{branch} of %{repo} at the commit\n %{commit} of %{date}\n'
+ + 'but HEAD of its source is already at the commit\n %{commitUpstream} of %{dateUpstream}.',
+ 'updates_checkout_diff': 'Checkout [the diff on GitHub](%{link}) to learn what is changed.',
+ 'updates_checkout_diff_nfmt': 'Checkout the diff on GitHub to learn what is changed:\n %{link}',
+ 'updates_upstream_isnt_changed': 'A corresponding branch of the source repository seems to have not changed.',
"Updating status...": "ブロックチェーンを更新中…", // status of block chain
+ 'new_account_briefing': 'A new account was created and it is being propagated to the network. '
+ + 'Please do not close this window, this might take a few minutes.\n\n'
+ + 'Your secret key is: *%{secretKey}*\n\n'
+ + 'It is highly recommended that you take this time to save your secret key. '
+ + 'Print it, do a screenshot, use the camera in your phone or write it down to a piece of paper.\n\n'
+ + 'The secret key will be needed to use this account from different computers. '
+ + 'If you ever lose your secret key your account will be locked forever '
+ + '(note: ~this is alpha software and it may crash, causing loss of data~).\n\n'
+ + 'Just wait. The OK button will be shown faster you can say ~decentralization~.',
"user_not_yet_accepted": "この新ユーザーが他のピアーにまだ認証されていない。\n" +
"なので、プロファイルの保存やメッセージの投稿は現在不可能です。\n" +
"しばらくしてから続行してください。\n\n" +
@@ -3237,6 +3668,27 @@ if(preferredLanguage == "ja"){
"Sound": "Sound",
"Users": "Users",
"Direct Message's copy to self": "Direct Message's copy to self",
+ "Traffic information": "Traffic information",
+ "DHT Torrents:": "DHT Torrents:",
+ "Peers:": "Peers:",
+ "Peer List Size:": "Peer List Size:",
+ "Active Requests:": "Active Requests:",
+ "Download:": "Download:",
+ "Upload:": "Upload:",
+ "DHT Download:": "DHT Download:",
+ "DHT Upload:": "DHT Upload:",
+ "IP Overhead Download:": "IP Overhead Download:",
+ "IP Overhead Upload:": "IP Overhead Upload:",
+ "Payload Download:": "Payload Download:",
+ "Payload Upload:": "Payload Upload:",
+ "No favs here because you are not logged in." : "No favs here because you are not logged in.",
+ "users_favs": "Favorites of @%{username}",
+ "Favorites": "Favorites",
+ "You have to log in to favorite messages.": "You have to log in to favorite messages.",
+ "fav_this": "Is it for you only?",
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -3260,6 +3712,8 @@ if(preferredLanguage == "pt-BR"){
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"btn_ok": "Okay",
"Cancel": "Cancelar",
+ 'cant_get_requested_resourse': 'Can\'t get resourse at %{link}\n status: %{status}.',
+ "clear_cache": "Clear cache",
"Confirm": "Confirm",
"сonfirm_group_leaving_header": "Confirm group leaving",
"сonfirm_group_leaving_body": "Are you sure want to leave %{alias} group?",
@@ -3269,12 +3723,14 @@ if(preferredLanguage == "pt-BR"){
"Gostaria de verificar o [Estado da Rede](%{page}) ao invés disso?",
"confirm_terminate_daemon": "Are you sure you want to exit the daemon?\nThe Twister client will stop working.",
"confirm_unfollow_@": "Are you sure you want to unfollow @%{alias}?",
+ "confirm_uri_shortener_clear_cache": "Are you sure you want to clear browser cache of shortened URIs?",
"Change user": "Trocar usuário",
"Checking...": "Verificando...", // checking if username is available
"Collapse": "Recolher", // smaller view of a post
"Configure block generation": "Configurar a geração de blocos",
"Connections:": "Conexões: ", // to network
"Connection lost.": "Conexão perdida.",
+ "daemon_is_obsolete": "twister daemon is obsolete, version %{versionReq} or higher is required",
"days": "%{smart_count} dia |||| %{smart_count} dias",
"Detailed information": "Informações detalhadas",
"DHT network down.": "Falha na rede DHT",
@@ -3282,11 +3738,16 @@ if(preferredLanguage == "pt-BR"){
"Group Messages": "Group Messages",
"Group Messages — New Group Creation": "Group Messages — New Group Creation",
"Group Messages — Join Group": "Group Messages — Join Group",
+ "group_key_cant_import": "Can\'t import DM group key",
+ "group_key_is_invalid_perhaps": "perhaps the key is invalid",
+ "group_key_was_imported": "Key for DM group %{alias} was imported.\n"
+ + "Its messages will be fetched soon.",
"direct_messages_with": "Mensagens Diretas com %{username}",
"Disable": "Desabilitado",
"display_mentions": "Exibir menções",
"Display retransmissions": "Exibir retransmissões",
"DNS to obtain list of peers:": "DNS para obter a lista de nós:",
+ "do_not_show_it_again": "don't show it again",
"downloading_block_chain": "Baixando a Cadeia de Blocos, por favor aguarde (A Cadeia de Blocos está %{days} dias desatualizada).",
"download_posts_status": "%{portion} postagens carregadas.", // Downloaded 10/30 posts
"Enable": "Habilitado",
@@ -3391,6 +3852,7 @@ if(preferredLanguage == "pt-BR"){
+ "Note: shortening an URL will produce an 'empty' twist on your behalf containing the full URL.\n"
+ "This special twist is not displayed by twister clients, but your twist counter will increase.",
"shorten_URI_its_public_is_it_ok": "Your link will be public available! Are you OK with that?",
+ "URI_shortener": "URI Shortener",
"The File APIs are not fully supported in this browser.": "O gerenciamento de arquivos não é completamente suportado neste navegador.",
"time_ago": "%{time} atrás", // 5 minutes ago
"Time of the last block:": "Horário do último bloco: ",
@@ -3398,7 +3860,24 @@ if(preferredLanguage == "pt-BR"){
"Unfollow": "Deixar de seguir",
"Update": "Atualizar",
"Auto updating": "Auto updating",
+ 'updates_are_available': 'Updates are available',
+ 'updates_not_available': 'No updates are available',
+ 'updates_check_client': 'Check for client\'s updates',
+ 'updates_repo_overview': 'Currently we are on the branch %{branch} of %{repo} at the commit\n %{commit} of %{date}\n'
+ + 'but HEAD of its source is already at the commit\n %{commitUpstream} of %{dateUpstream}.',
+ 'updates_checkout_diff': 'Checkout [the diff on GitHub](%{link}) to learn what is changed.',
+ 'updates_checkout_diff_nfmt': 'Checkout the diff on GitHub to learn what is changed:\n %{link}',
+ 'updates_upstream_isnt_changed': 'A corresponding branch of the source repository seems to have not changed.',
"Updating status...": "Atualizando estado da Cadeia de Blocos...", // status of block chain
+ 'new_account_briefing': 'A new account was created and it is being propagated to the network. '
+ + 'Please do not close this window, this might take a few minutes.\n\n'
+ + 'Your secret key is: *%{secretKey}*\n\n'
+ + 'It is highly recommended that you take this time to save your secret key. '
+ + 'Print it, do a screenshot, use the camera in your phone or write it down to a piece of paper.\n\n'
+ + 'The secret key will be needed to use this account from different computers. '
+ + 'If you ever lose your secret key your account will be locked forever '
+ + '(note: ~this is alpha software and it may crash, causing loss of data~).\n\n'
+ + 'Just wait. The OK button will be shown faster you can say ~decentralization~.',
"user_not_yet_accepted": "Outros nós ainda não aceitaram este novo usuário.\n" +
"Infelizmente não é possível salvar o perfil\n" +
"ou realizar postagens neste estado.\n\n" +
@@ -3546,7 +4025,6 @@ if(preferredLanguage == "pt-BR"){
"post_rt_time_prep": "at",
"undo": "undo",
"Daemon exited...": "Daemon exited...",
- "Secret Key": "Secret Key",
"Copy to clipboard": "Copy to clipboard",
"Full name here": "Full name here",
"Describe yourself": "Describe yourself",
@@ -3558,6 +4036,27 @@ if(preferredLanguage == "pt-BR"){
"Sound": "Sound",
"Users": "Users",
"Direct Message's copy to self": "Direct Message's copy to self",
+ "Traffic information": "Traffic information",
+ "DHT Torrents:": "DHT Torrents:",
+ "Peers:": "Peers:",
+ "Peer List Size:": "Peer List Size:",
+ "Active Requests:": "Active Requests:",
+ "Download:": "Download:",
+ "Upload:": "Upload:",
+ "DHT Download:": "DHT Download:",
+ "DHT Upload:": "DHT Upload:",
+ "IP Overhead Download:": "IP Overhead Download:",
+ "IP Overhead Upload:": "IP Overhead Upload:",
+ "Payload Download:": "Payload Download:",
+ "Payload Upload:": "Payload Upload:",
+ "No favs here because you are not logged in." : "No favs here because you are not logged in.",
+ "users_favs": "Favorites of @%{username}",
+ "Favorites": "Favorites",
+ "You have to log in to favorite messages.": "You have to log in to favorite messages.",
+ "fav_this": "Is it for you only?",
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -3580,6 +4079,8 @@ if(preferredLanguage == "tr"){
"busted_avowal": "Şüpheli bir şeyler iliştirmeye çalışırken enselendim.",
"btn_ok": "Tamam",
"Cancel": "İptal",
+ 'cant_get_requested_resourse': 'Can\'t get resourse at %{link}\n status: %{status}.',
+ "clear_cache": "Geçmişi temizle",
"Confirm": "Onayla",
"сonfirm_group_leaving_header": "Gruptan ayrılmayı onayla",
"сonfirm_group_leaving_body": "%{alias} grubundan ayrılmak istiyor musun?",
@@ -3588,13 +4089,15 @@ if(preferredLanguage == "tr"){
"Eğer bu sayfada kalırsanız eylemlerinizi işlemeyebilir.\n" +
"Bunun yerine [Ağ Durumu sayfasını](%{page}) kontrol etmek ister misiniz?",
"confirm_terminate_daemon": "Hizmeti sonlandırmak istiyor musun?\nTwister istemcisi çalışmayacak.",
- "confirm_unfollow_@": "Are you sure you want to unfollow @%{alias}?",
+ "confirm_unfollow_@": "@%{alias} kullanıcısını takip etmeyi bırakmak istiyor musun?",
+ "confirm_uri_shortener_clear_cache": "Kısaltılmış adres geçimişini temizlemek istiyor musun?",
"Change user": "Kullanıcı değiştir",
"Checking...": "Denetleniyor...", // checking if username is available
"Collapse": "Kapat", // smaller view of a post
"Configure block generation": "Blok üretim ayarları",
"Connections:": "Bağlantılar: ", // to network
"Connection lost.": "Bağlantı koptu.",
+ "daemon_is_obsolete": "twister daemon is obsolete, version %{versionReq} or higher is required",
"days": "%{smart_count} gün |||| %{smart_count} gün",
"Detailed information": "Detaylı bilgi",
"DHT network down.": "DHT ağı çalışmıyor.",
@@ -3602,11 +4105,16 @@ if(preferredLanguage == "tr"){
"Group Messages": "Grup Mesajları",
"Group Messages — New Group Creation": "Grup Mesajları — Yeni Grup Oluştur",
"Group Messages — Join Group": "Grup Mesajları — Gruba katıl",
+ "group_key_cant_import": "Can\'t import DM group key",
+ "group_key_is_invalid_perhaps": "perhaps the key is invalid",
+ "group_key_was_imported": "Key for DM group %{alias} was imported.\n"
+ + "Its messages will be fetched soon.",
"direct_messages_with": "%{username} ile Direk Mesajlar",
"Disable": "Kullanılmaz",
- "display_mentions": "@ adının geçtiği gönderiler", // FIXME
+ "display_mentions": "Bahsedenleri göster",
"Display retransmissions": "Tekrar iletimleri göster",
"DNS to obtain list of peers:": "Eş listesini almak için DNS:",
+ "do_not_show_it_again": "bir daha gösterme",
"downloading_block_chain": "Blok zinciri indiriliyor, devam edebilmek için lütfen bekleyiniz (blok zinciri %{days} günlük).",
"download_posts_status": "Göderilerin indirilme oranı: %{portion}", // Downloaded 10/30 posts
"Enable": "Kullanılabilir",
@@ -3663,12 +4171,12 @@ if(preferredLanguage == "tr"){
"new_group_messages": "%{smart_count} yeni grup mesajı |||| %{smart_count} yeni grup mesajı",
"nobody": "hiçkimse", // used to promote a post without attaching the user
"Not available": "Kullanılamaz", // username is not available
- "warn_following_not_any": "Not following any twisters!\nSearch and follow someone.",
- "warn_followers_not_all": "Well, currently here's no easy way to obtain all your followers.\n"
- + "The counter indicates only a number of known peers sharing your torrent.\n"
- + "In the list below are included ones, mostly, who are followed by you.",
- "warn_followers_not_all_of": "Well, currently here's no easy way to obtain all followers of whoever.\n"
- + "In the list below are included only few, perhaps, of ones who follow @%{alias} publicly.",
+ "warn_following_not_any": "Hiç kimseyi takip etmiyorsun!\nAra ve birilerini takip et.",
+ "warn_followers_not_all": "Tüm takipçilerini belirlemenin kolay bir yolu bulunmuyor.\n"
+ + "Takipçi sayacı torrent'ini paylaşan eşlerin sayısından ibaret ve\n"
+ + "aşağıdaki liste çoğunlukla takip ettiklerinden seni takip edenleri içerir.",
+ "warn_followers_not_all_of": "Tüm takipçilerini belirlemenin kolay bir yolu bulunmuyor.\n"
+ + "Aşağıdaki liste takipçilerin bir kısmını ve çoğunlukla takip ettiklerinden @%{alias} kullanıcısını gizlemeden takip edenleri içerir.",
"notify_desktop_error": "Twister masaüstü uyarısını gösterimiyor: bilimeyen bir hata oluştu.",
"notify_desktop_perm_denied": "Twister masaüstü uyarısını gösteremiyor: yetkilendirme hatası.\n\nUyarıları almak istiyorsanız, tarayıcı ayarlarında %{this_domain} alan adı için izin veriniz.",
"notify_desktop_test": "Kasırga her yanı saracak\nBu karnavala hoşgeldin!",
@@ -3705,11 +4213,12 @@ if(preferredLanguage == "tr"){
"send_DM": "Direk Mesaj Gönder",
"Sent Post to @": "@ Kullanıcıya Gönder",
"Setup account": "Hesap ayarları",
- "shorten_URI": "Shorten URL",
- "shorten_URI_enter_link": "Enter the long link.\n"
- + "Note: shortening an URL will produce an 'empty' twist on your behalf containing the full URL.\n"
- + "This special twist is not displayed by twister clients, but your twist counter will increase.",
+ "shorten_URI": "URL kısalt",
+ "shorten_URI_enter_link": "Uzun bağlantıyı yazın.\n"
+ + "Not: URL kısaltma işlemi tam URL'i barındıran 'boş' bir twist oluşturacak.\n"
+ + "Bu özel twist görüntülenmeyecek, fakat gönderi sayınızda hesaba katılacak.",
"shorten_URI_its_public_is_it_ok": "Your link will be public available! Are you OK with that?",
+ "URI_shortener": "Adres kısalt",
"The File APIs are not fully supported in this browser.": "Dosya API'si tarayıcınızda tam olarak desteklenmiyor.",
"time_ago": "%{time} önce", // 5 minutes ago
"Time of the last block:": "Son blok saati: ",
@@ -3717,7 +4226,24 @@ if(preferredLanguage == "tr"){
"Unfollow": "Takibi bırak",
"Update": "Güncelle",
"Auto updating": "Otomatik güncelleme",
+ 'updates_are_available': 'Updates are available',
+ 'updates_not_available': 'No updates are available',
+ 'updates_check_client': 'Check for client\'s updates',
+ 'updates_repo_overview': 'Currently we are on the branch %{branch} of %{repo} at the commit\n %{commit} of %{date}\n'
+ + 'but HEAD of its source is already at the commit\n %{commitUpstream} of %{dateUpstream}.',
+ 'updates_checkout_diff': 'Checkout [the diff on GitHub](%{link}) to learn what is changed.',
+ 'updates_checkout_diff_nfmt': 'Checkout the diff on GitHub to learn what is changed:\n %{link}',
+ 'updates_upstream_isnt_changed': 'A corresponding branch of the source repository seems to have not changed.',
"Updating status...": "Durum güncelleniyor...", // status of block chain
+ 'new_account_briefing': 'A new account was created and it is being propagated to the network. '
+ + 'Please do not close this window, this might take a few minutes.\n\n'
+ + 'Your secret key is: *%{secretKey}*\n\n'
+ + 'It is highly recommended that you take this time to save your secret key. '
+ + 'Print it, do a screenshot, use the camera in your phone or write it down to a piece of paper.\n\n'
+ + 'The secret key will be needed to use this account from different computers. '
+ + 'If you ever lose your secret key your account will be locked forever '
+ + '(note: ~this is alpha software and it may crash, causing loss of data~).\n\n'
+ + 'Just wait. The OK button will be shown faster you can say ~decentralization~.',
"user_not_yet_accepted": "Diğer eşler bu yeni kullanıcıyı henüz kabul etmediler.\n" +
"Malesef profili kaydetmek ya da bu durumda\n" +
"ileti gönedermek mümkün değil.\n\n" +
@@ -3752,8 +4278,8 @@ if(preferredLanguage == "tr"){
"Terminate Daemon:": "Servisi Durdur:",
"Exit": "Çıkış",
"Save Changes": "Değişiklikleri Kaydet",
- "profile_saved": "Profile data has been saved to DHT.",
- "profile_not_saved": "Profile data has been not saved.",
+ "profile_saved": "Profil bilgileri DHT'ye kaydedildi.",
+ "profile_not_saved": "Profil bilgileri kaydedilmedi.",
"Secret key:": "Gizli anahtar:",
"Options": "Ayarlar",
"Switch to Promoted posts": "Destekli Mesajlara Geç",
@@ -3829,7 +4355,7 @@ if(preferredLanguage == "tr"){
"not analyzed": "incelenmedi",
"Reason: this": "Sebep: %{this}",
"this doesnt contain that": "%{that} %{this} tarafından kapsanmıyor",
- "this is undefined": "%{this} is undefined",
+ "this is undefined": "%{this} tanımsız",
"blacklist": "beyaz liste",
"whitelist": "kara liste",
"language of this": "dili",
@@ -3875,6 +4401,27 @@ if(preferredLanguage == "tr"){
"Sound": "Ses",
"Users": "Kullanıcılar",
"Direct Message's copy to self": "Özel iletinin kopyasını sakla",
+ "Traffic information": "Trafik bilgileri",
+ "DHT Torrents:": "DHT Torrentleri:",
+ "Peers:": "Eşler:",
+ "Peer List Size:": "Eş listesi uzunluğu:",
+ "Active Requests:": "Aktif istekler:",
+ "Download:": "İndirme:",
+ "Upload:": "Yükleme:",
+ "DHT Download:": "DHT İndirme:",
+ "DHT Upload:": "DHT Yükleme:",
+ "IP Overhead Download:": "IP Başlık İndirme:",
+ "IP Overhead Upload:": "IP Başlık Yükleme:",
+ "Payload Download:": "İçerik İndirme:",
+ "Payload Upload:": "İçerik Yükleme:",
+ "No favs here because you are not logged in." : "Giriş yapmadan favorileri göremezsin.",
+ "users_favs": "@%{username} kullanıcısının favorileri",
+ "Favorites": "Favoriler",
+ "You have to log in to favorite messages.": "İletileri favorine eklemek için giriş yapmalısın.",
+ "fav_this": "Sana özel mi?",
+ "Last activity": "Son etkinlik",
+ "New Users": "Yeni Kullanıcılar",
+ "Live tracking" : "Canlı takip"
};
}
@@ -3897,6 +4444,8 @@ if(preferredLanguage == "cs"){
"busted_avowal": "I\'m busted trying inject this suspicious stuff here",
"btn_ok": "Okay",
"Cancel": "Zrušit",
+ 'cant_get_requested_resourse': 'Can\'t get resourse at %{link}\n status: %{status}.',
+ "clear_cache": "Clear cache",
"Confirm": "Confirm",
"сonfirm_group_leaving_header": "Confirm group leaving",
"сonfirm_group_leaving_body": "Are you sure want to leave %{alias} group?",
@@ -3906,12 +4455,14 @@ if(preferredLanguage == "cs"){
"Chcete se místo toho podívat na [stav sítě](%{page})?",
"confirm_terminate_daemon": "Skutečně chcete ukončit server?\nTwister tím vypnete.",
"confirm_unfollow_@": "Are you sure you want to unfollow @%{alias}?",
+ "confirm_uri_shortener_clear_cache": "Are you sure you want to clear browser cache of shortened URIs?",
"Change user": "Změnit uživatele",
"Checking...": "Ověřuji...", // checking if username is available
"Collapse": "Složit", // smaller view of a post
"Configure block generation": "Nastavení generace bloků",
"Connections:": "Připojení: ", // to network
"Connection lost.": "Žádné připojení do sítě.",
+ "daemon_is_obsolete": "twister daemon is obsolete, version %{versionReq} or higher is required",
"days": "%{smart_count} dnem |||| %{smart_count} dny |||| %{smart_count} dny",
"Detailed information": "Podrobné informace",
"DHT network down.": "Síť DHT je nedostupná.",
@@ -3919,11 +4470,16 @@ if(preferredLanguage == "cs"){
"Group Messages": "Group Messages",
"Group Messages — New Group Creation": "Group Messages — New Group Creation",
"Group Messages — Join Group": "Group Messages — Join Group",
+ "group_key_cant_import": "Can\'t import DM group key",
+ "group_key_is_invalid_perhaps": "perhaps the key is invalid",
+ "group_key_was_imported": "Key for DM group %{alias} was imported.\n"
+ + "Its messages will be fetched soon.",
"direct_messages_with": "Direct messages with %{username}",
"Disable": "Vypnuto",
"display_mentions": "Zobrazit zmínky",
"Display retransmissions": "Zobrazit přeposlané",
"DNS to obtain list of peers:": "DNS pro načtení seznamu uzlů:",
+ "do_not_show_it_again": "don't show it again",
"downloading_block_chain": "Stahuji blockchain, prosím počkejte (blockchain je %{days} dnů starý).",
"download_posts_status": "Staženo %{portion} příspěvků", // Downloaded 10/30 posts
"Enable": "Zapnuto",
@@ -4028,6 +4584,7 @@ if(preferredLanguage == "cs"){
+ "Note: shortening an URL will produce an 'empty' twist on your behalf containing the full URL.\n"
+ "This special twist is not displayed by twister clients, but your twist counter will increase.",
"shorten_URI_its_public_is_it_ok": "Your link will be public available! Are you OK with that?",
+ "URI_shortener": "URI Shortener",
"The File APIs are not fully supported in this browser.": "Upozornění: váš webový prohlížeč nepodporuje File API.",
"time_ago": "před %{time}", // 5 minutes ago
"Time of the last block:": "Čas posledního bloku: ",
@@ -4035,7 +4592,24 @@ if(preferredLanguage == "cs"){
"Unfollow": "Přestat sledovat",
"Update": "Aktualizovat",
"Auto updating": "Automatická aktualizace",
+ 'updates_are_available': 'Updates are available',
+ 'updates_not_available': 'No updates are available',
+ 'updates_check_client': 'Check for client\'s updates',
+ 'updates_repo_overview': 'Currently we are on the branch %{branch} of %{repo} at the commit\n %{commit} of %{date}\n'
+ + 'but HEAD of its source is already at the commit\n %{commitUpstream} of %{dateUpstream}.',
+ 'updates_checkout_diff': 'Checkout [the diff on GitHub](%{link}) to learn what is changed.',
+ 'updates_checkout_diff_nfmt': 'Checkout the diff on GitHub to learn what is changed:\n %{link}',
+ 'updates_upstream_isnt_changed': 'A corresponding branch of the source repository seems to have not changed.',
"Updating status...": "Aktualizuji stav...", // status of block chain
+ 'new_account_briefing': 'A new account was created and it is being propagated to the network. '
+ + 'Please do not close this window, this might take a few minutes.\n\n'
+ + 'Your secret key is: *%{secretKey}*\n\n'
+ + 'It is highly recommended that you take this time to save your secret key. '
+ + 'Print it, do a screenshot, use the camera in your phone or write it down to a piece of paper.\n\n'
+ + 'The secret key will be needed to use this account from different computers. '
+ + 'If you ever lose your secret key your account will be locked forever '
+ + '(note: ~this is alpha software and it may crash, causing loss of data~).\n\n'
+ + 'Just wait. The OK button will be shown faster you can say ~decentralization~.',
"user_not_yet_accepted": "Ostatní uzly ještě nepřijaly tohoto nového uživatele.\n" +
"Proto zatím není možné uložit profil nebo vkládat příspěvky.\n" +
"Počkejte prosím pár minut.\n\n" +
@@ -4208,6 +4782,14 @@ if(preferredLanguage == "cs"){
"IP Overhead Upload:": "IP Overhead - odesílání:",
"Payload Download:": "Data aplikace - stahování:",
"Payload Upload:": "Data aplikace - odesílání:",
+ "No favs here because you are not logged in." : "No favs here because you are not logged in.",
+ "users_favs": "Favorites of @%{username}",
+ "Favorites": "Favorites",
+ "You have to log in to favorite messages.": "You have to log in to favorite messages.",
+ "fav_this": "Is it for you only?",
+ "Last activity": "Last activity",
+ "New Users": "New Users",
+ "Live tracking" : "Live tracking"
};
}
@@ -4251,12 +4833,7 @@ var fixedLabels = [
".network label",
".network input",
- // login page
- ".login ul li span",
".module span",
- ".login span",
- ".login-local-username",
- ".login input",
// mobile version //
diff --git a/js/interface_login.js b/js/interface_login.js
deleted file mode 100644
index a39e97e..0000000
--- a/js/interface_login.js
+++ /dev/null
@@ -1,37 +0,0 @@
-// interface_login.js
-// 2013 Miguel Freitas
-
-function processCreateUser(username, secretKey) {
- defaultScreenName = username;
- if (defaultScreenName)
- saveScreenName();
-
- openModal({
- classAdd: 'new-user',
- content: $('#new-user-modal-template').children().clone(true),
- title: polyglot.t('propagating_nickname', {username: username})
- })
- .content.find('.secret-key').text(secretKey);
-
- sendNewUserTransaction(username, processSendnewusertransaction);
-}
-
-function processSendnewusertransaction() {
- $( ".login-created-user").show();
-}
-
-function loginCreatedUser() {
- $.MAL.goProfileEdit();
-}
-
-function initInterfaceLogin() {
- initUser();
- initInterfaceCommon();
- checkNetworkStatusAndAskRedirect();
-
- interfaceCommonLoginHandlers();
- $( ".create-user").bind( "click", function() { createUserClick( processCreateUser ); } );
- $( ".login-created-user").bind( "click", loginCreatedUser );
-}
-
-
diff --git a/js/mobile_abstract.js b/js/mobile_abstract.js
index a2406ea..769d851 100644
--- a/js/mobile_abstract.js
+++ b/js/mobile_abstract.js
@@ -321,12 +321,12 @@ var MAL = function()
}
this.goLogin = function() {
- if( $.hasOwnProperty("mobile") ) {
- $.mobile.navigate( "#login" );
+ if ($.hasOwnProperty('mobile')) {
+ $.mobile.navigate('#login');
} else {
- window.location.href = "login.html";
+ window.location.hash = '#/login';
}
- }
+ };
this.goNetwork = function() {
if( $.hasOwnProperty("mobile") ) {
@@ -418,6 +418,38 @@ var MAL = function()
}
}
+ this.processCreateAccount = function (peerAlias, secretKey) {
+ defaultScreenName = peerAlias;
+ if (defaultScreenName) {
+ saveScreenName();
+ }
+
+ if ($.hasOwnProperty('mobile')) {
+ $('.secret-key').text(secretKey);
+ sendNewUserTransaction(peerAlias);
+ $.mobile.navigate('#new-user-modal');
+ } else {
+ var modal = confirmPopup({
+ classAdd: 'new-account-briefing',
+ txtTitle: polyglot.t('propagating_nickname', {username: peerAlias}),
+ txtMessage: polyglot.t('new_account_briefing', {secretKey: secretKey}),
+ txtConfirm: polyglot.t('Login'),
+ cbConfirm: $.MAL.goProfileEdit,
+ addBlackout: true,
+ removeCancel: true,
+ removeClose: true
+ });
+
+ modal.content.find('.confirm').attr('disabled', true);
+
+ sendNewUserTransaction(peerAlias,
+ function (accountCreatedModal) {
+ accountCreatedModal.content.find('.confirm').attr('disabled', false);
+ }, modal
+ );
+ }
+ };
+
this.changedUser = function() {
if( $.hasOwnProperty("mobile") ) {
timelineChangedUser();
@@ -592,3 +624,166 @@ function filterLang(string) {
}
}
+function checkUpdatesClient(alertIfNoUpdates) {
+ function handleGetFail(jqXHR) {
+ twister.var.updatesCheckClient.isOngoing = false;
+
+ console.warn(polyglot.t('cant_get_requested_resourse', {link: this.url, status: jqXHR.status + ', \'' + jqXHR.statusText + '\''}));
+
+ if (alertIfNoUpdates) {
+ if ($.hasOwnProperty('mobile'))
+ alert(polyglot.t('updates_not_available') + '.\n\n'
+ + polyglot.t('cant_get_requested_resourse', {link: this.url, status: jqXHR.status + ', \'' + jqXHR.statusText + '\''})
+ );
+ else
+ alertPopup({
+ txtTitle: polyglot.t('updates_not_available'),
+ txtMessage: polyglot.t('cant_get_requested_resourse', {link: this.url, status: jqXHR.status + ', ~' + jqXHR.statusText + '~'})
+ });
+ }
+ }
+
+ if (twister.var.updatesCheckClient.isOngoing)
+ return;
+
+ twister.var.updatesCheckClient.isOngoing = true;
+
+ $.get('.git/HEAD', function (ret) {
+ if (ret.slice(0, 16) !== 'ref: refs/heads/') {
+ twister.var.updatesCheckClient.isOngoing = false;
+ if (alertIfNoUpdates)
+ alert(polyglot.t('updates_not_available') + '.\n\nCan\'t parse local HEAD: unknown syntax, FUBAR!');
+
+ return;
+ }
+
+ var branch = ret.slice(16).trim();
+
+ $.get('.git/refs/heads/' + branch, function (ret) {
+ var commit = ret.trim();
+ if (!commit) {
+ twister.var.updatesCheckClient.isOngoing = false;
+ if (alertIfNoUpdates)
+ alert(polyglot.t('updates_not_available') + '.\n\nCan\'t parse local HEAD: \'' + '.git/refs/heads/' + branch + '\' is empty, FUBAR!');
+
+ return;
+ }
+
+ var repo = 'twister-html'; // TODO source repo selection in options
+ var repoOwner = 'miguelfreitas';
+
+ // TODO notification if local branch was changed ('r u wanna reload the page?')
+ /*if (!twister.var.updatesCheckClient.formerBranch || !twister.var.updatesCheckClient.formerCommit) {
+ twister.var.updatesCheckClient.formerBranch = branch;
+ twister.var.updatesCheckClient.formerCommit = commit;
+ }*/
+
+ console.log('currently we are on the branch \'' + branch + '\' of ' + repo + ' at the commit ' + commit);
+
+ $.get('https://api.github.com/repos/' + repoOwner + '/' + repo + '/branches', function (ret) {
+ for (var i = 0; i < ret.length; i++) {
+ if (ret[i].name === branch) {
+ if (ret[i].commit.sha === commit) {
+ twister.var.updatesCheckClient.isOngoing = false;
+
+ console.log(polyglot.t('updates_upstream_isnt_changed'));
+
+ if (alertIfNoUpdates) {
+ if ($.hasOwnProperty('mobile'))
+ alert(polyglot.t('updates_not_available') + '.\n\n'
+ + polyglot.t('updates_upstream_isnt_changed')
+ );
+ else
+ alertPopup({
+ txtTitle: polyglot.t('updates_not_available'),
+ txtMessage: polyglot.t('updates_upstream_isnt_changed')
+ });
+ }
+ } else {
+ console.log('source branch has a different HEAD: ' + ret[i].commit.sha);
+
+ var commitUpstream = ret[i].commit.sha;
+
+ $.get('https://api.github.com/repos/' + repoOwner + '/' + repo + '/git/commits/' + commit, function (ret) {
+ if (ret.sha !== commit) { // the response is wrong if so, should be 404 instead
+ twister.var.updatesCheckClient.isOngoing = false;
+ console.log('upstream tree doesn\'t have our most recent commit,\nlooks like we are in the process of development locally.');
+ if (alertIfNoUpdates)
+ alert(polyglot.t('updates_not_available') + '.\n\nUpstream tree doesn\'t have our most recent commit,\nlooks like we are in the process of development locally.');
+
+ return;
+ }
+
+ commit = ret;
+
+ $.get('https://api.github.com/repos/' + repoOwner + '/' + repo + '/git/commits/' + commitUpstream, function (ret) {
+ twister.var.updatesCheckClient.isOngoing = false;
+
+ if (ret.sha !== commitUpstream) { // the response is wrong if so, should be 404 instead
+ console.warn('upstream tree doesn\'t have the commit which is named most recent in the list of branches, FUBAR!');
+ if (alertIfNoUpdates)
+ alert(polyglot.t('updates_not_available') + '.\n\nUpstream tree doesn\'t have the commit which is named most recent in the list of branches, FUBAR!');
+
+ return;
+ }
+
+ commitUpstream = ret;
+ var linkGitHubDiff = 'https://github.com/' + repoOwner + '/' + repo + '/compare/' + commit.sha + '...' + repoOwner + ':' + branch;
+
+ console.log(polyglot.t('updates_checkout_diff_nfmt', {link: linkGitHubDiff}));
+
+ if ($.hasOwnProperty('mobile'))
+ alert(polyglot.t('updates_are_available') + '.\n\n'
+ + polyglot.t('updates_repo_overview', {
+ branch: '\'' + branch + '\'',
+ repo: repo,
+ commit: commit.sha,
+ date: new Date(commit.author.date).toString().replace(/ GMT.*/g, ''),
+ commitUpstream: commitUpstream.sha,
+ dateUpstream: new Date(commitUpstream.author.date).toString().replace(/ GMT.*/g, '')
+ }) + '\n\n'
+ + polyglot.t('updates_checkout_diff_nfmt', {link: linkGitHubDiff})
+ );
+ else
+ alertPopup({
+ txtTitle: polyglot.t('updates_are_available'),
+ txtMessage: polyglot.t('updates_repo_overview', {
+ branch: '~' + branch + '~',
+ repo: repo,
+ commit: '*' + commit.sha + '*',
+ date: new Date(commit.author.date).toString().replace(/ GMT.*/g, ''),
+ commitUpstream: '*' + commitUpstream.sha + '*',
+ dateUpstream: new Date(commitUpstream.author.date).toString().replace(/ GMT.*/g, '')
+ }) + '\n\n'
+ + polyglot.t('updates_checkout_diff', {link: linkGitHubDiff})
+ });
+ }).fail(function (jqXHR) {
+ if (jqXHR.status === 404) {
+ twister.var.updatesCheckClient.isOngoing = false;
+ console.warn('upstream tree doesn\'t have the commit which is named most recent in the list of branches, FUBAR!');
+ if (alertIfNoUpdates)
+ alert(polyglot.t('updates_not_available') + '.\n\nUpstream tree doesn\'t have the commit which is named most recent in the list of branches, FUBAR!');
+ } else
+ handleGetFail(jqXHR);
+ });
+ }).fail(function (jqXHR) {
+ if (jqXHR.status === 404) {
+ twister.var.updatesCheckClient.isOngoing = false;
+ console.log('upstream tree doesn\'t have our most recent commit,\nlooks like we are in the process of development locally.');
+ if (alertIfNoUpdates)
+ alert(polyglot.t('updates_not_available') + '.\n\nUpstream tree doesn\'t have our most recent commit,\nlooks like we are in the process of development locally.');
+ } else
+ handleGetFail(jqXHR);
+ });
+ }
+ return;
+ }
+ }
+ twister.var.updatesCheckClient.isOngoing = false;
+ console.log('upstream tree doesn\'t have our branch,\nlooks like we are in the process of development locally.');
+ if (alertIfNoUpdates)
+ alert(polyglot.t('updates_not_available') + '.\n\nUpstream tree doesn\'t have our branch,\nlooks like we are in the process of development locally.');
+ }).fail(handleGetFail);
+ }).fail(handleGetFail);
+ }).fail(handleGetFail);
+}
diff --git a/js/options.js b/js/options.js
index b3d034b..84f17cb 100644
--- a/js/options.js
+++ b/js/options.js
@@ -41,6 +41,17 @@ function twisterOptions() {
name: 'WhoToFollow',
valDefault: 'enable'
});
+ this.add({
+ name: 'NewUsers',
+ valDefault: 'enable',
+ tickMethod: function (elem) {
+ $('#NewUsersCont').css('display', (elem.value === 'enable') ? 'block' : 'none');
+ }
+ });
+ this.add({
+ name: 'NewUsersLiveTracking',
+ valDefault: 'enable'
+ });
this.add({
name: 'TwistdayReminder',
valDefault: 'enable',
@@ -309,6 +320,16 @@ function twisterOptions() {
name: 'WebTorrentAutoDownload',
valDefault: 'enable'
});
+ this.add({
+ name: 'skipWarnFollowersNotAll',
+ type: 'checkbox',
+ valDefault: false
+ });
+ this.add({
+ name: 'skipWarnFollowersNotAllOf',
+ type: 'checkbox',
+ valDefault: false
+ });
}
twisterOptions.prototype.add = function (option) {
@@ -316,6 +337,20 @@ twisterOptions.prototype.add = function (option) {
this[option.name] = new twisterOption(option);
};
+twisterOptions.prototype.get = function (optionName) {
+ if (optionName && typeof this[optionName] !== 'undefined')
+ return this[optionName].val;
+ else
+ console.warn('option \'' + optionName + '\' does not exist');
+};
+
+twisterOptions.prototype.set = function (optionName, val) {
+ if (optionName && typeof this[optionName] !== 'undefined')
+ this[optionName].set(val);
+ else
+ console.warn('option \'' + optionName + '\' does not exist');
+};
+
twisterOptions.prototype.initControls = function () {
var elem;
diff --git a/js/tmobile.js b/js/tmobile.js
index 517b9d6..bf69bbe 100644
--- a/js/tmobile.js
+++ b/js/tmobile.js
@@ -8,7 +8,6 @@ var handlersInstalled = false;
function initializeTwister( redirectNetwork, redirectLogin, cbFunc, cbArg ) {
if( !handlersInstalled ) {
interfaceNetworkHandlers();
- interfaceCommonLoginHandlers();
installUserSearchHandler();
installProfileEditHandlers();
// install scrollbottom handler to load more posts as needed
@@ -253,11 +252,12 @@ var router=new $.mobile.Router(
});
},
login: function(type,match,ui) {
+ if (!$('#login .content').children().length)
+ $('#login .content').append(twister.tmpl.loginMC.clone(true)).trigger('create');
$.mobile.showPageLoadingMsg();
initializeTwister( true, false, function() {
$.mobile.hidePageLoadingMsg();
- $("select.local-usernames.login-user").selectmenu("refresh", true);
- installCreateUserClick();
+ $("select.local-usernames").selectmenu("refresh", true);
});
},
network: function(type,match,ui) {
@@ -421,19 +421,6 @@ function installRetransmitConfirmClick() {
});
}
-function installCreateUserClick() {
- $( ".create-user").unbind('click').click( function(e) {
- createUserClick( function(username, secretKey) {
- defaultScreenName = username;
- if(defaultScreenName) {
- saveScreenName();
- }
- $(".secret-key").text(secretKey);
- sendNewUserTransaction( username, function() {} );
- $.mobile.navigate( "#new-user-modal" ); } );
- });
-}
-
function installUserSearchHandler() {
$('.userMenu-search-field')
.off('click input')
@@ -541,27 +528,22 @@ function encode_utf8(s) {
return s;
}
-var tmobileQueryReq = {}; // FIXME need to rework all that searching
+var tmobileQueryReq;
-function setupHashtagOrMention(postboard, tag, res) {
+function setupHashtagOrMention(board, query, resource) {
$.MAL.setPostTemplate( $("#post-template-home") );
$.mobile.showPageLoadingMsg();
+ board.empty();
- var reqId = tag + '@' + res;
-
- clearQueryProcessed(reqId);
-
- tmobileQueryReq.postboard = postboard.text('').attr('data-request-id', reqId);
- tmobileQueryReq.query = tag;
- tmobileQueryReq.resource = res;
-
- if (tag === defaultScreenName && res === 'mention') {
- // obtain already cached mention posts from twister_newmsgs.js
- tmobileQueryReq.posts = getMentionsData();
- processQuery(tmobileQueryReq);
- }
+ var req = queryStart(board, query, resource, undefined, undefined, {
+ boardAutoAppend: true,
+ skidoo: function (req) {
+ var curPage = $.mobile.activePage.attr('id');
+ return (curPage !== 'mentions' && curPage !== 'hashtag') || req !== tmobileQueryReq;
+ }
+ });
- requestQuery(tmobileQueryReq);
+ tmobileQueryReq = req;
}
// every 2 seconds do something page specific.
@@ -583,12 +565,6 @@ function tmobileTick() {
}
}, {} );
}
-
- else if (curPage === 'mentions' || curPage === 'hashtag') {
- autoUpdateQuery = true;
- requestQuery(tmobileQueryReq);
- }
-
if (curPage === 'dmchat')
requestDmConversation($('#dmchat .direct-messages-thread'), dmChatUser);
}
@@ -600,4 +576,3 @@ $(document).bind('mobileinit', function () {
$.mobile.defaultDialogTransition = 'none';
$.mobile.defaultPageTransition = 'none';
});
-
diff --git a/js/twister_actions.js b/js/twister_actions.js
index 83ec131..3626440 100644
--- a/js/twister_actions.js
+++ b/js/twister_actions.js
@@ -12,9 +12,6 @@
var postsPerRefresh = 10;
var maxExpandPost = 8;
var maxExpandPostTop = 4;
-var _queryProcessedMap = {};
-var _queryPendingPosts = {};
-var autoUpdateQuery = false;
// ----------------
@@ -271,10 +268,11 @@ function newRtMsg(postData, msg) {
if (userpost.rt) {
if (parseInt(twisterVersion) <= 93000) {
- alert(polyglot.t('error',
- {error: 'can\'t handle retwisting of commented retwisted twists with daemon version '
- + twisterDisplayVersion + ' and below of that. Please upgrade it.'}
- ));
+ alertPopup({
+ //txtTitle: polyglot.t(''), add some title (not 'error', please) or just KISS
+ txtMessage: 'Can\'t handle retwisting of commented retwisted twists —\n'
+ + polyglot.t('daemon_is_obsolete', {versionReq: '0.9.3+'})
+ });
return;
} else {
@@ -319,17 +317,53 @@ function newRtMsg(postData, msg) {
}
}
+function newFavMsg(postData, priv, msg) {
+ var userpost = $.evalJSON(postData.attr('data-content_to_rt'));
+ var sig_userpost = postData.attr('data-content_to_sigrt');
+
+ if (typeof sig_userpost === 'undefined') {
+ alert(polyglot.t('error',
+ {error: 'can\'t sig_userpost is not deifned'}
+ ));
+
+ return;
+ }
+ var rtObj = {sig_userpost: sig_userpost, userpost: userpost};
+
+ if (typeof lastPostId !== 'undefined') {
+ if (typeof _sendedPostIDs !== 'undefined')
+ _sendedPostIDs.push(lastPostId + 1);
+
+ var params = [defaultScreenName, lastPostId + 1, rtObj, priv];
+
+ if (typeof msg !== 'undefined')
+ params.push(msg);
+
+ twisterRpc('newfavmsg', params,
+ function(arg, ret) {incLastPostId();}, null,
+ function(arg, ret) {var msg = ('message' in ret) ? ret.message : ret;
+ alert(polyglot.t('ajax_error', {error: msg}));
+ }, null
+ );
+ } else {
+ alert(polyglot.t('Internal error: lastPostId unknown (following yourself may fix!)'));
+ }
+}
+
function newShortURI(uri, cbFunc, cbReq) {
if (!uri || !defaultScreenName) return;
if (parseInt(twisterVersion) < 93500) {
- console.warn('can\'t shorten URI "' + uri + '": daemon is obsolete, version 0.9.35 or higher is required');
+ console.warn('can\'t shorten URI "' + uri + '" — '
+ + polyglot.t('daemon_is_obsolete', {versionReq: '0.9.35'}));
return;
}
- for (var i in twister.URIs)
- if (twister.URIs[i] === uri) {
+ for (var short in twister.URIs)
+ if (twister.URIs[short] instanceof Array ?
+ twister.URIs[short][0] === uri : twister.URIs[short] === uri) {
if (typeof cbFunc === 'function')
- cbFunc(uri, i, cbReq);
+ cbFunc(uri, short, cbReq);
+
return;
}
@@ -402,102 +436,204 @@ function updateProfilePosts(postsView, username, useGetposts) {
});
}
-function clearQueryProcessed(id) {
- if (!id) return;
+function queryStart(board, query, resource, timeoutArgs, intervalTimeout, extra) {
+ var req = query + '@' + resource;
+
+ if (typeof twister.res[req] !== 'object') {
+ twister.res[req] = {
+ board: board,
+ query: query,
+ resource: resource,
+ twists: {
+ cached: {},
+ pending: []
+ }
+ };
+ if (extra) {
+ for (i in extra)
+ twister.res[req][i] = extra[i];
+
+ if (typeof extra.ready === 'function')
+ extra.ready(req, extra.readyReq);
+ }
+ } else {
+ twister.res[req].board = board;
+ for (var i in twister.res[req].twists.cached)
+ if (twister.res[req].twists.pending.indexOf(i) === -1)
+ twister.res[req].twists.pending.push(i);
+
+ queryPendingDraw(req);
+ }
+
+ if (twister.res[req].interval)
+ return req;
+
+ queryRequest(req);
+
+ // use extended timeout parameters on modal refresh (requires twister_core >= 0.9.14).
+ // our first query above should be faster (with default timeoutArgs of twisterd),
+ // then we may possibly collect more posts on our second try by waiting more.
+ twister.res[req].timeoutArgs = timeoutArgs ? timeoutArgs : [10000, 2000, 3];
- _queryProcessedMap[id] = {};
- _queryPendingPosts[id] = [];
+ twister.res[req].interval = setInterval(queryTick, intervalTimeout ? intervalTimeout : 5000, req);
+
+ return req;
}
-function requestQuery(req) {
- req.postboard.closest('div').find('.postboard-loading').show();
- dhtget(req.query, req.resource, 'm',
- function(req, posts) {
- req.posts = posts;
- processQuery(req);
- },
- req,
- req.timeoutArgs
- );
+function queryTick(req) {
+ if (typeof twister.res[req].skidoo === 'function' ? twister.res[req].skidoo(req)
+ : !isModalWithElemExists(twister.res[req].board)) {
+ clearInterval(twister.res[req].interval);
+ twister.res[req].interval = 0;
+ queryPendingClear(req);
+ return;
+ }
+
+ queryRequest(req);
+}
+
+function queryPendingClear(req) {
+ twister.res[req].twists.pending = [];
+}
+
+function queryRequest(req) {
+ if (twister.res[req].board && isModalWithElemExists(twister.res[req].board))
+ twister.res[req].board.closest('div').find('.postboard-loading').show();
+
+ if (twister.res[req].resource === 'mention' && twister.res[req].query === defaultScreenName) {
+ twisterRpc('getmentions', [twister.res[req].query, 100, {since_id: twister.res[req].lastTorrentId}],
+ queryProcess, req,
+ function () {console.warn('getmentions API requires twister-core > 0.9.27');}
+ );
+ dhtget(twister.res[req].query, twister.res[req].resource, 'm',
+ queryProcess, req, twister.res[req].timeoutArgs);
+ } else if (twister.res[req].resource === 'fav')
+ twisterRpc('getfavs', [twister.res[req].query, 1000],
+ queryProcess, req);
+ else
+ dhtget(twister.res[req].query, twister.res[req].resource, 'm',
+ queryProcess, req, twister.res[req].timeoutArgs);
}
-function processQuery(req) {
- if (!isModalWithElemExists(req.postboard) || !req.posts || !req.posts.length)
+function queryProcess(req, twists) {
+ if (!req || !twister.res[req] || !twists || !twists.length)
return;
- if (!req.id)
- req.id = req.query + '@' + req.resource;
- if (typeof _queryProcessedMap[req.id] !== 'object')
- _queryProcessedMap[req.id] = {};
- if (typeof _queryPendingPosts[req.id] !== 'object')
- _queryPendingPosts[req.id] = [];
+ var lengthNew = 0;
+ var lengthPending = twister.res[req].twists.pending.length;
- for (var i = req.posts.length - 1; i >= 0; i--) {
- var userpost = req.posts[i].userpost;
- var key = userpost.n + ';' + userpost.time;
+ if (twister.res[req].resource === 'mention' && twister.res[req].query === defaultScreenName)
+ lengthNew = queryPendingPushMentions(req, twists);
+ else
+ lengthNew = queryPendingPush(req, twists);
- if (!_queryProcessedMap[req.id][key]) {
- _queryProcessedMap[req.id][key] = true;
+ if (typeof twister.res[req].skidoo === 'function' && twister.res[req].skidoo(req))
+ return;
+
+ if (lengthNew)
+ if (twister.res[req].resource === 'mention' && twister.res[req].query === defaultScreenName) {
+ $.MAL.updateNewMentionsUI(twister.res[req].lengthNew);
+ $.MAL.soundNotifyMentions();
+ if (!$.mobile && $.Options.showDesktopNotifMentions.val === 'enable')
+ $.MAL.showDesktopNotification({
+ body: polyglot.t('You got') + ' ' + polyglot.t('new_mentions', twister.res[req].lengthNew) + '.',
+ tag: 'twister_notification_new_mentions',
+ timeout: $.Options.showDesktopNotifMentionsTimer.val,
+ funcClick: (function () {
+ if (!twister.res[this.req].board || !focusModalWithElement(twister.res[this.req].board,
+ function (req) {
+ twister.res[req].board.closest('.postboard')
+ .find('.postboard-news').click();
+ },
+ this.req
+ ))
+ $.MAL.showMentions(defaultScreenName);
+ }).bind({req: req})
+ });
+ } else if (!$.mobile && $.Options.showDesktopNotifPostsModal.val === 'enable'
+ && (twister.res[req].resource !== 'mention' || twister.res[req].query !== defaultScreenName)
+ && twister.res[req].board && isModalWithElemExists(twister.res[req].board)
+ && twister.res[req].board.children().length)
+ $.MAL.showDesktopNotification({
+ body: polyglot.t('You got') + ' ' + polyglot.t('new_posts', twister.res[req].twists.pending.length) + ' '
+ + polyglot.t('in search result') + '.',
+ tag: 'twister_notification_new_posts_modal',
+ timeout: $.Options.showDesktopNotifPostsModalTimer.val,
+ funcClick: (function() {
+ focusModalWithElement(twister.res[this.req].board,
+ function (req) {
+ twister.res[req].board.closest('.postboard')
+ .find('.postboard-news').click();
+ },
+ this.req
+ );
+ }).bind({req: req})
+ });
+
+ if (twister.res[req].twists.pending.length > lengthPending) { // there is some twists may be which are not considered new so lengthNew equals zero (mentions thing)
+ if (!twister.res[req].board || (!$.mobile && !isModalWithElemExists(twister.res[req].board)))
+ return;
+
+ if (!twister.res[req].board.children().length || twister.res[req].boardAutoAppend)
+ queryPendingDraw(req);
+ else {
+ twister.res[req].board.closest('div').find('.postboard-news') // FIXME we'd replace 'div' with '.postboard' but need to dig through tmobile first
+ .text(polyglot.t('new_posts', twister.res[req].twists.pending.length))
+ .fadeIn('slow')
+ ;
+ twister.res[req].board.closest('div').find('.postboard-loading').hide();
+ }
+ }
+}
+
+function queryPendingPush(req, twists) {
+ var lengthNew = 0;
+ var needForFilter = $.Options.filterLang.val !== 'disable' && $.Options.filterLangForSearching.val;
+
+ for (var i = twists.length - 1; i >= 0; i--) {
+ var userpost = twists[i].userpost;
+ var j = userpost.n + '/' + userpost.time;
+
+ if (typeof twister.res[req].twists.cached[j] === 'undefined') {
+ if (userpost.fav)
+ userpost = userpost.fav;
if ((typeof userpost.msg !== 'string' || userpost.msg === '')
&& (typeof userpost.rt !== 'object'
|| typeof userpost.rt.msg !== 'string' || userpost.rt.msg === ''))
continue;
- if ($.Options.filterLang.val !== 'disable' && $.Options.filterLangForSearching.val) {
+ if (needForFilter) {
if (typeof userpost.msg === 'string' && userpost.msg !== '')
langFilterData = filterLang(userpost.msg);
else
langFilterData = filterLang(userpost.rt.msg);
if ($.Options.filterLangSimulate.val) {
- req.posts[i].langFilter = langFilterData;
+ twists[i].langFilter = langFilterData;
} else {
if (!langFilterData.pass)
continue;
}
}
- _queryPendingPosts[req.id].push(req.posts[i]);
+ lengthNew++;
+ twister.res[req].twists.cached[j] = twists[i];
+ twister.res[req].twists.pending.push(j);
}
}
- if (_queryPendingPosts[req.id].length) {
- if (!$.hasOwnProperty('mobile') && $.Options.showDesktopNotifPostsModal.val === 'enable'
- && (req.resource !== 'mention' || req.query !== defaultScreenName)) {
- $.MAL.showDesktopNotification({
- body: polyglot.t('You got') + ' ' + polyglot.t('new_posts', _queryPendingPosts[req.id].length) + ' '
- + polyglot.t('in search result') + '.',
- tag: 'twister_notification_new_posts_modal',
- timeout: $.Options.showDesktopNotifPostsModalTimer.val,
- funcClick: (function() {
- focusModalWithElement(this.postboard,
- function (req) {
- req.postboard.closest('.postboard').find('.postboard-news').hide();
- displayQueryPending(req.postboard);
- }, {postboard: this.postboard}
- );
- }).bind({postboard: req.postboard})
- });
- }
-
- if (!req.postboard.children().length || autoUpdateQuery) {
- displayQueryPending(req.postboard);
- } else {
- req.postboard.closest('div').find('.postboard-news') // FIXME we'd replace 'div' with '.postboard' but need to dig through tmobile first
- .text(polyglot.t('new_posts', _queryPendingPosts[req.id].length))
- .fadeIn('slow')
- ;
- req.postboard.closest('div').find('.postboard-loading').hide();
- }
- }
+ return lengthNew;
}
-function displayQueryPending(postboard) {
- var reqId = postboard.attr('data-request-id');
+function queryPendingDraw(req) {
+ var twists = [];
+ for (var i = 0; i < twister.res[req].twists.pending.length; i++)
+ twists.push(twister.res[req].twists.cached[twister.res[req].twists.pending[i]]);
+
+ attachPostsToStream(twister.res[req].board, twists, false);
- attachPostsToStream(postboard, _queryPendingPosts[reqId], false);
- _queryPendingPosts[reqId] = [];
+ queryPendingClear(req);
$.MAL.postboardLoaded();
}
diff --git a/js/twister_directmsg.js b/js/twister_directmsg.js
index 8df5aa5..c21877d 100644
--- a/js/twister_directmsg.js
+++ b/js/twister_directmsg.js
@@ -179,13 +179,14 @@ function openCommonDMsModal() {
modal.self.find('.mark-all-as-read')
.css('display', 'inline')
.attr('title', polyglot.t('Mark all as read'))
- .on('click', function() {
+ .on('click', function (event) {
for (var user in _newDMsPerUser) {
if (user[0] !== '*')
_newDMsPerUser[user] = 0;
}
saveDMsToStorage();
$.MAL.updateNewDMsUI(getNewDMsCount());
+ $(event.target).closest('.directMessages').find('.direct-messages-list .messages-qtd').hide();
})
;
}
@@ -236,13 +237,14 @@ function openGroupMessagesModal(groupAlias) {
modal.self.find('.mark-all-as-read')
.css('display', 'inline')
.attr('title', polyglot.t('Mark all as read'))
- .on('click', function() {
+ .on('click', function (event) {
for (var user in _newDMsPerUser) {
if (user[0] === '*')
_newDMsPerUser[user] = 0;
}
saveDMsToStorage();
$.MAL.updateNewGroupDMsUI(getNewGroupDMsCount());
+ $(event.target).closest('.groupMessages').find('.direct-messages-list .messages-qtd').hide();
})
;
} else {
@@ -359,22 +361,13 @@ function openGroupMessagesJoinGroupModal() {
closeModal(event);
});
- modal.content.find('.secret-key-import, .username-import').on('input', importSecretKeypress);
+ modal.content.find('.secret-key-import').on('input',
+ {parentSelector: '.module', enterSelector: '.import-secret-key'}, inputEnterActivator);
modal.content.find('.import-secret-key').on('click', function (event) {
- var elemModule = $(event.target).closest('.module');
- var groupAlias = elemModule.find('.username-import').val().toLowerCase();
- var secretKey = elemModule.find('.secret-key-import').val();
+ groupMsgImportKey($(event.target).closest('.module').find('.secret-key-import').val());
- twisterRpc('importprivkey', [secretKey, groupAlias],
- function(req, ret) {
- groupMsgInviteToGroup(req.groupAlias, [defaultScreenName]);
- closeModal(req.elem);
- }, {groupAlias: groupAlias, elem: elemModule},
- function(req, ret) {
- alert(polyglot.t('Error in \'importprivkey\'', {rpc: ret.message}));
- }
- );
+ closeModal(event);
});
}
@@ -392,8 +385,54 @@ function groupMsgCreateGroup(description, peersToInvite) {
);
}
-function groupMsgInviteToGroup(groupAlias, peersToInvite) {
- _groupMsgInviteToGroupQueue.push({groupAlias: groupAlias, peersToInvite: peersToInvite});
+function groupMsgImportKey(key) {
+ if (parseInt(twisterVersion) < 93800) {
+ alertPopup({
+ //txtTitle: polyglot.t(''), add some title (not 'error', please) or just KISS
+ txtMessage: polyglot.t('group_key_cant_import') + ' —\n'
+ + polyglot.t('daemon_is_obsolete', {versionReq: '0.9.38'})
+ });
+ return;
+ }
+
+ twisterRpc('creategroup', ['whatever', key],
+ function(req, ret) {
+ if (!ret) {
+ alertPopup({
+ //txtTitle: polyglot.t(''), add some title (not 'error', please) or just KISS
+ txtMessage: polyglot.t('group_key_cant_import') + ' —\n'
+ + polyglot.t('group_key_is_invalid_perhaps')
+ });
+ return;
+ }
+
+ groupMsgInviteToGroup(ret, [defaultScreenName],
+ function () {
+ twisterRpc('rescandirectmsgs', [defaultScreenName],
+ function () {}, undefined, function () {});
+ }
+ );
+ alertPopup({
+ //txtTitle: polyglot.t(''), add some title (not 'error', please) or just KISS
+ txtMessage: polyglot.t('group_key_was_imported', {alias: ret})
+ });
+ }, undefined,
+ function(req, ret) {
+ alertPopup({
+ //txtTitle: polyglot.t(''), add some title (not 'error', please) or just KISS
+ txtMessage: polyglot.t('group_key_cant_import') + ' —\n' + ret.message
+ });
+ }
+ );
+}
+
+function groupMsgInviteToGroup(groupAlias, peersToInvite, cbFunc, cbReq) {
+ _groupMsgInviteToGroupQueue.push({
+ groupAlias: groupAlias,
+ peersToInvite: peersToInvite,
+ cbFunc: cbFunc,
+ cbReq: cbReq
+ });
if (_groupMsgInviteToGroupQueue.length === 1)
doGroupMsgInviteToGroup();
@@ -408,7 +447,10 @@ function doGroupMsgInviteToGroup() {
_groupMsgInviteToGroupQueue.shift();
if (_groupMsgInviteToGroupQueue.length)
setTimeout(doGroupMsgInviteToGroup, 200);
- }, null,
+
+ if (typeof req.cbFunc === 'function')
+ req.cbFunc(req.cbReq);
+ }, {cbFunc: _groupMsgInviteToGroupQueue[0].cbFunc, cbReq: _groupMsgInviteToGroupQueue[0].cbReq},
function(req, ret) {
alert(polyglot.t('error',
{error: 'can\'t invite ' + req[1] + ' to ' + req[0] + ' group — ' + ret.message}));
diff --git a/js/twister_following.js b/js/twister_following.js
index a45cd89..848234e 100644
--- a/js/twister_following.js
+++ b/js/twister_following.js
@@ -17,6 +17,7 @@ var _lastSearchUsersResultsRemovedFromDHTgetQueue = true;
var _lastLoadFromDhtTime = 0;
var twisterFollowingO = undefined;
+var newUsers = undefined;
var TwisterFollowing = function (user) {
if (!(this instanceof TwisterFollowing))
@@ -145,7 +146,8 @@ TwisterFollowing.prototype = {
.find('li[data-peer-alias="' + args.fu + '"]').remove();
}
}
- $(".open-followers").attr("title", args.tf.knownFollowers.length.toString());
+ $('.module.mini-profile .open-followers')
+ .attr('title', args.tf.knownFollowers.length.toString());
var ctime = new Date().getTime() / 1000;
if (typeof(args.tf.followingsFollowings[args.fu]) === 'undefined' ||
@@ -426,6 +428,127 @@ function followingEmptyOrMyself() {
return (!followingUsers.length || (followingUsers.length === 1 && followingUsers[0] === defaultScreenName))
}
+/* NEW USER SEARCH */
+var NewUserSearch = function(){
+ if (!(this instanceof NewUserSearch))
+ return new NewUserSearch();
+
+ this.init();
+};
+
+NewUserSearch.knownNewUsers = [];
+NewUserSearch.isNewUserThRunning = false;
+NewUserSearch.isNewUserModalOpen = false;
+NewUserSearch.startProcessedBlock = -1;
+NewUserSearch.lastProcessedBlock = -1;
+NewUserSearch.processBlockUsersProxy = function(block, args){
+ if (args.obj instanceof NewUserSearch)
+ args.obj.processBlockUsers(block, args);
+};
+NewUserSearch.live = function(module) {
+ newUsers.getNewUsers(module);
+};
+NewUserSearch.processBestBlockUsersProxy = function(block, args){
+ if (block.height > NewUserSearch.startProcessedBlock) {
+ if (args.obj instanceof NewUserSearch)
+ args.obj.processBlockUsers(block, {obj: args.obj, args: {n: 0, offset: 0, module: args.args.module, prepend: true, live: true}});
+ }
+};
+
+NewUserSearch.prototype = {
+ storage: undefined,
+ isForced: false,
+
+ init: function() {
+ this.storage = $.initNamespaceStorage(defaultScreenName).sessionStorage;
+ if (this.storage.isSet("knownNewUsers"))
+ NewUserSearch.knownNewUsers = this.storage.get("knownNewUsers");
+ if (this.storage.isSet("lastProcessedBlock"))
+ NewUserSearch.lastProcessedBlock = this.storage.get("lastProcessedBlock");
+ if (this.storage.isSet("startProcessedBlock"))
+ NewUserSearch.startProcessedBlock = this.storage.get("startProcessedBlock");
+
+ if ($.Options.NewUsersLiveTracking.val === 'enable')
+ setInterval(function(){NewUserSearch.live($('.module.new-users'));}, 10000);
+ },
+
+ save: function(){
+ this.storage.set("knownNewUsers", NewUserSearch.knownNewUsers);
+ this.storage.set("lastProcessedBlock", NewUserSearch.lastProcessedBlock);
+ this.storage.set("startProcessedBlock", NewUserSearch.startProcessedBlock);
+ },
+
+ getNewUsers: function(module) {
+ requestBestBlock(NewUserSearch.processBestBlockUsersProxy, {obj: this, args: {module: module}});
+ },
+
+ getLastNUsers: function (n, offset, module, forced) {
+ for (var i = offset; i < NewUserSearch.knownNewUsers.length && i < offset + n; i++)
+ processWhoToFollowSuggestion(module, NewUserSearch.knownNewUsers[i]);
+
+ if (NewUserSearch.knownNewUsers.length >= n + offset) {
+ NewUserSearch.isNewUserThRunning = false;
+ return true;
+ }
+
+ if (NewUserSearch.isNewUserThRunning)
+ return false;
+
+ NewUserSearch.isNewUserThRunning = true;
+ this.isForced = forced;
+
+ if (NewUserSearch.lastProcessedBlock == -1)
+ requestBestBlock(NewUserSearch.processBlockUsersProxy, {obj: this, args: {n: n, offset: offset, module: module}});
+ else
+ requestNthBlock(NewUserSearch.lastProcessedBlock - 1, NewUserSearch.processBlockUsersProxy, {obj: this, args: {n: n, offset: offset, module: module}});
+
+ return true;
+ },
+
+ processBlockUsers: function (block, args) {
+ if (NewUserSearch.startProcessedBlock === -1)
+ NewUserSearch.startProcessedBlock = block.height;
+ if (NewUserSearch.lastProcessedBlock === -1 || block.height < NewUserSearch.lastProcessedBlock)
+ NewUserSearch.lastProcessedBlock = block.height;
+
+ if ((this.isForced || NewUserSearch.isNewUserModalOpen) &&
+ NewUserSearch.knownNewUsers.length + block.usernames.length < args.args.n + args.args.offset &&
+ typeof block.previousblockhash !== 'undefined') {
+
+ setTimeout(function () {
+ requestBlock(block.previousblockhash, NewUserSearch.processBlockUsersProxy, {obj: args.obj, args: args.args});
+ }, 10);
+
+ } else {
+ NewUserSearch.isNewUserThRunning = false;
+ this.isForced = false;
+ }
+
+ var i = 0;
+ for (; i < block.usernames.length; i++) {
+ if (NewUserSearch.knownNewUsers.indexOf(block.usernames[i]) == -1) {
+ processWhoToFollowSuggestion(args.args.module, block.usernames[i], undefined, args.args.prepend);
+ if (args.args.prepend)
+ NewUserSearch.knownNewUsers.unshift(block.usernames[i]);
+ else
+ NewUserSearch.knownNewUsers.push(block.usernames[i]);
+ if (!args.args.live && NewUserSearch.knownNewUsers.length >= args.args.n + args.args.offset)
+ break;
+ }
+ }
+ for (; i < block.usernames.length; i++) {
+ if (NewUserSearch.knownNewUsers.indexOf(block.usernames[i]) == -1) {
+ if (args.args.prepend)
+ NewUserSearch.knownNewUsers.unshift(block.usernames[i]);
+ else
+ NewUserSearch.knownNewUsers.push(block.usernames[i]);
+ }
+ }
+
+ this.save();
+ }
+};
+
// randomly choose a user we follow, get "following1" from him and them
// choose a suggestion from their list. this function could be way better, but
// that's about the simplest we may get to start with.
@@ -445,10 +568,11 @@ function getRandomFollowSuggestion() {
var suggested = false;
var j = Math.floor(Math.random() * twisterFollowingO.followingsFollowings[followingUsers[i]].following.length);
+ var module = $('.module.who-to-follow');
for( ; j < twisterFollowingO.followingsFollowings[followingUsers[i]].following.length; j++ ) {
if( followingUsers.indexOf(twisterFollowingO.followingsFollowings[followingUsers[i]].following[j]) < 0 &&
_followSuggestions.indexOf(twisterFollowingO.followingsFollowings[followingUsers[i]].following[j]) < 0) {
- processWhoToFollowSuggestion(twisterFollowingO.followingsFollowings[followingUsers[i]].following[j], followingUsers[i]);
+ processWhoToFollowSuggestion(module, twisterFollowingO.followingsFollowings[followingUsers[i]].following[j], followingUsers[i]);
_followSuggestions.push(twisterFollowingO.followingsFollowings[followingUsers[i]].following[j]);
suggested = true;
break;
@@ -500,31 +624,50 @@ function getWhoFollows(peerAlias, elem) {
;
}
-function processWhoToFollowSuggestion(suggestion, followedBy) {
- if (suggestion) {
- var module = $('.module.who-to-follow');
- var list = module.find('.follow-suggestions');
- var item = $('#follow-suggestion-template').clone(true)
- .removeAttr('id');
+function processWhoToFollowSuggestion(module, peerAlias, followedBy, prepend) {
+ if (!peerAlias) {
+ console.warn('nothing to proceed: no twisters to follow was suggested');
+ return;
+ }
+
+ var list = module.find('.follow-suggestions');
+ var item = twister.tmpl.whoTofollowPeer.clone(true);
- item.find('.twister-user-info').attr('data-screen-name', suggestion);
- item.find('.twister-user-name').attr('href', $.MAL.userUrl(suggestion));
- item.find('.twister-by-user-name').attr('href', $.MAL.userUrl(followedBy));
- item.find('.twister-user-tag').text('@' + suggestion);
+ item.find('.twister-user-info').attr('data-screen-name', peerAlias);
+ item.find('.twister-user-name').attr('href', $.MAL.userUrl(peerAlias));
+ item.find('.twister-user-tag').text('@' + peerAlias);
- getAvatar(suggestion, item.find('.twister-user-photo'));
- getFullname(followedBy, item.find('.followed-by').text(followedBy));
+ getAvatar(peerAlias, item.find('.twister-user-photo'));
+ getStatusTime(peerAlias, item.find('.latest-activity .time'));
- item.find('.twister-user-remove').on('click', function() {
- item.remove();
+ if (module.hasClass('who-to-follow') || module.hasClass('who-to-follow-modal')) {
+ item.find('.twister-by-user-name').attr('href', $.MAL.userUrl(followedBy));
+ getFullname(followedBy, item.find('.followed-by').text(followedBy));
+ item.find('.twister-user-remove').on('click', {item: item}, function (event) {
+ event.data.item.remove();
getRandomFollowSuggestion();
});
+ } else if (module.hasClass('new-users') || module.hasClass('new-users-modal')) {
+ item.find('.followers').remove();
+ item.find('.twister-user-remove').remove();
+ }
+ if (module.hasClass('modal-wrapper')) {
+ getFullname(peerAlias, item.find('.twister-user-full'));
+ getBioToElem(peerAlias, item.find('.bio'));
+ item.find('.twister-user-remove').remove();
+ }
+
+ if (prepend)
+ list.prepend(item).show();
+ else
list.append(item).show();
- module.find('.refresh-users').show();
- module.find('.loading-roller').hide();
- } else
- console.warn('nothing to proceed: no twisters to follow was suggested');
+
+ while (module.hasClass('new-users') && list.children().length > 3)
+ list.children().last().remove();
+
+ module.find('.refresh-users').show();
+ module.find('.loading-roller').hide();
}
function closeSearchDialog(event) {
diff --git a/js/twister_formatpost.js b/js/twister_formatpost.js
index 79fd1e5..acc3c97 100644
--- a/js/twister_formatpost.js
+++ b/js/twister_formatpost.js
@@ -43,6 +43,8 @@ function postToElem(post, kind, promoted) {
"dm" : encrypted message (dm) -opt
"rt" : original userpost - opt
"sig_rt" : sig of rt - opt
+ "fav" : original userpost - opt
+ "sif_fav" : sig of fav - opt
"reply" : - opt
{
"n" : reference username
@@ -57,6 +59,10 @@ function postToElem(post, kind, promoted) {
// Obtain data from userpost
var userpost = post.userpost;
+ //TODO: favorites may have comment also...
+ if (userpost.fav)
+ userpost = userpost.fav;
+
if (post.sig_wort)
userpost.sig_wort = post.sig_wort;
@@ -238,7 +244,7 @@ function setPostReference(elem, rt, sig_rt) {
.attr('data-screen-name', rt.n)
.attr('data-id', rt.k)
.attr('data-userpost', $.toJSON({userpost: rt, sig_userpost: sig_rt}))
- .find('.post-text').each(function (i, elem) {fillElemWithTxt($(elem), rt.msg);})
+ .find('.post-text').each(function (i, elem) {fillElemWithTxt($(elem), rt.msg + (rt.msg2 || ''));})
;
setPostCommon(elem, rt.n, rt.time);
}
@@ -490,56 +496,31 @@ function htmlFormatMsg(msg, opt) {
}
// changing the string
- if (chr === '`' && markoutOpt === 'apply') { // if markoutOpt === 'clear' then ` does not escape anythyng so it needs to be handled like other tags
- for (i = 0; i < p.length; i++) {
- if (p[i].a > -1) {
- if (p[i].t === -1 || (p[i].t === 0 && p[i].a > i)) {
- if (p[i].k > 1)
- t = Array(p[i].k).join(chr);
- else
- t = '';
- j = p[i].a;
- t = t + msg.str.slice(p[i].i + p[i].k, p[j].i);
- if (p[j].k > 1)
- t = t + Array(p[i].k).join(chr);
- t = '<' + tag + '>' + t + '' + tag + '>';
- msg.htmlEntities.push(t.replace(/&(?!lt;|gt;)/g, '&'));
- htmlEntityEncoded = '>' + (msg.htmlEntities.length - 1).toString() + '<';
- msg.str = msg.str.slice(0, p[i].i) + htmlEntityEncoded + msg.str.slice(p[j].i + p[j].k);
- l = htmlEntityEncoded.length - p[j].i - p[j].k + p[i].i;
- i = j;
- for (j += 1; j < p.length; j++)
- p[j].i += l;
- }
- }
- }
- } else {
- if (markoutOpt === 'apply') {
- t = '' + tag + '>';
- tag = '<' + tag + '>';
- } else { // markoutOpt === 'clear' so we're clearing markup
- t = '';
- tag = '';
- }
- for (i = 0; i < p.length; i++) {
- if (p[i].a > -1) {
- if (p[i].t === -1 || (p[i].t === 0 && p[i].a > i)) {
- if (p[i].k > 1)
- msg.htmlEntities.push(tag + Array(p[i].k).join(chr));
- else
- msg.htmlEntities.push(tag);
- } else if (p[i].t === 1 || (p[i].t === 0 && p[i].a < i)) {
- if (p[i].k > 1)
- msg.htmlEntities.push(Array(p[i].k).join(chr) + t);
- else
- msg.htmlEntities.push(t);
- }
- htmlEntityEncoded = '>' + (msg.htmlEntities.length - 1).toString() + '<';
- msg.str = msg.str.slice(0, p[i].i) + htmlEntityEncoded + msg.str.slice(p[i].i + p[i].k);
- l = htmlEntityEncoded.length - p[i].k;
- for (j = i + 1; j < p.length; j++)
- p[j].i += l;
+ if (markoutOpt === 'apply') {
+ t = '' + tag + '>';
+ tag = '<' + tag + '>';
+ } else { // markoutOpt === 'clear' so we're clearing markup
+ t = '';
+ tag = '';
+ }
+ for (i = 0; i < p.length; i++) {
+ if (p[i].a > -1) {
+ if (p[i].t === -1 || (p[i].t === 0 && p[i].a > i)) {
+ if (p[i].k > 1)
+ msg.htmlEntities.push(tag + Array(p[i].k).join(chr));
+ else
+ msg.htmlEntities.push(tag);
+ } else if (p[i].t === 1 || (p[i].t === 0 && p[i].a < i)) {
+ if (p[i].k > 1)
+ msg.htmlEntities.push(Array(p[i].k).join(chr) + t);
+ else
+ msg.htmlEntities.push(t);
}
+ htmlEntityEncoded = '>' + (msg.htmlEntities.length - 1).toString() + '<';
+ msg.str = msg.str.slice(0, p[i].i) + htmlEntityEncoded + msg.str.slice(p[i].i + p[i].k);
+ l = htmlEntityEncoded.length - p[i].k;
+ for (j = i + 1; j < p.length; j++)
+ p[j].i += l;
}
}
@@ -604,7 +585,17 @@ function htmlFormatMsg(msg, opt) {
msg = {str: escapeHtmlEntities(msg), htmlEntities: []};
- msg = markout(msg, markoutOpt, '`', 'samp'); // tag is kind of monospace, here sequence of chars inside it will be escaped from markup
+ // markout is not applied for chars inside of ``; to escape ` use backslash
+ if (markoutOpt === 'apply')
+ msg.str = msg.str.replace(/`(?:[^`\\]|\\.)*`/g, function (s) {
+ msg.htmlEntities.push('' + s.slice(1, -1).replace(/\\`/g, '`')
+ .replace(/&(?!lt;|gt;)/g, '&') + '');
+ return '>' + (msg.htmlEntities.length - 1).toString() + '<';
+ });
+ else if (markoutOpt === 'clear')
+ msg.str = msg.str.replace(/`((?:[^`\\]|\\.)*)`/g, function (s) {
+ return s.slice(1, -1).replace(/\\`/g, '`');
+ });
// handling links
for (i = 0; i < msg.str.length - 7; i++) {
@@ -620,21 +611,25 @@ function htmlFormatMsg(msg, opt) {
break;
}
if (i < k) {
- var x = getSubStrEnd(msg.str, i, ':', false, '') + 1;
// following check is NOT for real protection (we have blocking CSP rule instead), it's just to aware people
- if (msg.str[i] === '#' || (x > i && x < k && (msg.str.slice(x - 6, x).toLowerCase() === 'script' // other things would be added when W3C and all the people invent it
- || msg.str.slice(x - 4, x).toLowerCase() === 'data'))) {
+ if (isUriSuspicious(msg.str.slice(i, k + 1))) {
msg = msgAddHtmlEntity(msg, j - 1, getSubStrEnd(msg.str, k + 1, ')', true, '') + 2,
'… ' + polyglot.t('busted_oh') + ' '
- + polyglot.t('busted_avowal') + ': '
+ + polyglot.t('busted_avowal') + ': ['
+ + linkName
+ .replace(/&(?!lt;|gt;)/g, '&')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''')
+ + ']('
+ msg.str.slice(i, k + 1)
.replace(/&(?!lt;|gt;)/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
- + ' '
+ + ') … '
);
} else {
- if ((x = getSubStrEnd(msg.str, i + 1, whiteSpacesUrl, false, '')) < k) // use only first word as href target, others drop silently
+ var x = getSubStrEnd(msg.str, i + 1, whiteSpacesUrl, false, '');
+ if (x < k) // use only first word as href target, others drop silently
k = x;
linkName = applyHtml( // we're handling markup inside [] of []()
markout(markout(markout(markout(
@@ -787,6 +782,27 @@ function htmlFormatMsg(msg, opt) {
return {html: msg, mentions: mentions};
}
+function isUriSuspicious(req) {
+ var colonPos = req.search(/:|%3A/gi);
+ if (colonPos === 0)
+ return true;
+
+ var hashPos = req.search(/#|%23/g);
+
+ if (colonPos === -1)
+ if (hashPos > -1)
+ return req = req.slice(hashPos + 1),
+ (req.search(/^(?:hashtag|profile|conversation|mentions|favs|directmessages|groupmessages|newusers|followers|following|whotofollow|groupmessages\+newgroup|groupmessages\+joingroup\/uri\-shortener)\b/) > -1) ? false : true;
+ else
+ return false; //(req.search(/^\s*@[A-Za-z0-9]+\/\d/g) === 0) ? false : true;
+
+ if (hashPos > -1 && hashPos < colonPos)
+ return true;
+
+ return req = req.slice(req.search(/\S/g), colonPos),
+ req.search(/[^A-Za-z0-9\+\.\-]/) > -1 || req.search(/(?:script|data)$/i) > -1;
+}
+
function proxyURL(url) {
var proxyOpt = $.Options.useProxy.val;
if (proxyOpt !== 'disable' && !$.Options.useProxyForImgOnly.val
diff --git a/js/twister_io.js b/js/twister_io.js
index 9ab1ac3..a613690 100644
--- a/js/twister_io.js
+++ b/js/twister_io.js
@@ -115,7 +115,8 @@ function dhtget(peerAlias, resource, multi, cbFunc, cbReq, timeoutArgs) {
function decodeShortURI(locator, cbFunc, cbReq, timeoutArgs) {
if (!locator) return;
if (parseInt(twisterVersion) < 93500) {
- console.warn('can\'t fetch URI "' + req + '": daemon is obsolete, version 0.9.35 or higher is required');
+ console.warn('can\'t fetch URI "' + req + '" — '
+ + polyglot.t('daemon_is_obsolete', {versionReq: '0.9.35'}));
return;
}
@@ -279,7 +280,8 @@ function getFullname(peerAlias, elem) {
twisterFollowingO.knownFollowers.push(req.peerAlias);
twisterFollowingO.save();
addPeerToFollowersList(getElem('.followers-modal .followers-list'), req.peerAlias, true);
- $('.open-followers').attr('title', twisterFollowingO.knownFollowers.length.toString());
+ $('.module.mini-profile .open-followers')
+ .attr('title', twisterFollowingO.knownFollowers.length.toString());
}
req.elem.addClass('isFollowing');
req.elem.attr('title', polyglot.t('follows you'));
@@ -291,7 +293,8 @@ function getFullname(peerAlias, elem) {
if (twisterFollowingO.knownFollowers.indexOf(req.peerAlias) === -1) {
twisterFollowingO.knownFollowers.push(req.peerAlias);
addPeerToFollowersList(getElem('.followers-modal .followers-list'), req.peerAlias, true);
- $('.open-followers').attr('title', twisterFollowingO.knownFollowers.length.toString());
+ $('.module.mini-profile .open-followers')
+ .attr('title', twisterFollowingO.knownFollowers.length.toString());
}
req.elem.addClass('isFollowing');
req.elem.attr('title', polyglot.t('follows you'));
@@ -520,6 +523,22 @@ function getPostsCount(peerAlias, elem) {
);
}
+function getStatusTime(peerAlias, elem) {
+ dhtget(peerAlias, 'status', 's',
+ function (req, ret) {
+ if (!ret || !ret.userpost)
+ return;
+
+ req.elem.text(timeGmtToText(ret.userpost.time))
+ .closest('.latest-activity')
+ .attr('data-screen-name', req.peerAlias)
+ .attr('data-id', ret.userpost.k)
+ .attr('data-time', ret.userpost.time)
+ ;
+ }, {peerAlias: peerAlias, elem: elem}
+ );
+}
+
function getPostMaxAvailability(peerAlias, k, cbFunc, cbReq) {
twisterRpc('getpiecemaxseen', [peerAlias, k],
function(req, ret) {
diff --git a/js/twister_network.js b/js/twister_network.js
index 38694f7..7f47a58 100644
--- a/js/twister_network.js
+++ b/js/twister_network.js
@@ -146,46 +146,56 @@ function requestBestBlock(cbFunc, cbArg) {
}, {});
}
+function requestNthBlock(n, cbFunc, cbArg) {
+ twisterRpc("getblockhash", [n],
+ function(args, hash) {
+ requestBlock(hash, args.cbFunc, args.cbArg);
+ }, {cbFunc:cbFunc, cbArg:cbArg},
+ function(args, ret) {
+ console.log("getblockhash error");
+ }, {});
+}
+
function requestBlock(hash, cbFunc, cbArg) {
twisterRpc("getblock", [hash],
function(args, block) {
- twisterdLastBlockTime = block.time;
- $(".last-block-time").text( timeGmtToText(twisterdLastBlockTime) );
-
if( args.cbFunc )
- args.cbFunc(args.cbArg);
+ args.cbFunc(block, args.cbArg);
}, {cbFunc:cbFunc, cbArg:cbArg},
function(args, ret) {
console.log("requestBlock error");
}, {});
}
-
function networkUpdate(cbFunc, cbArg) {
requestNetInfo(function () {
- requestBestBlock(function(args) {
+ requestBestBlock(function(block, args) {
+
+ twisterdLastBlockTime = block.time;
+ $(".last-block-time").text(timeGmtToText(twisterdLastBlockTime));
+
var curTime = new Date().getTime() / 1000;
- if( twisterdConnections ) {
- if( twisterdLastBlockTime > curTime + 3600 ) {
+ if (twisterdConnections) {
+ if (twisterdLastBlockTime > curTime + 3600) {
$.MAL.setNetworkStatusMsg(polyglot.t("Last block is ahead of your computer time, check your clock."), false);
twisterdConnectedAndUptodate = false;
- } else if( twisterdLastBlockTime > curTime - (2 * 3600) ) {
- if( twisterDhtNodes ) {
+ } else if (twisterdLastBlockTime > curTime - (2 * 3600)) {
+ if (twisterDhtNodes) {
$.MAL.setNetworkStatusMsg(polyglot.t("Block chain is up-to-date, twister is ready to use!"), true);
twisterdConnectedAndUptodate = true;
- } else {
+ } else {
$.MAL.setNetworkStatusMsg(polyglot.t("DHT network down."), false);
twisterdConnectedAndUptodate = true;
- }
+ }
} else {
- var daysOld = (curTime - twisterdLastBlockTime) / (3600*24);
- $.MAL.setNetworkStatusMsg(polyglot.t("downloading_block_chain", { days: daysOld.toFixed(2) }), false);
+ var daysOld = (curTime - twisterdLastBlockTime) / (3600 * 24);
+ $.MAL.setNetworkStatusMsg(polyglot.t("downloading_block_chain", {days: daysOld.toFixed(2)}), false);
// don't alarm user if blockchain is just a little bit behind
twisterdConnectedAndUptodate = (daysOld < 2);
}
}
- if( args.cbFunc )
- args.cbFunc(args.cbArg)
+ if (args.cbFunc)
+ args.cbFunc(args.cbArg);
}, {cbFunc:cbFunc, cbArg:cbArg} );
});
}
@@ -318,12 +328,9 @@ function initInterfaceNetwork() {
initMentionsCount();
initDMsCount();
});
+ } else {
+ $('.userMenu-profile > a').attr('href', '#/login').text(polyglot.t('Login'));
}
- else
- {
- $(".userMenu-profile > a").text(polyglot.t("Login"));
- $(".userMenu-profile > a").attr("href","login.html");
- }
});
networkUpdate();
setInterval("networkUpdate()", 2000);
diff --git a/js/twister_newmsgs.js b/js/twister_newmsgs.js
index 535c3ed..7a2c9c8 100644
--- a/js/twister_newmsgs.js
+++ b/js/twister_newmsgs.js
@@ -6,190 +6,170 @@
// --- mentions ---
-var _knownMentions = {}
-var _lastMentionTime = 0;
-var _newMentions = 0;
-var _lastLocalMentionId = -1;
-var PURGE_OLD_MENTIONS_TIMEOUT = 3600 * 24 * 30; // one month
-var _newMentionsUpdated = false;
-var _newDMsUpdated = false;
var groupChatAliases = []
-// process a mention received to check if it is really new
-function processMention(user, mentionTime, data) {
- var key = user + ';' + mentionTime;
- var curTime = new Date().getTime() / 1000;
- if (mentionTime > curTime + 7200) // 3600 * 2
- console.warn('ignoring mention from the future');
- else {
- if (!_knownMentions[key]) {
- // mention must be somewhat recent compared to last known one to be considered new
- if (mentionTime + 259200 > _lastMentionTime) { // 3600 * 24 * 3
- _newMentions++;
- _newMentionsUpdated = true;
- _lastMentionTime = Math.max(mentionTime, _lastMentionTime);
- data.isNew = true;
-
- var reqId = defaultScreenName + '@mention';
- if (typeof _queryPendingPosts[reqId] !== 'object')
- _queryPendingPosts[reqId] = [];
- _queryPendingPosts[reqId].push(data);
+function saveMentionsToStorage() {
+ var twists = [], length = 0;
+ for (var j in twister.mentions.twists.cached) {
+ for (var i = 0; i < length; i++)
+ if (twister.mentions.twists.cached[j].userpost.time > twists[i].userpost.time) {
+ twists.splice(i, 0, twister.mentions.twists.cached[j]);
+ break;
}
- _knownMentions[key] = {mentionTime: mentionTime, data: data};
- purgeOldMentions();
- saveMentionsToStorage();
- }
- }
-}
-function purgeOldMentions() {
- for (var key in _knownMentions) {
- if (_knownMentions[key]) {
- if (!_knownMentions[key].mentionTime || !_knownMentions[key].data ||
- _knownMentions[key].mentionTime + PURGE_OLD_MENTIONS_TIMEOUT < _lastMentionTime) {
- delete _knownMentions[key];
- }
- }
+ if (length === twists.length)
+ twists.push(twister.mentions.twists.cached[j]);
+
+ length++;
}
-}
-function saveMentionsToStorage() {
- var ns = $.initNamespaceStorage(defaultScreenName);
- ns.localStorage.set('knownMentions', _knownMentions);
- ns.localStorage.set('lastMentionTime', _lastMentionTime);
- ns.localStorage.set('newMentions', _newMentions);
- ns.localStorage.set('lastLocalMentionId', _lastLocalMentionId);
+ $.initNamespaceStorage(defaultScreenName).localStorage
+ .set('mentions', {
+ twists: twists.slice(0, 100), // TODO add an option to specify number of mentions to cache
+ lastTime: twister.mentions.lastTime,
+ lastTorrentId: twister.mentions.lastTorrentId
+ })
+ ;
}
function loadMentionsFromStorage() {
- var ns = $.initNamespaceStorage(defaultScreenName);
- if (ns.localStorage.isSet('knownMentions'))
- _knownMentions = ns.localStorage.get('knownMentions');
- if (ns.localStorage.isSet('lastMentionTime'))
- _lastMentionTime = ns.localStorage.get('lastMentionTime');
- if (ns.localStorage.isSet('newMentions'))
- _newMentions = ns.localStorage.get('newMentions');
- if (ns.localStorage.isSet('lastLocalMentionId'))
- _lastLocalMentionId = ns.localStorage.get('lastLocalMentionId');
-}
-
-function requestMentionsCount() {
- // first: getmentions from torrents we follow
- twisterRpc('getmentions', [defaultScreenName, 100, {since_id: _lastLocalMentionId}],
- function(args, data) {
- if (data) {
- for (var i = 0; i < data.length; i++) {
- _lastLocalMentionId = Math.max(_lastLocalMentionId, data[i].id);
- var userpost = data[i].userpost;
- processMention(userpost.n, userpost.time, data[i]);
+ var storage = $.initNamespaceStorage(defaultScreenName).localStorage;
+
+ if (storage.isSet('mentions')) {
+ var mentions = storage.get('mentions');
+ if (typeof mentions === 'object') {
+ for (var i = 0; i < mentions.twists.length; i++) {
+ var j = mentions.twists[i].userpost.n + '/' + mentions.twists[i].userpost.time;
+ if (typeof twister.mentions.twists.cached[j] === 'undefined') {
+ twister.mentions.twists.cached[j] = mentions.twists[i];
+ if (twister.mentions.twists.cached[j].isNew)
+ twister.mentions.lengthNew++;
+
+ twister.mentions.lengthFromTorrent++;
}
- $.MAL.updateNewMentionsUI(_newMentions);
}
- }, null,
- function(req, ret) {console.warn('getmentions API requires twister-core > 0.9.27');}, null
- );
- // second: get mentions from dht (not-following)
- dhtget(defaultScreenName, 'mention', 'm',
- function(args, data) {
- if (data) {
- for (var i = 0; i < data.length; i++) {
- var userpost = data[i].userpost;
- processMention(userpost.n, userpost.time, data[i]);
- }
- $.MAL.updateNewMentionsUI(_newMentions);
- }
- }, {},
- [10000, 2000, 3] // use extended timeout parameters (requires twister_core >= 0.9.14)
- );
-
- if (_newMentionsUpdated) {
- _newMentionsUpdated = false;
-
- if (_newMentions) {
- $.MAL.soundNotifyMentions();
-
- if (!$.hasOwnProperty('mobile') && $.Options.showDesktopNotifMentions.val === 'enable')
- $.MAL.showDesktopNotification({
- body: polyglot.t('You got') + ' ' + polyglot.t('new_mentions', _newMentions) + '.',
- tag: 'twister_notification_new_mentions',
- timeout: $.Options.showDesktopNotifMentionsTimer.val,
- funcClick: function () {
- var postboardSelector =
- '.postboard-posts[data-request-id="' + defaultScreenName + '@mention"]';
- if (!focusModalWithElement(postboardSelector,
- function (req) {
- var postboard = $(req.postboardSelector);
- postboard.closest('.postboard').find('.postboard-news').hide();
- displayQueryPending(postboard);
- resetMentionsCount();
- }, {postboardSelector: postboardSelector}
- ))
- $.MAL.showMentions(defaultScreenName);
- }
- });
+ twister.mentions.lastTime = mentions.lastTime;
+ twister.mentions.lastTorrentId = mentions.lastTorrentId;
}
}
- // was moved here from requestDMsCount() because that is not ticking right
- // we would place it with other notifications into separate notification center
- if (_newDMsUpdated) {
- _newDMsUpdated = false;
-
- var newDMs = getNewDMsCount();
- if (newDMs) {
- $.MAL.soundNotifyDM();
-
- if (!$.hasOwnProperty('mobile') && $.Options.showDesktopNotifDMs.val === 'enable') {
- $.MAL.showDesktopNotification({
- body: polyglot.t('You got') + ' ' + polyglot.t('new_direct_messages', newDMs) + '.',
- tag: 'twister_notification_new_DMs',
- timeout: $.Options.showDesktopNotifDMsTimer.val,
- funcClick: function () {$.MAL.showDMchat();}
- });
+ // WARN all following storage keys are deprecated (see commit dc8cfc20ef10ff3008b4abfdb30d31e7fcbec0cd)
+ if (storage.isSet('knownMentions')) {
+ var mentions = storage.get('knownMentions');
+ if (typeof mentions === 'object')
+ for (var i in mentions) {
+ var j = mentions[i].data.userpost.n + '/' + mentions[i].mentionTime;
+ if (typeof twister.mentions.twists.cached[j] === 'undefined') {
+ twister.mentions.twists.cached[j] = mentions[i].data;
+ if (twister.mentions.twists.cached[j].isNew)
+ twister.mentions.lengthNew++;
+
+ twister.mentions.lengthFromTorrent++;
+ }
}
+
+ storage.remove('knownMentions');
+ }
+ if (storage.isSet('lastMentionTime')) {
+ twister.mentions.lastTime = storage.get('lastMentionTime');
+ storage.remove('lastMentionTime');
+ }
+ if (storage.isSet('lastLocalMentionId')) {
+ twister.mentions.lastTorrentId = storage.get('lastLocalMentionId');
+ storage.remove('lastLocalMentionId');
+ }
+ if (storage.isSet('newMentions'))
+ storage.remove('newMentions');
+}
+
+function queryPendingPushMentions(req, res) {
+ var lengthNew = 0;
+ var lengthPending = twister.res[req].twists.pending.length;
+ var timeCurrent = new Date().getTime() / 1000 + 7200; // 60 * 60 * 2
+ var timeLastMention = twister.res[req].lastTime;
+
+ for (var i = 0; i < res.length; i++) {
+ if (res[i].userpost.time > timeCurrent) {
+ console.warn('ignoring mention from the future:');
+ console.log(res[i]);
+ continue;
}
- var newDMs = getNewGroupDMsCount();
- if (newDMs) {
- $.MAL.soundNotifyDM();
-
- if (!$.hasOwnProperty('mobile') && $.Options.showDesktopNotifDMs.val === 'enable') {
- $.MAL.showDesktopNotification({
- body: polyglot.t('You got') + ' ' + polyglot.t('new_group_messages', newDMs) + '.',
- tag: 'twister_notification_new_DMs',
- timeout: $.Options.showDesktopNotifDMsTimer.val,
- funcClick: function () {$.MAL.showDMchat({group: true});}
- });
+
+ if (res[i].id) {
+ twister.res[req].lastTorrentId = Math.max(twister.res[req].lastTorrentId, res[i].id);
+ delete res[i].id;
+ twister.res[req].lengthFromTorrent++;
+ }
+
+ var j = res[i].userpost.n + '/' + res[i].userpost.time;
+ if (typeof twister.res[req].twists.cached[j] === 'undefined') {
+ twister.res[req].twists.cached[j] = res[i];
+ twister.res[req].twists.pending.push(j);
+
+ // mention must be somewhat recent compared to last known one to be considered new
+ if (res[i].userpost.time + 259200 > timeLastMention) { // 3600 * 24 * 3
+ lengthNew++;
+ twister.res[req].lastTime = Math.max(res[i].userpost.time, twister.res[req].lastTime);
+ twister.res[req].twists.cached[j].isNew = true;
}
}
}
+
+ if (lengthNew)
+ twister.res[req].lengthNew += lengthNew;
+
+ if (twister.res[req].twists.pending.length > lengthPending)
+ saveMentionsToStorage();
+
+ return lengthNew;
}
function resetMentionsCount() {
- _newMentions = 0;
- for (var key in _knownMentions) {
- if (_knownMentions[key] && _knownMentions[key].data)
- delete _knownMentions[key].data.isNew
- }
+ twister.mentions.lengthNew = 0;
+
+ for (var j in twister.mentions.twists.cached)
+ if (twister.mentions.twists.cached[j].isNew)
+ delete twister.mentions.twists.cached[j].isNew;
+
saveMentionsToStorage();
- $.MAL.updateNewMentionsUI(_newMentions);
+ $.MAL.updateNewMentionsUI(twister.mentions.lengthNew);
}
function initMentionsCount() {
- // polling mentions is a temporary solution
- loadMentionsFromStorage();
- $.MAL.updateNewMentionsUI(_newMentions);
- requestMentionsCount();
- setInterval(requestMentionsCount, 10000);
+ var req = queryStart('', defaultScreenName, 'mention', [10000, 2000, 3], 10000, {
+ lastTime: 0,
+ lastTorrentId: -1,
+ lengthNew: 0,
+ ready: function (req) {
+ twister.mentions = twister.res[req];
+ twister.mentions.lengthFromTorrent = 0;
+ loadMentionsFromStorage();
+ },
+ skidoo: function () {return false;}
+ });
+
+ $.MAL.updateNewMentionsUI(twister.mentions.lengthNew);
}
-function getMentionsData() {
- mentions = []
- for (var key in _knownMentions) {
- if (_knownMentions[key] && _knownMentions[key].data) {
- mentions.push(_knownMentions[key].data);
- }
+function handleMentionsModalScroll(event) {
+ if (!event || twister.mentions.scrollQueryActive)
+ return;
+
+ var elem = $(event.target);
+ if (elem.scrollTop() >= elem[0].scrollHeight - elem.height() - 50) {
+ twister.mentions.scrollQueryActive = true;
+
+ twisterRpc('getmentions', [twister.mentions.query, 10,
+ {max_id: twister.mentions.lastTorrentId - twister.mentions.lengthFromTorrent}],
+ function (req, res) {
+ twister.mentions.scrollQueryActive = false;
+ twister.res[req].boardAutoAppend = true; // FIXME all pending twists will be appended
+ queryProcess(req, res);
+ twister.res[req].boardAutoAppend = false;
+ }, twister.mentions.query + '@' + twister.mentions.resource,
+ function () {console.warn('getmentions API requires twister-core > 0.9.27');}
+ );
}
- return mentions;
}
// --- direct messages ---
@@ -220,25 +200,53 @@ function requestDMsCount() {
twisterRpc('getdirectmsgs', [defaultScreenName, 1, followList],
function(req, dmUsers) {
+ var newDMsUpdated;
+
for (var u in dmUsers) {
if (dmUsers[u]) {
var dmData = dmUsers[u][0];
if (u in _lastDMIdPerUser && u in _newDMsPerUser) {
if (dmData.id !== _lastDMIdPerUser[u]) {
_newDMsPerUser[u] += dmData.id - _lastDMIdPerUser[u];
- _newDMsUpdated = true;
+ newDMsUpdated = true;
}
} else {
_newDMsPerUser[u] = dmData.id + 1;
- _newDMsUpdated = true;
+ newDMsUpdated = true;
}
_lastDMIdPerUser[u] = dmData.id;
}
}
- if (_newDMsUpdated) {
+ if (newDMsUpdated) {
saveDMsToStorage();
- $.MAL.updateNewDMsUI(getNewDMsCount());
- $.MAL.updateNewGroupDMsUI(getNewGroupDMsCount());
+ var newDMs = getNewDMsCount();
+ if (newDMs) {
+ $.MAL.updateNewDMsUI(newDMs);
+ $.MAL.soundNotifyDM();
+
+ if (!$.mobile && $.Options.showDesktopNotifDMs.val === 'enable') {
+ $.MAL.showDesktopNotification({
+ body: polyglot.t('You got') + ' ' + polyglot.t('new_direct_messages', newDMs) + '.',
+ tag: 'twister_notification_new_DMs',
+ timeout: $.Options.showDesktopNotifDMsTimer.val,
+ funcClick: function () {$.MAL.showDMchat();}
+ });
+ }
+ }
+ var newDMs = getNewGroupDMsCount();
+ if (newDMs) {
+ $.MAL.updateNewGroupDMsUI(newDMs);
+ $.MAL.soundNotifyDM();
+
+ if (!$.mobile && $.Options.showDesktopNotifDMs.val === 'enable') {
+ $.MAL.showDesktopNotification({
+ body: polyglot.t('You got') + ' ' + polyglot.t('new_group_messages', newDMs) + '.',
+ tag: 'twister_notification_new_DMs',
+ timeout: $.Options.showDesktopNotifDMsTimer.val,
+ funcClick: function () {$.MAL.showDMchat({group: true});}
+ });
+ }
+ }
}
}, null,
function(req, ret) {console.warn('ajax error:' + ret);}, null
@@ -297,7 +305,5 @@ function initDMsCount() {
}
function newmsgsChangedUser() {
- _knownMentions = {}
- _lastMentionTime = 0;
- _newMentions = 0;
+ clearInterval(twister.mentions.interval);
}
diff --git a/js/twister_user.js b/js/twister_user.js
index 77a419a..4d28c1c 100644
--- a/js/twister_user.js
+++ b/js/twister_user.js
@@ -6,47 +6,48 @@
// Load/save profile (profile-edit.html)
var defaultScreenName = undefined;
-var localUsernames = [];
var lastPostId = undefined;
// basic user functions
// -------------------------------
-function initUser(cbFunc, cbArg) {
- loadWalletlUsers( function() {
- var $localUsersList = $("select.local-usernames");
- if( $localUsersList.length ) {
- for( var i = 0; i < localUsernames.length; i++ ) {
- var $existingOption = $localUsersList.find("option[value='" + localUsernames[i] + "']");
- if( !$existingOption.length ) {
- var $userOption = $("");
- $userOption.val(localUsernames[i]);
- $userOption.text(localUsernames[i]);
- $localUsersList.append($userOption);
- }
- }
- }
-
- loadScreenName();
- if( !defaultScreenName || localUsernames.indexOf(defaultScreenName) < 0 ) {
- defaultScreenName = undefined;
- } else {
- var $localUsersLogin = $("select.local-usernames.login-user");
- if( $localUsersLogin.length ) {
- $localUsersLogin.val(defaultScreenName);
- }
-
- var $userMenuConfig = $(".userMenu-config");
- if( $userMenuConfig.length ) {
- $userMenuConfig.find("a.mini-profile-name").attr("href",$.MAL.userUrl(defaultScreenName));
- $userMenuConfig.find(".mini-profile-name").text(defaultScreenName);
- getFullname( defaultScreenName, $userMenuConfig.find(".mini-profile-name") );
- }
- }
- lastPostId = undefined;
- if( cbFunc )
- cbFunc(cbArg);
- });
+function initUser(cbFunc, cbReq) {
+ loadWalletlUsers(
+ function (req) {
+ var elemAccountsList = getElem('select.local-usernames', true);
+ if (elemAccountsList.length) {
+ for (var i = 0; i < twister.var.localAccounts.length; i++) {
+ if (!elemAccountsList.find('option[value=\'' + twister.var.localAccounts[i] + '\']').length) {
+ $('')
+ .val(twister.var.localAccounts[i])
+ .text(twister.var.localAccounts[i])
+ .appendTo(elemAccountsList)
+ ;
+ }
+ }
+ }
+
+ loadScreenName();
+ if (!defaultScreenName || twister.var.localAccounts.indexOf(defaultScreenName) < 0) {
+ defaultScreenName = undefined;
+ } else {
+ getElem('select.local-usernames', true).val(defaultScreenName);
+
+ var userMenuConfig = $('.userMenu-config');
+ if (userMenuConfig.length) {
+ var elem = userMenuConfig.find('.mini-profile-name')
+ .attr('href', $.MAL.userUrl(defaultScreenName)).text(defaultScreenName);
+ getFullname(defaultScreenName, elem);
+ }
+ }
+
+ lastPostId = undefined;
+
+ if (typeof req.cbFunc === 'function') {
+ req.cbFunc(req.cbReq);
+ }
+ }, {cbFunc: cbFunc, cbReq: cbReq}
+ );
}
function incLastPostId( optionalNewValue ) {
@@ -60,150 +61,102 @@ function incLastPostId( optionalNewValue ) {
$.MAL.updateMyOwnPostCount(lastPostId+1);
}
-function loadWalletlUsers(cbFunc, cbArg) {
- twisterRpc("listwalletusers", [],
- function(args, ret) {
- localUsernames = [];
- for( var i = 0; i < ret.length; i++ ) {
- // filter out group aliases
- if( ret.length && ret[i][0] !== '*' ) {
- localUsernames.push(ret[i]);
- }
- }
- args.cbFunc(args.cbArg);
- }, {cbFunc:cbFunc, cbArg:cbArg},
- function(args, ret) {
- alert(polyglot.t("error_connecting_to_daemon"));
- }, {});
+function loadWalletlUsers(cbFunc, cbReq) {
+ twisterRpc('listwalletusers', [],
+ function (req, ret) {
+ twister.var.localAccounts = [];
+ for (var i = 0; i < ret.length; i++) {
+ if (ret.length && ret[i][0] !== '*') { // filter out group aliases (starting with '*')
+ twister.var.localAccounts.push(ret[i]);
+ }
+ }
+
+ if (typeof req.cbFunc === 'function') {
+ req.cbFunc(req.cbReq);
+ }
+ }, {cbFunc: cbFunc, cbReq: cbReq},
+ function (req, ret) {
+ alert(polyglot.t('error_connecting_to_daemon'));
+ }
+ );
}
function loadScreenName() {
- if( $.localStorage.isSet("defaultScreenName") ) {
- defaultScreenName = $.localStorage.get("defaultScreenName").toString();
+ if ($.localStorage.isSet('defaultScreenName')) {
+ defaultScreenName = $.localStorage.get('defaultScreenName').toString();
}
}
function saveScreenName() {
- $.localStorage.set("defaultScreenName", defaultScreenName);
+ $.localStorage.set('defaultScreenName', defaultScreenName);
}
// user-related functions used by login page (desktop/mobile)
// ----------------------------------------------------------
-function loginLocalUsername() {
- defaultScreenName = $("select.local-usernames.login-user").val();
- if(defaultScreenName) {
- saveScreenName();
- $.MAL.changedUser();
- $.MAL.goHome();
- }
-}
-
-function checkUsernameAvailability() {
- var $newUsername = $(".new-username");
- var username = $newUsername.val().toLowerCase();
- $newUsername.val(username);
- var $availField = $(".availability");
-
- if( !username.length )
- return;
- if( username.length > 16 ) {
- $availField.text(polyglot.t("Must be 16 characters or less."));
- return;
- }
-
- //Check for non-alphabetic characters and space
- if(username.search(/[^a-z0-9_]/) != -1) {
- $availField.text(polyglot.t("Only alphanumeric and underscore allowed."));
+function loginToAccount(peerAlias) {
+ if (!peerAlias) {
+ console.warn('can\'t login to account: empty alias was given');
return;
}
- $availField.text(polyglot.t("Checking..."));
-
- dumpPubkey(username, function(dummy, pubkey) {
- var notAvailable = pubkey.length > 0
- var $availField = $(".availability");
- if( notAvailable ) {
- $availField.text(polyglot.t("Not available"));
- } else {
- $availField.text(polyglot.t("Available"));
-
- var $createButton = $(".create-user");
- $.MAL.enableButton( $createButton );
- }
- }, null);
-}
-
-function newUserNameKeypress() {
- var $availField = $(".availability");
- $availField.text("");
- var $createButton = $(".create-user");
- $.MAL.disableButton( $createButton );
+ defaultScreenName = peerAlias;
+ saveScreenName();
+ $.MAL.changedUser();
+ $.MAL.goHome();
}
-// create user and call cbFunc(username, privkey)
-function createUserClick(cbFunc) {
- var $newUsername = $(".new-username");
- var username = $newUsername.val().toLowerCase();
-
- if( localUsernames.indexOf(username) < 0 ) {
- twisterRpc("createwalletuser", [username],
- function(args, ret) {
- args.cbFunc(args.username, ret);
- }, {username:username, cbFunc:cbFunc},
- function(args, ret) {
- alert(polyglot.t("Error in 'createwalletuser' RPC."));
- }, {cbFunc:cbFunc});
- } else {
- // user exists in wallet but transaction not sent
- dumpPrivkey(username,
- function(args, ret) {
- args.cbFunc(args.username, ret);
- }, {username:username, cbFunc:cbFunc});
+function createAccount(peerAlias) {
+ if (!peerAlias) {
+ console.warn('can\'t create account: empty alias was given');
+ return;
}
-}
-function sendNewUserTransaction(username, cbFunc) {
- twisterRpc("sendnewusertransaction", [username],
- function(args, ret) {
- args.cbFunc();
- }, {cbFunc:cbFunc},
- function(args, ret) {
- alert(polyglot.t("Error in 'sendnewusertransaction' RPC."));
- }, {});
+ twisterRpc('createwalletuser', [peerAlias],
+ function(req, ret) {
+ $.MAL.processCreateAccount(req.peerAlias, ret);
+ }, {peerAlias: peerAlias},
+ function(req, ret) {
+ alert(polyglot.t('Error in \'createwalletuser\' RPC.'));
+ }
+ );
}
-function importSecretKeyClick() {
- var secretKey = $(".secret-key-import").val();
- var username = $(".username-import").val().toLowerCase();
-
- twisterRpc("importprivkey", [secretKey,username],
- function(args, ret) {
- processNewSecretKeyImported(args.username);
- }, {username:username},
- function(args, ret) {
- alert(polyglot.t("Error in 'importprivkey'", {rpc: ret.message }));
- }, {});
-}
+function importAccount(peerAlias, secretKey) {
+ if (!peerAlias) {
+ console.warn('can\'t import account: empty alias was given');
+ return;
+ }
+ if (!secretKey) {
+ console.warn('can\'t import account: empty secret key was given');
+ return;
+ }
-function processNewSecretKeyImported(username) {
- defaultScreenName = username;
- saveScreenName();
- $.MAL.changedUser();
- $.MAL.goHome();
+ twisterRpc('importprivkey', [secretKey, peerAlias],
+ function (req, ret) {
+ defaultScreenName = req.peerAlias;
+ saveScreenName();
+ $.MAL.changedUser();
+ $.MAL.goHome();
+ }, {peerAlias: peerAlias},
+ function (req, ret) {
+ alert(polyglot.t('Error in \'importprivkey\'', {rpc: ret.message}));
+ }
+ );
}
-// handlers common to both desktop and mobile
-function interfaceCommonLoginHandlers() {
- $( ".login-local-username" ).bind( "click", loginLocalUsername );
- $( ".check-availability").bind( "click", checkUsernameAvailability );
- /* must specialize: $( ".create-user").bind( "click", function() { createUserClick( processCreateUser ); } ); */
- /* must specialize: $( ".login-created-user").bind( "click", loginCreatedUser ); */
- $( ".new-username" ).keyup( newUserNameKeypress );
- $('.secret-key-import').on('input', importSecretKeypress);
- $('.username-import').on('input', importSecretKeypress);
- $( ".import-secret-key").bind( "click", importSecretKeyClick );
+function sendNewUserTransaction(peerAlias, cbFunc, cbReq) {
+ twisterRpc('sendnewusertransaction', [peerAlias],
+ function (req, ret) {
+ if (typeof req.cbFunc === 'function') {
+ req.cbFunc(req.cbReq);
+ }
+ }, {cbFunc: cbFunc, cbReq: cbReq},
+ function (req, ret) {
+ alert(polyglot.t('Error in \'sendnewusertransaction\' RPC.'));
+ }
+ );
}
// profile-related functions used by profile-edit
diff --git a/login.html b/login.html
deleted file mode 100644
index eebcccb..0000000
--- a/login.html
+++ /dev/null
@@ -1,142 +0,0 @@
-
-
-
-
- twister login
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
twister login
-
-
Existing local users
-
-
-
-
-
-
-
-
Create a new user
-
-
-
-
-
-
-
-
-
-
-
-
-
Import secret key
-
-
-
-
With nickname
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ×
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- A new user was created and it is being propagated to the network.
- Please do not close this window, this might take a few minutes.
-
-
- Your secret key is:
-
-
- It is highly recommended that you take this time to save your secret key.
- Print it, do a screenshot, use the camera in your phone or write it down
- to a piece of paper.
-
-
- The secret key will be needed to use this account from different computers.
- If you ever lose your secret key (remember: this is alpha software and it may
- crash, causing loss of data) your nickname will be locked forever.
- There is no way to recover a lost key for twister accounts.
-
-
-
- Please wait. The 'OK' button will be shown when process completes.
-