Browse Source

Merge branch 'blaster'

master
Miguel Freitas 8 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
opacity: 0.9; 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 { .userMenu li.userMenu-profile > a {
background: url(../img/profile.png) no-repeat 5px center; background: url(../img/profile.png) no-repeat 5px center;
} }
@ -833,13 +843,13 @@ textarea.splited-post {
/*********************************** /***********************************
********************* WHO TO FOLLOW ********************* WHO TO FOLLOW
***********************************/ ***********************************/
.who-to-follow .who-to-follow,
{ .new-users {
padding: 10px; padding: 10px;
margin-bottom: 10px; margin-bottom: 10px;
} }
.who-to-follow h3 .who-to-follow h3,
{ .new-users h3 {
display: inline; display: inline;
} }
.twister-user .twister-user
@ -880,17 +890,20 @@ textarea.splited-post {
color: #e34f42; color: #e34f42;
} }
.followers .followers,
{ .latest-activity {
font-size: 12px; font-size: 12px;
color: rgba( 0, 0, 0, .6 ); color: rgba( 0, 0, 0, .6 );
margin-left: 58px;
} }
.followed-by
{ .followed-by,
.latest-activity .time {
color: #e34f42; color: #e34f42;
font-size: 13px; font-size: 13px;
cursor: pointer; cursor: pointer;
} }
.twister-user-name, .twister-user-name,
.twister-by-user-name .twister-by-user-name
{ {
@ -1280,6 +1293,7 @@ ol.toptrends-list {
.post-favorite:before .post-favorite:before
{ {
content: "★"; content: "★";
font-size: 18px;
} }
.post-reply:hover, .post-reply:hover,
.post-propagate:hover, .post-propagate:hover,
@ -1305,6 +1319,10 @@ ol.toptrends-list {
{ {
width: 100%; width: 100%;
} }
.image-preview img
{
max-width: 100%;
}
.preview-container .preview-container
{ {
max-height: 500px; max-height: 500px;
@ -1390,8 +1408,7 @@ ol.toptrends-list {
border: solid 1px rgba( 69, 71, 77, .05 ); border: solid 1px rgba( 69, 71, 77, .05 );
padding: 10px; padding: 10px;
} }
.singleBlock h2, .header-bold .singleBlock h2 {
{
font-weight: bold; font-weight: bold;
line-height: 40px; line-height: 40px;
color: rgba( 255, 255, 255, 1 ); color: rgba( 255, 255, 255, 1 );
@ -1462,76 +1479,6 @@ ol.toptrends-list {
margin-right: 20px; 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 ************ ************* POPUP MODAL ************
**************************************/ **************************************/
@ -1562,12 +1509,12 @@ ol.toptrends-list {
font-weight: bold; font-weight: bold;
} }
.modal-wrapper .modal-content { .modal-content {
background: #fff; background: #fff;
overflow-y: auto; overflow-y: auto;
} }
.modal-wrapper .modal-blackout { .modal-blackout {
background: rgba(0,0,0, .6); background: rgba(0,0,0, .6);
z-index: -1; z-index: -1;
position: fixed; position: fixed;
@ -1631,6 +1578,84 @@ ol.toptrends-list {
padding: 10px 15px; 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 ******* ******** DIRECT MESSAGES MODAL *******
**************************************/ **************************************/
@ -1780,7 +1805,7 @@ ol.toptrends-list {
.group-messages-join-group.modal-wrapper { .group-messages-join-group.modal-wrapper {
height: auto; /*about 360px*/ height: auto; /*about 360px*/
margin-top: -240px; margin-top: -204px;
} }
.group-messages-join-group .modal-content .module { .group-messages-join-group .modal-content .module {
@ -1825,38 +1850,6 @@ ol.toptrends-list {
margin: 8px 8px 0; 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 *********** ************ HASHTAG MODAL ***********
**************************************/ **************************************/
@ -1901,36 +1894,79 @@ ol.toptrends-list {
********* WHO TO FOLLOW MODAL ******** ********* WHO TO FOLLOW MODAL ********
**************************************/ **************************************/
.who-to-follow-modal ol { .who-to-follow-modal ol,
.new-users-modal ol {
margin: 5px; 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; 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; 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; text-decoration: underline;
} }
.who-to-follow-modal .follow { .who-to-follow-modal .follow,
.new-users-modal .follow {
float: right; float: right;
margin: -30px 10px 0 10px; 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; vertical-align: bottom;
} }
.who-to-follow-modal .bio { .who-to-follow-modal .bio,
.new-users-modal .bio {
font-size: 12px; font-size: 12px;
color: rgba( 0, 0, 0, .6 ); 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 ************ ************ POPUP PROMPT ************
**************************************/ **************************************/
@ -1948,7 +1984,7 @@ ol.toptrends-list {
} }
.prompt-wrapper .modal-buttons { .prompt-wrapper .modal-buttons {
margin: 4px 16px; padding: 4px 16px 16px;
text-align: right; text-align: right;
} }
@ -1968,12 +2004,19 @@ ol.toptrends-list {
.confirm-popup .message { .confirm-popup .message {
text-align: center; text-align: center;
margin: 12px; padding: 12px;
} }
.confirm-popup .modal-buttons { .confirm-popup .modal-buttons {
text-align: center; text-align: center;
padding: 4px; }
/*************************************
********* NEW ACCOUNT POPUP **********
**************************************/
.new-account-briefing.prompt-wrapper {
margin-top: -164px;
} }
/************************************* /*************************************
@ -2268,7 +2311,7 @@ ol.toptrends-list {
display: inline-block; display: inline-block;
text-align: initial; text-align: initial;
width: 320px; width: 320px;
height: 120px; height: 130px;
margin: 2px; margin: 2px;
padding: 2px; padding: 2px;
border: solid 1px rgba(69, 71, 77, .1); border: solid 1px rgba(69, 71, 77, .1);
@ -2311,6 +2354,13 @@ ol.toptrends-list {
right: 32px; right: 32px;
} }
.following-own-modal .following-list .latest-activity {
position: absolute;
top: 110px;
right: 32px;
margin: 0;
}
/************************************* /*************************************
*********** AUTOCOMPLETING *********** *********** AUTOCOMPLETING ***********
**************************************/ **************************************/

116
home.html

@ -49,12 +49,13 @@
<a href="#" class="mini-profile-name">Fulano da Silva</a> <a href="#" class="mini-profile-name">Fulano da Silva</a>
<span class="mini-profile-view">View</span> <span class="mini-profile-view">View</span>
</div> </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="options.html">Options</a>
<a class="dropdown-menu-item" href="network.html">Network config</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="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 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 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 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> <a class="dropdown-menu-item groupmessages selectable_theme theme_original theme_calm" href="#">Group Messages</a>
@ -76,6 +77,7 @@
<span class="messages-qtd" style="display:none;">0</span> <span class="messages-qtd" style="display:none;">0</span>
</a> </a>
</li> </li>
<li class="userMenu-favs"><a href="#"></a></li>
<li class="userMenu-dhtindicator selectable_theme theme_calm"><a href="network.html"></a></li> <li class="userMenu-dhtindicator selectable_theme theme_calm"><a href="network.html"></a></li>
<!-- BUSCA --> <!-- BUSCA -->
@ -145,6 +147,8 @@
<!-- TWISTDAY REMINDER MODULE --> <!-- TWISTDAY REMINDER MODULE -->
<div class="module twistday-reminder" style="display: none;"></div> <div class="module twistday-reminder" style="display: none;"></div>
<div class="module new-users" style="display: none;"></div>
</div> </div>
<!-- LADO ESQUERDO DE MÓDULOS END --> <!-- LADO ESQUERDO DE MÓDULOS END -->
@ -217,9 +221,22 @@
<a class="refresh-users">Refresh</a> <a class="refresh-users">Refresh</a>
<small>.</small> <small>.</small>
<a class="view-all-users" href="#whotofollow">View All</a> <a class="view-all-users" href="#whotofollow">View All</a>
<ol class="follow-suggestions"> <ol class="follow-suggestions"></ol>
<!-- use "follow-suggestion-template" here --> </div>
</ol> <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>
<div class="loading-roller"> <div class="loading-roller">
<div></div> <div></div>
@ -281,8 +298,8 @@
</div> </div>
</li> </li>
<!-- TEMPLATE DE WHO-TO-FOLLOW SUGGESTION --> <div id="template-whotofollow-peer">
<li id="follow-suggestion-template" class="twister-user"> <li class="twister-user">
<div class=""> <div class="">
<a href="#" class="twister-user-name open-profile-modal"> <a href="#" class="twister-user-name open-profile-modal">
<img class="twister-user-photo" src="img/grayed_avatar_placeholder_24.png" alt="user-photo"/> <img class="twister-user-photo" src="img/grayed_avatar_placeholder_24.png" alt="user-photo"/>
@ -301,9 +318,14 @@
</a> </a>
</div> </div>
<a class="twister-user-remove">&times;</a> <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> <button class="follow">Follow</button>
</div> </div>
</li> </li>
</div>
<!-- TEMPLATE DA OL INVÓLUCRO DAS LIST ELEMENTS DO POST EXPANDIDO INIT --> <!-- TEMPLATE DA OL INVÓLUCRO DAS LIST ELEMENTS DO POST EXPANDIDO INIT -->
<ol class="expanded-post"> <ol class="expanded-post">
@ -343,7 +365,7 @@
<div class="post-interactions"> <div class="post-interactions">
<span class="post-reply">Reply</span> <span class="post-reply">Reply</span>
<span class="post-propagate">Retransmit</span> <span class="post-propagate">Retransmit</span>
<!--span class="post-favorite">Favorite</span--> <span class="post-favorite">Favorite</span>
</div> </div>
<div class="expanded-content" style="display: none;"> <div class="expanded-content" style="display: none;">
<ul class="post-stats" style="display: none;"> <ul class="post-stats" style="display: none;">
@ -425,12 +447,23 @@
<div class="modal-blackout"></div> <div class="modal-blackout"></div>
</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="prompt-wrapper">
<div class="modal-header"> <div class="modal-header">
<h3></h3> <h3></h3>
<span class="modal-close prompt-close">&times;</span> <span class="modal-close prompt-close">&times;</span>
</div> </div>
<div class="modal-content"></div> <div class="modal-content"></div>
<div class="modal-blackout"></div>
</div> </div>
<div id="confirm-popup-template"> <div id="confirm-popup-template">
@ -441,6 +474,42 @@
</div> </div>
</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 id="reTwist-modal-template">
<div class="post-area"> <div class="post-area">
<form class="post-area-new open"> <form class="post-area-new open">
@ -472,6 +541,14 @@
</div> </div>
</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 --> <!-- MODAL DE DIRECT MESSAGES INIT -->
<!-- Este modal possui dois templates, o primeiro da lista de pessoas que enviaram mensagens e o segundo <!-- Este modal possui dois templates, o primeiro da lista de pessoas que enviaram mensagens e o segundo
com a thread de mensagens individual --> com a thread de mensagens individual -->
@ -609,10 +686,6 @@
<p class="label">Import secret key</p> <p class="label">Import secret key</p>
<input class="secret-key-import" type="textbox" placeholder="52-characters secret" size="52" rows="1"></input> <input class="secret-key-import" type="textbox" placeholder="52-characters secret" size="52" rows="1"></input>
</div> </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> <div>
<button class="import-secret-key" disabled="disabled">Import key</button> <button class="import-secret-key" disabled="disabled">Import key</button>
</div> </div>
@ -655,13 +728,14 @@
<ul class="module profile-data"> <ul class="module profile-data">
<li><a href="#"><span class="posts-count">&nbsp;</span><span class="label">Posts</span></a></li> <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="#" 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> </ul>
</div> </div>
<div class="profile-card-buttons b-buttons"> <div class="profile-card-buttons b-buttons">
<button class="follow" href="#">Follow</button> <button class="follow" href="#">Follow</button>
<button class="direct-messages-with-user" href="#">Direct Messages</button> <button class="direct-messages-with-user" href="#">Direct Messages</button>
<button class="mentions-from-user" href="#">Mentions</button> <button class="mentions-from-user" href="#">Mentions</button>
<button class="favs-from-user" href="#">Favorites</button>
</div> </div>
</div> </div>
<div class="who-follow"></div> <div class="who-follow"></div>
@ -756,6 +830,10 @@
<div> <div>
<span class="swarm-status" style="display: none;"></span> <span class="swarm-status" style="display: none;"></span>
</div> </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> </div>
</li> </li>
</div> </div>
@ -793,6 +871,18 @@
</div> </div>
</div> </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> </div>
<!-- TEMPLATES END --> <!-- TEMPLATES END -->

539
js/interface_common.js

@ -16,7 +16,12 @@ var twister = {
tmpl: { // templates pointers are stored here tmpl: { // templates pointers are stored here
root: $('<div>') // templates should be detached from DOM and attached here; use extractTemplate() 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 window_scrollY = 0;
var _watchHashChangeRelaxDontDoIt = window.location.hash === '' ? true : false; var _watchHashChangeRelaxDontDoIt = window.location.hash === '' ? true : false;
@ -55,6 +60,9 @@ function openModal(modal) {
modal.self = $('#templates ' + modal.classBase).clone(true) modal.self = $('#templates ' + modal.classBase).clone(true)
.addClass(modal.classAdd); .addClass(modal.classAdd);
if (modal.removeBlackout)
modal.self.find('.modal-blackout').remove();
if (modal.title) if (modal.title)
modal.self.find('.modal-header h3').html(modal.title); modal.self.find('.modal-header h3').html(modal.title);
if (modal.content) if (modal.content)
@ -63,6 +71,16 @@ function openModal(modal) {
else else
modal.content = modal.self.find('.modal-content'); 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 modal.self.appendTo('body').fadeIn('fast'); // FIXME maybe it's better to append it to some container inside body
if (modal.classBase === '.modal-wrapper') { if (modal.classBase === '.modal-wrapper') {
@ -71,7 +89,9 @@ function openModal(modal) {
modal.drapper = $('<div>').appendTo(twister.html.detached); // here modal goes instead detaching 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(); var windowHeight = $(window).height();
if (modal.self.outerHeight() > windowHeight) { if (modal.self.outerHeight() > windowHeight) {
@ -107,6 +127,9 @@ function closeModal(req, switchMode) {
else else
this.remove(); // if it's minimized it will be removed with twister.modal[i].drapper 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].drapper.remove();
twister.modal[i] = undefined; twister.modal[i] = undefined;
} }
@ -287,8 +310,9 @@ function confirmPopup(req) {
var modal = openModal({ var modal = openModal({
classBase: '.prompt-wrapper', classBase: '.prompt-wrapper',
classAdd: 'confirm-popup', classAdd: req.classAdd ? 'confirm-popup ' + req.classAdd : 'confirm-popup',
content: $('#confirm-popup-template').children().clone(true), content: $('#confirm-popup-template').children().clone(true),
removeBlackout: !req.addBlackout,
title: req.txtTitle title: req.txtTitle
}); });
@ -343,6 +367,8 @@ function confirmPopup(req) {
btn.on('click', {cbFunc: req.cbClose, cbReq: req.cbCloseReq}, closePrompt); btn.on('click', {cbFunc: req.cbClose, cbReq: req.cbCloseReq}, closePrompt);
} }
} }
return modal;
} }
function alertPopup(req) { function alertPopup(req) {
@ -359,7 +385,7 @@ function alertPopup(req) {
req.removeCancel = true; req.removeCancel = true;
} }
confirmPopup(req); return confirmPopup(req);
} }
function checkNetworkStatusAndAskRedirect(cbFunc, cbReq) { function checkNetworkStatusAndAskRedirect(cbFunc, cbReq) {
@ -377,6 +403,7 @@ function checkNetworkStatusAndAskRedirect(cbFunc, cbReq) {
} }
function timeGmtToText(t) { function timeGmtToText(t) {
if (t == 0) return '-';
var d = new Date(0); var d = new Date(0);
d.setUTCSeconds(t); d.setUTCSeconds(t);
return d.toString().replace(/GMT.*/g, ''); return d.toString().replace(/GMT.*/g, '');
@ -400,6 +427,94 @@ function timeSincePost(t) {
return polyglot.t('time_ago', {time: expression}); 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) { function openGroupProfileModalWithNameHandler(groupAlias) {
var modal = openModal({ var modal = openModal({
classAdd: 'profile-modal', classAdd: 'profile-modal',
@ -449,6 +564,8 @@ function openUserProfileModalWithNameHandler(peerAlias) {
content.find('.tox-ctc').attr('title', polyglot.t('Copy to clipboard')); content.find('.tox-ctc').attr('title', polyglot.t('Copy to clipboard'));
content.find('.bitmessage-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({ var modal = openModal({
classAdd: 'profile-modal', classAdd: 'profile-modal',
content: content, content: content,
@ -475,37 +592,54 @@ function openHashtagModalFromSearchHandler(hashtag) {
title: '#' + 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) { function handleClickDisplayPendingTwists(event) {
var req = { if (!event || !event.data || !event.data.req)
postboard: postboard, return;
query: query,
resource: resource,
id: query + '@' + resource
};
postboard.attr('data-request-id', req.id);
requestQuery(req); $(event.target).hide();
// use extended timeout parameters on modal refresh (requires twister_core >= 0.9.14). queryPendingDraw(event.data.req);
// 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];
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) { function openFavsModal(event) {
if (!isModalWithElemExists(req.postboard)) { if (event && typeof event.stopPropagation === 'function') {
clearInterval(req.postboard.attr('data-request-interval')); event.preventDefault();
clearQueryProcessed(req.id); 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; 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) { function openMentionsModal(event) {
@ -537,22 +671,22 @@ function openMentionsModalHandler(peerAlias) {
title: polyglot.t('users_mentions', {username: 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) { if (peerAlias === defaultScreenName) {
// obtain already cached mention posts from twister_newmsgs.js modal.content.on('scroll', handleMentionsModalScroll);
processQuery({
postboard: modal.content.find('.postboard-posts'),
query: defaultScreenName,
resource: 'mention',
posts: getMentionsData()
});
resetMentionsCount(); resetMentionsCount();
} }
} }
function openFollowersModal(peerAlias) { function openFollowersModal(peerAlias) {
var followers, title, txtAlert; var followers, title, warn;
if (!peerAlias || peerAlias === defaultScreenName) { if (!peerAlias || peerAlias === defaultScreenName) {
if (!defaultScreenName) { if (!defaultScreenName) {
@ -565,22 +699,27 @@ function openFollowersModal(peerAlias) {
} }
title = polyglot.t('Followers'); title = polyglot.t('Followers');
followers = twisterFollowingO.knownFollowers.slice(); followers = twisterFollowingO.knownFollowers.slice();
txtAlert = '* ' + polyglot.t('warn_followers_not_all'); warn = {
name: 'FollowersNotAll',
text: '* ' + polyglot.t('warn_followers_not_all')
};
} else { } else {
title = polyglot.t('Followers_of', {alias: peerAlias}); title = polyglot.t('Followers_of', {alias: peerAlias});
followers = whoFollows(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({ var modal = openModal({
classAdd: 'followers-modal', classAdd: 'followers-modal',
content: twister.tmpl.followersList.clone(true), content: twister.tmpl.followersList.clone(true),
title: title title: title,
warn: warn
}); });
appendFollowersToElem(modal.content.find('ol'), followers); appendFollowersToElem(modal.content.find('ol'), followers);
alertPopup({txtMessage: txtAlert});
} }
function appendFollowersToElem(list, followers) { function appendFollowersToElem(list, followers) {
@ -658,6 +797,7 @@ function addPeerToFollowingList(list, peerAlias) {
.on('mouseup', {route: $.MAL.mentionsUrl(peerAlias)}, routeOnClick); .on('mouseup', {route: $.MAL.mentionsUrl(peerAlias)}, routeOnClick);
getAvatar(peerAlias, item.find('.mini-profile-photo')); getAvatar(peerAlias, item.find('.mini-profile-photo'));
getFullname(peerAlias, item.find('.mini-profile-name')); getFullname(peerAlias, item.find('.mini-profile-name'));
getStatusTime(peerAlias, item.find('.latest-activity .time'));
if (peerAlias === defaultScreenName) if (peerAlias === defaultScreenName)
item.find('.following-config').hide(); item.find('.following-config').hide();
@ -677,9 +817,6 @@ function addPeerToFollowingList(list, peerAlias) {
} }
function fillWhoToFollowModal(list, hlist, start) { 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++) { for (var i = 0; i < followingUsers.length && list.length < start + 20; i++) {
if (typeof twisterFollowingO.followingsFollowings[followingUsers[i]] !== 'undefined') { if (typeof twisterFollowingO.followingsFollowings[followingUsers[i]] !== 'undefined') {
for (var j = 0; j < twisterFollowingO.followingsFollowings[followingUsers[i]].following.length && list.length < start + 25; j++) { for (var j = 0; j < twisterFollowingO.followingsFollowings[followingUsers[i]].following.length && list.length < start + 25; j++) {
@ -687,26 +824,11 @@ function fillWhoToFollowModal(list, hlist, start) {
if (followingUsers.indexOf(utf) < 0 && list.indexOf(utf) < 0) { if (followingUsers.indexOf(utf) < 0 && list.indexOf(utf) < 0) {
list.push(utf); list.push(utf);
var item = itemTmp.clone(true); processWhoToFollowSuggestion(hlist, utf, followingUsers[i]);
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);
} }
} }
} }
} }
itemTmp.remove();
if (i >= followingUsers.length - 1) if (i >= followingUsers.length - 1)
return false; return false;
@ -727,12 +849,60 @@ function openWhoToFollowModal() {
modal.content.on('scroll', function() { modal.content.on('scroll', function() {
if (modal.content.scrollTop() >= hlist.height() - modal.content.height() - 20) { 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'); 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) { function newConversationModal(peerAlias, resource) {
@ -796,14 +966,22 @@ function handleClickOpenProfileModal(event) {
} }
function handleClickOpenConversation(event) { function handleClickOpenConversation(event) {
event.preventDefault(); var elem = $(event.target).closest(event.data.feeder);
event.stopPropagation(); if (!elem.length) {
muteEvent(event, true);
return;
}
var elem = $(event.target); var post = {
var postData = elem.closest(event.data.feeder); 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') event.data.route = '#conversation?post=' + post.writer + ':post' + post.id;
+ ':post' + postData.attr('data-id');
routeOnClick(event); routeOnClick(event);
} }
@ -828,8 +1006,8 @@ function openRequestShortURIForm(event) {
if (parseInt(twisterVersion) < 93500) { if (parseInt(twisterVersion) < 93500) {
alertPopup({ alertPopup({
//txtTitle: polyglot.t(''), add some title (not 'error', please) or just KISS //txtTitle: polyglot.t(''), add some title (not 'error', please) or just KISS
txtMessage: 'You can\'t shorten links because twister daemon is obsolete!\n' txtMessage: 'You can\'t shorten links \n'
+ 'Version 0.9.35 or higher is required. Please keep your twister up to date.' + polyglot.t('daemon_is_obsolete', {versionReq: '0.9.35'})
}); });
return; return;
} }
@ -845,7 +1023,7 @@ function openRequestShortURIForm(event) {
function showURIPair(uriLong, uriShort) { // FIXME req function showURIPair(uriLong, uriShort) { // FIXME req
if (uriShort) if (uriShort)
alertPopup({ alertPopup({
txtTitle: 'URI shortener', txtTitle: polyglot.t('URI_shortener'),
txtMessage: uriLong + ' — `' + uriShort + '`' txtMessage: uriLong + ' — `' + uriShort + '`'
}); });
else else
@ -854,7 +1032,7 @@ function showURIPair(uriLong, uriShort) { // FIXME req
function showURIShortenerErrorRPC(ret) { function showURIShortenerErrorRPC(ret) {
alertPopup({ alertPopup({
txtTitle: 'URI shortener', txtTitle: polyglot.t('URI_shortener'),
txtMessage: 'something went wrong. RPC error message:\n' + (ret && ret.message ? ret.message : ret) txtMessage: 'something went wrong. RPC error message:\n' + (ret && ret.message ? ret.message : ret)
}); });
} }
@ -909,12 +1087,28 @@ function fetchShortenedURI(req, attemptCount) {
function applyShortenedURI(short, uriAndMimetype) { function applyShortenedURI(short, uriAndMimetype) {
var long = (uriAndMimetype instanceof Array) ? uriAndMimetype[0] : uriAndMimetype; var long = (uriAndMimetype instanceof Array) ? uriAndMimetype[0] : uriAndMimetype;
var mimetype = (uriAndMimetype instanceof Array) ? uriAndMimetype[1] : undefined; 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) .attr('href', long)
.removeClass('link-shortened') .removeClass('link-shortened')
.off('click mouseup') .off('click mouseup')
.on('click mouseup', muteEvent) .on('click mouseup', muteEvent)
; ;
var cropped = (/*$.Options.cropLongURIs &&*/ long.length > 23) ? long.slice(0, 23) + '…' : undefined; var cropped = (/*$.Options.cropLongURIs &&*/ long.length > 23) ? long.slice(0, 23) + '…' : undefined;
for (var i = 0; i < elems.length; i++) { 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 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) {
elem.pause(); elem.pause();
} }
}); });
imagePreview.find("video").removeAttr("autoplay"); var $vid = imagePreview.find("video");
$vid.removeAttr("autoplay");
$vid.on('click mouseup', muteEvent);
} else { } else {
file.getBlobURL(function (err, url) { file.getBlobURL(function (err, url) {
if (err) return console.error(err) if (err) return console.error(err)
@ -1039,6 +1235,9 @@ function routeOnClick(event) {
if (!event || !event.data || !event.data.route) if (!event || !event.data || !event.data.route)
return; return;
if (event.button === 0 && window.getSelection().toString() !== '')
return;
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();
@ -1100,7 +1299,7 @@ function loadModalFromHash() {
// FIXME rework hash scheme from '#following?user=twister' to something like '#/@twister/following' // FIXME rework hash scheme from '#following?user=twister' to something like '#/@twister/following'
if (hashdata[0] !== '#web+twister') 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 && hashdata[1] !== undefined && hashdata[2] !== undefined) {
if (hashdata[1] === 'profile') if (hashdata[1] === 'profile')
@ -1127,6 +1326,8 @@ function loadModalFromHash() {
splithashdata2 = hashdata[2].split(':'); splithashdata2 = hashdata[2].split(':');
openConversationModal(splithashdata2[0], splithashdata2[1]); openConversationModal(splithashdata2[0], splithashdata2[1]);
} }
else if (hashdata[1] === 'favs')
openFavsModalHandler(hashdata[2]);
} else if (hashstring === '#directmessages') } else if (hashstring === '#directmessages')
openCommonDMsModal(); openCommonDMsModal();
else if (hashstring === '#followers') else if (hashstring === '#followers')
@ -1139,8 +1340,14 @@ function loadModalFromHash() {
openGroupMessagesNewGroupModal(); openGroupMessagesNewGroupModal();
else if (hashstring === '#groupmessages+joingroup') else if (hashstring === '#groupmessages+joingroup')
openGroupMessagesJoinGroupModal(); openGroupMessagesJoinGroupModal();
else if (hashstring === '#/login')
openModalLogin();
else if (hashstring === '#whotofollow') else if (hashstring === '#whotofollow')
openWhoToFollowModal(); openWhoToFollowModal();
else if (hashstring === '#/uri-shortener')
openModalUriShortener();
else if (hashstring === '#newusers')
openNewUsersModal();
} }
function initHashWatching() { function initHashWatching() {
@ -1213,6 +1420,49 @@ function reTwistPopup(event, post, textArea) {
replyArea.find('.post-submit').addClass('with-reference'); 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 // Expande Área do Novo post
function replyInitPopup(e, post, textArea) { function replyInitPopup(e, post, textArea) {
var modal = openModal({ var modal = openModal({
@ -1426,7 +1676,7 @@ function postExpandFunction(e, postLi) {
var originalLi = $('<li/>', {class: 'module post original'}).appendTo(itemOl) var originalLi = $('<li/>', {class: 'module post original'}).appendTo(itemOl)
.append(originalPost); .append(originalPost);
setPostImagePreview(postExpandedContent, originalPost.find('a[rel="nofollow"]')); setPostImagePreview(postExpandedContent, originalPost.find('a[rel^="nofollow"]'));
postExpandedContent.slideDown('fast'); postExpandedContent.slideDown('fast');
@ -2265,6 +2515,17 @@ function retweetSubmit(event) {
closePrompt(prompt); 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() { function changeStyle() {
var style, profile, menu; var style, profile, menu;
var theme = $.Options.theme.val; var theme = $.Options.theme.val;
@ -2335,9 +2596,86 @@ function replaceDashboards() {
} }
function initInterfaceCommon() { 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.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) { $('.minimize-modal').on('click', function (event) {
minimizeModal($(event.target).closest('.modal-wrapper')); minimizeModal($(event.target).closest('.modal-wrapper'));
@ -2347,18 +2685,19 @@ function initInterfaceCommon() {
$('.prompt-close').on('click', closePrompt); $('.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) { $('.following-config-method-buttons .public-following').on('click', function(event) {
setFollowingMethod(event); setFollowingMethod(event);
closePrompt(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-text').on('click', 'a', muteEvent);
$('.post-reply').on('click', postReplyClick); $('.post-reply').on('click', postReplyClick);
$('.post-propagate').on('click', reTwistPopup); $('.post-propagate').on('click', reTwistPopup);
$('.post-favorite').on('click', favPopup);
$('.userMenu-config').clickoutside(closeThis.bind($('.config-menu'))); $('.userMenu-config').clickoutside(closeThis.bind($('.config-menu')));
$('.userMenu-config-dropdown').on('click', dropDownMenu); $('.userMenu-config-dropdown').on('click', dropDownMenu);
$('#post-template.module.post').on('click', function(event) { $('#post-template.module.post').on('click', function(event) {
@ -2378,6 +2717,8 @@ function initInterfaceCommon() {
; ;
$('.post-submit').on('click', postSubmit); $('.post-submit').on('click', postSubmit);
$('.modal-propagate').on('click', retweetSubmit); $('.modal-propagate').on('click', retweetSubmit);
$('.modal-fav-public').on('click', favSubmit);
$('.modal-fav-private').on('click', favSubmit);
$('.expanded-content .show-more').on('mouseup', $('.expanded-content .show-more').on('mouseup',
{feeder: '.module.post.original.open .module.post.original .post-data'}, handleClickOpenConversation) {feeder: '.module.post.original.open .module.post.original .post-data'}, handleClickOpenConversation)
.on('click', muteEvent) // to prevent post collapsing .on('click', muteEvent) // to prevent post collapsing
@ -2393,11 +2734,11 @@ function initInterfaceCommon() {
//$('.open-following-modal').on('click', openFollowingModal); //$('.open-following-modal').on('click', openFollowingModal);
$('.userMenu-connections a').on('click', openMentionsModal); $('.userMenu-connections a').on('click', openMentionsModal);
$('.mentions-from-user').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 () { getElem('.latest-activity', true).on('mouseup',
$(this).hide(); {feeder: '.latest-activity'}, handleClickOpenConversation);
displayQueryPending($('.hashtag-modal .postboard-posts'));
});
replaceDashboards(); replaceDashboards();
$(window).resize(replaceDashboards); $(window).resize(replaceDashboards);
@ -2438,7 +2779,14 @@ function initInterfaceCommon() {
$('.tox-ctc').on('click', promptCopyAttrData); $('.tox-ctc').on('click', promptCopyAttrData);
$('.bitmessage-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') $('.post-area-new textarea')
.on('focus', .on('focus',
@ -2494,18 +2842,6 @@ function inputEnterActivator(event) {
.attr('disabled', elemEvent.val().trim() === ''); .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) { function pasteToTextarea(ta, p) {
if (!ta || typeof ta.val !== 'function') return; if (!ta || typeof ta.val !== 'function') return;
@ -2563,10 +2899,21 @@ $(document).ready(function () {
if ($.localStorage.isSet('twistaURIs')) if ($.localStorage.isSet('twistaURIs'))
twister.URIs = $.localStorage.get('twistaURIs'); twister.URIs = $.localStorage.get('twistaURIs');
twister.html.blanka.appendTo('body').hide(); 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.followersList = extractTemplate('#template-followers-list');
twister.tmpl.followersPeer = extractTemplate('#template-followers-peer'); twister.tmpl.followersPeer = extractTemplate('#template-followers-peer');
twister.tmpl.followingList = extractTemplate('#template-following-list'); twister.tmpl.followingList = extractTemplate('#template-following-list');
twister.tmpl.followingPeer = extractTemplate('#template-following-peer'); twister.tmpl.followingPeer = extractTemplate('#template-following-peer');
twister.tmpl.whoTofollowPeer = extractTemplate('#template-whotofollow-peer');
twister.tmpl.commonDMsListItem = extractTemplate('#template-direct-messages-list-item') twister.tmpl.commonDMsListItem = extractTemplate('#template-direct-messages-list-item')
.on('mouseup', function (event) { .on('mouseup', function (event) {
event.data = {route: event.data = {route:
@ -2620,9 +2967,7 @@ $(document).ready(function () {
var path = window.location.pathname; var path = window.location.pathname;
var page = path.split("/").pop(); var page = path.split("/").pop();
if (page.indexOf("login.html") === 0) { if (page.indexOf('network.html') === 0) {
initInterfaceLogin();
} else if (page.indexOf("network.html") === 0) {
initInterfaceNetwork(); initInterfaceNetwork();
} else if (page.indexOf('options.html') === 0) { } else if (page.indexOf('options.html') === 0) {
initInterfaceCommon(); initInterfaceCommon();

38
js/interface_home.js

@ -49,8 +49,7 @@ var InterfaceFunctions = function() {
//$("span.screen-name").text('@' + user); //$("span.screen-name").text('@' + user);
var $miniProfile = $(".mini-profile"); var $miniProfile = $(".mini-profile");
if (!defaultScreenName) { if (!defaultScreenName) {
$(".userMenu-profile > a").text(polyglot.t("Login")); $('.userMenu-profile > a').attr('href', '#/login').text(polyglot.t('Login'));
$(".userMenu-profile > a").attr("href","login.html");
$(".post-area-new > textarea").attr("placeholder",polyglot.t("You have to log in to post messages.")); $(".post-area-new > textarea").attr("placeholder",polyglot.t("You have to log in to post messages."));
$(".post-area-new > textarea").attr("disabled","true"); $(".post-area-new > textarea").attr("disabled","true");
$miniProfile.find(".mini-profile-name").text("guest"); $miniProfile.find(".mini-profile-name").text("guest");
@ -100,6 +99,11 @@ var InterfaceFunctions = function() {
else else
killInterfaceModule('who-to-follow'); killInterfaceModule('who-to-follow');
if ($.Options.NewUsers.val === 'enable')
initNewUsers();
else
killInterfaceModule('new-users');
if ($.Options.TwistdayReminder.val === 'enable') if ($.Options.TwistdayReminder.val === 'enable')
initTwistdayReminder(); initTwistdayReminder();
else else
@ -113,7 +117,7 @@ var InterfaceFunctions = function() {
if ($.Options.WebTorrent.val === 'enable') if ($.Options.WebTorrent.val === 'enable')
initWebTorrent(); initWebTorrent();
} }
} };
function initTopTrends() { function initTopTrends() {
var $tt = initInterfaceModule('toptrends'); var $tt = initInterfaceModule('toptrends');
@ -200,6 +204,30 @@ function refreshWhoToFollow() {
} }
} }
function initNewUsers() {
var nus = initInterfaceModule('new-users');
newUsers = NewUserSearch();
if (nus.length) {
var nusRefresh = nus.find('.refresh-users');
nusRefresh.on('click', refreshNewUsers);
setTimeout(function() {nusRefresh.click();}, 100);
}
}
function refreshNewUsers() {
var module = $('.module.new-users');
var list = module.find('.follow-suggestions');
if (list.length) {
list.empty().hide();
module.find('.refresh-users').hide();
module.find('.loading-roller').show();
newUsers.getLastNUsers(3, 0, module, true);
}
}
function initTwistdayReminder() { function initTwistdayReminder() {
var $module = initInterfaceModule('twistday-reminder'); var $module = initInterfaceModule('twistday-reminder');
@ -268,7 +296,9 @@ function refreshTwistdayReminder() {
}); });
for (var i = 0; i < posts.length; i++) { 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.setTime(0);
d.setUTCSeconds(posts[i].userpost.time); d.setUTCSeconds(posts[i].userpost.time);
if (d.getMonth() === curMonth && d.getDate() === curDate) { 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 @@
// 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()
} }
this.goLogin = function() { this.goLogin = function() {
if( $.hasOwnProperty("mobile") ) { if ($.hasOwnProperty('mobile')) {
$.mobile.navigate( "#login" ); $.mobile.navigate('#login');
} else { } else {
window.location.href = "login.html"; window.location.hash = '#/login';
}
} }
};
this.goNetwork = function() { this.goNetwork = function() {
if( $.hasOwnProperty("mobile") ) { if( $.hasOwnProperty("mobile") ) {
@ -418,6 +418,38 @@ var MAL = function()
} }
} }
this.processCreateAccount = function (peerAlias, secretKey) {
defaultScreenName = peerAlias;
if (defaultScreenName) {
saveScreenName();
}
if ($.hasOwnProperty('mobile')) {
$('.secret-key').text(secretKey);
sendNewUserTransaction(peerAlias);
$.mobile.navigate('#new-user-modal');
} else {
var modal = confirmPopup({
classAdd: 'new-account-briefing',
txtTitle: polyglot.t('propagating_nickname', {username: peerAlias}),
txtMessage: polyglot.t('new_account_briefing', {secretKey: secretKey}),
txtConfirm: polyglot.t('Login'),
cbConfirm: $.MAL.goProfileEdit,
addBlackout: true,
removeCancel: true,
removeClose: true
});
modal.content.find('.confirm').attr('disabled', true);
sendNewUserTransaction(peerAlias,
function (accountCreatedModal) {
accountCreatedModal.content.find('.confirm').attr('disabled', false);
}, modal
);
}
};
this.changedUser = function() { this.changedUser = function() {
if( $.hasOwnProperty("mobile") ) { if( $.hasOwnProperty("mobile") ) {
timelineChangedUser(); timelineChangedUser();
@ -592,3 +624,166 @@ function filterLang(string) {
} }
} }
function checkUpdatesClient(alertIfNoUpdates) {
function handleGetFail(jqXHR) {
twister.var.updatesCheckClient.isOngoing = false;
console.warn(polyglot.t('cant_get_requested_resourse', {link: this.url, status: jqXHR.status + ', \'' + jqXHR.statusText + '\''}));
if (alertIfNoUpdates) {
if ($.hasOwnProperty('mobile'))
alert(polyglot.t('updates_not_available') + '.\n\n'
+ polyglot.t('cant_get_requested_resourse', {link: this.url, status: jqXHR.status + ', \'' + jqXHR.statusText + '\''})
);
else
alertPopup({
txtTitle: polyglot.t('updates_not_available'),
txtMessage: polyglot.t('cant_get_requested_resourse', {link: this.url, status: jqXHR.status + ', ~' + jqXHR.statusText + '~'})
});
}
}
if (twister.var.updatesCheckClient.isOngoing)
return;
twister.var.updatesCheckClient.isOngoing = true;
$.get('.git/HEAD', function (ret) {
if (ret.slice(0, 16) !== 'ref: refs/heads/') {
twister.var.updatesCheckClient.isOngoing = false;
if (alertIfNoUpdates)
alert(polyglot.t('updates_not_available') + '.\n\nCan\'t parse local HEAD: unknown syntax, FUBAR!');
return;
}
var branch = ret.slice(16).trim();
$.get('.git/refs/heads/' + branch, function (ret) {
var commit = ret.trim();
if (!commit) {
twister.var.updatesCheckClient.isOngoing = false;
if (alertIfNoUpdates)
alert(polyglot.t('updates_not_available') + '.\n\nCan\'t parse local HEAD: \'' + '.git/refs/heads/' + branch + '\' is empty, FUBAR!');
return;
}
var repo = 'twister-html'; // TODO source repo selection in options
var repoOwner = 'miguelfreitas';
// TODO notification if local branch was changed ('r u wanna reload the page?')
/*if (!twister.var.updatesCheckClient.formerBranch || !twister.var.updatesCheckClient.formerCommit) {
twister.var.updatesCheckClient.formerBranch = branch;
twister.var.updatesCheckClient.formerCommit = commit;
}*/
console.log('currently we are on the branch \'' + branch + '\' of ' + repo + ' at the commit ' + commit);
$.get('https://api.github.com/repos/' + repoOwner + '/' + repo + '/branches', function (ret) {
for (var i = 0; i < ret.length; i++) {
if (ret[i].name === branch) {
if (ret[i].commit.sha === commit) {
twister.var.updatesCheckClient.isOngoing = false;
console.log(polyglot.t('updates_upstream_isnt_changed'));
if (alertIfNoUpdates) {
if ($.hasOwnProperty('mobile'))
alert(polyglot.t('updates_not_available') + '.\n\n'
+ polyglot.t('updates_upstream_isnt_changed')
);
else
alertPopup({
txtTitle: polyglot.t('updates_not_available'),
txtMessage: polyglot.t('updates_upstream_isnt_changed')
});
}
} else {
console.log('source branch has a different HEAD: ' + ret[i].commit.sha);
var commitUpstream = ret[i].commit.sha;
$.get('https://api.github.com/repos/' + repoOwner + '/' + repo + '/git/commits/' + commit, function (ret) {
if (ret.sha !== commit) { // the response is wrong if so, should be 404 instead
twister.var.updatesCheckClient.isOngoing = false;
console.log('upstream tree doesn\'t have our most recent commit,\nlooks like we are in the process of development locally.');
if (alertIfNoUpdates)
alert(polyglot.t('updates_not_available') + '.\n\nUpstream tree doesn\'t have our most recent commit,\nlooks like we are in the process of development locally.');
return;
}
commit = ret;
$.get('https://api.github.com/repos/' + repoOwner + '/' + repo + '/git/commits/' + commitUpstream, function (ret) {
twister.var.updatesCheckClient.isOngoing = false;
if (ret.sha !== commitUpstream) { // the response is wrong if so, should be 404 instead
console.warn('upstream tree doesn\'t have the commit which is named most recent in the list of branches, FUBAR!');
if (alertIfNoUpdates)
alert(polyglot.t('updates_not_available') + '.\n\nUpstream tree doesn\'t have the commit which is named most recent in the list of branches, FUBAR!');
return;
}
commitUpstream = ret;
var linkGitHubDiff = 'https://github.com/' + repoOwner + '/' + repo + '/compare/' + commit.sha + '...' + repoOwner + ':' + branch;
console.log(polyglot.t('updates_checkout_diff_nfmt', {link: linkGitHubDiff}));
if ($.hasOwnProperty('mobile'))
alert(polyglot.t('updates_are_available') + '.\n\n'
+ polyglot.t('updates_repo_overview', {
branch: '\'' + branch + '\'',
repo: repo,
commit: commit.sha,
date: new Date(commit.author.date).toString().replace(/ GMT.*/g, ''),
commitUpstream: commitUpstream.sha,
dateUpstream: new Date(commitUpstream.author.date).toString().replace(/ GMT.*/g, '')
}) + '\n\n'
+ polyglot.t('updates_checkout_diff_nfmt', {link: linkGitHubDiff})
);
else
alertPopup({
txtTitle: polyglot.t('updates_are_available'),
txtMessage: polyglot.t('updates_repo_overview', {
branch: '~' + branch + '~',
repo: repo,
commit: '*' + commit.sha + '*',
date: new Date(commit.author.date).toString().replace(/ GMT.*/g, ''),
commitUpstream: '*' + commitUpstream.sha + '*',
dateUpstream: new Date(commitUpstream.author.date).toString().replace(/ GMT.*/g, '')
}) + '\n\n'
+ polyglot.t('updates_checkout_diff', {link: linkGitHubDiff})
});
}).fail(function (jqXHR) {
if (jqXHR.status === 404) {
twister.var.updatesCheckClient.isOngoing = false;
console.warn('upstream tree doesn\'t have the commit which is named most recent in the list of branches, FUBAR!');
if (alertIfNoUpdates)
alert(polyglot.t('updates_not_available') + '.\n\nUpstream tree doesn\'t have the commit which is named most recent in the list of branches, FUBAR!');
} else
handleGetFail(jqXHR);
});
}).fail(function (jqXHR) {
if (jqXHR.status === 404) {
twister.var.updatesCheckClient.isOngoing = false;
console.log('upstream tree doesn\'t have our most recent commit,\nlooks like we are in the process of development locally.');
if (alertIfNoUpdates)
alert(polyglot.t('updates_not_available') + '.\n\nUpstream tree doesn\'t have our most recent commit,\nlooks like we are in the process of development locally.');
} else
handleGetFail(jqXHR);
});
}
return;
}
}
twister.var.updatesCheckClient.isOngoing = false;
console.log('upstream tree doesn\'t have our branch,\nlooks like we are in the process of development locally.');
if (alertIfNoUpdates)
alert(polyglot.t('updates_not_available') + '.\n\nUpstream tree doesn\'t have our branch,\nlooks like we are in the process of development locally.');
}).fail(handleGetFail);
}).fail(handleGetFail);
}).fail(handleGetFail);
}

35
js/options.js

@ -41,6 +41,17 @@ function twisterOptions() {
name: 'WhoToFollow', name: 'WhoToFollow',
valDefault: 'enable' 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({ this.add({
name: 'TwistdayReminder', name: 'TwistdayReminder',
valDefault: 'enable', valDefault: 'enable',
@ -309,6 +320,16 @@ function twisterOptions() {
name: 'WebTorrentAutoDownload', name: 'WebTorrentAutoDownload',
valDefault: 'enable' valDefault: 'enable'
}); });
this.add({
name: 'skipWarnFollowersNotAll',
type: 'checkbox',
valDefault: false
});
this.add({
name: 'skipWarnFollowersNotAllOf',
type: 'checkbox',
valDefault: false
});
} }
twisterOptions.prototype.add = function (option) { twisterOptions.prototype.add = function (option) {
@ -316,6 +337,20 @@ twisterOptions.prototype.add = function (option) {
this[option.name] = new twisterOption(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 () { twisterOptions.prototype.initControls = function () {
var elem; var elem;

51
js/tmobile.js

@ -8,7 +8,6 @@ var handlersInstalled = false;
function initializeTwister( redirectNetwork, redirectLogin, cbFunc, cbArg ) { function initializeTwister( redirectNetwork, redirectLogin, cbFunc, cbArg ) {
if( !handlersInstalled ) { if( !handlersInstalled ) {
interfaceNetworkHandlers(); interfaceNetworkHandlers();
interfaceCommonLoginHandlers();
installUserSearchHandler(); installUserSearchHandler();
installProfileEditHandlers(); installProfileEditHandlers();
// install scrollbottom handler to load more posts as needed // install scrollbottom handler to load more posts as needed
@ -253,11 +252,12 @@ var router=new $.mobile.Router(
}); });
}, },
login: function(type,match,ui) { login: function(type,match,ui) {
if (!$('#login .content').children().length)
$('#login .content').append(twister.tmpl.loginMC.clone(true)).trigger('create');
$.mobile.showPageLoadingMsg(); $.mobile.showPageLoadingMsg();
initializeTwister( true, false, function() { initializeTwister( true, false, function() {
$.mobile.hidePageLoadingMsg(); $.mobile.hidePageLoadingMsg();
$("select.local-usernames.login-user").selectmenu("refresh", true); $("select.local-usernames").selectmenu("refresh", true);
installCreateUserClick();
}); });
}, },
network: function(type,match,ui) { network: function(type,match,ui) {
@ -421,19 +421,6 @@ function installRetransmitConfirmClick() {
}); });
} }
function installCreateUserClick() {
$( ".create-user").unbind('click').click( function(e) {
createUserClick( function(username, secretKey) {
defaultScreenName = username;
if(defaultScreenName) {
saveScreenName();
}
$(".secret-key").text(secretKey);
sendNewUserTransaction( username, function() {} );
$.mobile.navigate( "#new-user-modal" ); } );
});
}
function installUserSearchHandler() { function installUserSearchHandler() {
$('.userMenu-search-field') $('.userMenu-search-field')
.off('click input') .off('click input')
@ -541,27 +528,22 @@ function encode_utf8(s) {
return 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") ); $.MAL.setPostTemplate( $("#post-template-home") );
$.mobile.showPageLoadingMsg(); $.mobile.showPageLoadingMsg();
board.empty();
var reqId = tag + '@' + res; var req = queryStart(board, query, resource, undefined, undefined, {
boardAutoAppend: true,
clearQueryProcessed(reqId); skidoo: function (req) {
var curPage = $.mobile.activePage.attr('id');
tmobileQueryReq.postboard = postboard.text('').attr('data-request-id', reqId); return (curPage !== 'mentions' && curPage !== 'hashtag') || req !== tmobileQueryReq;
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);
} }
});
requestQuery(tmobileQueryReq); tmobileQueryReq = req;
} }
// every 2 seconds do something page specific. // every 2 seconds do something page specific.
@ -583,12 +565,6 @@ function tmobileTick() {
} }
}, {} ); }, {} );
} }
else if (curPage === 'mentions' || curPage === 'hashtag') {
autoUpdateQuery = true;
requestQuery(tmobileQueryReq);
}
if (curPage === 'dmchat') if (curPage === 'dmchat')
requestDmConversation($('#dmchat .direct-messages-thread'), dmChatUser); requestDmConversation($('#dmchat .direct-messages-thread'), dmChatUser);
} }
@ -600,4 +576,3 @@ $(document).bind('mobileinit', function () {
$.mobile.defaultDialogTransition = 'none'; $.mobile.defaultDialogTransition = 'none';
$.mobile.defaultPageTransition = 'none'; $.mobile.defaultPageTransition = 'none';
}); });

282
js/twister_actions.js

@ -12,9 +12,6 @@
var postsPerRefresh = 10; var postsPerRefresh = 10;
var maxExpandPost = 8; var maxExpandPost = 8;
var maxExpandPostTop = 4; var maxExpandPostTop = 4;
var _queryProcessedMap = {};
var _queryPendingPosts = {};
var autoUpdateQuery = false;
// ---------------- // ----------------
@ -271,10 +268,11 @@ function newRtMsg(postData, msg) {
if (userpost.rt) { if (userpost.rt) {
if (parseInt(twisterVersion) <= 93000) { if (parseInt(twisterVersion) <= 93000) {
alert(polyglot.t('error', alertPopup({
{error: 'can\'t handle retwisting of commented retwisted twists with daemon version ' //txtTitle: polyglot.t(''), add some title (not 'error', please) or just KISS
+ twisterDisplayVersion + ' and below of that. Please upgrade it.'} txtMessage: 'Can\'t handle retwisting of commented retwisted twists —\n'
)); + polyglot.t('daemon_is_obsolete', {versionReq: '0.9.3+'})
});
return; return;
} else { } else {
@ -319,17 +317,53 @@ function newRtMsg(postData, msg) {
} }
} }
function newFavMsg(postData, priv, msg) {
var userpost = $.evalJSON(postData.attr('data-content_to_rt'));
var sig_userpost = postData.attr('data-content_to_sigrt');
if (typeof sig_userpost === 'undefined') {
alert(polyglot.t('error',
{error: 'can\'t sig_userpost is not deifned'}
));
return;
}
var rtObj = {sig_userpost: sig_userpost, userpost: userpost};
if (typeof lastPostId !== 'undefined') {
if (typeof _sendedPostIDs !== 'undefined')
_sendedPostIDs.push(lastPostId + 1);
var params = [defaultScreenName, lastPostId + 1, rtObj, priv];
if (typeof msg !== 'undefined')
params.push(msg);
twisterRpc('newfavmsg', params,
function(arg, ret) {incLastPostId();}, null,
function(arg, ret) {var msg = ('message' in ret) ? ret.message : ret;
alert(polyglot.t('ajax_error', {error: msg}));
}, null
);
} else {
alert(polyglot.t('Internal error: lastPostId unknown (following yourself may fix!)'));
}
}
function newShortURI(uri, cbFunc, cbReq) { function newShortURI(uri, cbFunc, cbReq) {
if (!uri || !defaultScreenName) return; if (!uri || !defaultScreenName) return;
if (parseInt(twisterVersion) < 93500) { 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; return;
} }
for (var i in twister.URIs) for (var short in twister.URIs)
if (twister.URIs[i] === uri) { if (twister.URIs[short] instanceof Array ?
twister.URIs[short][0] === uri : twister.URIs[short] === uri) {
if (typeof cbFunc === 'function') if (typeof cbFunc === 'function')
cbFunc(uri, i, cbReq); cbFunc(uri, short, cbReq);
return; return;
} }
@ -402,102 +436,204 @@ function updateProfilePosts(postsView, username, useGetposts) {
}); });
} }
function clearQueryProcessed(id) { function queryStart(board, query, resource, timeoutArgs, intervalTimeout, extra) {
if (!id) return; 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] = {}; twister.res[req].interval = setInterval(queryTick, intervalTimeout ? intervalTimeout : 5000, req);
_queryPendingPosts[id] = [];
return req;
} }
function requestQuery(req) { function queryTick(req) {
req.postboard.closest('div').find('.postboard-loading').show(); if (typeof twister.res[req].skidoo === 'function' ? twister.res[req].skidoo(req)
dhtget(req.query, req.resource, 'm', : !isModalWithElemExists(twister.res[req].board)) {
function(req, posts) { clearInterval(twister.res[req].interval);
req.posts = posts; twister.res[req].interval = 0;
processQuery(req); queryPendingClear(req);
}, return;
req, }
req.timeoutArgs
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) { function queryProcess(req, twists) {
if (!isModalWithElemExists(req.postboard) || !req.posts || !req.posts.length) if (!req || !twister.res[req] || !twists || !twists.length)
return; return;
if (!req.id) var lengthNew = 0;
req.id = req.query + '@' + req.resource; var lengthPending = twister.res[req].twists.pending.length;
if (typeof _queryProcessedMap[req.id] !== 'object')
_queryProcessedMap[req.id] = {};
if (typeof _queryPendingPosts[req.id] !== 'object')
_queryPendingPosts[req.id] = [];
for (var i = req.posts.length - 1; i >= 0; i--) { if (twister.res[req].resource === 'mention' && twister.res[req].query === defaultScreenName)
var userpost = req.posts[i].userpost; lengthNew = queryPendingPushMentions(req, twists);
var key = userpost.n + ';' + userpost.time; else
lengthNew = queryPendingPush(req, twists);
if (!_queryProcessedMap[req.id][key]) { if (typeof twister.res[req].skidoo === 'function' && twister.res[req].skidoo(req))
_queryProcessedMap[req.id][key] = true; 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 === '') if ((typeof userpost.msg !== 'string' || userpost.msg === '')
&& (typeof userpost.rt !== 'object' && (typeof userpost.rt !== 'object'
|| typeof userpost.rt.msg !== 'string' || userpost.rt.msg === '')) || typeof userpost.rt.msg !== 'string' || userpost.rt.msg === ''))
continue; continue;
if ($.Options.filterLang.val !== 'disable' && $.Options.filterLangForSearching.val) { if (needForFilter) {
if (typeof userpost.msg === 'string' && userpost.msg !== '') if (typeof userpost.msg === 'string' && userpost.msg !== '')
langFilterData = filterLang(userpost.msg); langFilterData = filterLang(userpost.msg);
else else
langFilterData = filterLang(userpost.rt.msg); langFilterData = filterLang(userpost.rt.msg);
if ($.Options.filterLangSimulate.val) { if ($.Options.filterLangSimulate.val) {
req.posts[i].langFilter = langFilterData; twists[i].langFilter = langFilterData;
} else { } else {
if (!langFilterData.pass) if (!langFilterData.pass)
continue; 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) { return lengthNew;
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();
}
}
} }
function displayQueryPending(postboard) { function queryPendingDraw(req) {
var reqId = postboard.attr('data-request-id'); 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); queryPendingClear(req);
_queryPendingPosts[reqId] = [];
$.MAL.postboardLoaded(); $.MAL.postboardLoaded();
} }

78
js/twister_directmsg.js

@ -179,13 +179,14 @@ function openCommonDMsModal() {
modal.self.find('.mark-all-as-read') modal.self.find('.mark-all-as-read')
.css('display', 'inline') .css('display', 'inline')
.attr('title', polyglot.t('Mark all as read')) .attr('title', polyglot.t('Mark all as read'))
.on('click', function() { .on('click', function (event) {
for (var user in _newDMsPerUser) { for (var user in _newDMsPerUser) {
if (user[0] !== '*') if (user[0] !== '*')
_newDMsPerUser[user] = 0; _newDMsPerUser[user] = 0;
} }
saveDMsToStorage(); saveDMsToStorage();
$.MAL.updateNewDMsUI(getNewDMsCount()); $.MAL.updateNewDMsUI(getNewDMsCount());
$(event.target).closest('.directMessages').find('.direct-messages-list .messages-qtd').hide();
}) })
; ;
} }
@ -236,13 +237,14 @@ function openGroupMessagesModal(groupAlias) {
modal.self.find('.mark-all-as-read') modal.self.find('.mark-all-as-read')
.css('display', 'inline') .css('display', 'inline')
.attr('title', polyglot.t('Mark all as read')) .attr('title', polyglot.t('Mark all as read'))
.on('click', function() { .on('click', function (event) {
for (var user in _newDMsPerUser) { for (var user in _newDMsPerUser) {
if (user[0] === '*') if (user[0] === '*')
_newDMsPerUser[user] = 0; _newDMsPerUser[user] = 0;
} }
saveDMsToStorage(); saveDMsToStorage();
$.MAL.updateNewGroupDMsUI(getNewGroupDMsCount()); $.MAL.updateNewGroupDMsUI(getNewGroupDMsCount());
$(event.target).closest('.groupMessages').find('.direct-messages-list .messages-qtd').hide();
}) })
; ;
} else { } else {
@ -359,22 +361,13 @@ function openGroupMessagesJoinGroupModal() {
closeModal(event); 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) { modal.content.find('.import-secret-key').on('click', function (event) {
var elemModule = $(event.target).closest('.module'); groupMsgImportKey($(event.target).closest('.module').find('.secret-key-import').val());
var groupAlias = elemModule.find('.username-import').val().toLowerCase();
var secretKey = elemModule.find('.secret-key-import').val();
twisterRpc('importprivkey', [secretKey, groupAlias], closeModal(event);
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}));
}
);
}); });
} }
@ -392,8 +385,54 @@ function groupMsgCreateGroup(description, peersToInvite) {
); );
} }
function groupMsgInviteToGroup(groupAlias, peersToInvite) { function groupMsgImportKey(key) {
_groupMsgInviteToGroupQueue.push({groupAlias: groupAlias, peersToInvite: peersToInvite}); 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) if (_groupMsgInviteToGroupQueue.length === 1)
doGroupMsgInviteToGroup(); doGroupMsgInviteToGroup();
@ -408,7 +447,10 @@ function doGroupMsgInviteToGroup() {
_groupMsgInviteToGroupQueue.shift(); _groupMsgInviteToGroupQueue.shift();
if (_groupMsgInviteToGroupQueue.length) if (_groupMsgInviteToGroupQueue.length)
setTimeout(doGroupMsgInviteToGroup, 200); setTimeout(doGroupMsgInviteToGroup, 200);
}, null,
if (typeof req.cbFunc === 'function')
req.cbFunc(req.cbReq);
}, {cbFunc: _groupMsgInviteToGroupQueue[0].cbFunc, cbReq: _groupMsgInviteToGroupQueue[0].cbReq},
function(req, ret) { function(req, ret) {
alert(polyglot.t('error', alert(polyglot.t('error',
{error: 'can\'t invite ' + req[1] + ' to ' + req[0] + ' group — ' + ret.message})); {error: 'can\'t invite ' + req[1] + ' to ' + req[0] + ' group — ' + ret.message}));

177
js/twister_following.js

@ -17,6 +17,7 @@ var _lastSearchUsersResultsRemovedFromDHTgetQueue = true;
var _lastLoadFromDhtTime = 0; var _lastLoadFromDhtTime = 0;
var twisterFollowingO = undefined; var twisterFollowingO = undefined;
var newUsers = undefined;
var TwisterFollowing = function (user) { var TwisterFollowing = function (user) {
if (!(this instanceof TwisterFollowing)) if (!(this instanceof TwisterFollowing))
@ -145,7 +146,8 @@ TwisterFollowing.prototype = {
.find('li[data-peer-alias="' + args.fu + '"]').remove(); .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; var ctime = new Date().getTime() / 1000;
if (typeof(args.tf.followingsFollowings[args.fu]) === 'undefined' || if (typeof(args.tf.followingsFollowings[args.fu]) === 'undefined' ||
@ -426,6 +428,127 @@ function followingEmptyOrMyself() {
return (!followingUsers.length || (followingUsers.length === 1 && followingUsers[0] === defaultScreenName)) 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 // 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 // choose a suggestion from their list. this function could be way better, but
// that's about the simplest we may get to start with. // that's about the simplest we may get to start with.
@ -445,10 +568,11 @@ function getRandomFollowSuggestion() {
var suggested = false; var suggested = false;
var j = Math.floor(Math.random() * twisterFollowingO.followingsFollowings[followingUsers[i]].following.length); 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++ ) { for( ; j < twisterFollowingO.followingsFollowings[followingUsers[i]].following.length; j++ ) {
if( followingUsers.indexOf(twisterFollowingO.followingsFollowings[followingUsers[i]].following[j]) < 0 && if( followingUsers.indexOf(twisterFollowingO.followingsFollowings[followingUsers[i]].following[j]) < 0 &&
_followSuggestions.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]); _followSuggestions.push(twisterFollowingO.followingsFollowings[followingUsers[i]].following[j]);
suggested = true; suggested = true;
break; break;
@ -500,31 +624,50 @@ function getWhoFollows(peerAlias, elem) {
; ;
} }
function processWhoToFollowSuggestion(suggestion, followedBy) { function processWhoToFollowSuggestion(module, peerAlias, followedBy, prepend) {
if (suggestion) { if (!peerAlias) {
var module = $('.module.who-to-follow'); console.warn('nothing to proceed: no twisters to follow was suggested');
return;
}
var list = module.find('.follow-suggestions'); var list = module.find('.follow-suggestions');
var item = $('#follow-suggestion-template').clone(true) var item = twister.tmpl.whoTofollowPeer.clone(true);
.removeAttr('id');
item.find('.twister-user-info').attr('data-screen-name', suggestion); item.find('.twister-user-info').attr('data-screen-name', peerAlias);
item.find('.twister-user-name').attr('href', $.MAL.userUrl(suggestion)); item.find('.twister-user-name').attr('href', $.MAL.userUrl(peerAlias));
item.find('.twister-by-user-name').attr('href', $.MAL.userUrl(followedBy)); item.find('.twister-user-tag').text('@' + peerAlias);
item.find('.twister-user-tag').text('@' + suggestion);
getAvatar(suggestion, item.find('.twister-user-photo')); getAvatar(peerAlias, item.find('.twister-user-photo'));
getFullname(followedBy, item.find('.followed-by').text(followedBy)); getStatusTime(peerAlias, item.find('.latest-activity .time'));
item.find('.twister-user-remove').on('click', function() { if (module.hasClass('who-to-follow') || module.hasClass('who-to-follow-modal')) {
item.remove(); 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(); 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(); list.append(item).show();
while (module.hasClass('new-users') && list.children().length > 3)
list.children().last().remove();
module.find('.refresh-users').show(); module.find('.refresh-users').show();
module.find('.loading-roller').hide(); module.find('.loading-roller').hide();
} else
console.warn('nothing to proceed: no twisters to follow was suggested');
} }
function closeSearchDialog(event) { function closeSearchDialog(event) {

82
js/twister_formatpost.js

@ -43,6 +43,8 @@ function postToElem(post, kind, promoted) {
"dm" : encrypted message (dm) -opt "dm" : encrypted message (dm) -opt
"rt" : original userpost - opt "rt" : original userpost - opt
"sig_rt" : sig of rt - opt "sig_rt" : sig of rt - opt
"fav" : original userpost - opt
"sif_fav" : sig of fav - opt
"reply" : - opt "reply" : - opt
{ {
"n" : reference username "n" : reference username
@ -57,6 +59,10 @@ function postToElem(post, kind, promoted) {
// Obtain data from userpost // Obtain data from userpost
var userpost = post.userpost; var userpost = post.userpost;
//TODO: favorites may have comment also...
if (userpost.fav)
userpost = userpost.fav;
if (post.sig_wort) if (post.sig_wort)
userpost.sig_wort = post.sig_wort; userpost.sig_wort = post.sig_wort;
@ -238,7 +244,7 @@ function setPostReference(elem, rt, sig_rt) {
.attr('data-screen-name', rt.n) .attr('data-screen-name', rt.n)
.attr('data-id', rt.k) .attr('data-id', rt.k)
.attr('data-userpost', $.toJSON({userpost: rt, sig_userpost: sig_rt})) .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); setPostCommon(elem, rt.n, rt.time);
} }
@ -490,30 +496,6 @@ function htmlFormatMsg(msg, opt) {
} }
// changing the string // 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') { if (markoutOpt === 'apply') {
t = '</' + tag + '>'; t = '</' + tag + '>';
tag = '<' + tag + '>'; tag = '<' + tag + '>';
@ -541,7 +523,6 @@ function htmlFormatMsg(msg, opt) {
p[j].i += l; p[j].i += l;
} }
} }
}
return msg; return msg;
} }
@ -604,7 +585,17 @@ function htmlFormatMsg(msg, opt) {
msg = {str: escapeHtmlEntities(msg), htmlEntities: []}; 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 // handling links
for (i = 0; i < msg.str.length - 7; i++) { for (i = 0; i < msg.str.length - 7; i++) {
@ -620,21 +611,25 @@ function htmlFormatMsg(msg, opt) {
break; break;
} }
if (i < k) { 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 // 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 if (isUriSuspicious(msg.str.slice(i, k + 1))) {
|| msg.str.slice(x - 4, x).toLowerCase() === 'data'))) {
msg = msgAddHtmlEntity(msg, j - 1, getSubStrEnd(msg.str, k + 1, ')', true, '') + 2, msg = msgAddHtmlEntity(msg, j - 1, getSubStrEnd(msg.str, k + 1, ')', true, '') + 2,
'…<br><b><i>' + polyglot.t('busted_oh') + '</i> ' '…<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) + msg.str.slice(i, k + 1)
.replace(/&(?!lt;|gt;)/g, '&amp;') .replace(/&(?!lt;|gt;)/g, '&amp;')
.replace(/"/g, '&quot;') .replace(/"/g, '&quot;')
.replace(/'/g, '&apos;') .replace(/'/g, '&apos;')
+ '</samp><br>' + ')</samp><br>…<br>'
); );
} else { } 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; k = x;
linkName = applyHtml( // we're handling markup inside [] of []() linkName = applyHtml( // we're handling markup inside [] of []()
markout(markout(markout(markout( markout(markout(markout(markout(
@ -787,6 +782,27 @@ function htmlFormatMsg(msg, opt) {
return {html: msg, mentions: mentions}; 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) { function proxyURL(url) {
var proxyOpt = $.Options.useProxy.val; var proxyOpt = $.Options.useProxy.val;
if (proxyOpt !== 'disable' && !$.Options.useProxyForImgOnly.val if (proxyOpt !== 'disable' && !$.Options.useProxyForImgOnly.val

25
js/twister_io.js

@ -115,7 +115,8 @@ function dhtget(peerAlias, resource, multi, cbFunc, cbReq, timeoutArgs) {
function decodeShortURI(locator, cbFunc, cbReq, timeoutArgs) { function decodeShortURI(locator, cbFunc, cbReq, timeoutArgs) {
if (!locator) return; if (!locator) return;
if (parseInt(twisterVersion) < 93500) { 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; return;
} }
@ -279,7 +280,8 @@ function getFullname(peerAlias, elem) {
twisterFollowingO.knownFollowers.push(req.peerAlias); twisterFollowingO.knownFollowers.push(req.peerAlias);
twisterFollowingO.save(); twisterFollowingO.save();
addPeerToFollowersList(getElem('.followers-modal .followers-list'), req.peerAlias, true); 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.addClass('isFollowing');
req.elem.attr('title', polyglot.t('follows you')); req.elem.attr('title', polyglot.t('follows you'));
@ -291,7 +293,8 @@ function getFullname(peerAlias, elem) {
if (twisterFollowingO.knownFollowers.indexOf(req.peerAlias) === -1) { if (twisterFollowingO.knownFollowers.indexOf(req.peerAlias) === -1) {
twisterFollowingO.knownFollowers.push(req.peerAlias); twisterFollowingO.knownFollowers.push(req.peerAlias);
addPeerToFollowersList(getElem('.followers-modal .followers-list'), req.peerAlias, true); 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.addClass('isFollowing');
req.elem.attr('title', polyglot.t('follows you')); req.elem.attr('title', polyglot.t('follows you'));
@ -520,6 +523,22 @@ function getPostsCount(peerAlias, elem) {
); );
} }
function getStatusTime(peerAlias, elem) {
dhtget(peerAlias, 'status', 's',
function (req, ret) {
if (!ret || !ret.userpost)
return;
req.elem.text(timeGmtToText(ret.userpost.time))
.closest('.latest-activity')
.attr('data-screen-name', req.peerAlias)
.attr('data-id', ret.userpost.k)
.attr('data-time', ret.userpost.time)
;
}, {peerAlias: peerAlias, elem: elem}
);
}
function getPostMaxAvailability(peerAlias, k, cbFunc, cbReq) { function getPostMaxAvailability(peerAlias, k, cbFunc, cbReq) {
twisterRpc('getpiecemaxseen', [peerAlias, k], twisterRpc('getpiecemaxseen', [peerAlias, k],
function(req, ret) { function(req, ret) {

45
js/twister_network.js

@ -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) { function requestBlock(hash, cbFunc, cbArg) {
twisterRpc("getblock", [hash], twisterRpc("getblock", [hash],
function(args, block) { function(args, block) {
twisterdLastBlockTime = block.time;
$(".last-block-time").text( timeGmtToText(twisterdLastBlockTime) );
if( args.cbFunc ) if( args.cbFunc )
args.cbFunc(args.cbArg); args.cbFunc(block, args.cbArg);
}, {cbFunc:cbFunc, cbArg:cbArg}, }, {cbFunc:cbFunc, cbArg:cbArg},
function(args, ret) { function(args, ret) {
console.log("requestBlock error"); console.log("requestBlock error");
}, {}); }, {});
} }
function networkUpdate(cbFunc, cbArg) { function networkUpdate(cbFunc, cbArg) {
requestNetInfo(function () { requestNetInfo(function () {
requestBestBlock(function(args) { requestBestBlock(function(block, args) {
twisterdLastBlockTime = block.time;
$(".last-block-time").text(timeGmtToText(twisterdLastBlockTime));
var curTime = new Date().getTime() / 1000; var curTime = new Date().getTime() / 1000;
if( twisterdConnections ) { if (twisterdConnections) {
if( twisterdLastBlockTime > curTime + 3600 ) { if (twisterdLastBlockTime > curTime + 3600) {
$.MAL.setNetworkStatusMsg(polyglot.t("Last block is ahead of your computer time, check your clock."), false); $.MAL.setNetworkStatusMsg(polyglot.t("Last block is ahead of your computer time, check your clock."), false);
twisterdConnectedAndUptodate = false; twisterdConnectedAndUptodate = false;
} else if( twisterdLastBlockTime > curTime - (2 * 3600) ) { } else if (twisterdLastBlockTime > curTime - (2 * 3600)) {
if( twisterDhtNodes ) { if (twisterDhtNodes) {
$.MAL.setNetworkStatusMsg(polyglot.t("Block chain is up-to-date, twister is ready to use!"), true); $.MAL.setNetworkStatusMsg(polyglot.t("Block chain is up-to-date, twister is ready to use!"), true);
twisterdConnectedAndUptodate = true; twisterdConnectedAndUptodate = true;
} else { } else {
@ -178,14 +188,14 @@ function networkUpdate(cbFunc, cbArg) {
twisterdConnectedAndUptodate = true; twisterdConnectedAndUptodate = true;
} }
} else { } else {
var daysOld = (curTime - twisterdLastBlockTime) / (3600*24); var daysOld = (curTime - twisterdLastBlockTime) / (3600 * 24);
$.MAL.setNetworkStatusMsg(polyglot.t("downloading_block_chain", { days: daysOld.toFixed(2) }), false); $.MAL.setNetworkStatusMsg(polyglot.t("downloading_block_chain", {days: daysOld.toFixed(2)}), false);
// don't alarm user if blockchain is just a little bit behind // don't alarm user if blockchain is just a little bit behind
twisterdConnectedAndUptodate = (daysOld < 2); twisterdConnectedAndUptodate = (daysOld < 2);
} }
} }
if( args.cbFunc ) if (args.cbFunc)
args.cbFunc(args.cbArg) args.cbFunc(args.cbArg);
}, {cbFunc:cbFunc, cbArg:cbArg} ); }, {cbFunc:cbFunc, cbArg:cbArg} );
}); });
} }
@ -318,11 +328,8 @@ function initInterfaceNetwork() {
initMentionsCount(); initMentionsCount();
initDMsCount(); initDMsCount();
}); });
} } else {
else $('.userMenu-profile > a').attr('href', '#/login').text(polyglot.t('Login'));
{
$(".userMenu-profile > a").text(polyglot.t("Login"));
$(".userMenu-profile > a").attr("href","login.html");
} }
}); });
networkUpdate(); networkUpdate();

318
js/twister_newmsgs.js

@ -6,190 +6,170 @@
// --- mentions --- // --- 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 = [] var groupChatAliases = []
// process a mention received to check if it is really new function saveMentionsToStorage() {
function processMention(user, mentionTime, data) { var twists = [], length = 0;
var key = user + ';' + mentionTime; for (var j in twister.mentions.twists.cached) {
var curTime = new Date().getTime() / 1000; for (var i = 0; i < length; i++)
if (mentionTime > curTime + 7200) // 3600 * 2 if (twister.mentions.twists.cached[j].userpost.time > twists[i].userpost.time) {
console.warn('ignoring mention from the future'); twists.splice(i, 0, twister.mentions.twists.cached[j]);
else { break;
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 purgeOldMentions() { if (length === twists.length)
for (var key in _knownMentions) { twists.push(twister.mentions.twists.cached[j]);
if (_knownMentions[key]) {
if (!_knownMentions[key].mentionTime || !_knownMentions[key].data || length++;
_knownMentions[key].mentionTime + PURGE_OLD_MENTIONS_TIMEOUT < _lastMentionTime) {
delete _knownMentions[key];
}
}
} }
}
function saveMentionsToStorage() { $.initNamespaceStorage(defaultScreenName).localStorage
var ns = $.initNamespaceStorage(defaultScreenName); .set('mentions', {
ns.localStorage.set('knownMentions', _knownMentions); twists: twists.slice(0, 100), // TODO add an option to specify number of mentions to cache
ns.localStorage.set('lastMentionTime', _lastMentionTime); lastTime: twister.mentions.lastTime,
ns.localStorage.set('newMentions', _newMentions); lastTorrentId: twister.mentions.lastTorrentId
ns.localStorage.set('lastLocalMentionId', _lastLocalMentionId); })
;
} }
function loadMentionsFromStorage() { function loadMentionsFromStorage() {
var ns = $.initNamespaceStorage(defaultScreenName); var storage = $.initNamespaceStorage(defaultScreenName).localStorage;
if (ns.localStorage.isSet('knownMentions'))
_knownMentions = ns.localStorage.get('knownMentions'); if (storage.isSet('mentions')) {
if (ns.localStorage.isSet('lastMentionTime')) var mentions = storage.get('mentions');
_lastMentionTime = ns.localStorage.get('lastMentionTime'); if (typeof mentions === 'object') {
if (ns.localStorage.isSet('newMentions')) for (var i = 0; i < mentions.twists.length; i++) {
_newMentions = ns.localStorage.get('newMentions'); var j = mentions.twists[i].userpost.n + '/' + mentions.twists[i].userpost.time;
if (ns.localStorage.isSet('lastLocalMentionId')) if (typeof twister.mentions.twists.cached[j] === 'undefined') {
_lastLocalMentionId = ns.localStorage.get('lastLocalMentionId'); twister.mentions.twists.cached[j] = mentions.twists[i];
} if (twister.mentions.twists.cached[j].isNew)
twister.mentions.lengthNew++;
function requestMentionsCount() {
// first: getmentions from torrents we follow twister.mentions.lengthFromTorrent++;
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]);
} }
$.MAL.updateNewMentionsUI(_newMentions);
} }
}, null, twister.mentions.lastTime = mentions.lastTime;
function(req, ret) {console.warn('getmentions API requires twister-core > 0.9.27');}, null twister.mentions.lastTorrentId = mentions.lastTorrentId;
);
// second: get mentions from dht (not-following)
dhtget(defaultScreenName, 'mention', 'm',
function(args, data) {
if (data) {
for (var i = 0; i < data.length; i++) {
var userpost = data[i].userpost;
processMention(userpost.n, userpost.time, data[i]);
} }
$.MAL.updateNewMentionsUI(_newMentions);
} }
}, {},
[10000, 2000, 3] // use extended timeout parameters (requires twister_core >= 0.9.14)
);
if (_newMentionsUpdated) {
_newMentionsUpdated = false;
if (_newMentions) { // WARN all following storage keys are deprecated (see commit dc8cfc20ef10ff3008b4abfdb30d31e7fcbec0cd)
$.MAL.soundNotifyMentions(); 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') storage.remove('knownMentions');
$.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);
} }
}); 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 function queryPendingPushMentions(req, res) {
// we would place it with other notifications into separate notification center var lengthNew = 0;
if (_newDMsUpdated) { var lengthPending = twister.res[req].twists.pending.length;
_newDMsUpdated = false; var timeCurrent = new Date().getTime() / 1000 + 7200; // 60 * 60 * 2
var timeLastMention = twister.res[req].lastTime;
var newDMs = getNewDMsCount();
if (newDMs) { for (var i = 0; i < res.length; i++) {
$.MAL.soundNotifyDM(); if (res[i].userpost.time > timeCurrent) {
console.warn('ignoring mention from the future:');
if (!$.hasOwnProperty('mobile') && $.Options.showDesktopNotifDMs.val === 'enable') { console.log(res[i]);
$.MAL.showDesktopNotification({ continue;
body: polyglot.t('You got') + ' ' + polyglot.t('new_direct_messages', newDMs) + '.',
tag: 'twister_notification_new_DMs',
timeout: $.Options.showDesktopNotifDMsTimer.val,
funcClick: function () {$.MAL.showDMchat();}
});
} }
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') { var j = res[i].userpost.n + '/' + res[i].userpost.time;
$.MAL.showDesktopNotification({ if (typeof twister.res[req].twists.cached[j] === 'undefined') {
body: polyglot.t('You got') + ' ' + polyglot.t('new_group_messages', newDMs) + '.', twister.res[req].twists.cached[j] = res[i];
tag: 'twister_notification_new_DMs', twister.res[req].twists.pending.push(j);
timeout: $.Options.showDesktopNotifDMsTimer.val,
funcClick: function () {$.MAL.showDMchat({group: true});} // 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() { function resetMentionsCount() {
_newMentions = 0; twister.mentions.lengthNew = 0;
for (var key in _knownMentions) {
if (_knownMentions[key] && _knownMentions[key].data) for (var j in twister.mentions.twists.cached)
delete _knownMentions[key].data.isNew if (twister.mentions.twists.cached[j].isNew)
} delete twister.mentions.twists.cached[j].isNew;
saveMentionsToStorage(); saveMentionsToStorage();
$.MAL.updateNewMentionsUI(_newMentions); $.MAL.updateNewMentionsUI(twister.mentions.lengthNew);
} }
function initMentionsCount() { 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(); loadMentionsFromStorage();
$.MAL.updateNewMentionsUI(_newMentions); },
requestMentionsCount(); skidoo: function () {return false;}
setInterval(requestMentionsCount, 10000); });
$.MAL.updateNewMentionsUI(twister.mentions.lengthNew);
} }
function getMentionsData() { function handleMentionsModalScroll(event) {
mentions = [] if (!event || twister.mentions.scrollQueryActive)
for (var key in _knownMentions) { return;
if (_knownMentions[key] && _knownMentions[key].data) {
mentions.push(_knownMentions[key].data); 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 --- // --- direct messages ---
@ -220,25 +200,53 @@ function requestDMsCount() {
twisterRpc('getdirectmsgs', [defaultScreenName, 1, followList], twisterRpc('getdirectmsgs', [defaultScreenName, 1, followList],
function(req, dmUsers) { function(req, dmUsers) {
var newDMsUpdated;
for (var u in dmUsers) { for (var u in dmUsers) {
if (dmUsers[u]) { if (dmUsers[u]) {
var dmData = dmUsers[u][0]; var dmData = dmUsers[u][0];
if (u in _lastDMIdPerUser && u in _newDMsPerUser) { if (u in _lastDMIdPerUser && u in _newDMsPerUser) {
if (dmData.id !== _lastDMIdPerUser[u]) { if (dmData.id !== _lastDMIdPerUser[u]) {
_newDMsPerUser[u] += dmData.id - _lastDMIdPerUser[u]; _newDMsPerUser[u] += dmData.id - _lastDMIdPerUser[u];
_newDMsUpdated = true; newDMsUpdated = true;
} }
} else { } else {
_newDMsPerUser[u] = dmData.id + 1; _newDMsPerUser[u] = dmData.id + 1;
_newDMsUpdated = true; newDMsUpdated = true;
} }
_lastDMIdPerUser[u] = dmData.id; _lastDMIdPerUser[u] = dmData.id;
} }
} }
if (_newDMsUpdated) { if (newDMsUpdated) {
saveDMsToStorage(); saveDMsToStorage();
$.MAL.updateNewDMsUI(getNewDMsCount()); var newDMs = getNewDMsCount();
$.MAL.updateNewGroupDMsUI(getNewGroupDMsCount()); 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, }, null,
function(req, ret) {console.warn('ajax error:' + ret);}, null function(req, ret) {console.warn('ajax error:' + ret);}, null
@ -297,7 +305,5 @@ function initDMsCount() {
} }
function newmsgsChangedUser() { function newmsgsChangedUser() {
_knownMentions = {} clearInterval(twister.mentions.interval);
_lastMentionTime = 0;
_newMentions = 0;
} }

225
js/twister_user.js

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

142
login.html

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

21
options.html

@ -38,7 +38,6 @@
<a class="dropdown-menu-item" href="options.html">Options</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="network.html">Network config</a>
<a class="dropdown-menu-item" href="profile-edit.html">Setup account</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> </div>
</a> </a>
</li> </li>
@ -353,6 +352,26 @@
</form> </form>
</div> </div>
</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"> <div class="module">
<p class="label label-h"> Twistday Reminder </p> <p class="label label-h"> Twistday Reminder </p>
<div class="container"> <div class="container">

2
profile-edit.html

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

306
theme_calm/css/style.css

@ -344,6 +344,16 @@ button.unfollow:hover {
opacity: 0.9; 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 { .userMenu li.userMenu-profile > a {
background: url(../img/profile.png) no-repeat 5px center; background: url(../img/profile.png) no-repeat 5px center;
padding-left: 35px; padding-left: 35px;
@ -1014,12 +1024,12 @@ textarea.splited-post {
/*********************************** /***********************************
********************* WHO TO FOLLOW ********************* WHO TO FOLLOW
***********************************/ ***********************************/
.who-to-follow .who-to-follow,
{ .new-users {
padding: 10px; padding: 10px;
} }
.who-to-follow h3 .who-to-follow h3,
{ .new-users h3 {
display: inline; display: inline;
} }
.twister-user .twister-user
@ -1072,16 +1082,19 @@ textarea.splited-post {
opacity: .8; opacity: .8;
} }
.followers .followers,
{ .latest-activity {
font-size: 12px; font-size: 12px;
color: rgba( 0, 0, 0, .6 ); color: rgba( 0, 0, 0, .6 );
margin-left: 58px;
} }
.followed-by
{ .followed-by,
.latest-activity .time {
font-size: 13px; font-size: 13px;
cursor: pointer; cursor: pointer;
} }
.twister-user-name, .twister-user-name,
.twister-by-user-name .twister-by-user-name
{ {
@ -1771,8 +1784,7 @@ textarea.splited-post {
padding: 10px; padding: 10px;
border-radius: 6px; border-radius: 6px;
} }
.singleBlock h2, .header-bold .singleBlock h2 {
{
font-weight: bold; font-weight: bold;
line-height: 40px; line-height: 40px;
color: rgba( 255, 255, 255, 1 ); color: rgba( 255, 255, 255, 1 );
@ -1843,83 +1855,6 @@ textarea.splited-post {
margin-right: 20px; 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 ************ ************* POPUP MODAL ************
**************************************/ **************************************/
@ -1950,12 +1885,12 @@ textarea.splited-post {
font-weight: bold; font-weight: bold;
} }
.modal-wrapper .modal-content { .modal-content {
background: #fff; background: #fff;
overflow-y: auto; overflow-y: auto;
} }
.modal-wrapper .modal-blackout { .modal-blackout {
background: rgba(0,0,0, .6); background: rgba(0,0,0, .6);
z-index: -1; z-index: -1;
position: fixed; position: fixed;
@ -2019,6 +1954,86 @@ textarea.splited-post {
padding: 10px 15px; 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 ******* ******** DIRECT MESSAGES MODAL *******
**************************************/ **************************************/
@ -2177,7 +2192,7 @@ textarea.splited-post {
.group-messages-join-group.modal-wrapper { .group-messages-join-group.modal-wrapper {
height: auto; /*about 360px*/ height: auto; /*about 360px*/
margin-top: -240px; margin-top: -204px;
} }
.group-messages-join-group .modal-content .module { .group-messages-join-group .modal-content .module {
@ -2223,38 +2238,6 @@ textarea.splited-post {
margin: 8px 8px 0; 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 *********** ************ HASHTAG MODAL ***********
**************************************/ **************************************/
@ -2308,19 +2291,23 @@ textarea.splited-post {
********* WHO TO FOLLOW MODAL ******** ********* WHO TO FOLLOW MODAL ********
**************************************/ **************************************/
.who-to-follow-modal .modal-content { .who-to-follow-modal .modal-content,
.new-users-modal .modal-content {
padding: 15px; padding: 15px;
} }
.who-to-follow-modal ol { .who-to-follow-modal ol,
.new-users-modal ol {
margin: 5px; 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; 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; vertical-align: middle;
} }
@ -2328,20 +2315,59 @@ textarea.splited-post {
text-decoration: underline; text-decoration: underline;
} }
.who-to-follow-modal .follow { .who-to-follow-modal .follow,
.new-users-modal .follow {
float: right; float: right;
margin: -30px 10px 0 10px; 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; vertical-align: bottom;
} }
.who-to-follow-modal .bio { .who-to-follow-modal .bio,
.new-users-modal .bio {
font-size: 12px; font-size: 12px;
color: rgba( 0, 0, 0, .6 ); 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 ************ ************ POPUP PROMPT ************
**************************************/ **************************************/
@ -2359,7 +2385,7 @@ textarea.splited-post {
} }
.prompt-wrapper .modal-buttons { .prompt-wrapper .modal-buttons {
margin: 4px 16px; margin: 4px 16px 16px;
text-align: right; text-align: right;
} }
@ -2379,12 +2405,19 @@ textarea.splited-post {
.confirm-popup .message { .confirm-popup .message {
text-align: center; text-align: center;
margin: 12px; padding: 12px;
} }
.confirm-popup .modal-buttons { .confirm-popup .modal-buttons {
text-align: center; text-align: center;
padding: 4px; }
/*************************************
********* NEW ACCOUNT POPUP **********
**************************************/
.new-account-briefing.prompt-wrapper {
margin-top: -164px;
} }
/************************************* /*************************************
@ -2707,7 +2740,7 @@ textarea.splited-post {
display: inline-block; display: inline-block;
text-align: initial; text-align: initial;
width: 320px; width: 320px;
height: 120px; height: 130px;
margin: 2px; margin: 2px;
padding: 2px; padding: 2px;
border: solid 1px rgba(69, 71, 77, .1); border: solid 1px rgba(69, 71, 77, .1);
@ -2753,6 +2786,13 @@ textarea.splited-post {
right: 32px; right: 32px;
} }
.following-own-modal .following-list .latest-activity {
position: absolute;
top: 110px;
right: 32px;
margin: 0;
}
.gifCheckBox { .gifCheckBox {
float: right; float: right;
vertical-align: middle; vertical-align: middle;

324
theme_nin/css/style.css

@ -389,6 +389,15 @@ samp {
font-size: 1.5em; 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 *********** ************ PROFILE MODAL ***********
**************************************/ **************************************/
@ -961,11 +970,6 @@ samp {
color: #727578; color: #727578;
} }
/* line 195, ../sass/_postboard.sass */
.post-favorite {
display: none !important;
}
/* line 200, ../sass/_postboard.sass */ /* line 200, ../sass/_postboard.sass */
.post .show-more { .post .show-more {
display: inline-block; display: inline-block;
@ -1014,7 +1018,7 @@ samp {
display: none !important; display: none !important;
} }
/* line 236, ../sass/_postboard.sass */ /* 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; display: inline-block !important;
} }
@ -1308,75 +1312,6 @@ h3 .isFollowing:after {
display: none; 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 *********** */ /************** BUTTONS *********** */
/* line 65, ../sass/_commons.sass */ /* line 65, ../sass/_commons.sass */
button, .mini-profile-actions span, a.button { button, .mini-profile-actions span, a.button {
@ -2155,27 +2090,32 @@ textarea.splited-post {
/******** WHO TO FOLLOW ********/ /******** WHO TO FOLLOW ********/
/* line 411, ../sass/style.sass */ /* line 411, ../sass/style.sass */
.who-to-follow.module { .who-to-follow.module,
.new-users.module {
width: inherit; width: inherit;
margin-bottom: 20px; margin-bottom: 20px;
} }
/* line 414, ../sass/style.sass */ /* line 414, ../sass/style.sass */
.who-to-follow small { .who-to-follow small,
.new-users small {
display: none; display: none;
} }
/* line 416, ../sass/style.sass */ /* line 416, ../sass/style.sass */
.who-to-follow h3 { .who-to-follow h3,
.new-users h3 {
float: left; float: left;
} }
/* line 418, ../sass/style.sass */ /* line 418, ../sass/style.sass */
.who-to-follow ol { .who-to-follow ol,
.new-users ol {
clear: both; clear: both;
} }
.who-to-follow .twister-user-info { .who-to-follow .twister-user-info,
.new-users .twister-user-info {
margin-top: 8px; margin-top: 8px;
} }
@ -2209,7 +2149,8 @@ textarea.splited-post {
} }
/* line 447, ../sass/style.sass */ /* line 447, ../sass/style.sass */
.followers { .followers,
.latest-activity {
font-size: 12px; font-size: 12px;
color: #66686B; color: #66686B;
} }
@ -2219,13 +2160,22 @@ textarea.splited-post {
} }
/* line 453, ../sass/style.sass */ /* line 453, ../sass/style.sass */
.followed-by { .followed-by,
.latest-activity {
color: #aaa; color: #aaa;
font-size: 12px; font-size: 12px;
cursor: pointer; cursor: pointer;
display: block; display: block;
} }
.who-to-follow .latest-activity {
margin-bottom: 8px;
}
.who-to-follow .latest-activity .label {
display: none;
}
/* line 459, ../sass/style.sass */ /* line 459, ../sass/style.sass */
.twister-user-name, .twister-by-user-name { .twister-user-name, .twister-by-user-name {
font-weight: bold; font-weight: bold;
@ -2582,6 +2532,31 @@ ol.toptrends-list a:hover {
margin: 4px; 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 ************ *********** CONFIRM POPUP ************
**************************************/ **************************************/
@ -2594,6 +2569,15 @@ ol.toptrends-list a:hover {
margin: 8px 12px 20px; margin: 8px 12px 20px;
} }
/*************************************
********* NEW ACCOUNT POPUP **********
**************************************/
.new-account-briefing.prompt-wrapper {
top: 50%;
margin-top: -164px;
}
/****** FOLLOWING-CONFIG PROMPT ******/ /****** FOLLOWING-CONFIG PROMPT ******/
.following-config-modal.prompt-wrapper { .following-config-modal.prompt-wrapper {
@ -2653,6 +2637,62 @@ ol.toptrends-list a:hover {
padding-bottom: 6px; 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********* */ /****** DIRECT MESSAGES MODAL********* */
/* line 736, ../sass/style.sass */ /* line 736, ../sass/style.sass */
.modal-wrapper.directMessages { .modal-wrapper.directMessages {
@ -2939,8 +2979,8 @@ ol.toptrends-list a:hover {
.group-messages-join-group.modal-wrapper { .group-messages-join-group.modal-wrapper {
width: 580px; width: 580px;
height: auto; /*about 360px*/ height: auto; /*about 409px*/
margin: -250px 0 0 -290px; margin: -204px 0 0 -290px;
} }
.group-messages-join-group .modal-content { .group-messages-join-group .modal-content {
@ -2988,39 +3028,6 @@ ol.toptrends-list a:hover {
margin: 8px 8px 0; 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********** */ /******** HASHTAG MODAL********** */
/* line 884, ../sass/style.sass */ /* line 884, ../sass/style.sass */
.modal-wrapper.hashtag-modal { .modal-wrapper.hashtag-modal {
@ -3091,49 +3098,108 @@ ol.toptrends-list a:hover {
/******* WHO TO FOLLOW MODAL****** */ /******* WHO TO FOLLOW MODAL****** */
/* line 943, ../sass/style.sass */ /* line 943, ../sass/style.sass */
.modal-wrapper.who-to-follow-modal { .modal-wrapper.who-to-follow-modal,
.modal-wrapper.new-users-modal {
width: 520px; width: 520px;
height: 580px; height: 580px;
margin: -290px 0 0 -260px; margin: -290px 0 0 -260px;
} }
/* line 949, ../sass/style.sass */ /* line 949, ../sass/style.sass */
.who-to-follow-modal .modal-content { .who-to-follow-modal .modal-content,
.new-users-modal .modal-content {
padding: 15px; padding: 15px;
} }
/* line 955, ../sass/style.sass */ /* line 955, ../sass/style.sass */
.who-to-follow-modal ol { .who-to-follow-modal ol,
.new-users-modal ol {
margin: 5px; margin: 5px;
} }
/* line 958, ../sass/style.sass */ /* 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; text-decoration: none;
} }
/* line 960, ../sass/style.sass */ /* line 960, ../sass/style.sass */
.who-to-follow-modal .twister-user { .who-to-follow-modal .twister-user,
position: relative; .new-users-modal .twister-user {
position: relative;
padding: 5px; padding: 5px;
} }
/* line 963, ../sass/style.sass */ /* 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; position: relative;
left: 0; left: 0;
float: left; float: left;
display: block; display: block;
} }
/* line 968, ../sass/style.sass */ /* 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; position: relative;
margin-top: 4px; margin-top: 4px;
padding-left: 70px; padding-left: 70px;
width: auto; width: auto;
} }
/* line 972, ../sass/style.sass */ /* 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); color: rgba(0, 0, 0, 0.6);
font-style: italic; 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 ************ */ /******* LOADER ************ */
/* line 978, ../sass/style.sass */ /* line 978, ../sass/style.sass */
.postboard-loading, .loading-roller { .postboard-loading, .loading-roller {
@ -3280,7 +3346,7 @@ ol.toptrends-list a:hover {
.following-own-modal .following-list > li { .following-own-modal .following-list > li {
display: inline-block; display: inline-block;
width: 320px; width: 320px;
height: 160px; height: 184px;
margin: 2px; margin: 2px;
padding: 2px; padding: 2px;
border: solid 1px rgba(69, 71, 77, .1); border: solid 1px rgba(69, 71, 77, .1);
@ -3380,6 +3446,10 @@ ol.toptrends-list a:hover {
display: block; display: block;
} }
.following-own-modal .following-list .latest-activity {
font-size: 11px;
}
/********** AUTOCOMPLETING *********/ /********** AUTOCOMPLETING *********/
/* line 1087, ../sass/style.sass */ /* line 1087, ../sass/style.sass */

55
theme_nin/sass/_login.sass

@ -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 @@
@import _profile @import _profile
@import _postboard @import _postboard
@import _following @import _following
@import _login
@import _network @import _network
@import _commons @import _commons
@import _tabs @import _tabs
@ -784,6 +783,43 @@ ol.toptrends-list
float: left float: left
margin: 4px 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 **********/ /************ FOLLOWING-CONFIG MODAL **********/
.prompt-wrapper.following-config-modal .prompt-wrapper.following-config-modal
@ -822,6 +858,44 @@ ol.toptrends-list
.post-area .post-area
padding-bottom: 6px 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**********/ /****** DIRECT MESSAGES MODAL**********/
.modal-wrapper.directMessages .modal-wrapper.directMessages

96
tmobile.html

@ -171,55 +171,7 @@
<h1 class="rtitle">twister login</h1> <h1 class="rtitle">twister login</h1>
</div> </div>
<div class="content" data-role="content" style=""> <div class="content" data-role="content" style=""></div>
<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="footer" data-role="footer" data-position="fixed" data-tap-toggle="false"> <div class="footer" data-role="footer" data-position="fixed" data-tap-toggle="false">
<a href="#home" data-role="button">Home</a> <a href="#home" data-role="button">Home</a>
@ -891,6 +843,52 @@
</div> </div>
</li> </li>
</div> </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 --> </div> <!-- templates -->

Loading…
Cancel
Save