Browse Source

Merge branch 'blaster'

master
Miguel Freitas 7 years ago
parent
commit
9c46573c33
  1. 302
      css/style.css
  2. 116
      home.html
  3. 539
      js/interface_common.js
  4. 38
      js/interface_home.js
  5. 623
      js/interface_localization.js
  6. 37
      js/interface_login.js
  7. 203
      js/mobile_abstract.js
  8. 35
      js/options.js
  9. 51
      js/tmobile.js
  10. 282
      js/twister_actions.js
  11. 78
      js/twister_directmsg.js
  12. 177
      js/twister_following.js
  13. 82
      js/twister_formatpost.js
  14. 25
      js/twister_io.js
  15. 45
      js/twister_network.js
  16. 318
      js/twister_newmsgs.js
  17. 225
      js/twister_user.js
  18. 142
      login.html
  19. 4
      network.html
  20. 21
      options.html
  21. 2
      profile-edit.html
  22. 306
      theme_calm/css/style.css
  23. 324
      theme_nin/css/style.css
  24. 55
      theme_nin/sass/_login.sass
  25. 76
      theme_nin/sass/style.sass
  26. 96
      tmobile.html

302
css/style.css

@ -300,6 +300,16 @@ button.follow:hover, button.unfollow:hover, .following-own-modal .following-list @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 ***********
**************************************/

116
home.html

@ -49,12 +49,13 @@ @@ -49,12 +49,13 @@
<a href="#" class="mini-profile-name">Fulano da Silva</a>
<span class="mini-profile-view">View</span>
</div>
<a class="dropdown-menu-item uri-shortener">URI shortener</a>
<a class="dropdown-menu-item uri-shortener">URI_shortener</a>
<a class="dropdown-menu-item" href="options.html">Options</a>
<a class="dropdown-menu-item" href="network.html">Network config</a>
<a class="dropdown-menu-item" href="profile-edit.html">Setup account</a>
<a class="dropdown-menu-item" href="#/login">Change user</a>
<a class="dropdown-menu-item updates-check-client">Check for client's updates</a>
<a class="dropdown-menu-item dropdown-menu-following" href="#following">Following users</a>
<a class="dropdown-menu-item" href="login.html">Change user</a>
<a class="dropdown-menu-item promoted-posts-only selectable_theme theme_original theme_calm" href="#">Switch to Promoted posts</a>
<a class="dropdown-menu-item direct-messages selectable_theme theme_original theme_calm" href="#">Direct Messages</a>
<a class="dropdown-menu-item groupmessages selectable_theme theme_original theme_calm" href="#">Group Messages</a>
@ -76,6 +77,7 @@ @@ -76,6 +77,7 @@
<span class="messages-qtd" style="display:none;">0</span>
</a>
</li>
<li class="userMenu-favs"><a href="#"></a></li>
<li class="userMenu-dhtindicator selectable_theme theme_calm"><a href="network.html"></a></li>
<!-- BUSCA -->
@ -145,6 +147,8 @@ @@ -145,6 +147,8 @@
<!-- TWISTDAY REMINDER MODULE -->
<div class="module twistday-reminder" style="display: none;"></div>
<div class="module new-users" style="display: none;"></div>
</div>
<!-- LADO ESQUERDO DE MÓDULOS END -->
@ -217,9 +221,22 @@ @@ -217,9 +221,22 @@
<a class="refresh-users">Refresh</a>
<small>.</small>
<a class="view-all-users" href="#whotofollow">View All</a>
<ol class="follow-suggestions">
<!-- use "follow-suggestion-template" here -->
</ol>
<ol class="follow-suggestions"></ol>
</div>
<div class="loading-roller">
<div></div>
</div>
</div>
<!-- TEMPLATE OF NEW-USERS MODULE -->
<div id="new-users-template">
<div>
<h3 class="label">New Users</h3>
<small>.</small>
<a class="refresh-users">Refresh</a>
<small>.</small>
<a class="view-all-users" href="#newusers">View All</a>
<ol class="follow-suggestions"></ol>
</div>
<div class="loading-roller">
<div></div>
@ -281,8 +298,8 @@ @@ -281,8 +298,8 @@
</div>
</li>
<!-- TEMPLATE DE WHO-TO-FOLLOW SUGGESTION -->
<li id="follow-suggestion-template" class="twister-user">
<div id="template-whotofollow-peer">
<li class="twister-user">
<div class="">
<a href="#" class="twister-user-name open-profile-modal">
<img class="twister-user-photo" src="img/grayed_avatar_placeholder_24.png" alt="user-photo"/>
@ -301,9 +318,14 @@ @@ -301,9 +318,14 @@
</a>
</div>
<a class="twister-user-remove">&times;</a>
<div class="latest-activity" data-screen-name="" data-id="" data-time="0">
<span class="label">Last activity</span>
<span class="time"></span>
</div>
<button class="follow">Follow</button>
</div>
</li>
</div>
<!-- TEMPLATE DA OL INVÓLUCRO DAS LIST ELEMENTS DO POST EXPANDIDO INIT -->
<ol class="expanded-post">
@ -343,7 +365,7 @@ @@ -343,7 +365,7 @@
<div class="post-interactions">
<span class="post-reply">Reply</span>
<span class="post-propagate">Retransmit</span>
<!--span class="post-favorite">Favorite</span-->
<span class="post-favorite">Favorite</span>
</div>
<div class="expanded-content" style="display: none;">
<ul class="post-stats" style="display: none;">
@ -425,12 +447,23 @@ @@ -425,12 +447,23 @@
<div class="modal-blackout"></div>
</div>
<div id="template-inline-warn">
<div class="inline-warn">
<div class="close">&times;</div>
<div class="text"></div>
<div class="options">
<div><input type="checkbox" class="never-again" /><span>don't show it again</span></div>
</div>
</div>
</div>
<div class="prompt-wrapper">
<div class="modal-header">
<h3></h3>
<span class="modal-close prompt-close">&times;</span>
</div>
<div class="modal-content"></div>
<div class="modal-blackout"></div>
</div>
<div id="confirm-popup-template">
@ -441,6 +474,42 @@ @@ -441,6 +474,42 @@
</div>
</div>
<div id="template-login-modal">
<div class="module">
<div>
<p class="label">Existing local users</p>
<select class="local-usernames"></select>
</div>
<div>
<button class="login">Login</button>
</div>
</div>
<div class="module create-account">
<div>
<p class="label">Create a new user</p>
<input class="alias" type="textbox" placeholder="Type nickname here"></input>
<div class="availability"></div>
</div>
<div>
<button class="check" disabled="disabled">Check availability</button>
<button class="create" disabled="disabled">Create this nickname</button>
</div>
</div>
<div class="module import-account">
<div>
<p class="label">Import secret key</p>
<input class="secret-key" type="textbox" placeholder="52-characters secret" size="52"></input>
</div>
<div>
<p class="label">With nickname</p>
<input class="alias" type="textbox" placeholder="Type nickname here"></input>
</div>
<div>
<button class="import" disabled="disabled">Import key</button>
</div>
</div>
</div>
<div id="reTwist-modal-template">
<div class="post-area">
<form class="post-area-new open">
@ -472,6 +541,14 @@ @@ -472,6 +541,14 @@
</div>
</div>
<div id="fav-modal-template">
<div class="post-area">
<div class="modal-buttons">
<button class="modal-fav-public">Public</button>
<button class="modal-fav-private">Private</button>
</div>
</div>
</div>
<!-- MODAL DE DIRECT MESSAGES INIT -->
<!-- Este modal possui dois templates, o primeiro da lista de pessoas que enviaram mensagens e o segundo
com a thread de mensagens individual -->
@ -609,10 +686,6 @@ @@ -609,10 +686,6 @@
<p class="label">Import secret key</p>
<input class="secret-key-import" type="textbox" placeholder="52-characters secret" size="52" rows="1"></input>
</div>
<div>
<p class="label">With group alias</p>
<input class="username-import" type="textbox" placeholder="Type group alias here" size="16" rows="1"></input>
</div>
<div>
<button class="import-secret-key" disabled="disabled">Import key</button>
</div>
@ -655,13 +728,14 @@ @@ -655,13 +728,14 @@
<ul class="module profile-data">
<li><a href="#"><span class="posts-count">&nbsp;</span><span class="label">Posts</span></a></li>
<li><a href="#" class="open-following-modal"><span class="following-count">&nbsp;</span><span class="label">Following</span></a></li>
<li><a href="#"><span class="followers-count">&nbsp;</span><span class="label">Followers</span></a></li>
<li><a class="open-followers"><span class="followers-count">&nbsp;</span><span class="label">Followers</span></a></li>
</ul>
</div>
<div class="profile-card-buttons b-buttons">
<button class="follow" href="#">Follow</button>
<button class="direct-messages-with-user" href="#">Direct Messages</button>
<button class="mentions-from-user" href="#">Mentions</button>
<button class="favs-from-user" href="#">Favorites</button>
</div>
</div>
<div class="who-follow"></div>
@ -756,6 +830,10 @@ @@ -756,6 +830,10 @@
<div>
<span class="swarm-status" style="display: none;"></span>
</div>
<div class="latest-activity" data-screen-name="" data-id="" data-time="0">
<span class="label">Last activity</span>
<span class="time"></span>
</div>
</div>
</li>
</div>
@ -793,6 +871,18 @@ @@ -793,6 +871,18 @@
</div>
</div>
</div>
<div id="template-uri-shortener-modal-content">
<div class="uri-shortener-control b-buttons">
<button class="shorten-uri">Shorten URL</button>
<button class="clear-cache">Clear cache</button>
</div>
<ol class="uris-list"></ol>
</div>
<div id="template-uri-shortener-uris-list-item">
<li><span class="short"></span><a class="long"></a></li>
</div>
</div>
<!-- TEMPLATES END -->

539
js/interface_common.js

@ -16,7 +16,12 @@ var twister = { @@ -16,7 +16,12 @@ var twister = {
tmpl: { // templates pointers are stored here
root: $('<div>') // 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) { @@ -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) { @@ -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) { @@ -71,7 +89,9 @@ function openModal(modal) {
modal.drapper = $('<div>').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) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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) { @@ -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() { @@ -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 = $('<ol class="follow-suggestions"></ol>')
.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) { @@ -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) { @@ -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) { @@ -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 @@ -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) { @@ -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(
'…<br><b><i>' + polyglot.t('busted_oh') + '</i> '
+ polyglot.t('busted_avowal') + ':</b><br><samp>'
+ long
.replace(/&(?!lt;|gt;)/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;')
+ '</samp><br>…<br>'
);
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
@ -1012,7 +1206,9 @@ function webtorrentFilePreview(file, previewContainer, isMedia) { @@ -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) { @@ -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() { @@ -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() { @@ -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() { @@ -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) { @@ -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) { @@ -1426,7 +1676,7 @@ function postExpandFunction(e, postLi) {
var originalLi = $('<li/>', {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');
@ -2265,6 +2515,17 @@ function retweetSubmit(event) { @@ -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() { @@ -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() { @@ -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() { @@ -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() { @@ -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() { @@ -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) { @@ -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 () { @@ -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 () { @@ -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();

38
js/interface_home.js

@ -49,8 +49,7 @@ var InterfaceFunctions = function() { @@ -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() { @@ -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() { @@ -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() { @@ -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() { @@ -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) {

623
js/interface_localization.js

File diff suppressed because it is too large Load Diff

37
js/interface_login.js

@ -1,37 +0,0 @@ @@ -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 );
}

203
js/mobile_abstract.js

@ -321,12 +321,12 @@ var MAL = function() @@ -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() @@ -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) { @@ -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);
}

35
js/options.js

@ -41,6 +41,17 @@ function twisterOptions() { @@ -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() { @@ -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) { @@ -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;

51
js/tmobile.js

@ -8,7 +8,6 @@ var handlersInstalled = false; @@ -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( @@ -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() { @@ -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) { @@ -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() { @@ -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 () { @@ -600,4 +576,3 @@ $(document).bind('mobileinit', function () {
$.mobile.defaultDialogTransition = 'none';
$.mobile.defaultPageTransition = 'none';
});

282
js/twister_actions.js

@ -12,9 +12,6 @@ @@ -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) { @@ -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) { @@ -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) { @@ -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();
}

78
js/twister_directmsg.js

@ -179,13 +179,14 @@ function openCommonDMsModal() { @@ -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) { @@ -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() { @@ -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) { @@ -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() { @@ -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}));

177
js/twister_following.js

@ -17,6 +17,7 @@ var _lastSearchUsersResultsRemovedFromDHTgetQueue = true; @@ -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 = { @@ -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() { @@ -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() { @@ -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) { @@ -500,31 +624,50 @@ function getWhoFollows(peerAlias, elem) {
;
}
function processWhoToFollowSuggestion(suggestion, followedBy) {
if (suggestion) {
var module = $('.module.who-to-follow');
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 = $('#follow-suggestion-template').clone(true)
.removeAttr('id');
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();
while (module.hasClass('new-users') && list.children().length > 3)
list.children().last().remove();
module.find('.refresh-users').show();
module.find('.loading-roller').hide();
} else
console.warn('nothing to proceed: no twisters to follow was suggested');
}
function closeSearchDialog(event) {

82
js/twister_formatpost.js

@ -43,6 +43,8 @@ function postToElem(post, kind, promoted) { @@ -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) { @@ -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) { @@ -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,30 +496,6 @@ function htmlFormatMsg(msg, opt) { @@ -490,30 +496,6 @@ function htmlFormatMsg(msg, opt) {
}
// changing the string
if (chr === '`' && markoutOpt === 'apply') { // if markoutOpt === 'clear' then ` does not escape anythyng so it needs to be handled like other tags
for (i = 0; i < p.length; i++) {
if (p[i].a > -1) {
if (p[i].t === -1 || (p[i].t === 0 && p[i].a > i)) {
if (p[i].k > 1)
t = Array(p[i].k).join(chr);
else
t = '';
j = p[i].a;
t = t + msg.str.slice(p[i].i + p[i].k, p[j].i);
if (p[j].k > 1)
t = t + Array(p[i].k).join(chr);
t = '<' + tag + '>' + t + '</' + tag + '>';
msg.htmlEntities.push(t.replace(/&(?!lt;|gt;)/g, '&amp;'));
htmlEntityEncoded = '>' + (msg.htmlEntities.length - 1).toString() + '<';
msg.str = msg.str.slice(0, p[i].i) + htmlEntityEncoded + msg.str.slice(p[j].i + p[j].k);
l = htmlEntityEncoded.length - p[j].i - p[j].k + p[i].i;
i = j;
for (j += 1; j < p.length; j++)
p[j].i += l;
}
}
}
} else {
if (markoutOpt === 'apply') {
t = '</' + tag + '>';
tag = '<' + tag + '>';
@ -541,7 +523,6 @@ function htmlFormatMsg(msg, opt) { @@ -541,7 +523,6 @@ function htmlFormatMsg(msg, opt) {
p[j].i += l;
}
}
}
return msg;
}
@ -604,7 +585,17 @@ function htmlFormatMsg(msg, opt) { @@ -604,7 +585,17 @@ function htmlFormatMsg(msg, opt) {
msg = {str: escapeHtmlEntities(msg), htmlEntities: []};
msg = markout(msg, markoutOpt, '`', 'samp'); // <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('<samp>' + s.slice(1, -1).replace(/\\`/g, '`')
.replace(/&(?!lt;|gt;)/g, '&amp;') + '</samp>');
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) { @@ -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,
'…<br><b><i>' + polyglot.t('busted_oh') + '</i> '
+ polyglot.t('busted_avowal') + ':</b><br><samp>'
+ polyglot.t('busted_avowal') + ':</b><br><samp>['
+ linkName
.replace(/&(?!lt;|gt;)/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;')
+ ']('
+ msg.str.slice(i, k + 1)
.replace(/&(?!lt;|gt;)/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;')
+ '</samp><br>'
+ ')</samp><br>…<br>'
);
} 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) { @@ -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

25
js/twister_io.js

@ -115,7 +115,8 @@ function dhtget(peerAlias, resource, multi, cbFunc, cbReq, timeoutArgs) { @@ -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) { @@ -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) { @@ -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) { @@ -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) {

45
js/twister_network.js

@ -146,31 +146,41 @@ function requestBestBlock(cbFunc, cbArg) { @@ -146,31 +146,41 @@ 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 {
@ -178,14 +188,14 @@ function networkUpdate(cbFunc, cbArg) { @@ -178,14 +188,14 @@ function networkUpdate(cbFunc, cbArg) {
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,11 +328,8 @@ function initInterfaceNetwork() { @@ -318,11 +328,8 @@ function initInterfaceNetwork() {
initMentionsCount();
initDMsCount();
});
}
else
{
$(".userMenu-profile > a").text(polyglot.t("Login"));
$(".userMenu-profile > a").attr("href","login.html");
} else {
$('.userMenu-profile > a').attr('href', '#/login').text(polyglot.t('Login'));
}
});
networkUpdate();

318
js/twister_newmsgs.js

@ -6,190 +6,170 @@ @@ -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);
}
_knownMentions[key] = {mentionTime: mentionTime, data: data};
purgeOldMentions();
saveMentionsToStorage();
}
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;
}
}
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]);
twister.mentions.lastTime = mentions.lastTime;
twister.mentions.lastTorrentId = mentions.lastTorrentId;
}
$.MAL.updateNewMentionsUI(_newMentions);
}
}, {},
[10000, 2000, 3] // use extended timeout parameters (requires twister_core >= 0.9.14)
);
if (_newMentionsUpdated) {
_newMentionsUpdated = false;
if (_newMentions) {
$.MAL.soundNotifyMentions();
// 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++;
}
}
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);
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');
}
// 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();}
});
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;
}
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 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});}
});
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
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();
$.MAL.updateNewMentionsUI(_newMentions);
requestMentionsCount();
setInterval(requestMentionsCount, 10000);
},
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() { @@ -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() { @@ -297,7 +305,5 @@ function initDMsCount() {
}
function newmsgsChangedUser() {
_knownMentions = {}
_lastMentionTime = 0;
_newMentions = 0;
clearInterval(twister.mentions.interval);
}

225
js/twister_user.js

@ -6,47 +6,48 @@ @@ -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 = $("<option/>");
$userOption.val(localUsernames[i]);
$userOption.text(localUsernames[i]);
$localUsersList.append($userOption);
function initUser(cbFunc, cbReq) {
loadWalletlUsers(
function (req) {
var elemAccountsList = getElem('select.local-usernames', true);
if (elemAccountsList.length) {
for (var i = 0; i < twister.var.localAccounts.length; i++) {
if (!elemAccountsList.find('option[value=\'' + twister.var.localAccounts[i] + '\']').length) {
$('<option/>')
.val(twister.var.localAccounts[i])
.text(twister.var.localAccounts[i])
.appendTo(elemAccountsList)
;
}
}
}
loadScreenName();
if( !defaultScreenName || localUsernames.indexOf(defaultScreenName) < 0 ) {
if (!defaultScreenName || twister.var.localAccounts.indexOf(defaultScreenName) < 0) {
defaultScreenName = undefined;
} else {
var $localUsersLogin = $("select.local-usernames.login-user");
if( $localUsersLogin.length ) {
$localUsersLogin.val(defaultScreenName);
}
getElem('select.local-usernames', true).val(defaultScreenName);
var $userMenuConfig = $(".userMenu-config");
if( $userMenuConfig.length ) {
$userMenuConfig.find("a.mini-profile-name").attr("href",$.MAL.userUrl(defaultScreenName));
$userMenuConfig.find(".mini-profile-name").text(defaultScreenName);
getFullname( defaultScreenName, $userMenuConfig.find(".mini-profile-name") );
var userMenuConfig = $('.userMenu-config');
if (userMenuConfig.length) {
var elem = userMenuConfig.find('.mini-profile-name')
.attr('href', $.MAL.userUrl(defaultScreenName)).text(defaultScreenName);
getFullname(defaultScreenName, elem);
}
}
lastPostId = undefined;
if( cbFunc )
cbFunc(cbArg);
});
if (typeof req.cbFunc === 'function') {
req.cbFunc(req.cbReq);
}
}, {cbFunc: cbFunc, cbReq: cbReq}
);
}
function incLastPostId( optionalNewValue ) {
@ -60,150 +61,102 @@ function incLastPostId( optionalNewValue ) { @@ -60,150 +61,102 @@ function incLastPostId( optionalNewValue ) {
$.MAL.updateMyOwnPostCount(lastPostId+1);
}
function loadWalletlUsers(cbFunc, cbArg) {
twisterRpc("listwalletusers", [],
function(args, ret) {
localUsernames = [];
for( var i = 0; i < ret.length; i++ ) {
// filter out group aliases
if( ret.length && ret[i][0] !== '*' ) {
localUsernames.push(ret[i]);
function loadWalletlUsers(cbFunc, cbReq) {
twisterRpc('listwalletusers', [],
function (req, ret) {
twister.var.localAccounts = [];
for (var i = 0; i < ret.length; i++) {
if (ret.length && ret[i][0] !== '*') { // filter out group aliases (starting with '*')
twister.var.localAccounts.push(ret[i]);
}
}
args.cbFunc(args.cbArg);
}, {cbFunc:cbFunc, cbArg:cbArg},
function(args, ret) {
alert(polyglot.t("error_connecting_to_daemon"));
}, {});
if (typeof req.cbFunc === 'function') {
req.cbFunc(req.cbReq);
}
}, {cbFunc: cbFunc, cbReq: cbReq},
function (req, ret) {
alert(polyglot.t('error_connecting_to_daemon'));
}
);
}
function loadScreenName() {
if( $.localStorage.isSet("defaultScreenName") ) {
defaultScreenName = $.localStorage.get("defaultScreenName").toString();
if ($.localStorage.isSet('defaultScreenName')) {
defaultScreenName = $.localStorage.get('defaultScreenName').toString();
}
}
function saveScreenName() {
$.localStorage.set("defaultScreenName", defaultScreenName);
$.localStorage.set('defaultScreenName', defaultScreenName);
}
// user-related functions used by login page (desktop/mobile)
// ----------------------------------------------------------
function loginLocalUsername() {
defaultScreenName = $("select.local-usernames.login-user").val();
if(defaultScreenName) {
function loginToAccount(peerAlias) {
if (!peerAlias) {
console.warn('can\'t login to account: empty alias was given');
return;
}
defaultScreenName = peerAlias;
saveScreenName();
$.MAL.changedUser();
$.MAL.goHome();
}
}
function checkUsernameAvailability() {
var $newUsername = $(".new-username");
var username = $newUsername.val().toLowerCase();
$newUsername.val(username);
var $availField = $(".availability");
if( !username.length )
return;
if( username.length > 16 ) {
$availField.text(polyglot.t("Must be 16 characters or less."));
function createAccount(peerAlias) {
if (!peerAlias) {
console.warn('can\'t create account: empty alias was given');
return;
}
//Check for non-alphabetic characters and space
if(username.search(/[^a-z0-9_]/) != -1) {
$availField.text(polyglot.t("Only alphanumeric and underscore allowed."));
return;
twisterRpc('createwalletuser', [peerAlias],
function(req, ret) {
$.MAL.processCreateAccount(req.peerAlias, ret);
}, {peerAlias: peerAlias},
function(req, ret) {
alert(polyglot.t('Error in \'createwalletuser\' RPC.'));
}
$availField.text(polyglot.t("Checking..."));
dumpPubkey(username, function(dummy, pubkey) {
var notAvailable = pubkey.length > 0
var $availField = $(".availability");
if( notAvailable ) {
$availField.text(polyglot.t("Not available"));
} else {
$availField.text(polyglot.t("Available"));
var $createButton = $(".create-user");
$.MAL.enableButton( $createButton );
}
}, null);
}
function newUserNameKeypress() {
var $availField = $(".availability");
$availField.text("");
var $createButton = $(".create-user");
$.MAL.disableButton( $createButton );
);
}
// create user and call cbFunc(username, privkey)
function createUserClick(cbFunc) {
var $newUsername = $(".new-username");
var username = $newUsername.val().toLowerCase();
if( localUsernames.indexOf(username) < 0 ) {
twisterRpc("createwalletuser", [username],
function(args, ret) {
args.cbFunc(args.username, ret);
}, {username:username, cbFunc:cbFunc},
function(args, ret) {
alert(polyglot.t("Error in 'createwalletuser' RPC."));
}, {cbFunc:cbFunc});
} else {
// user exists in wallet but transaction not sent
dumpPrivkey(username,
function(args, ret) {
args.cbFunc(args.username, ret);
}, {username:username, cbFunc:cbFunc});
function importAccount(peerAlias, secretKey) {
if (!peerAlias) {
console.warn('can\'t import account: empty alias was given');
return;
}
if (!secretKey) {
console.warn('can\'t import account: empty secret key was given');
return;
}
}
function sendNewUserTransaction(username, cbFunc) {
twisterRpc("sendnewusertransaction", [username],
function(args, ret) {
args.cbFunc();
}, {cbFunc:cbFunc},
function(args, ret) {
alert(polyglot.t("Error in 'sendnewusertransaction' RPC."));
}, {});
}
function importSecretKeyClick() {
var secretKey = $(".secret-key-import").val();
var username = $(".username-import").val().toLowerCase();
twisterRpc("importprivkey", [secretKey,username],
function(args, ret) {
processNewSecretKeyImported(args.username);
}, {username:username},
function(args, ret) {
alert(polyglot.t("Error in 'importprivkey'", {rpc: ret.message }));
}, {});
}
function processNewSecretKeyImported(username) {
defaultScreenName = username;
twisterRpc('importprivkey', [secretKey, peerAlias],
function (req, ret) {
defaultScreenName = req.peerAlias;
saveScreenName();
$.MAL.changedUser();
$.MAL.goHome();
}, {peerAlias: peerAlias},
function (req, ret) {
alert(polyglot.t('Error in \'importprivkey\'', {rpc: ret.message}));
}
);
}
// handlers common to both desktop and mobile
function interfaceCommonLoginHandlers() {
$( ".login-local-username" ).bind( "click", loginLocalUsername );
$( ".check-availability").bind( "click", checkUsernameAvailability );
/* must specialize: $( ".create-user").bind( "click", function() { createUserClick( processCreateUser ); } ); */
/* must specialize: $( ".login-created-user").bind( "click", loginCreatedUser ); */
$( ".new-username" ).keyup( newUserNameKeypress );
$('.secret-key-import').on('input', importSecretKeypress);
$('.username-import').on('input', importSecretKeypress);
$( ".import-secret-key").bind( "click", importSecretKeyClick );
function sendNewUserTransaction(peerAlias, cbFunc, cbReq) {
twisterRpc('sendnewusertransaction', [peerAlias],
function (req, ret) {
if (typeof req.cbFunc === 'function') {
req.cbFunc(req.cbReq);
}
}, {cbFunc: cbFunc, cbReq: cbReq},
function (req, ret) {
alert(polyglot.t('Error in \'sendnewusertransaction\' RPC.'));
}
);
}
// profile-related functions used by profile-edit

142
login.html

@ -1,142 +0,0 @@ @@ -1,142 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>twister login</title>
<link id="stylecss" rel="stylesheet" href="css/style.css" type="text/css"/>
<script src="js/jquery.min.js"></script>
<script src="js/jQueryPlugins.js"></script>
<script src="js/jquery.json-2.4.js"></script>
<script src="js/jquery.jsonrpcclient.js"></script>
<script src="js/jquery.storageapi.js"></script>
<script src="js/options.js"></script>
<script src="js/franc.js"></script>
<script src="js/notify.js"></script>
<script src="js/mobile_abstract.js"></script>
<script src="js/twister_io.js"></script>
<script src="js/twister_network.js"></script>
<script src="js/twister_user.js"></script>
<script src="js/interface_common.js"></script>
<script src="js/interface_login.js"></script>
<script src="js/polyglot.min.js"></script>
<script src="js/interface_localization.js"></script>
<link rel="shortcut icon" type="image/png" href="img/twister_mini.png" />
</head>
<body>
<!-- MENU SUPERIOR INIT -->
<nav class="userMenu">
<ul>
<li class="userMenu-home"><a href="home.html"><span class="selectable_theme theme_original label">Home</span></a></li>
<li class="userMenu-network selectable_theme theme_original"><a class="label" href="network.html">Network</a></li>
<li class="userMenu-profile current"><a class="label" href="login.html">Login</a></li>
<li class="userMenu-config">
</li>
</ul>
</nav>
<!-- MENU SUPERIOR END -->
<div class="wrapper">
<!-- LADO ESQUERDO DE MÓDULOS INIT -->
<div class="login">
<h2 class="header-bold"> twister login </h2>
<div class="module">
<p> <span>Existing local users</span> </p>
<div>
<select class="local-usernames login-user">
</select>
<button class="login-local-username">Login</button>
</div>
</div>
<!-- <span> Or... </span> -->
<div class="module">
<p> <span>Create a new user</span> </p>
<div>
<input class="new-username" type="textbox" placeholder="Type nickname here" cols="16" rows="1"></input>
<button class="check-availability">Check availability</button>
<span class="availability"></span>
</div>
<div>
<button class="create-user disabled" disable="true">Create this nickname</button>
</div>
</div>
<!-- <span> Or... </span> -->
<div class="module">
<div>
<p> <span>Import secret key</span> </p>
<input class="secret-key-import" type="textbox" placeholder="52-characters secret" size="52" rows="1"></input>
</div>
<div>
<p class="with-nickname"> <span>With nickname</span> </p>
<input class="username-import" type="textbox" placeholder="Type nickname here" size="16" rows="1"></input>
</div>
<div>
<button class="import-secret-key disabled" disable="true">Import key</button>
</div>
</div>
</div>
<!-- LADO ESQUERDO DE MÓDULOS END -->
</div>
<!-- TEMPLATES INIT -->
<div id="templates" style="display:none;">
<!-- TEMPLATE DO MODAL GENÉRICO INIT -->
<div class="modal-wrapper">
<div class="modal-header">
<h3></h3>
</div>
<div class="modal-content"></div>
<div class="modal-blackout"></div>
</div>
<!-- TEMPLATE DO MODAL GENÉRICO END -->
<div class="prompt-wrapper">
<div class="modal-header">
<h3></h3>
<span class="modal-close prompt-close">&times;</span>
</div>
<div class="modal-content"></div>
</div>
<div id="confirm-popup-template">
<div class="message"></div>
<div class="modal-buttons">
<button class="confirm"></button>
<button class="cancel"></button>
</div>
</div>
<!-- MODAL DE NEW USER INIT -->
<div id="new-user-modal-template">
<div class="warning">
<div class="text">
A new user was created and it is being propagated to the network.
Please do not close this window, this might take a few minutes.
</div>
<div class="text emphasis">
Your secret key is: <span class="secret-key"></span>
</div>
<div class="text">
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.
</div>
<div class="text">
The secret key will be needed to use this account from different computers.
If you ever lose your secret key (remember: this is alpha software and it may
crash, causing loss of data) your nickname will be locked forever.
There is no way to recover a lost key for twister accounts.
</div>
<div class="text"></div>
<div class="text">
Please wait. The 'OK' button will be shown when process completes.
</div>
<div class="text">
<button class="login-created-user" style="display:none;">OK</button>
</div>
</div>
</div>
</div>
<!-- TEMPLATES END -->
</body>
</html>

4
network.html

@ -45,8 +45,7 @@ @@ -45,8 +45,7 @@
</div>
<a class="dropdown-menu-item" href="options.html">Options</a>
<a class="dropdown-menu-item" href="profile-edit.html">Setup account</a>
<a class="dropdown-menu-item" href="network.html">Network config</a>
<a class="dropdown-menu-item" href="login.html">Change user</a>
<a class="dropdown-menu-item updates-check-client">Check for client's updates</a>
</div>
</a>
</li>
@ -275,6 +274,7 @@ @@ -275,6 +274,7 @@
<span class="modal-close prompt-close">&times;</span>
</div>
<div class="modal-content"></div>
<div class="modal-blackout"></div>
</div>
<div id="confirm-popup-template">

21
options.html

@ -38,7 +38,6 @@ @@ -38,7 +38,6 @@
<a class="dropdown-menu-item" href="options.html">Options</a>
<a class="dropdown-menu-item" href="network.html">Network config</a>
<a class="dropdown-menu-item" href="profile-edit.html">Setup account</a>
<a class="dropdown-menu-item" href="login.html">Change user</a>
</div>
</a>
</li>
@ -353,6 +352,26 @@ @@ -353,6 +352,26 @@
</form>
</div>
</div>
<div class="module">
<p class="label label-h"> New Users </p>
<div class="container">
<form>
<p>
<select id="NewUsers">
<option value="enable">Enable</option>
<option value="disable">Disable</option>
</select>
</p>
<div id="NewUsersCont" class="container">
<p class="label">Live tracking</p>
<select id="NewUsersLiveTracking" class="container">
<option value="enable">Enable</option>
<option value="disable">Disable</option>
</select>
</div>
</form>
</div>
</div>
<div class="module">
<p class="label label-h"> Twistday Reminder </p>
<div class="container">

2
profile-edit.html

@ -50,7 +50,6 @@ @@ -50,7 +50,6 @@
<a class="dropdown-menu-item" href="options.html">Options</a>
<a class="dropdown-menu-item" href="profile-edit.html">Setup account</a>
<a class="dropdown-menu-item" href="network.html">Network config</a>
<a class="dropdown-menu-item" href="login.html">Change user</a>
</div>
</a>
</li>
@ -95,6 +94,7 @@ @@ -95,6 +94,7 @@
<span class="modal-close prompt-close">&times;</span>
</div>
<div class="modal-content"></div>
<div class="modal-blackout"></div>
</div>
<div id="confirm-popup-template">

306
theme_calm/css/style.css

@ -344,6 +344,16 @@ button.unfollow:hover { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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;

324
theme_nin/css/style.css

@ -389,6 +389,15 @@ samp { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 */

55
theme_nin/sass/_login.sass

@ -1,55 +0,0 @@ @@ -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

76
theme_nin/sass/style.sass

@ -8,7 +8,6 @@ @@ -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 @@ -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 @@ -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

96
tmobile.html

@ -171,55 +171,7 @@ @@ -171,55 +171,7 @@
<h1 class="rtitle">twister login</h1>
</div>
<div class="content" data-role="content" style="">
<div class="login">
<div class="module">
<span> Existing local users </span>
<div class="ui-grid-a">
<div class="ui-block-a">
<select class="local-usernames login-user"></select>
</div>
<div class="ui-block-b">
<button class="login-local-username">Login</button>
</div>
</div>
</div>
<hr/>
<span> Or... </span>
<div class="module">
<span> Create a new user </span>
<div>
<input class="new-username" type="textbox" placeholder="Type nickname here" cols="16" rows="1"></input>
<button class="check-availability">Check availability</button>
<span class="availability"></span>
</div>
<div>
<button class="create-user disabled" disabled="disabled">Create this nickname</button>
</div>
</div>
<hr/>
<span> Or... </span>
<div class="module">
<div>
<span> Import secret key </span>
<input class="secret-key-import" type="textbox" placeholder="52-characters secret" size="52" rows="1"></input>
</div>
<div>
<span> With nickname </span>
<input class="username-import" type="textbox" placeholder="Type nickname here" size="16" rows="1"></input>
</div>
<div>
<button class="import-secret-key disabled" disabled="disabled">Import key</button>
</div>
</div>
</div>
</div>
<div class="content" data-role="content" style=""></div>
<div class="footer" data-role="footer" data-position="fixed" data-tap-toggle="false">
<a href="#home" data-role="button">Home</a>
@ -891,6 +843,52 @@ @@ -891,6 +843,52 @@
</div>
</li>
</div>
<div id="template-login-modal">
<div class="module">
<span>Existing local users</span>
<div class="ui-grid-a">
<div class="ui-block-a">
<select class="local-usernames"></select>
</div>
<div class="ui-block-b">
<button class="login">Login</button>
</div>
</div>
</div>
<hr/>
<span> Or... </span>
<div class="module create-account">
<span>Create a new user</span>
<div>
<input class="alias" type="textbox" placeholder="Type nickname here" cols="16" rows="1"></input>
<span class="availability"></span>
</div>
<div>
<button class="check" disabled="disabled">Check availability</button>
<button class="create" disabled="disabled">Create this nickname</button>
</div>
</div>
<hr/>
<span> Or... </span>
<div class="module import-account">
<div>
<span>Import secret key</span>
<input class="secret-key" type="textbox" placeholder="52-characters secret" size="52" rows="1"></input>
</div>
<div>
<span>With nickname</span>
<input class="alias" type="textbox" placeholder="Type nickname here" size="16" rows="1"></input>
</div>
<div>
<button class="import" disabled="disabled">Import key</button>
</div>
</div>
</div>
</div> <!-- templates -->

Loading…
Cancel
Save