diff --git a/CTRLW.user.js b/CTRLW.user.js index ae3763c..d517a46 100644 --- a/CTRLW.user.js +++ b/CTRLW.user.js @@ -69,6 +69,7 @@ Main.k.domain = document.domain; Main.k.mushurl = 'http://' + document.domain; Main.k.debug = true; Main.k.errorList = []; +Main.k.windowFocus = true; if(Main.k.debug){ var console = unsafeWindow.console; }else{ @@ -403,6 +404,14 @@ Main.k.init = function(){ Main.k.Game.init(); Main.k.initData(); Main.k.displayMainMenu(); + + //Check if tab is focused + $( window ).focus(function() { + Main.k.windowFocus = true; + }).blur(function() { + Main.k.windowFocus = false; + }); + //Integration with others scripts $( window ).load(function() { @@ -412,6 +421,9 @@ Main.k.init = function(){ $(this).removeAttr('data-async_src'); }); + //Start notification check and reloads + Main.k.statusCheck(); + }); }; Main.k.getFullName = function(dev_surname) { @@ -427,6 +439,58 @@ Main.k.getHeroBySurname = function(dev_surname) { } return null; }; +Main.k.browserNotice = function(msg){ + + // Let's check if the browser supports notifications + if (!("Notification" in window)) { + Main.k.quickNoticeError("This browser does not support desktop notifications"); + } + + // Let's check if the user is okay to get some notification + else if (Notification.permission === "granted") { + // If it's okay let's create a notification + // If window currently in focus, don't notify + if ( Main.k.windowFocus ) return; + Main.k.browserNotify(msg); + } + + // Otherwise, we need to ask the user for permission + // Note, Chrome does not implement the permission static property + // So we have to check for NOT 'denied' instead of 'default' + else if (Notification.permission !== 'denied') { + Notification.requestPermission(function (permission) { + + // Whatever the user answers, we make sure we store the information + if(!('permission' in Notification)) { + Notification.permission = permission; + } + + // If the user is okay, let's create a notification + if (permission === "granted") { + // If window currently in focus, don't notify + if ( Main.k.windowFocus ) return; + Main.k.browserNotify(msg); + } + }); + } + + // At last, if the user already denied any notification, and you + // want to be respectful there is no need to bother him any more. +}; + +Main.k.browserNotify = function(msg) { + var options = { + body: msg, + icon: "/img/icons/ui/mush.png" + } + + var notification = new Notification("Mush", options); + notification.onclick = function() { + window.focus(); + this.close(); + } + +} Main.k.MakeButton = function(content, href, onclick, tiptitle, tipdesc) { var but = $("
").addClass("warning").text(Main.k.text.gettext("Plus d'options disponibles prochainement.")).appendTo(td);
- for (var i=0; i ").addClass("warning").text(Main.k.text.gettext("Plus d'options disponibles prochainement.")).appendTo(td);
- for (var i=0; i "+ Main.k.text.gettext("Vider le cache du script"), null, null, Main.k.text.gettext("Vider le cache du script"),
@@ -2115,18 +2277,20 @@ Main.k.Options.update = function(e) {
var tgt = $(e.target);
var key = $(tgt).attr("optname");
var val = $(tgt).is(":checked") ? "y" : "n";
- var i = $(tgt).attr("opti");
+ var optname = $(tgt).attr("optname");
Main.k.Options.updateOpt(key,val);
Main.k.Options.updateCookie();
- if (Main.k.Options.options[i][3]) Main.k.Options.options[i][3]();
+ if (!!Main.k.Options.options[optname].after) Main.k.Options.options[optname].after();
};
Main.k.Options.updateCookie = function() {
var cook = "";
- for (var i=0; i
"+ Main.k.text.gettext("Actualiser"), null, null, Main.k.text.gettext("Actualiser"),
Main.k.text.gettext("Actualiser la page sans tout recharger. Fonctionnalité en cours d'optimisation."))
- .appendTo(leftbar).find("a").on("mousedown", function() {
- // TODO: loading screen -- Optimize
-
- Main.refreshChat();
- Main.acListMaintainer.refresh(true);
- Main.syncInvOffset(null,true);
- Main.doChatPacks();
- Main.topChat();
- Main.onChanDone(ChatType.Local[1],true)
- });
+ .appendTo(leftbar).find("a").on("mousedown", Main.k.refreshAll);
Main.k.MakeButton(Main.k.text.gettext("Nouvelle partie ?"), null, null, Main.k.text.gettext("Nouvelle partie"),
Main.k.text.gettext("Vous venez de commencer une nouvelle partie ? Utilisez ce bouton pour supprimer les informations de votre ancienne partie"))
diff --git a/README.md b/README.md
index 2c2e507..dcb8ef6 100644
--- a/README.md
+++ b/README.md
@@ -8,19 +8,46 @@ Mush (Spanish) : http://mush.twinoid.es
Initially created by kill0u, now maintained by badconker.
-Download
+How to install
======
+
+CTRL+W works with Firefox(GreaseMonkey) or Chrome(TamperMonkey).
+
+ - In Firefox, install the [GreaseMonkey](https://addons.mozilla.org/firefox/addon/greasemonkey/) Add-On
+ - In Chrome, install the [TamperMonkey](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo) extension
+
+After you've added the script, you can install CTRL+W by opening one of the following files :
+
+Enjoy!
Translators
======
I you want to help me to translate the script in English and Spanish, you have only to edit the .po file in translations directory with .po editor (like poedit : http://www.poedit.net/)
-Thank you. :)
\ No newline at end of file
+Thank you. :)
+
+
+
+Developers
+======
+
+First make sure you have gulp installed - you can install it by running the following commands from the root directory ( provided you have `npm` installed )
+```
+npm install
+npm install gulp-cli -g
+```
+
+After making your changes in the `src` folder, build the latest CTRLW.user.js with :
+```
+gulp
+```
+
+Finally submit your PR requests to the `dev` branch.
\ No newline at end of file
diff --git a/ctrl-w.pot b/ctrl-w.pot
index d4e421f..033acee 100644
--- a/ctrl-w.pot
+++ b/ctrl-w.pot
@@ -1080,3 +1080,18 @@ msgstr ""
msgid "Canal privé"
msgstr ""
+
+msgid "You have %1 unread message"
+msgstr ""
+
+msgid "You have %1 unread messages"
+msgstr ""
+
+msgid "Cycle change about to happen"
+msgstr ""
+
+msgid "Cycle change just happened"
+msgstr ""
+
+msgid "Show browser notifications when tab is inactive."
+msgstr ""
\ No newline at end of file
diff --git a/src/globalVariable.js b/src/globalVariable.js
index 6e7d2bb..3918442 100644
--- a/src/globalVariable.js
+++ b/src/globalVariable.js
@@ -47,6 +47,7 @@ Main.k.domain = document.domain;
Main.k.mushurl = 'http://' + document.domain;
Main.k.debug = true;
Main.k.errorList = [];
+Main.k.windowFocus = true;
if(Main.k.debug){
var console = unsafeWindow.console;
}else{
diff --git a/src/main/BrowserNotice.js b/src/main/BrowserNotice.js
new file mode 100644
index 0000000..8545f8b
--- /dev/null
+++ b/src/main/BrowserNotice.js
@@ -0,0 +1,52 @@
+Main.k.browserNotice = function(msg){
+
+ // Let's check if the browser supports notifications
+ if (!("Notification" in window)) {
+ Main.k.quickNoticeError("This browser does not support desktop notifications");
+ }
+
+ // Let's check if the user is okay to get some notification
+ else if (Notification.permission === "granted") {
+ // If it's okay let's create a notification
+ // If window currently in focus, don't notify
+ if ( Main.k.windowFocus ) return;
+ Main.k.browserNotify(msg);
+ }
+
+ // Otherwise, we need to ask the user for permission
+ // Note, Chrome does not implement the permission static property
+ // So we have to check for NOT 'denied' instead of 'default'
+ else if (Notification.permission !== 'denied') {
+ Notification.requestPermission(function (permission) {
+
+ // Whatever the user answers, we make sure we store the information
+ if(!('permission' in Notification)) {
+ Notification.permission = permission;
+ }
+
+ // If the user is okay, let's create a notification
+ if (permission === "granted") {
+ // If window currently in focus, don't notify
+ if ( Main.k.windowFocus ) return;
+ Main.k.browserNotify(msg);
+ }
+ });
+ }
+
+ // At last, if the user already denied any notification, and you
+ // want to be respectful there is no need to bother him any more.
+};
+
+Main.k.browserNotify = function(msg) {
+ var options = {
+ body: msg,
+ icon: "/img/icons/ui/mush.png"
+ }
+
+ var notification = new Notification("Mush", options);
+ notification.onclick = function() {
+ window.focus();
+ this.close();
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/Refresh.js b/src/main/Refresh.js
new file mode 100644
index 0000000..d543b1a
--- /dev/null
+++ b/src/main/Refresh.js
@@ -0,0 +1,10 @@
+Main.k.refreshAll = function() {
+ // TODO: loading screen -- Optimize
+
+ Main.refreshChat();
+ Main.acListMaintainer.refresh(true);
+ Main.syncInvOffset(null,true);
+ Main.doChatPacks();
+ Main.topChat();
+ Main.onChanDone(ChatType.Local[1],true)
+}
\ No newline at end of file
diff --git a/src/main/StatusCheck.js b/src/main/StatusCheck.js
new file mode 100644
index 0000000..0e49628
--- /dev/null
+++ b/src/main/StatusCheck.js
@@ -0,0 +1,45 @@
+Main.k.statusCheck = function(){
+
+ if (!!Main.k.statusTimeout) clearTimeout(Main.k.statusTimeout);
+ if (!Main.k.Options.browserNot) return;
+
+ Main.k.refreshAll();
+
+ var _now = new Date();
+ var _elapsed = _now.getTime() - Main.tData.clientNow.getTime();
+ var _timeToGo = (Main.tData.timeToCycle - _elapsed) / 1000.0 | 0;
+
+ var _diffHI = parseInt(_timeToGo / 3600.0 | 0);
+ var _diffMI = parseInt(Math.abs(_timeToGo / 60.0 % 60.0));
+ var _diffSI = parseInt(Math.abs(_timeToGo % 60));
+
+ var _unreads = 0;
+
+ $('.cdNbNotRead').each(function(i, notReadEl ) {
+ _unreads += parseInt( $( notReadEl ).text() );
+ });
+
+ if(_unreads > 0) {
+ var _unreadMSG = Main.k.text.strargs(Main.k.text.ngettext("You have %1 unread message","You have %1 unread messages",_unreads),[_unreads]);
+ Main.k.browserNotice(_unreadMSG);
+ }
+
+ if(_diffHI == 0 && _diffMI < 3) {
+ Main.k.browserNotice(Main.k.text.gettext('Cycle change about to happen'));
+ }
+
+ if(_diffHI == 2 && _diffMI > 55) {
+ Main.k.browserNotice(Main.k.text.gettext('Cycle change just happened'));
+ }
+
+ // TODO : Make this configurable?
+ // TODO : Increase timer if long time in inactive tab
+
+ // Check every minute
+ var _timeout = 60000;
+ // If in hidden tab, check every 5 minutes
+ if(!Main.k.windowFocus) _timeout = 300000;
+
+ Main.k.statusTimeout = setTimeout(Main.k.statusCheck, _timeout);
+
+}
\ No newline at end of file
diff --git a/src/main/init.js b/src/main/init.js
index eb4924b..64cd5a7 100644
--- a/src/main/init.js
+++ b/src/main/init.js
@@ -5,6 +5,14 @@ Main.k.init = function(){
Main.k.Game.init();
Main.k.initData();
Main.k.displayMainMenu();
+
+ //Check if tab is focused
+ $( window ).focus(function() {
+ Main.k.windowFocus = true;
+ }).blur(function() {
+ Main.k.windowFocus = false;
+ });
+
//Integration with others scripts
$( window ).load(function() {
@@ -14,6 +22,9 @@ Main.k.init = function(){
$(this).removeAttr('data-async_src');
});
+ //Start notification check and reloads
+ Main.k.statusCheck();
+
});
};
Main.k.getFullName = function(dev_surname) {
diff --git a/src/main/options/init.js b/src/main/options/init.js
index f914db2..b9e4fe7 100644
--- a/src/main/options/init.js
+++ b/src/main/options/init.js
@@ -1,12 +1,55 @@
Main.k.Options.init = function() {
- Main.k.Options.options = [
- // Option Name, Option Object, Need refresh, After(), Desc
- ["cbubbles", Main.k.Options.cbubbles, false, Main.k.customBubbles, Main.k.text.gettext("Activer la mise en forme personnalisée des messages (bordure + couleur nom + image de fond).")],
- ["cbubblesNB", Main.k.Options.cbubblesNB, false, Main.k.customBubbles, Main.k.text.gettext("Simplifier la mise en forme personnalisée des messages (suppression de l'image de fond).")],
- ["dlogo", Main.k.Options.dlogo, true, null, Main.k.text.gettext("Afficher le logo Mush au dessus des onglets.")],
- ["splitpjt", Main.k.Options.splitpjt, false, Main.k.updateBottom, Main.k.text.gettext("Séparer les projets / recherches / pilgred sous la zone de jeu.")]
- //["altpa", Main.k.Options.altpa, true, null, "Utiliser des images alternatives pour les pa / pm."]
- ];
+
+ Main.k.Options.options = {};
+
+ /**
+
+ Option format :
+
+ Main.k.Options.options.OPTIONNAME = {
+ option: Main.k.Options.OPTIONNAME, // Option value to change
+ text: Main.k.text.gettext("description"), // Description text
+ after: callback, // (Optional) After option changed, call this function
+ refresh: true, // (Optional) Page refresh needed after option change?
+ };
+
+ */
+
+ Main.k.Options.options.cbubbles = {
+ option: Main.k.Options.cbubbles,
+ after: Main.k.customBubbles,
+ text: Main.k.text.gettext("Activer la mise en forme personnalisée des messages (bordure + couleur nom + image de fond)."),
+ };
+
+ Main.k.Options.options.cbubblesNB = {
+ option: Main.k.Options.cbubblesNB,
+ after: Main.k.customBubbles,
+ text: Main.k.text.gettext("Simplifier la mise en forme personnalisée des messages (suppression de l'image de fond)."),
+ };
+
+ Main.k.Options.options.dlogo = {
+ option: Main.k.Options.dlogo,
+ refresh: true,
+ text: Main.k.text.gettext("Afficher le logo Mush au dessus des onglets."),
+ };
+
+ Main.k.Options.options.splitpjt = {
+ option: Main.k.Options.splitpjt,
+ after: Main.k.updateBottom,
+ text: Main.k.text.gettext("Séparer les projets / recherches / pilgred sous la zone de jeu."),
+ };
+
+ // Main.k.Options.options.altpa = {
+ // option: Main.k.Options.altpa,
+ // refresh: true,
+ // text: "Utiliser des images alternatives pour les pa / pm."
+ // };
+
+ Main.k.Options.options.browserNot = {
+ option: Main.k.Options.browserNot,
+ after: Main.k.statusCheck,
+ text: Main.k.text.gettext("Show browser notifications when tab is inactive.")
+ };
var cook = js.Cookie.get("ctrlwoptions");
if (!cook) return;
diff --git a/src/main/options/initData.js b/src/main/options/initData.js
index 6274334..6823c3e 100644
--- a/src/main/options/initData.js
+++ b/src/main/options/initData.js
@@ -9,4 +9,5 @@ Main.k.Options.dlogo = false;
Main.k.Options.splitpjt = true;
Main.k.Options.altpa = false;
Main.k.Options.mushNoConf = false;
-Main.k.Options.options = [];
+Main.k.Options.browserNot = true;
+Main.k.Options.options = {};
diff --git a/src/main/options/open.js b/src/main/options/open.js
index 986eab3..a1ff14d 100644
--- a/src/main/options/open.js
+++ b/src/main/options/open.js
@@ -17,10 +17,10 @@ Main.k.Options.open = function() {
$(" "+ Main.k.text.gettext("Vider le cache du script"), null, null, Main.k.text.gettext("Vider le cache du script"),
diff --git a/src/main/options/update.js b/src/main/options/update.js
index 07c1a4e..90b92f1 100644
--- a/src/main/options/update.js
+++ b/src/main/options/update.js
@@ -2,9 +2,9 @@ Main.k.Options.update = function(e) {
var tgt = $(e.target);
var key = $(tgt).attr("optname");
var val = $(tgt).is(":checked") ? "y" : "n";
- var i = $(tgt).attr("opti");
+ var optname = $(tgt).attr("optname");
Main.k.Options.updateOpt(key,val);
Main.k.Options.updateCookie();
- if (Main.k.Options.options[i][3]) Main.k.Options.options[i][3]();
+ if (!!Main.k.Options.options[optname].after) Main.k.Options.options[optname].after();
};
\ No newline at end of file
diff --git a/src/main/options/updateCookie.js b/src/main/options/updateCookie.js
index 597e2d3..1dbde25 100644
--- a/src/main/options/updateCookie.js
+++ b/src/main/options/updateCookie.js
@@ -1,9 +1,11 @@
Main.k.Options.updateCookie = function() {
var cook = "";
- for (var i=0; i
"+ Main.k.text.gettext("Actualiser"), null, null, Main.k.text.gettext("Actualiser"),
Main.k.text.gettext("Actualiser la page sans tout recharger. Fonctionnalité en cours d'optimisation."))
- .appendTo(leftbar).find("a").on("mousedown", function() {
- // TODO: loading screen -- Optimize
-
- Main.refreshChat();
- Main.acListMaintainer.refresh(true);
- Main.syncInvOffset(null,true);
- Main.doChatPacks();
- Main.topChat();
- Main.onChanDone(ChatType.Local[1],true)
- });
+ .appendTo(leftbar).find("a").on("mousedown", Main.k.refreshAll);
Main.k.MakeButton(Main.k.text.gettext("Nouvelle partie ?"), null, null, Main.k.text.gettext("Nouvelle partie"),
Main.k.text.gettext("Vous venez de commencer une nouvelle partie ? Utilisez ce bouton pour supprimer les informations de votre ancienne partie"))
diff --git a/translations/en/LC_MESSAGES/ctrl-w.po b/translations/en/LC_MESSAGES/ctrl-w.po
index 593a863..bc0fbaf 100644
--- a/translations/en/LC_MESSAGES/ctrl-w.po
+++ b/translations/en/LC_MESSAGES/ctrl-w.po
@@ -1128,3 +1128,18 @@ msgstr "connected"
msgid "Canal privé"
msgstr "Private channel"
+
+msgid "You have %1 unread message"
+msgstr "You have %1 unread message"
+
+msgid "You have %1 unread messages"
+msgstr "You have %1 unread messages"
+
+msgid "Cycle change about to happen"
+msgstr "Cycle change about to happen"
+
+msgid "Cycle change just happened"
+msgstr "Cycle change just happened"
+
+msgid "Show browser notifications when tab is inactive."
+msgstr "Show browser notifications when tab is inactive."
\ No newline at end of file
diff --git a/translations/es/LC_MESSAGES/ctrl-w.po b/translations/es/LC_MESSAGES/ctrl-w.po
index dc4e517..dbbe1d9 100644
--- a/translations/es/LC_MESSAGES/ctrl-w.po
+++ b/translations/es/LC_MESSAGES/ctrl-w.po
@@ -1097,6 +1097,21 @@ msgstr "conectado(a)"
msgid "Canal privé"
msgstr "Canal privado"
+msgid "You have %1 unread message"
+msgstr ""
+
+msgid "You have %1 unread messages"
+msgstr ""
+
+msgid "Cycle change about to happen"
+msgstr ""
+
+msgid "Cycle change just happened"
+msgstr ""
+
+msgid "Show browser notifications when tab is inactive."
+msgstr ""
+
#~ msgid "Description inactif"
#~ msgstr "Si tus barras de
están llenas, eres considerado como inactivo y te vuelves un blanco fácil. No queremos imaginar lo que pasará..."
diff --git a/translations/fr/LC_MESSAGES/ctrl-w.po b/translations/fr/LC_MESSAGES/ctrl-w.po
index 9cab3ed..8cc17ce 100644
--- a/translations/fr/LC_MESSAGES/ctrl-w.po
+++ b/translations/fr/LC_MESSAGES/ctrl-w.po
@@ -1079,3 +1079,18 @@ msgstr ""
msgid "Canal privé"
msgstr ""
+
+msgid "You have %1 unread message"
+msgstr ""
+
+msgid "You have %1 unread messages"
+msgstr ""
+
+msgid "Cycle change about to happen"
+msgstr ""
+
+msgid "Cycle change just happened"
+msgstr ""
+
+msgid "Show browser notifications when tab is inactive."
+msgstr ""
\ No newline at end of file