diff --git a/css/style.css b/css/style.css index c42a4be..c758d00 100644 --- a/css/style.css +++ b/css/style.css @@ -300,6 +300,16 @@ button.follow:hover, button.unfollow:hover, .following-own-modal .following-list opacity: 0.9; } +.userMenu li.userMenu-favs > a { + padding: 0 14px; + opacity: 1; +} + +.userMenu li.userMenu-favs > a:before { + content: '★'; + font-size: 24px; +} + .userMenu li.userMenu-profile > a { background: url(../img/profile.png) no-repeat 5px center; } @@ -833,13 +843,13 @@ textarea.splited-post { /*********************************** ********************* WHO TO FOLLOW ***********************************/ -.who-to-follow -{ +.who-to-follow, +.new-users { padding: 10px; margin-bottom: 10px; } -.who-to-follow h3 -{ +.who-to-follow h3, +.new-users h3 { display: inline; } .twister-user @@ -880,17 +890,20 @@ textarea.splited-post { color: #e34f42; } -.followers -{ +.followers, +.latest-activity { font-size: 12px; color: rgba( 0, 0, 0, .6 ); + margin-left: 58px; } -.followed-by -{ + +.followed-by, +.latest-activity .time { color: #e34f42; font-size: 13px; cursor: pointer; } + .twister-user-name, .twister-by-user-name { @@ -1280,6 +1293,7 @@ ol.toptrends-list { .post-favorite:before { content: "★"; + font-size: 18px; } .post-reply:hover, .post-propagate:hover, @@ -1305,6 +1319,10 @@ ol.toptrends-list { { width: 100%; } +.image-preview img +{ + max-width: 100%; +} .preview-container { max-height: 500px; @@ -1390,8 +1408,7 @@ ol.toptrends-list { border: solid 1px rgba( 69, 71, 77, .05 ); padding: 10px; } -.singleBlock h2, .header-bold -{ +.singleBlock h2 { font-weight: bold; line-height: 40px; color: rgba( 255, 255, 255, 1 ); @@ -1462,76 +1479,6 @@ ol.toptrends-list { margin-right: 20px; } -/************************************* -************* LOGIN PAGE ************* -**************************************/ - -.login .header-bold { - display: block; - width: 720px; - margin: 0px auto 12px auto; -} - -.login .module { - display: block; - width: 720px; - padding: 32px 40px; - margin: 8px auto; - background: #fff; -} - -.login .module p { - margin-bottom: 5px; -} - -.login .module input { - padding: 5px 10px; - background: #f3f3f3; - border: solid 1px #dcdcdc; - transition: box-shadow 0.3s, border 0.3s; - font-size: 14px; -} - -.login .module input:focus, .login .module select:focus { - background: #fff; - transition: background-color 100ms linear; - border: solid 1px rgba( 227, 79, 66, .5 ); - box-shadow: 0 0 10px rgba(0, 0, 0, .3 ); -} - -.login .module select { - height: 30px; - padding: 3px 30px 3px 10px; - margin: 0; - border: 1px solid #ccc; - font-size: 14px; -} - -.login .module span.availability { - margin-left: 10px; - color: #45474d; -} - -.with-nickname, .import-secret-key, .create-user { - margin-top: 10px; -} - -.login .module:nth-child(2) div , -.login .module:nth-child(3) div:nth-child(2), -.login .secret-key-import, -.login .username-import { - margin-top: 20px; - margin-bottom: 20px; - margin-left: 16px; -} - -.login .create-user, -.login .import-secret-key { - display: block; - margin-left: auto; - margin-right: 16px; -} - /************************************* ************* POPUP MODAL ************ **************************************/ @@ -1562,12 +1509,12 @@ ol.toptrends-list { font-weight: bold; } -.modal-wrapper .modal-content { +.modal-content { background: #fff; overflow-y: auto; } -.modal-wrapper .modal-blackout { +.modal-blackout { background: rgba(0,0,0, .6); z-index: -1; position: fixed; @@ -1631,6 +1578,84 @@ ol.toptrends-list { padding: 10px 15px; } +.inline-warn { + background-color: #FEFEDF; + padding: 10px; +} + +.inline-warn .close { + float: right; + font-size: 1.2em; + color: #e34f42; + cursor: pointer; + margin: -8px 2px 8px 8px; +} + +.inline-warn .text { + font-size: 0.8em; + text-align: center; +} + +.inline-warn .options { + font-size: 0.8em; + text-align: right; + margin-top: 4px; +} + +/************************************* +******* LOGIN TO ACCOUNT MODAL ******* +**************************************/ + +.login-modal.modal-wrapper { + height: auto; /*about 580px*/ + margin-top: -290px; +} + +.login-modal .module { + margin: 4px; +} + +.login-modal .module > div { + width: 100%; + margin: 4px 0; + padding: 4px 12px; +} + +.login-modal .module > div:last-child { + text-align: right; + margin: 8px 0; +} + +.login-modal .module input { + border: solid 1px rgba(0, 0, 0, .3); + border-radius: 3px; + width: 320px; + margin: 12px 16px; + padding: 2px 4px; +} + +.login-modal .module select { + border: solid 1px rgba(0, 0, 0, .3); + border-radius: 3px; + width: 310px; + margin: 12px 16px; + padding: 2px 4px; +} + +.login-modal .module input:focus, .login-modal .module select:focus { + border: solid 1px rgba(227, 79, 66, .5); +} + +.login-modal .module .secret-key { + width: 500px; +} + +.login-modal .module .availability { + color: #45474D; + display: inline-block; + margin-left: 16px; +} + /************************************* ******** DIRECT MESSAGES MODAL ******* **************************************/ @@ -1780,7 +1805,7 @@ ol.toptrends-list { .group-messages-join-group.modal-wrapper { height: auto; /*about 360px*/ - margin-top: -240px; + margin-top: -204px; } .group-messages-join-group .modal-content .module { @@ -1825,38 +1850,6 @@ ol.toptrends-list { margin: 8px 8px 0; } -/************************************* -*********** NEW USER MODAL *********** -**************************************/ - -.new-user.modal-wrapper { - width: 720px; - height: 580px; - margin: -290px 0 0 -360px; -} - -.new-user .modal-content { - padding: 25px; -} - -.new-user .modal-close { - display: none; -} - -.new-user .text { - margin: 0 0 15px 0; -} - -.new-user .emphasis { - font-size: 18px; - text-align: center; -} - -.new-user .secret-key { - color: rgba(.5,0,0, 1.0); - font-weight: bold; -} - /************************************* ************ HASHTAG MODAL *********** **************************************/ @@ -1901,36 +1894,79 @@ ol.toptrends-list { ********* WHO TO FOLLOW MODAL ******** **************************************/ -.who-to-follow-modal ol { +.who-to-follow-modal ol, +.new-users-modal ol { margin: 5px; } -.who-to-follow-modal .open-profile-modal:hover { +.who-to-follow-modal .open-profile-modal:hover, +.new-users-modal .open-profile-modal:hover { text-decoration: none; } -.who-to-follow-modal .open-profile-modal span { +.who-to-follow-modal .open-profile-modal span, +.new-users-modal .open-profile-modal span { vertical-align: middle; } -.who-to-follow-modal .open-profile-modal span:hover { +.who-to-follow-modal .open-profile-modal span:hover, +.new-users-modal .open-profile-modal span:hover { text-decoration: underline; } -.who-to-follow-modal .follow { +.who-to-follow-modal .follow, +.new-users-modal .follow { float: right; margin: -30px 10px 0 10px; } -.who-to-follow-modal .twister-user-info span { +.who-to-follow-modal .twister-user-info span, +.new-users-modal .twister-user-info span { vertical-align: bottom; } -.who-to-follow-modal .bio { +.who-to-follow-modal .bio, +.new-users-modal .bio { font-size: 12px; color: rgba( 0, 0, 0, .6 ); } +/************************************* +********* URI SHORTENER MODAL ******** +**************************************/ + +.uri-shortener-modal .uris-list { + font-size: 12px; + overflow-x: hidden; +} + +.uri-shortener-modal .uris-list li { + padding-left: 2%; + padding-right: 2%; + margin-bottom: 4px; +} + +.uri-shortener-modal .uris-list li:last-child { + margin-bottom: 16px; +} + +.uri-shortener-modal .uris-list li.highlighted, +.uri-shortener-modal .uris-list li:hover { + background-color: #FEFEDF; +} + +.uri-shortener-modal .uris-list .short { + background-color: #F0EFCC; + display: inline-block; + width: 26%; + padding-left: 2px; + padding-right: 2px; +} + +.uri-shortener-modal .uris-list .long { + margin-left: 4px; +} + /************************************* ************ POPUP PROMPT ************ **************************************/ @@ -1948,7 +1984,7 @@ ol.toptrends-list { } .prompt-wrapper .modal-buttons { - margin: 4px 16px; + padding: 4px 16px 16px; text-align: right; } @@ -1968,12 +2004,19 @@ ol.toptrends-list { .confirm-popup .message { text-align: center; - margin: 12px; + padding: 12px; } .confirm-popup .modal-buttons { text-align: center; - padding: 4px; +} + +/************************************* +********* NEW ACCOUNT POPUP ********** +**************************************/ + +.new-account-briefing.prompt-wrapper { + margin-top: -164px; } /************************************* @@ -2268,7 +2311,7 @@ ol.toptrends-list { display: inline-block; text-align: initial; width: 320px; - height: 120px; + height: 130px; margin: 2px; padding: 2px; border: solid 1px rgba(69, 71, 77, .1); @@ -2311,6 +2354,13 @@ ol.toptrends-list { right: 32px; } +.following-own-modal .following-list .latest-activity { + position: absolute; + top: 110px; + right: 32px; + margin: 0; +} + /************************************* *********** AUTOCOMPLETING *********** **************************************/ diff --git a/home.html b/home.html index 2fe864a..d83a2fe 100644 --- a/home.html +++ b/home.html @@ -49,12 +49,13 @@ Fulano da Silva View - URI shortener + URI_shortener Options Network config Setup account + Change user + Check for client's updates Following users - Change user Direct Messages Group Messages @@ -76,6 +77,7 @@ +
  • @@ -145,6 +147,8 @@ + + @@ -217,15 +221,28 @@ Refresh . View All -
      - -
    +
      + +
      +
      +

      New Users

      + . + Refresh + . + View All + +
      +
      +
      +
      +
      +
      @@ -281,8 +298,8 @@
      - -
    1. +
      +
    2. user-photo @@ -301,9 +318,14 @@
      × +
      + Last activity + +
    3. +
        @@ -343,7 +365,7 @@
        Reply Retransmit - + Favorite
        +
        +
        +
        ×
        +
        +
        +
        don't show it again
        +
        +
        +
        +
        - - + + +
        @@ -441,6 +474,42 @@
        +
        +
        +
        +

        Existing local users

        + +
        +
        + +
        +
        + + +
        +
        @@ -472,6 +541,14 @@
        +
        +
        + +
        +
        @@ -609,10 +686,6 @@

        Import secret key

        -
        -

        With group alias

        - -
        @@ -655,13 +728,14 @@
        +
        @@ -756,6 +830,10 @@
        +
        + Last activity + +
        @@ -793,6 +871,18 @@ + +
        +
        + + +
        +
          +
          + +
          +
        1. +
          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 = $('
        2. ', {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 + ''; - 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 + '>'; - } 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 + '>'; + } 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 = $("
        3. Options Setup account - Network config - Change user + Check for client's updates
          @@ -275,6 +274,7 @@ ×
          +
          diff --git a/options.html b/options.html index 8338e62..7035574 100644 --- a/options.html +++ b/options.html @@ -38,7 +38,6 @@ Options Network config Setup account - Change user
          @@ -353,6 +352,26 @@ +
          +

          New Users

          +
          +
          +

          + +

          +
          +

          Live tracking

          + +
          +
          +
          +

          Twistday Reminder

          diff --git a/profile-edit.html b/profile-edit.html index 5afdaf4..dcbe2e6 100644 --- a/profile-edit.html +++ b/profile-edit.html @@ -50,7 +50,6 @@ Options Setup account Network config - Change user
          @@ -95,6 +94,7 @@ ×
          +
          diff --git a/theme_calm/css/style.css b/theme_calm/css/style.css index 5980d06..6d538c5 100644 --- a/theme_calm/css/style.css +++ b/theme_calm/css/style.css @@ -344,6 +344,16 @@ button.unfollow:hover { opacity: 0.9; } +.userMenu li.userMenu-favs > a { + padding: 0 14px; + opacity: 1; +} + +.userMenu li.userMenu-favs > a:before { + content: '★'; + font-size: 24px; +} + .userMenu li.userMenu-profile > a { background: url(../img/profile.png) no-repeat 5px center; padding-left: 35px; @@ -1014,12 +1024,12 @@ textarea.splited-post { /*********************************** ********************* WHO TO FOLLOW ***********************************/ -.who-to-follow -{ +.who-to-follow, +.new-users { padding: 10px; } -.who-to-follow h3 -{ +.who-to-follow h3, +.new-users h3 { display: inline; } .twister-user @@ -1072,16 +1082,19 @@ textarea.splited-post { opacity: .8; } -.followers -{ +.followers, +.latest-activity { font-size: 12px; color: rgba( 0, 0, 0, .6 ); + margin-left: 58px; } -.followed-by -{ + +.followed-by, +.latest-activity .time { font-size: 13px; cursor: pointer; } + .twister-user-name, .twister-by-user-name { @@ -1771,8 +1784,7 @@ textarea.splited-post { padding: 10px; border-radius: 6px; } -.singleBlock h2, .header-bold -{ +.singleBlock h2 { font-weight: bold; line-height: 40px; color: rgba( 255, 255, 255, 1 ); @@ -1843,83 +1855,6 @@ textarea.splited-post { margin-right: 20px; } -/************************************* -************* LOGIN PAGE ************* -**************************************/ - -.login .header-bold { - display: block; - width: 500px; - margin: 0px auto 12px auto; -} - -.login .module { - padding: 20px; - width: 500px; - margin: 10px auto; - border: 3px solid #c7cdda; - border-radius: 6px; -} -.login .module p { - font: 14px "Open Sans", sans-serif; - margin-bottom: 5px; - -} -.login .module input { - padding: 5px 10px; - font: 13px/24px "Open sans"; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - background: #f3f3f3; -} -.login .module input:focus { - background: #fff; - transition: background-color 100ms linear; -} -.login .module select { - height: 30px; - font: 13px/24px "Open sans"; - text-align: center; - padding: 3px 30px 3px 10px; - margin: 0; - background: #fff url(../img/form-arrow-down-black.png) no-repeat right center; - border: 1px solid #ccc; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - -/* hide default apperance select element and arrow in firefox */ - -webkit-appearance:none; - -moz-appearance:none; - appearance:none; - text-indent: 0.01px; - text-overflow: ''; -/* end */ -} - -.login .module span.availability { - margin-left: 10px; - font: italic 16px "Open sans"; - color: #45474d; -} -.with-nickname, .import-secret-key, .create-user { - margin-top: 10px; -} - -.login .module input:focus::-webkit-input-placeholder { - color: #fff; -} -.login .module input:focus:-moz-placeholder { - color: #fff; -} -.login .module input:focus::-moz-placeholder { - color: #fff; -} -.login .module input::-ms-input-placeholder { - color: #fff; -} - /************************************* ************* POPUP MODAL ************ **************************************/ @@ -1950,12 +1885,12 @@ textarea.splited-post { font-weight: bold; } -.modal-wrapper .modal-content { +.modal-content { background: #fff; overflow-y: auto; } -.modal-wrapper .modal-blackout { +.modal-blackout { background: rgba(0,0,0, .6); z-index: -1; position: fixed; @@ -2019,6 +1954,86 @@ textarea.splited-post { padding: 10px 15px; } +.inline-warn { + background-color: #FEFEDF; + padding: 10px; +} + +.inline-warn .close { + float: right; + font-size: 1.2em; + color: #e34f42; + cursor: pointer; + margin: -8px 2px 8px 8px; +} + +.inline-warn .text { + font-size: 0.8em; + text-align: center; +} + +.inline-warn .options { + font-size: 0.8em; + text-align: right; + margin-top: 4px; +} + +/************************************* +******* LOGIN TO ACCOUNT MODAL ******* +**************************************/ + +.login-modal.modal-wrapper { + height: auto; /*about 580px*/ + margin-top: -290px; +} + +.login-modal .module { + margin: 4px; +} + +.login-modal .module > div { + width: 100%; + margin: 4px 0; + padding: 4px 12px; +} + +.login-modal .module > div:last-child { + text-align: right; + margin: 8px 0; +} + +.login-modal .module input { + border: solid 1px rgba(0, 0, 0, .3); + border-radius: 4px; + width: 320px; + margin: 12px 16px; + padding: 2px 4px; +} + +.login-modal .module select { + border: solid 1px rgba(0, 0, 0, .3); + border-radius: 4px; + width: 310px; + margin: 12px 16px; + padding: 2px 4px; +} + +.login-modal .module input:focus, .login-modal .module select:focus { + border: solid 1px rgba(118, 145, 206, .8); + box-shadow: 0 0 10px rgba(0, 0, 0, .3); +} + +.login-modal .module .secret-key { + width: 500px; +} + +.login-modal .module .availability { + font: italic 13px "Open sans"; + color: #45474D; + display: inline-block; + margin-left: 16px; +} + /************************************* ******** DIRECT MESSAGES MODAL ******* **************************************/ @@ -2177,7 +2192,7 @@ textarea.splited-post { .group-messages-join-group.modal-wrapper { height: auto; /*about 360px*/ - margin-top: -240px; + margin-top: -204px; } .group-messages-join-group .modal-content .module { @@ -2223,38 +2238,6 @@ textarea.splited-post { margin: 8px 8px 0; } -/************************************* -*********** NEW USER MODAL *********** -**************************************/ - -.new-user.modal-wrapper { - width: 720px; - height: 580px; - margin: -290px 0 0 -360px; -} - -.new-user .modal-content { - padding: 25px; -} - -.new-user .modal-close { - display: none; -} - -.new-user .text { - margin: 0 0 15px 0; -} - -.new-user .emphasis { - font-size: 18px; - text-align: center; -} - -.new-user .secret-key { - color: rgba(.5,0,0, 1.0); - font-weight: bold; -} - /************************************* ************ HASHTAG MODAL *********** **************************************/ @@ -2308,19 +2291,23 @@ textarea.splited-post { ********* WHO TO FOLLOW MODAL ******** **************************************/ -.who-to-follow-modal .modal-content { +.who-to-follow-modal .modal-content, +.new-users-modal .modal-content { padding: 15px; } -.who-to-follow-modal ol { +.who-to-follow-modal ol, +.new-users-modal ol { margin: 5px; } -.who-to-follow-modal .open-profile-modal:hover { +.who-to-follow-modal .open-profile-modal:hover, +.new-users-modal .open-profile-modal span:hover { text-decoration: none; } -.who-to-follow-modal .open-profile-modal span { +.who-to-follow-modal .open-profile-modal span, +.new-users-modal .open-profile-modal span { vertical-align: middle; } @@ -2328,20 +2315,59 @@ textarea.splited-post { text-decoration: underline; } -.who-to-follow-modal .follow { +.who-to-follow-modal .follow, +.new-users-modal .follow { float: right; margin: -30px 10px 0 10px; } -.who-to-follow-modal .twister-user-info span { +.who-to-follow-modal .twister-user-info span, +.new-users-modal .twister-user-info span { vertical-align: bottom; } -.who-to-follow-modal .bio { +.who-to-follow-modal .bio, +.new-users-modal .bio { font-size: 12px; color: rgba( 0, 0, 0, .6 ); } +/************************************* +********* URI SHORTENER MODAL ******** +**************************************/ + +.uri-shortener-modal .uris-list { + font-size: 12px; + overflow-x: hidden; +} + +.uri-shortener-modal .uris-list li { + padding-left: 2%; + padding-right: 2%; + margin-bottom: 4px; +} + +.uri-shortener-modal .uris-list li:last-child { + margin-bottom: 16px; +} + +.uri-shortener-modal .uris-list li.highlighted, +.uri-shortener-modal .uris-list li:hover { + background-color: #FEFEDF; +} + +.uri-shortener-modal .uris-list .short { + background-color: #F0EFCC; + display: inline-block; + width: 26%; + padding-left: 2px; + padding-right: 2px; +} + +.uri-shortener-modal .uris-list .long { + margin-left: 4px; +} + /************************************* ************ POPUP PROMPT ************ **************************************/ @@ -2359,7 +2385,7 @@ textarea.splited-post { } .prompt-wrapper .modal-buttons { - margin: 4px 16px; + margin: 4px 16px 16px; text-align: right; } @@ -2379,12 +2405,19 @@ textarea.splited-post { .confirm-popup .message { text-align: center; - margin: 12px; + padding: 12px; } .confirm-popup .modal-buttons { text-align: center; - padding: 4px; +} + +/************************************* +********* NEW ACCOUNT POPUP ********** +**************************************/ + +.new-account-briefing.prompt-wrapper { + margin-top: -164px; } /************************************* @@ -2707,7 +2740,7 @@ textarea.splited-post { display: inline-block; text-align: initial; width: 320px; - height: 120px; + height: 130px; margin: 2px; padding: 2px; border: solid 1px rgba(69, 71, 77, .1); @@ -2753,6 +2786,13 @@ textarea.splited-post { right: 32px; } +.following-own-modal .following-list .latest-activity { + position: absolute; + top: 110px; + right: 32px; + margin: 0; +} + .gifCheckBox { float: right; vertical-align: middle; diff --git a/theme_nin/css/style.css b/theme_nin/css/style.css index fbea4da..dd551e0 100644 --- a/theme_nin/css/style.css +++ b/theme_nin/css/style.css @@ -389,6 +389,15 @@ samp { font-size: 1.5em; } +.userMenu li.userMenu-favs > a { + padding: 0 14px; + opacity: 1; +} + +.userMenu li.userMenu-favs > a:before { + content: '★'; + font-size: 24px; +} /************************************* ************ PROFILE MODAL *********** **************************************/ @@ -961,11 +970,6 @@ samp { color: #727578; } -/* line 195, ../sass/_postboard.sass */ -.post-favorite { - display: none !important; -} - /* line 200, ../sass/_postboard.sass */ .post .show-more { display: inline-block; @@ -1014,7 +1018,7 @@ samp { display: none !important; } /* line 236, ../sass/_postboard.sass */ -.open .related:hover .post-reply, .mini-profile .post-area-new .related:hover .post-reply, #postboard-top .post-area .post-area-new .related:hover .post-reply, .open .related:hover .post-propagate, .mini-profile .post-area-new .related:hover .post-propagate, #postboard-top .post-area .post-area-new .related:hover .post-propagate { +.open .related:hover .post-reply, .mini-profile .post-area-new .related:hover .post-reply, #postboard-top .post-area .post-area-new .related:hover .post-reply, .open .related:hover .post-propagate, .mini-profile .post-area-new .related:hover .post-propagate, #postboard-top .post-area .post-area-new .related:hover .post-propagate, .open .related:hover .post-favorite, .mini-profile .post-area-new .related:hover .post-favorite, #postboard-top .post-area .post-area-new .related:hover .post-favorite { display: inline-block !important; } @@ -1308,75 +1312,6 @@ h3 .isFollowing:after { display: none; } -/************************************* -************* LOGIN PAGE ************* -**************************************/ - -.login .header-bold { - display: block; - width: 720px; - margin: 0px auto 12px auto; -} - -.login .module { - display: block; - width: 720px; - padding: 32px 40px; - margin: 8px auto; - background: #fff; -} - -.login .module p { - margin-bottom: 5px; -} - -.login .module input { - padding: 5px 10px; - background: #f3f3f3; - border: solid 1px #dcdcdc; - transition: box-shadow 0.3s, border 0.3s; - font-size: 14px; -} - -.login .module input:focus, .login .module select:focus { - background: #fff; - transition: background-color 100ms linear; - border-bottom: solid 2px #B4C669; -} - -.login .module select { - height: 30px; - padding: 3px 30px 3px 10px; - margin: 0; - border: 1px solid #ccc; - font-size: 14px; -} - -.login .module span.availability { - margin-left: 10px; - color: #45474d; -} - -.with-nickname, .import-secret-key, .create-user { - margin-top: 10px; -} - -.login .module:nth-child(2) div , -.login .module:nth-child(3) div:nth-child(2), -.login .secret-key-import, -.login .username-import { - margin-top: 20px; - margin-bottom: 20px; - margin-left: 16px; -} - -.login .create-user, -.login .import-secret-key { - display: block; - margin-left: auto; - margin-right: 16px; -} - /************** BUTTONS *********** */ /* line 65, ../sass/_commons.sass */ button, .mini-profile-actions span, a.button { @@ -2155,27 +2090,32 @@ textarea.splited-post { /******** WHO TO FOLLOW ********/ /* line 411, ../sass/style.sass */ -.who-to-follow.module { +.who-to-follow.module, +.new-users.module { width: inherit; margin-bottom: 20px; } /* line 414, ../sass/style.sass */ -.who-to-follow small { +.who-to-follow small, +.new-users small { display: none; } /* line 416, ../sass/style.sass */ -.who-to-follow h3 { +.who-to-follow h3, +.new-users h3 { float: left; } /* line 418, ../sass/style.sass */ -.who-to-follow ol { +.who-to-follow ol, +.new-users ol { clear: both; } -.who-to-follow .twister-user-info { +.who-to-follow .twister-user-info, +.new-users .twister-user-info { margin-top: 8px; } @@ -2209,7 +2149,8 @@ textarea.splited-post { } /* line 447, ../sass/style.sass */ -.followers { +.followers, +.latest-activity { font-size: 12px; color: #66686B; } @@ -2219,13 +2160,22 @@ textarea.splited-post { } /* line 453, ../sass/style.sass */ -.followed-by { +.followed-by, +.latest-activity { color: #aaa; font-size: 12px; cursor: pointer; display: block; } +.who-to-follow .latest-activity { + margin-bottom: 8px; +} + +.who-to-follow .latest-activity .label { + display: none; +} + /* line 459, ../sass/style.sass */ .twister-user-name, .twister-by-user-name { font-weight: bold; @@ -2582,6 +2532,31 @@ ol.toptrends-list a:hover { margin: 4px; } + +.inline-warn { + background-color: #FEFEDF; + padding: 10px; +} + +.inline-warn .close { + float: right; + font-size: 1.2em; + color: #e34f42; + cursor: pointer; + margin: -8px 2px 8px 8px; +} + +.inline-warn .text { + font-size: 0.8em; + text-align: center; +} + +.inline-warn .options { + font-size: 0.8em; + text-align: right; + margin-top: 4px; +} + /************************************* *********** CONFIRM POPUP ************ **************************************/ @@ -2594,6 +2569,15 @@ ol.toptrends-list a:hover { margin: 8px 12px 20px; } +/************************************* +********* NEW ACCOUNT POPUP ********** +**************************************/ + +.new-account-briefing.prompt-wrapper { + top: 50%; + margin-top: -164px; +} + /****** FOLLOWING-CONFIG PROMPT ******/ .following-config-modal.prompt-wrapper { @@ -2653,6 +2637,62 @@ ol.toptrends-list a:hover { padding-bottom: 6px; } +/************************************* +******* LOGIN TO ACCOUNT MODAL ******* +**************************************/ + +.login-modal.modal-wrapper { + width: 580px; + height: auto; /*about 532px*/ + margin: -270px 0 0 -290px; +} + +.login-modal .modal-content { + padding: 0; +} + +.login-modal .module { + margin: 4px; +} + +.login-modal .module > div { + margin: 4px 0; + padding: 4px 12px; +} + +.login-modal .module > div:last-child { + text-align: right; + margin: 8px 0; +} + +.login-modal .module input { + border: 1px solid rgba(0, 0, 0, .1); + width: 320px; + margin: 12px 16px; + padding: 2px 4px; +} + +.login-modal .module select { + border: 1px solid rgba(0, 0, 0, .1); + width: 310px; + margin: 12px 16px; + padding: 2px 4px; +} + +.login-modal .module input:focus, .login-modal .module select:focus { + border-bottom: solid 1px #B4C669; +} + +.login-modal .module .secret-key { + width: 500px; +} + +.login-modal .module .availability { + color: #45474D; + display: inline-block; + margin-left: 16px; +} + /****** DIRECT MESSAGES MODAL********* */ /* line 736, ../sass/style.sass */ .modal-wrapper.directMessages { @@ -2939,8 +2979,8 @@ ol.toptrends-list a:hover { .group-messages-join-group.modal-wrapper { width: 580px; - height: auto; /*about 360px*/ - margin: -250px 0 0 -290px; + height: auto; /*about 409px*/ + margin: -204px 0 0 -290px; } .group-messages-join-group .modal-content { @@ -2988,39 +3028,6 @@ ol.toptrends-list a:hover { margin: 8px 8px 0; } -/********* NEW USER MODAL************* */ - -.new-user.modal-wrapper { - width: 720px; - height: 580px; - margin: -290px 0 0 -360px; -} - -.new-user .modal-content { - padding: 25px; -} - -/* line 870, ../sass/style.sass */ -.new-user .modal-close { - display: none; -} -/* line 872, ../sass/style.sass */ -.new-user .text { - margin: 0 0 15px 0; -} -/* line 874, ../sass/style.sass */ -.new-user .emphasis { - text-align: center; -} -/* line 877, ../sass/style.sass */ -.new-user .secret-key { - display: block; - margin-top: 8px; - color: black; - font-weight: bold; - font-size: 110%; -} - /******** HASHTAG MODAL********** */ /* line 884, ../sass/style.sass */ .modal-wrapper.hashtag-modal { @@ -3091,49 +3098,108 @@ ol.toptrends-list a:hover { /******* WHO TO FOLLOW MODAL****** */ /* line 943, ../sass/style.sass */ -.modal-wrapper.who-to-follow-modal { +.modal-wrapper.who-to-follow-modal, +.modal-wrapper.new-users-modal { width: 520px; height: 580px; margin: -290px 0 0 -260px; } /* line 949, ../sass/style.sass */ -.who-to-follow-modal .modal-content { +.who-to-follow-modal .modal-content, +.new-users-modal .modal-content { padding: 15px; } /* line 955, ../sass/style.sass */ -.who-to-follow-modal ol { +.who-to-follow-modal ol, +.new-users-modal ol { margin: 5px; } /* line 958, ../sass/style.sass */ -.who-to-follow-modal .open-profile-modal:hover { +.who-to-follow-modal .open-profile-modal:hover, +.new-users-modal .open-profile-modal:hover { text-decoration: none; } /* line 960, ../sass/style.sass */ -.who-to-follow-modal .twister-user { - position: relative; +.who-to-follow-modal .twister-user, +.new-users-modal .twister-user { +position: relative; padding: 5px; } /* line 963, ../sass/style.sass */ -.who-to-follow-modal .twister-user-photo { +.who-to-follow-modal .twister-user-photo, +.new-users-modal .twister-user-photo { position: relative; left: 0; float: left; display: block; } /* line 968, ../sass/style.sass */ -.who-to-follow-modal .twister-user-info { +.who-to-follow-modal .twister-user-info, +.new-users-modal .twister-user-info { position: relative; margin-top: 4px; padding-left: 70px; width: auto; } /* line 972, ../sass/style.sass */ -.who-to-follow-modal .bio { +.who-to-follow-modal .bio, +.new-users-modal .bio { color: rgba(0, 0, 0, 0.6); font-style: italic; } +/************************************* +********* URI SHORTENER MODAL ******** +**************************************/ + +.modal-wrapper.uri-shortener-modal { + width: 520px; + height: 720px; + margin: -360px 0 0 -260px; +} + +.uri-shortener-modal .modal-content { + padding: 20px; +} + +.uri-shortener-control.b-buttons { + padding: 4px; +} + +.uri-shortener-modal .uris-list { + font-size: 12px; + overflow-x: hidden; +} + +.uri-shortener-modal .uris-list li { + background-color: #FFF; + padding-left: 2%; + padding-right: 2%; + margin-bottom: 2px; +} + +.uri-shortener-modal .uris-list li:last-child { + margin-bottom: 16px; +} + +.uri-shortener-modal .uris-list li.highlighted, +.uri-shortener-modal .uris-list li:hover { + background-color: #FEFEDF; +} + +.uri-shortener-modal .uris-list .short { + background-color: #EEE; + display: inline-block; + width: 26%; + padding-left: 2px; + padding-right: 2px; +} + +.uri-shortener-modal .uris-list .long { + margin-left: 4px; +} + /******* LOADER ************ */ /* line 978, ../sass/style.sass */ .postboard-loading, .loading-roller { @@ -3280,7 +3346,7 @@ ol.toptrends-list a:hover { .following-own-modal .following-list > li { display: inline-block; width: 320px; - height: 160px; + height: 184px; margin: 2px; padding: 2px; border: solid 1px rgba(69, 71, 77, .1); @@ -3380,6 +3446,10 @@ ol.toptrends-list a:hover { display: block; } +.following-own-modal .following-list .latest-activity { + font-size: 11px; +} + /********** AUTOCOMPLETING *********/ /* line 1087, ../sass/style.sass */ diff --git a/theme_nin/sass/_login.sass b/theme_nin/sass/_login.sass deleted file mode 100644 index 350832c..0000000 --- a/theme_nin/sass/_login.sass +++ /dev/null @@ -1,55 +0,0 @@ -.login .header-bold - display: block - width: 720px - margin: 0px auto 12px auto - -.login .module - display: block - width: 720px - padding: 32px 40px - margin: 8px auto - background: white - -.login .module p - margin-bottom: 5px - -.login .module input - padding: 5px 10px - background: #f3f3f3 - border: solid 1px #dcdcdc - transition: box-shadow 0.3s, border 0.3s - font-size: 14px - -.login .module input:focus, -.login .module select:focus - background: white - transition: background-color 100ms linear - border-bottom: solid 2px $color-green - -.login .module select - height: 30px - padding: 3px 30px 3px 10px - margin: 0 - border: 1px solid #ccc - font-size: 14px - -.login .module span.availability - margin-left: 10px - color: #45474d - -.with-nickname, .import-secret-key, .create-user - margin-top: 10px - -.login .module:nth-child(2) div, -.login .module:nth-child(3) div:nth-child(2), -.login .secret-key-import, -.login .username-import - margin-top: 20px - margin-bottom: 20px - margin-left: 16px - -.login .create-user, -.login .import-secret-key - display: block - margin-left: auto - margin-right: 16px diff --git a/theme_nin/sass/style.sass b/theme_nin/sass/style.sass index 1c951c7..0eda3a2 100755 --- a/theme_nin/sass/style.sass +++ b/theme_nin/sass/style.sass @@ -8,7 +8,6 @@ @import _profile @import _postboard @import _following -@import _login @import _network @import _commons @import _tabs @@ -784,6 +783,43 @@ ol.toptrends-list float: left margin: 4px + +.inline-warn + background-color: #FEFEDF + padding: 10px + .close + float: right + font-size: 1.2em + color: #E34F42 + cursor: pointer + margin: -8px 2px 8px 8px + .text + font-size: 0.8em + text-align: center + .options + font-size: 0.8em + text-align: right + margin-top: 4px + +/************************************* +*********** CONFIRM POPUP ************ +**************************************/ + +.confirm-popup + &.prompt-wrapper + top: 30% + .message + margin: 8px 12px 20px + +/************************************* +********* NEW ACCOUNT POPUP ********** +**************************************/ + +.new-account-briefing + &.prompt-wrapper + top: 50% + margin-top: -164px + /************ FOLLOWING-CONFIG MODAL **********/ .prompt-wrapper.following-config-modal @@ -822,6 +858,44 @@ ol.toptrends-list .post-area padding-bottom: 6px +/************************************* +******* LOGIN TO ACCOUNT MODAL ******* +**************************************/ + +.login-modal + &.modal-wrapper + width: 580px + height: auto /*about 532px*/ + margin: -270px 0 0 -290px + .modal-content + padding: 0 + .module + margin: 4px + > div + margin: 4px 0 + padding: 4px 12px + > div:last-child + text-align: right + margin: 8px 0 + input + border: 1px solid rgba(0, 0, 0, .1) + width: 320px + margin: 12px 16px + padding: 2px 4px + select + border: 1px solid rgba(0, 0, 0, .1) + width: 310px + margin: 12px 16px + padding: 2px 4px + input:focus, select:focus + border-bottom: solid 1px #B4C669 + .secret-key + width: 500px + .availability + color: #45474D + display: inline-block + margin-left: 16px + /****** DIRECT MESSAGES MODAL**********/ .modal-wrapper.directMessages diff --git a/tmobile.html b/tmobile.html index e9a7699..41328d3 100644 --- a/tmobile.html +++ b/tmobile.html @@ -171,55 +171,7 @@

          twister login

          -
          - - -
          +
          + +
          +
          + Existing local users +
          +
          + +
          +
          + +
          +
          +
          + +
          + Or... + + + +
          + Or... + + +