Browse Source

initial commit of desktop notifications via notify.js by alexgibson

master
Simon Grim 10 years ago
parent
commit
09f4a64980
  1. 1
      following.html
  2. 2
      home.html
  3. 17
      js/interface_common.js
  4. 81
      js/interface_localization.js
  5. 11
      js/mobile_abstract.js
  6. 196
      js/notify.js
  7. 19
      js/options.js
  8. 2
      js/twister_actions.js
  9. 49
      js/twister_newmsgs.js
  10. 1
      login.html
  11. 1
      network.html
  12. 13
      options.html
  13. 1
      profile-edit.html
  14. 2
      theme_nin/css/style.css
  15. 2
      theme_nin/sass/_tabs.sass

1
following.html

@ -11,6 +11,7 @@
<script src="js/jquery.jsonrpcclient.js"></script> <script src="js/jquery.jsonrpcclient.js"></script>
<script src="js/jquery.storageapi.js"></script> <script src="js/jquery.storageapi.js"></script>
<script src="js/options.js"></script> <script src="js/options.js"></script>
<script src="js/notify.js"></script>
<script src="js/mobile_abstract.js"></script> <script src="js/mobile_abstract.js"></script>
<script src="js/twister_io.js"></script> <script src="js/twister_io.js"></script>
<script src="js/polyglot.min.js"></script> <script src="js/polyglot.min.js"></script>

2
home.html

@ -11,6 +11,7 @@
<script src="js/jquery.jsonrpcclient.js"></script> <script src="js/jquery.jsonrpcclient.js"></script>
<script src="js/jquery.storageapi.js"></script> <script src="js/jquery.storageapi.js"></script>
<script src="js/options.js"></script> <script src="js/options.js"></script>
<script src="js/notify.js"></script>
<script src="js/mobile_abstract.js"></script> <script src="js/mobile_abstract.js"></script>
<script src="js/twister_io.js"></script> <script src="js/twister_io.js"></script>
<script src="js/polyglot.min.js"></script> <script src="js/polyglot.min.js"></script>
@ -26,6 +27,7 @@
<script src="js/interface_common.js"></script> <script src="js/interface_common.js"></script>
<script src="js/interface_home.js"></script> <script src="js/interface_home.js"></script>
<script src="js/jquery.textcomplete.js"></script> <script src="js/jquery.textcomplete.js"></script>
<script> <script>
$(function(){setTimeout(mensAutocomplete, 800);}) $(function(){setTimeout(mensAutocomplete, 800);})
changeStyle(); changeStyle();

17
js/interface_common.js

@ -200,6 +200,23 @@ function updateHashtagModal(postboard,hashtag,timeoutArgs) {
var resource = $hashtagModalClass.attr("data-resource"); var resource = $hashtagModalClass.attr("data-resource");
requestHashtag(postboard,hashtag,resource,timeoutArgs); requestHashtag(postboard,hashtag,resource,timeoutArgs);
if( _hashtagPendingPostsUpdated ) {
var desktopNotification = new Notify(polyglot.t('notify_desktop_title'), {
body: 'You got '+polyglot.t("new_posts", _hashtagPendingPostsUpdated)+' in search result.',
icon: '../img/twister_mini.png',
tag: 'twister_notification_new_posts_modal',
timeout: _desktopNotificationTimeout,
notifyClick: function() {
$(".postboard-news").hide();
displayHashtagPending($(".hashtag-modal .postboard-posts"));
}
});
desktopNotification.show();
_hashtagPendingPostsUpdated = 0;
}
// use extended timeout parameters on modal refresh (requires twister_core >= 0.9.14). // 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), // 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. // then we may possibly collect more posts on our second try by waiting more.

81
js/interface_localization.js

@ -49,6 +49,7 @@ if(preferredLanguage == "en"){
"Connections:": "Connections: ", // to network "Connections:": "Connections: ", // to network
"Connection lost.": "Connection lost.", "Connection lost.": "Connection lost.",
"days": "%{smart_count} day |||| %{smart_count} days", "days": "%{smart_count} day |||| %{smart_count} days",
"Desktop notifications": "Desktop notifications",
"Detailed information": "Detailed information", "Detailed information": "Detailed information",
"DHT network down.": "DHT network down.", "DHT network down.": "DHT network down.",
"Direct Messages": "Direct Messages", "Direct Messages": "Direct Messages",
@ -92,8 +93,14 @@ if(preferredLanguage == "en"){
"New direct message...": "New direct message...", "New direct message...": "New direct message...",
"New Post...": "New Post...", "New Post...": "New Post...",
"new_posts": "%{smart_count} new post |||| %{smart_count} new posts", "new_posts": "%{smart_count} new post |||| %{smart_count} new posts",
"new_mentions": "%{smart_count} new mention |||| %{smart_count} new mentions",
"new_direct_messages": "%{smart_count} new direct message |||| %{smart_count} new direct messages",
"nobody": "nobody", // used to promote a post without attaching the user "nobody": "nobody", // used to promote a post without attaching the user
"Not available": "Not available", // username is not available "Not available": "Not available", // username is not available
"notify_desktop_error": "Twister cannot perform desktop notification: unknown error occured. Try to change browser permissions for this domain.",
"notify_desktop_perm_denied": "Twister cannot perform desktop notification: permission denied. Check out browser's policy for this domain.",
"notify_desktop_test": "All the twisters gonna twist. Now you are welcome too.",
"notify_desktop_title": "Watch out, it's twister over here!",
"Number of blocks in block chain:": "Number of blocks in block chain: ", "Number of blocks in block chain:": "Number of blocks in block chain: ",
"Number of CPUs to use": "Number of CPUs to use ", "Number of CPUs to use": "Number of CPUs to use ",
"Only alphanumeric and underscore allowed.": "Only alphanumeric and underscore allowed.", "Only alphanumeric and underscore allowed.": "Only alphanumeric and underscore allowed.",
@ -184,6 +191,7 @@ if(preferredLanguage == "en"){
"Ignore": "Ignore", "Ignore": "Ignore",
"Theme": "Theme", "Theme": "Theme",
"Keys": "Keys", "Keys": "Keys",
"Notifications": "Notifications",
"Sound notifications": "Sound notifications", "Sound notifications": "Sound notifications",
"Send key": "Send key", "Send key": "Send key",
"Posts display": "Posts display", "Posts display": "Posts display",
@ -322,8 +330,14 @@ if(preferredLanguage == "es"){
"New direct message...": "Nuevo mensaje directo...", "New direct message...": "Nuevo mensaje directo...",
"New Post...": "Nuevo Post...", "New Post...": "Nuevo Post...",
"new_posts": "%{smart_count} nuevo post |||| %{smart_count} nuevos posts", "new_posts": "%{smart_count} nuevo post |||| %{smart_count} nuevos posts",
"new_mentions": "%{smart_count} new mention |||| %{smart_count} new mentions",
"new_direct_messages": "%{smart_count} new direct message |||| %{smart_count} new direct messages",
"nobody": "Nadie", // used to promote a post without attaching the user "nobody": "Nadie", // used to promote a post without attaching the user
"Not available": "No disponible", // username is not available "Not available": "No disponible", // username is not available
"notify_desktop_error": "Twister cannot perform desktop notification: unknown error occured. Try to change browser permissions for this domain.",
"notify_desktop_perm_denied": "Twister cannot perform desktop notification: permission denied. Check out browser's policy for this domain.",
"notify_desktop_test": "All the twisters gonna twist. Now you are welcome too.",
"notify_desktop_title": "Watch out, it's twister over here!",
"Number of blocks in block chain:": "Número de bloques en la cadena de bloques: ", "Number of blocks in block chain:": "Número de bloques en la cadena de bloques: ",
"Number of CPUs to use": "Número de CPUs para utilizar ", "Number of CPUs to use": "Número de CPUs para utilizar ",
"Only alphanumeric and underscore allowed.": "Sólo alfanuméricos y subrayados permitido.", "Only alphanumeric and underscore allowed.": "Sólo alfanuméricos y subrayados permitido.",
@ -550,8 +564,14 @@ if(preferredLanguage == "uk"){
"New direct message...": "Нове особисте повідомлення...", "New direct message...": "Нове особисте повідомлення...",
"New Post...": "Нове повідомлення...", "New Post...": "Нове повідомлення...",
"new_posts": "%{smart_count} нове повідомлення |||| %{smart_count} нових повідомлень", "new_posts": "%{smart_count} нове повідомлення |||| %{smart_count} нових повідомлень",
"new_mentions": "%{smart_count} new mention |||| %{smart_count} new mentions",
"new_direct_messages": "%{smart_count} new direct message |||| %{smart_count} new direct messages",
"nobody": "nobody", // used to promote a post without attaching the user "nobody": "nobody", // used to promote a post without attaching the user
"Not available": "Не доступне", // username is not available "Not available": "Не доступне", // username is not available
"notify_desktop_error": "Twister cannot perform desktop notification: unknown error occured. Try to change browser permissions for this domain.",
"notify_desktop_perm_denied": "Twister cannot perform desktop notification: permission denied. Check out browser's policy for this domain.",
"notify_desktop_test": "All the twisters gonna twist. Now you are welcome too.",
"notify_desktop_title": "Watch out, it's twister over here!",
"Number of blocks in block chain:": "Кількість блоків у ланцюгу: ", "Number of blocks in block chain:": "Кількість блоків у ланцюгу: ",
"Number of CPUs to use": "Кількість CPUs до використання ", "Number of CPUs to use": "Кількість CPUs до використання ",
"Only alphanumeric and underscore allowed.": "Тільки літеро-численні сиволи та нижнє підкреслення дозволені.", "Only alphanumeric and underscore allowed.": "Тільки літеро-численні сиволи та нижнє підкреслення дозволені.",
@ -776,8 +796,14 @@ if(preferredLanguage == "zh"){
"New direct message...": "新的即时信息...", "New direct message...": "新的即时信息...",
"New Post...": "新推文...", "New Post...": "新推文...",
"new_posts": "%{smart_count} 新推文", "new_posts": "%{smart_count} 新推文",
"new_mentions": "%{smart_count} new mention |||| %{smart_count} new mentions",
"new_direct_messages": "%{smart_count} new direct message |||| %{smart_count} new direct messages",
"nobody": "nobody", // used to promote a post without attaching the user "nobody": "nobody", // used to promote a post without attaching the user
"Not available": "用户名不可用", // username is not available "Not available": "用户名不可用", // username is not available
"notify_desktop_error": "Twister cannot perform desktop notification: unknown error occured. Try to change browser permissions for this domain.",
"notify_desktop_perm_denied": "Twister cannot perform desktop notification: permission denied. Check out browser's policy for this domain.",
"notify_desktop_test": "All the twisters gonna twist. Now you are welcome too.",
"notify_desktop_title": "Watch out, it's twister over here!",
"Number of blocks in block chain:": "块链中的块数:", "Number of blocks in block chain:": "块链中的块数:",
"Number of CPUs to use": "使用CPU数目 ", "Number of CPUs to use": "使用CPU数目 ",
"Only alphanumeric and underscore allowed.": "只允许字母和下划线", "Only alphanumeric and underscore allowed.": "只允许字母和下划线",
@ -1002,8 +1028,14 @@ if(preferredLanguage == "nl"){
"New direct message...": "Nieuw privébericht...", "New direct message...": "Nieuw privébericht...",
"New Post...": "Nieuw bericht...", "New Post...": "Nieuw bericht...",
"new_posts": "%{smart_count} nieuw bericht |||| %{smart_count} nieuwe berichten", "new_posts": "%{smart_count} nieuw bericht |||| %{smart_count} nieuwe berichten",
"new_mentions": "%{smart_count} new mention |||| %{smart_count} new mentions",
"new_direct_messages": "%{smart_count} new direct message |||| %{smart_count} new direct messages",
"nobody": "nobody", // used to promote a post without attaching the user "nobody": "nobody", // used to promote a post without attaching the user
"Not available": "Niet beschikbaar", // username is not available "Not available": "Niet beschikbaar", // username is not available
"notify_desktop_error": "Twister cannot perform desktop notification: unknown error occured. Try to change browser permissions for this domain.",
"notify_desktop_perm_denied": "Twister cannot perform desktop notification: permission denied. Check out browser's policy for this domain.",
"notify_desktop_test": "All the twisters gonna twist. Now you are welcome too.",
"notify_desktop_title": "Watch out, it's twister over here!",
"Number of blocks in block chain:": "Aantal blocks in block chain: ", "Number of blocks in block chain:": "Aantal blocks in block chain: ",
"Number of CPUs to use": "Aantal CPUs om te gebruiken ", "Number of CPUs to use": "Aantal CPUs om te gebruiken ",
"Only alphanumeric and underscore allowed.": "Alleen alphanumeriek en underscore toegestaan.", "Only alphanumeric and underscore allowed.": "Alleen alphanumeriek en underscore toegestaan.",
@ -1229,8 +1261,14 @@ if(preferredLanguage == "it"){
"New direct message...": "Nuovo messaggio diretto...", "New direct message...": "Nuovo messaggio diretto...",
"New Post...": "Nuovo messaggio...", "New Post...": "Nuovo messaggio...",
"new_posts": "%{smart_count} nuovo messaggio |||| %{smart_count} nuovi messaggi", "new_posts": "%{smart_count} nuovo messaggio |||| %{smart_count} nuovi messaggi",
"new_mentions": "%{smart_count} new mention |||| %{smart_count} new mentions",
"new_direct_messages": "%{smart_count} new direct message |||| %{smart_count} new direct messages",
"nobody": "nessuno", // used to promote a post without attaching the user "nobody": "nessuno", // used to promote a post without attaching the user
"Not available": "Non disponibile", // username is not available "Not available": "Non disponibile", // username is not available
"notify_desktop_error": "Twister cannot perform desktop notification: unknown error occured. Try to change browser permissions for this domain.",
"notify_desktop_perm_denied": "Twister cannot perform desktop notification: permission denied. Check out browser's policy for this domain.",
"notify_desktop_test": "All the twisters gonna twist. Now you are welcome too.",
"notify_desktop_title": "Watch out, it's twister over here!",
"Number of blocks in block chain:": "Numero di blocchi nella catena: ", "Number of blocks in block chain:": "Numero di blocchi nella catena: ",
"Number of CPUs to use": "Numero di processori da usare:", "Number of CPUs to use": "Numero di processori da usare:",
"Only alphanumeric and underscore allowed.": "Sono permessi solo caratteri alfanumerici e '_'", "Only alphanumeric and underscore allowed.": "Sono permessi solo caratteri alfanumerici e '_'",
@ -1454,8 +1492,14 @@ if(preferredLanguage == "fr"){
"New direct message...": "Nouveau message privé...", "New direct message...": "Nouveau message privé...",
"New Post...": "Nouveau billets...", "New Post...": "Nouveau billets...",
"new_posts": "%{smart_count} nouveau billet |||| %{smart_count} nouveaux billets", "new_posts": "%{smart_count} nouveau billet |||| %{smart_count} nouveaux billets",
"new_mentions": "%{smart_count} new mention |||| %{smart_count} new mentions",
"new_direct_messages": "%{smart_count} new direct message |||| %{smart_count} new direct messages",
"nobody": "nobody", // used to promote a post without attaching the user "nobody": "nobody", // used to promote a post without attaching the user
"Not available": "Non disponible", // username is not available "Not available": "Non disponible", // username is not available
"notify_desktop_error": "Twister cannot perform desktop notification: unknown error occured. Try to change browser permissions for this domain.",
"notify_desktop_perm_denied": "Twister cannot perform desktop notification: permission denied. Check out browser's policy for this domain.",
"notify_desktop_test": "All the twisters gonna twist. Now you are welcome too.",
"notify_desktop_title": "Watch out, it's twister over here!",
"Number of blocks in block chain:": "Nombre de blocs dans la chaîne de blocs: ", "Number of blocks in block chain:": "Nombre de blocs dans la chaîne de blocs: ",
"Number of CPUs to use": "Nombre de processeurs à utiliser", "Number of CPUs to use": "Nombre de processeurs à utiliser",
"Only alphanumeric and underscore allowed.": "Seuls les caractères alphanumériques et la barre de soulignement sont permis.", "Only alphanumeric and underscore allowed.": "Seuls les caractères alphanumériques et la barre de soulignement sont permis.",
@ -1642,6 +1686,7 @@ if(preferredLanguage == "ru"){
"Connections:": "Соединений: ", "Connections:": "Соединений: ",
"Connection lost.": "Соединение с сетью было потеряно.", "Connection lost.": "Соединение с сетью было потеряно.",
"days": "%{smart_count} день |||| %{smart_count} дней", "days": "%{smart_count} день |||| %{smart_count} дней",
"Desktop notifications": "Уведомления рабочего стола",
"Detailed information": "Подробная информация", "Detailed information": "Подробная информация",
"DHT network down.": "Недоступна DHT сеть.", "DHT network down.": "Недоступна DHT сеть.",
"Direct Messages": "Личные сообщения", "Direct Messages": "Личные сообщения",
@ -1685,8 +1730,14 @@ if(preferredLanguage == "ru"){
"New direct message...": "Новое личное сообщение...", "New direct message...": "Новое личное сообщение...",
"New Post...": "Новый пост...", "New Post...": "Новый пост...",
"new_posts": "%{smart_count} новый пост |||| %{smart_count} новых постов", "new_posts": "%{smart_count} новый пост |||| %{smart_count} новых постов",
"new_mentions": "%{smart_count} новое упоминание |||| %{smart_count} новых упоминаний",
"new_direct_messages": "%{smart_count} новое личное сообщение |||| %{smart_count} новых личных сообщений",
"nobody": "Анонимно", // used to promote a post without attaching the user "nobody": "Анонимно", // used to promote a post without attaching the user
"Not available": "Недоступно", "Not available": "Недоступно",
"notify_desktop_error": "Твистер не может выполнить уведомление: произошла неизвестная ошибка. Попробуйте изменить предпочтения браузера для уведомлений рабочего стола.",
"notify_desktop_perm_denied": "Твистер не может выполниь уведомление: разрешение не получено. Убедитесь, что в браузере разрешены уведомления для этого домена.",
"notify_desktop_test": "All the twisters gonna twist. Now you are welcome too.",
"notify_desktop_title": "Watch out, it's twister over here!",
"Number of blocks in block chain:": "Количество блоков в цепочке: ", "Number of blocks in block chain:": "Количество блоков в цепочке: ",
"Number of CPUs to use": "Сколько использовать ядер процессора", "Number of CPUs to use": "Сколько использовать ядер процессора",
"Only alphanumeric and underscore allowed.": "Разрешены только латинские буквы, цифры и подчеркивания.", "Only alphanumeric and underscore allowed.": "Разрешены только латинские буквы, цифры и подчеркивания.",
@ -1917,8 +1968,14 @@ if(preferredLanguage == "de"){
"New direct message...": "Neue Direktnachricht...", "New direct message...": "Neue Direktnachricht...",
"New Post...": "Neuer Post...", "New Post...": "Neuer Post...",
"new_posts": "%{smart_count} neuer Post |||| %{smart_count} neue Posts", "new_posts": "%{smart_count} neuer Post |||| %{smart_count} neue Posts",
"new_mentions": "%{smart_count} new mention |||| %{smart_count} new mentions",
"new_direct_messages": "%{smart_count} new direct message |||| %{smart_count} new direct messages",
"nobody": "nobody", // used to promote a post without attaching the user "nobody": "nobody", // used to promote a post without attaching the user
"Not available": "Nicht verfügbar", // username is not available "Not available": "Nicht verfügbar", // username is not available
"notify_desktop_error": "Twister cannot perform desktop notification: unknown error occured. Try to change browser permissions for this domain.",
"notify_desktop_perm_denied": "Twister cannot perform desktop notification: permission denied. Check out browser's policy for this domain.",
"notify_desktop_test": "All the twisters gonna twist. Now you are welcome too.",
"notify_desktop_title": "Watch out, it's twister over here!",
"Number of blocks in block chain:": "Anzahl der Blöcke in der Block-Chain: ", "Number of blocks in block chain:": "Anzahl der Blöcke in der Block-Chain: ",
"Number of CPUs to use": "Anzahl der zu benutzenden CPU's ", "Number of CPUs to use": "Anzahl der zu benutzenden CPU's ",
"Only alphanumeric and underscore allowed.": "Nur Buchstaben, Zahlen und Unterstrich erlaubt.", "Only alphanumeric and underscore allowed.": "Nur Buchstaben, Zahlen und Unterstrich erlaubt.",
@ -2145,8 +2202,14 @@ if(preferredLanguage == "ja"){
"New direct message...": "ダイレクトメッセージ...", "New direct message...": "ダイレクトメッセージ...",
"New Post...": "投稿する", "New Post...": "投稿する",
"new_posts": "%{smart_count} 新投稿 |||| %{smart_count} 新投稿", "new_posts": "%{smart_count} 新投稿 |||| %{smart_count} 新投稿",
"new_mentions": "%{smart_count} new mention |||| %{smart_count} new mentions",
"new_direct_messages": "%{smart_count} new direct message |||| %{smart_count} new direct messages",
"nobody": "ナナシ", // used to promote a post without attaching the user "nobody": "ナナシ", // used to promote a post without attaching the user
"Not available": "使用中", // username is not available "Not available": "使用中", // username is not available
"notify_desktop_error": "Twister cannot perform desktop notification: unknown error occured. Try to change browser permissions for this domain.",
"notify_desktop_perm_denied": "Twister cannot perform desktop notification: permission denied. Check out browser's policy for this domain.",
"notify_desktop_test": "All the twisters gonna twist. Now you are welcome too.",
"notify_desktop_title": "Watch out, it's twister over here!",
"Number of blocks in block chain:": "全ブロック数: ", "Number of blocks in block chain:": "全ブロック数: ",
"Number of CPUs to use": "利用するCPUの数", "Number of CPUs to use": "利用するCPUの数",
"Only alphanumeric and underscore allowed.": "アルファベットとアンダースコア(_)が利用可能です", "Only alphanumeric and underscore allowed.": "アルファベットとアンダースコア(_)が利用可能です",
@ -2370,8 +2433,14 @@ if(preferredLanguage == "pt-BR"){
"New direct message...": "Nova mensagem direta...", "New direct message...": "Nova mensagem direta...",
"New Post...": "Nova Postagem...", "New Post...": "Nova Postagem...",
"new_posts": "%{smart_count} nova postagem |||| %{smart_count} novas postagens", "new_posts": "%{smart_count} nova postagem |||| %{smart_count} novas postagens",
"new_mentions": "%{smart_count} new mention |||| %{smart_count} new mentions",
"new_direct_messages": "%{smart_count} new direct message |||| %{smart_count} new direct messages",
"nobody": "nobody", // used to promote a post without attaching the user "nobody": "nobody", // used to promote a post without attaching the user
"Not available": "Indisponível", // username is not available "Not available": "Indisponível", // username is not available
"notify_desktop_error": "Twister cannot perform desktop notification: unknown error occured. Try to change browser permissions for this domain.",
"notify_desktop_perm_denied": "Twister cannot perform desktop notification: permission denied. Check out browser's policy for this domain.",
"notify_desktop_test": "All the twisters gonna twist. Now you are welcome too.",
"notify_desktop_title": "Watch out, it's twister over here!",
"Number of blocks in block chain:": "Número de blocos: ", "Number of blocks in block chain:": "Número de blocos: ",
"Number of CPUs to use": "Número de CPUs a serem utilizados ", "Number of CPUs to use": "Número de CPUs a serem utilizados ",
"Only alphanumeric and underscore allowed.": "Permitido apenas caracteres alfanuméricos e underscore '_'.", "Only alphanumeric and underscore allowed.": "Permitido apenas caracteres alfanuméricos e underscore '_'.",
@ -2599,8 +2668,14 @@ if(preferredLanguage == "tr"){
"New direct message...": "Yeni direk mesaj...", "New direct message...": "Yeni direk mesaj...",
"New Post...": "Yeni gönderi...", "New Post...": "Yeni gönderi...",
"new_posts": "%{smart_count} yeni gönederi |||| %{smart_count} yeni gönderi", "new_posts": "%{smart_count} yeni gönederi |||| %{smart_count} yeni gönderi",
"new_mentions": "%{smart_count} new mention |||| %{smart_count} new mentions",
"new_direct_messages": "%{smart_count} new direct message |||| %{smart_count} new direct messages",
"nobody": "hiçkimse", // used to promote a post without attaching the user "nobody": "hiçkimse", // used to promote a post without attaching the user
"Not available": "Kullanılamaz", // username is not available "Not available": "Kullanılamaz", // username is not available
"notify_desktop_error": "Twister cannot perform desktop notification: unknown error occured. Try to change browser permissions for this domain.",
"notify_desktop_perm_denied": "Twister cannot perform desktop notification: permission denied. Check out browser's policy for this domain.",
"notify_desktop_test": "All the twisters gonna twist. Now you are welcome too.",
"notify_desktop_title": "Watch out, it's twister over here!",
"Number of blocks in block chain:": "Blok zincirindeki blok sayısı: ", "Number of blocks in block chain:": "Blok zincirindeki blok sayısı: ",
"Number of CPUs to use": "Kullanılacak CPU sayısı ", "Number of CPUs to use": "Kullanılacak CPU sayısı ",
"Only alphanumeric and underscore allowed.": "Sadece harf ve alt çizgi kullanılabilir.", "Only alphanumeric and underscore allowed.": "Sadece harf ve alt çizgi kullanılabilir.",
@ -2825,8 +2900,14 @@ if(preferredLanguage == "cs"){
"New direct message...": "Nová přímá zpráva...", "New direct message...": "Nová přímá zpráva...",
"New Post...": "Nový příspěvek...", "New Post...": "Nový příspěvek...",
"new_posts": "%{smart_count} nový příspěvek |||| %{smart_count} nové příspěvky |||| %{smart_count} nových příspěvků", "new_posts": "%{smart_count} nový příspěvek |||| %{smart_count} nové příspěvky |||| %{smart_count} nových příspěvků",
"new_mentions": "%{smart_count} new mention |||| %{smart_count} new mentions",
"new_direct_messages": "%{smart_count} new direct message |||| %{smart_count} new direct messages",
"nobody": "nikdo", // used to promote a post without attaching the user "nobody": "nikdo", // used to promote a post without attaching the user
"Not available": "Tuto přezdívku již někdo používá", // username is not available "Not available": "Tuto přezdívku již někdo používá", // username is not available
"notify_desktop_error": "Twister cannot perform desktop notification: unknown error occured. Try to change browser permissions for this domain.",
"notify_desktop_perm_denied": "Twister cannot perform desktop notification: permission denied. Check out browser's policy for this domain.",
"notify_desktop_test": "All the twisters gonna twist. Now you are welcome too.",
"notify_desktop_title": "Watch out, it's twister over here!",
"Number of blocks in block chain:": "Počet bloků v blockchainu: ", "Number of blocks in block chain:": "Počet bloků v blockchainu: ",
"Number of CPUs to use": "Kolik jader procesoru použít? ", "Number of CPUs to use": "Kolik jader procesoru použít? ",
"Only alphanumeric and underscore allowed.": "Povolena jsou jen písmena, čísla a podtržítko.", "Only alphanumeric and underscore allowed.": "Povolena jsou jen písmena, čísla a podtržítko.",

11
js/mobile_abstract.js

@ -102,6 +102,17 @@ var MAL = function()
newTweetsBar.fadeIn("slow"); newTweetsBar.fadeIn("slow");
newTweetsBarMenu.text(String(newPosts)); newTweetsBarMenu.text(String(newPosts));
newTweetsBarMenu.addClass("show"); newTweetsBarMenu.addClass("show");
var desktopNotification = new Notify(polyglot.t('notify_desktop_title'), {
body: 'You got '+polyglot.t("new_posts", newPosts)+' in postboard.',
icon: '../img/twister_mini.png',
tag: 'twister_notification_new_postboard',
timeout: _desktopNotificationTimeout,
notifyClick: function() {
requestTimelineUpdate("latest",postsPerRefresh,followingUsers,promotedPostsOnly);
}
});
desktopNotification.show();
} else { } else {
newTweetsBar.hide(); newTweetsBar.hide();
newTweetsBar.text(""); newTweetsBar.text("");

196
js/notify.js

@ -0,0 +1,196 @@
/*
* Author: Alex Gibson
* https://github.com/alexgibson/notify.js
* License: MIT license
*/
(function(global, factory) {
if (typeof define === 'function' && define.amd) {
// AMD environment
define(function() {
return factory(global, global.document);
});
} else if (typeof module !== 'undefined' && module.exports) {
// CommonJS environment
module.exports = factory(global, global.document);
} else {
// Browser environment
global.Notify = factory(global, global.document);
}
} (typeof window !== 'undefined' ? window : this, function (w, d) {
'use strict';
function isFunction (item) {
return typeof item === 'function';
}
function Notify(title, options) {
if (typeof title !== 'string') {
throw new Error('Notify(): first arg (title) must be a string.');
}
this.title = title;
this.options = {
icon: '',
body: '',
tag: '',
notifyShow: null,
notifyClose: null,
notifyClick: null,
notifyError: null,
permissionGranted: null,
permissionDenied: null,
timeout: null
};
this.permission = null;
if (!Notify.isSupported) {
return;
}
//User defined options for notification content
if (typeof options === 'object') {
for (var i in options) {
if (options.hasOwnProperty(i)) {
this.options[i] = options[i];
}
}
//callback when notification is displayed
if (isFunction(this.options.notifyShow)) {
this.onShowCallback = this.options.notifyShow;
}
//callback when notification is closed
if (isFunction(this.options.notifyClose)) {
this.onCloseCallback = this.options.notifyClose;
}
//callback when notification is clicked
if (isFunction(this.options.notifyClick)) {
this.onClickCallback = this.options.notifyClick;
}
//callback when notification throws error
if (isFunction(this.options.notifyError)) {
this.onErrorCallback = this.options.notifyError;
}
}
}
// true if the browser supports HTML5 Notification
Notify.isSupported = 'Notification' in w;
// true if the permission is not granted
Notify.needsPermission = !(Notify.isSupported && Notification.permission === 'granted');
// returns current permission level ('granted', 'default', 'denied' or null)
Notify.permissionLevel = (Notify.isSupported ? Notification.permission : null);
// asks the user for permission to display notifications. Then calls the callback functions is supplied.
Notify.requestPermission = function (onPermissionGrantedCallback, onPermissionDeniedCallback) {
if (!Notify.isSupported) {
return;
}
w.Notification.requestPermission(function (perm) {
switch (perm) {
case 'granted':
Notify.needsPermission = false;
if (isFunction(onPermissionGrantedCallback)) {
onPermissionGrantedCallback();
}
break;
case 'denied':
if (isFunction(onPermissionDeniedCallback)) {
onPermissionDeniedCallback();
}
break;
}
});
};
Notify.prototype.show = function () {
if (!Notify.isSupported) {
return;
}
this.myNotify = new Notification(this.title, {
'body': this.options.body,
'tag' : this.options.tag,
'icon' : this.options.icon
});
if (this.options.timeout && !isNaN(this.options.timeout)) {
setTimeout(this.close.bind(this), this.options.timeout * 1000);
}
this.myNotify.addEventListener('show', this, false);
this.myNotify.addEventListener('error', this, false);
this.myNotify.addEventListener('close', this, false);
this.myNotify.addEventListener('click', this, false);
};
Notify.prototype.onShowNotification = function (e) {
if (this.onShowCallback) {
this.onShowCallback(e);
}
};
Notify.prototype.onCloseNotification = function (e) {
if (this.onCloseCallback) {
this.onCloseCallback(e);
}
this.destroy();
};
Notify.prototype.onClickNotification = function (e) {
if (this.onClickCallback) {
this.onClickCallback(e);
}
};
Notify.prototype.onErrorNotification = function (e) {
if (this.onErrorCallback) {
this.onErrorCallback(e);
}
this.destroy();
};
Notify.prototype.destroy = function () {
this.myNotify.removeEventListener('show', this, false);
this.myNotify.removeEventListener('error', this, false);
this.myNotify.removeEventListener('close', this, false);
this.myNotify.removeEventListener('click', this, false);
};
Notify.prototype.close = function () {
this.myNotify.close();
};
Notify.prototype.handleEvent = function (e) {
switch (e.type) {
case 'show':
this.onShowNotification(e);
break;
case 'close':
this.onCloseNotification(e);
break;
case 'click':
this.onClickNotification(e);
break;
case 'error':
this.onErrorNotification(e);
break;
}
};
return Notify;
}));

19
js/options.js

@ -2,6 +2,8 @@ $(function() {
}); });
var _desktopNotificationTimeout = 4; // it should be an option
var TwisterOptions = function() var TwisterOptions = function()
{ {
this.getOption = function(optionName, defaultValue) { this.getOption = function(optionName, defaultValue) {
@ -88,6 +90,20 @@ var TwisterOptions = function()
player[0].play(); player[0].play();
} }
this.notificationDesktopTest = function() {
$('#notifications-desktop-test').on('click', function(){
var desktopNotification = new Notify(polyglot.t('notify_desktop_title'), {
body: polyglot.t('notify_desktop_test'),
icon: '../img/twister_mini.png',
tag: 'twister_notification_test',
timeout: _desktopNotificationTimeout,
notifyError: function() { alert(polyglot.t('notify_desktop_error')); },
permissionDenied: function() { alert(polyglot.t('notify_desktop_perm_denied')); }
});
desktopNotification.show();
})
}
this.keysSendDefault = "ctrlenter"; this.keysSendDefault = "ctrlenter";
this.keysSend = function() { this.keysSend = function() {
$('#keysOpt select')[0].value = $.Options.getOption('keysSend',this.keysSendDefault); $('#keysOpt select')[0].value = $.Options.getOption('keysSend',this.keysSendDefault);
@ -338,6 +354,7 @@ var TwisterOptions = function()
this.InitOptions = function() { this.InitOptions = function() {
this.soundNotifOptions(); this.soundNotifOptions();
this.volumeControl(); this.volumeControl();
this.notificationDesktopTest();
this.keysSend(); this.keysSend();
this.setLang(); this.setLang();
this.setTheme(); this.setTheme();
@ -365,7 +382,7 @@ function localizeLabels()
{ {
$("label[for=tab_language]").text(polyglot.t("Language")); $("label[for=tab_language]").text(polyglot.t("Language"));
$("label[for=t-2]").text(polyglot.t("Theme")); $("label[for=t-2]").text(polyglot.t("Theme"));
$("label[for=t-3]").text(polyglot.t("Sound")); $("label[for=t-3]").text(polyglot.t("Notifications"));
$("label[for=t-4]").text(polyglot.t("Keys")); $("label[for=t-4]").text(polyglot.t("Keys"));
$("label[for=t-5]").text(polyglot.t("Postboard")); $("label[for=t-5]").text(polyglot.t("Postboard"));
$("label[for=t-6]").text(polyglot.t("Users")); $("label[for=t-6]").text(polyglot.t("Users"));

2
js/twister_actions.js

@ -14,6 +14,7 @@ var maxExpandPost = 8;
var maxExpandPostTop = 4; var maxExpandPostTop = 4;
var _hashtagProcessedMap = {}; var _hashtagProcessedMap = {};
var _hashtagPendingPosts = []; var _hashtagPendingPosts = [];
var _hashtagPendingPostsUpdated = 0;
var autoUpdateHashtag = false; var autoUpdateHashtag = false;
// ---------------- // ----------------
@ -335,6 +336,7 @@ function processHashtag(postboard, hashtag, data) {
if( !(key in _hashtagProcessedMap) ) { if( !(key in _hashtagProcessedMap) ) {
_hashtagProcessedMap[key] = true; _hashtagProcessedMap[key] = true;
_hashtagPendingPosts.push(data[i]); _hashtagPendingPosts.push(data[i]);
_hashtagPendingPostsUpdated++;
} }
} }

49
js/twister_newmsgs.js

@ -11,6 +11,8 @@ var _lastMentionTime = 0;
var _newMentions = 0; var _newMentions = 0;
var _lastLocalMentionId = -1; var _lastLocalMentionId = -1;
var PURGE_OLD_MENTIONS_TIMEOUT = 3600 * 24 * 30; // one month var PURGE_OLD_MENTIONS_TIMEOUT = 3600 * 24 * 30; // one month
var _newMentionsUpdated = false;
var _newDMsUpdated = false;
// process a mention received to check if it is really new // process a mention received to check if it is really new
function processMention(user, mentionTime, data) { function processMention(user, mentionTime, data) {
@ -19,12 +21,11 @@ function processMention(user, mentionTime, data) {
if( mentionTime > curTime + 3600 * 2 ) { if( mentionTime > curTime + 3600 * 2 ) {
console.log("mention from the future will be ignored"); console.log("mention from the future will be ignored");
} else { } else {
var newMentionsUpdated = false;
if( !(key in _knownMentions) ) { if( !(key in _knownMentions) ) {
// mention must be somewhat recent compared to last known one to be considered new // mention must be somewhat recent compared to last known one to be considered new
if( mentionTime + 3600 * 24 * 3 > _lastMentionTime ) { if( mentionTime + 3600 * 24 * 3 > _lastMentionTime ) {
_newMentions++; _newMentions++;
newMentionsUpdated = true; _newMentionsUpdated = true;
_lastMentionTime = Math.max(mentionTime,_lastMentionTime); _lastMentionTime = Math.max(mentionTime,_lastMentionTime);
data["isNew"] = true; data["isNew"] = true;
} }
@ -32,9 +33,6 @@ function processMention(user, mentionTime, data) {
purgeOldMentions(); purgeOldMentions();
saveMentionsToStorage(); saveMentionsToStorage();
} }
if( newMentionsUpdated ) {
$.MAL.soundNotifyMentions();
}
} }
} }
@ -96,6 +94,40 @@ function requestMentionsCount() {
} }
}, {}, }, {},
[10000,2000,3]); // use extended timeout parameters (requires twister_core >= 0.9.14) [10000,2000,3]); // use extended timeout parameters (requires twister_core >= 0.9.14)
if( _newMentionsUpdated ) {
_newMentionsUpdated = false;
$.MAL.soundNotifyMentions();
var desktopNotification = new Notify(polyglot.t('notify_desktop_title'), {
body: 'You got '+polyglot.t('new_mentions', _newMentions)+'.',
icon: '../img/twister_mini.png',
tag: 'twister_notification_new_mentions',
timeout: _desktopNotificationTimeout,
notifyClick: openMentionsModal
});
desktopNotification.show();
}
// was moved here from requestDMsCount() because that is not ticking right
// we would place it with other notifications into separate notification center
if( _newDMsUpdated ) {
_newDMsUpdated = false;
$.MAL.soundNotifyDM();
var desktopNotification = new Notify(polyglot.t('notify_desktop_title'), {
body: 'You got '+polyglot.t('new_direct_messages', getNewDMsCount())+'.',
icon: '../img/twister_mini.png',
tag: 'twister_notification_new_DMs',
timeout: _desktopNotificationTimeout,
notifyClick: function() {
window.location.hash = '#directmessages';
}
});
desktopNotification.show();
}
} }
function resetMentionsCount() { function resetMentionsCount() {
@ -154,23 +186,22 @@ function requestDMsCount() {
twisterRpc("getdirectmsgs", [defaultScreenName, 1, followList], twisterRpc("getdirectmsgs", [defaultScreenName, 1, followList],
function(req, dmUsers) { function(req, dmUsers) {
var updated = false;
for( var u in dmUsers ) { for( var u in dmUsers ) {
if( dmUsers.hasOwnProperty(u) ) { if( dmUsers.hasOwnProperty(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]);
updated = true; _newDMsUpdated = true;
} }
} else { } else {
_newDMsPerUser[u] = dmData.id+1; _newDMsPerUser[u] = dmData.id+1;
updated = true; _newDMsUpdated = true;
} }
_lastDMIdPerUser[u] = dmData.id; _lastDMIdPerUser[u] = dmData.id;
} }
} }
if( updated ) { if( _newDMsUpdated ) {
saveDMsToStorage(); saveDMsToStorage();
$.MAL.updateNewDMsUI(getNewDMsCount()); $.MAL.updateNewDMsUI(getNewDMsCount());
} }

1
login.html

@ -10,6 +10,7 @@
<script src="js/jquery.jsonrpcclient.js"></script> <script src="js/jquery.jsonrpcclient.js"></script>
<script src="js/jquery.storageapi.js"></script> <script src="js/jquery.storageapi.js"></script>
<script src="js/options.js"></script> <script src="js/options.js"></script>
<script src="js/notify.js"></script>
<script src="js/mobile_abstract.js"></script> <script src="js/mobile_abstract.js"></script>
<script src="js/twister_io.js"></script> <script src="js/twister_io.js"></script>
<script src="js/twister_network.js"></script> <script src="js/twister_network.js"></script>

1
network.html

@ -10,6 +10,7 @@
<script src="js/jquery.jsonrpcclient.js"></script> <script src="js/jquery.jsonrpcclient.js"></script>
<script src="js/jquery.storageapi.js"></script> <script src="js/jquery.storageapi.js"></script>
<script src="js/options.js"></script> <script src="js/options.js"></script>
<script src="js/notify.js"></script>
<script src="js/mobile_abstract.js"></script> <script src="js/mobile_abstract.js"></script>
<script src="js/twister_io.js"></script> <script src="js/twister_io.js"></script>
<script src="js/twister_user.js"></script> <script src="js/twister_user.js"></script>

13
options.html

@ -10,6 +10,7 @@
<script src="js/jquery.jsonrpcclient.js"></script> <script src="js/jquery.jsonrpcclient.js"></script>
<script src="js/jquery.storageapi.js"></script> <script src="js/jquery.storageapi.js"></script>
<script src="js/options.js"></script> <script src="js/options.js"></script>
<script src="js/notify.js"></script>
<script src="js/mobile_abstract.js"></script> <script src="js/mobile_abstract.js"></script>
<script src="js/twister_io.js"></script> <script src="js/twister_io.js"></script>
<script src="js/twister_network.js"></script> <script src="js/twister_network.js"></script>
@ -18,6 +19,7 @@
<script src="js/interface_login.js"></script> <script src="js/interface_login.js"></script>
<script src="js/polyglot.min.js"></script> <script src="js/polyglot.min.js"></script>
<script src="js/interface_localization.js"></script> <script src="js/interface_localization.js"></script>
<script>$(function(){ <script>$(function(){
initInterfaceCommon(); initInterfaceCommon();
$.Options.InitOptions();}) $.Options.InitOptions();})
@ -54,7 +56,7 @@
<input id="t-2" name="option_tab" type="radio" class="selectable_theme theme_nin"/> <input id="t-2" name="option_tab" type="radio" class="selectable_theme theme_nin"/>
<label for="t-2" class="tabs selectable_theme theme_nin">Theme</label> <label for="t-2" class="tabs selectable_theme theme_nin">Theme</label>
<input id="t-3" name="option_tab" type="radio" class="selectable_theme theme_nin"/> <input id="t-3" name="option_tab" type="radio" class="selectable_theme theme_nin"/>
<label for="t-3" class="tabs selectable_theme theme_nin">Sound</label> <label for="t-3" class="tabs selectable_theme theme_nin">Notifications</label>
<input id="t-4" name="option_tab" type="radio" class="selectable_theme theme_nin"/> <input id="t-4" name="option_tab" type="radio" class="selectable_theme theme_nin"/>
<label for="t-4" class="tabs selectable_theme theme_nin">Keys</label> <label for="t-4" class="tabs selectable_theme theme_nin">Keys</label>
<input id="t-5" name="option_tab" type="radio" class="selectable_theme theme_nin"/> <input id="t-5" name="option_tab" type="radio" class="selectable_theme theme_nin"/>
@ -108,8 +110,7 @@
</div> </div>
</div> </div>
<div class="sounds"> <div class="notifications">
<div class="module"> <div class="module">
<p class="label"> Sound notifications </p> <p class="label"> Sound notifications </p>
<div> <div>
@ -141,6 +142,12 @@
<audio id="player"></audio> <audio id="player"></audio>
</div> </div>
</div> </div>
<div class="module">
<p class="label"> Desktop notifications </p>
<div>
<button id="notifications-desktop-test">Test</button>
</div>
</div>
</div> </div>
<div class="keys"> <div class="keys">

1
profile-edit.html

@ -10,6 +10,7 @@
<script src="js/jquery.jsonrpcclient.js"></script> <script src="js/jquery.jsonrpcclient.js"></script>
<script src="js/jquery.storageapi.js"></script> <script src="js/jquery.storageapi.js"></script>
<script src="js/options.js"></script> <script src="js/options.js"></script>
<script src="js/notify.js"></script>
<script src="js/mobile_abstract.js"></script> <script src="js/mobile_abstract.js"></script>
<script src="js/twister_io.js"></script> <script src="js/twister_io.js"></script>
<script src="js/polyglot.min.js"></script> <script src="js/polyglot.min.js"></script>

2
theme_nin/css/style.css

@ -1704,7 +1704,7 @@ button.disabled:hover, .mini-profile-actions span.disabled:hover, a.button.disab
visibility: hidden; visibility: hidden;
} }
/* line 39, ../sass/_tabs.sass */ /* line 39, ../sass/_tabs.sass */
.options input#tab_language:checked ~ .tab-content .language, .options input#t-2:checked ~ .tab-content .theme, .options input#t-3:checked ~ .tab-content .sounds, .options input#t-4:checked ~ .tab-content .keys, .options input#t-5:checked ~ .tab-content .postboard-display, .options input#t-6:checked ~ .tab-content .users { .options input#tab_language:checked ~ .tab-content .language, .options input#t-2:checked ~ .tab-content .theme, .options input#t-3:checked ~ .tab-content .notifications, .options input#t-4:checked ~ .tab-content .keys, .options input#t-5:checked ~ .tab-content .postboard-display, .options input#t-6:checked ~ .tab-content .users {
position: relative; position: relative;
z-index: 10; z-index: 10;
opacity: 1; opacity: 1;

2
theme_nin/sass/_tabs.sass

@ -38,7 +38,7 @@
input input
&#tab_language:checked ~ .tab-content .language, &#tab_language:checked ~ .tab-content .language,
&#t-2:checked ~ .tab-content .theme, &#t-2:checked ~ .tab-content .theme,
&#t-3:checked ~ .tab-content .sounds, &#t-3:checked ~ .tab-content .notifications,
&#t-4:checked ~ .tab-content .keys, &#t-4:checked ~ .tab-content .keys,
&#t-5:checked ~ .tab-content .postboard-display, &#t-5:checked ~ .tab-content .postboard-display,
&#t-6:checked ~ .tab-content .users &#t-6:checked ~ .tab-content .users

Loading…
Cancel
Save