From 005ac589cca2b385ccab9f453f9bb488c7fbb943 Mon Sep 17 00:00:00 2001
From: Jorys_Paulin
Date: Thu, 14 Jun 2018 13:14:15 +0200
Subject: [PATCH 01/14] Rewired bitrate logic to only one function
---
static/js/index.js | 48 ++++++++++++++++++++++++++--------------------
1 file changed, 27 insertions(+), 21 deletions(-)
diff --git a/static/js/index.js b/static/js/index.js
index 6d6c649b..0a5d3d09 100644
--- a/static/js/index.js
+++ b/static/js/index.js
@@ -12,8 +12,7 @@ function attachListeners() {
$('.resolutionMenu li').on('click', saveResolution);
$('.framerateMenu li').on('click', saveFramerate);
- $('#bitrateSlider').on('input', updateBitrateField); // input occurs every notch you slide
- //$('#bitrateSlider').on('change', saveBitrate); //FIXME: it seems not working
+ $('#bitrateSlider').on('input', e => changeBitrate(e.target.value)); // input occurs every notch you slide
$("#remoteAudioEnabledSwitch").on('click', saveRemoteAudio);
$('#optimizeGamesSwitch').on('click', saveOptimize);
$('#addHostCell').on('click', addHost);
@@ -65,6 +64,25 @@ function onBoundsChanged() {
}
}
+/**
+ * changeBitrate - Changes the bitrate value
+ *
+ * @param {Number} value The bitrate value
+ * @return {Number} The bitrate value
+ */
+function changeBitrate(value) {
+ // First, change UI
+ var slider = document.querySelector('#bitrateSlider')
+ slider.MaterialSlider.change(value)
+ var field = document.querySelector('#bitrateField')
+ field.innerText = value + "Mbps"
+ // Second, save to storage
+ storeData('bitrate', value, null)
+ window.currentBitrate = value; // DEBUG: This is meant for debugging
+ // Third, return value
+ return value
+}
+
function changeUiModeForNaClLoad() {
$('#main-navigation').children().hide();
$("#main-content").children().not("#listener, #naclSpinner").hide();
@@ -183,11 +201,6 @@ function snackbarLogLong(givenMessage) {
document.querySelector('#snackbar').MaterialSnackbar.showSnackbar(data);
}
-function updateBitrateField() {
- $('#bitrateField').html($('#bitrateSlider').val() + " Mbps");
- saveBitrate();
-}
-
function moduleDidLoad() {
// load the HTTP cert and unique ID if we have one.
chrome.storage.sync.get('cert', function(savedCert) {
@@ -857,10 +870,6 @@ function saveHosts() {
storeData('hosts', hosts, null);
}
-function saveBitrate() {
- storeData('bitrate', $('#bitrateSlider').val(), null);
-}
-
function saveRemoteAudio() {
// MaterialDesignLight uses the mouseup trigger, so we give it some time to change the class name before
// checking the new state
@@ -877,28 +886,25 @@ function updateDefaultBitrate() {
if (res === "1920:1080") {
if (frameRate === "30") { // 1080p, 30fps
- $('#bitrateSlider')[0].MaterialSlider.change('10');
+ changeBitrate(10)
} else { // 1080p, 60fps
- $('#bitrateSlider')[0].MaterialSlider.change('20');
+ changeBitrate(20)
}
} else if (res === "1280:720") {
if (frameRate === "30") { // 720, 30fps
- $('#bitrateSlider')[0].MaterialSlider.change('5');
+ changeBitrate(5)
} else { // 720, 60fps
- $('#bitrateSlider')[0].MaterialSlider.change('10');
+ changeBitrate(10)
}
} else if (res === "3840:2160") {
if (frameRate === "30") { // 2160p, 30fps
- $('#bitrateSlider')[0].MaterialSlider.change('40');
+ changeBitrate(40)
} else { // 2160p, 60fps
- $('#bitrateSlider')[0].MaterialSlider.change('80');
+ changeBitrate(80)
}
} else { // unrecognized option. In case someone screws with the JS to add custom resolutions
- $('#bitrateSlider')[0].MaterialSlider.change('10');
+ changeBitrate(10)
}
-
- updateBitrateField();
- saveBitrate();
}
function onWindowLoad() {
From c851c3eb41863f6f5289f8d8c31de853821024d5 Mon Sep 17 00:00:00 2001
From: Jorys_Paulin
Date: Thu, 14 Jun 2018 13:28:02 +0200
Subject: [PATCH 02/14] Added input to better finetune bitrate
---
index.html | 1 +
static/css/style.css | 9 ++++++++-
static/js/index.js | 7 +++++--
3 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/index.html b/index.html
index abe56317..d437e8d1 100644
--- a/index.html
+++ b/index.html
@@ -62,6 +62,7 @@
+
diff --git a/static/css/style.css b/static/css/style.css
index 387a5082..7b79f743 100644
--- a/static/css/style.css
+++ b/static/css/style.css
@@ -91,7 +91,13 @@ main {
text-transform: none;
}
.bitrateMenu {
- width: 170px;
+ width: auto;
+ display: flex;
+ align-items: center;
+ padding: 8px;
+}
+#bitrateInput {
+ width: 50%;
}
.mdl-button {
@@ -128,6 +134,7 @@ main {
}
.mdl-textfield__input {
border-bottom: 1px solid rgba(255, 255, 255, 0.90);
+ width: 25%;
}
.mdl-textfield__label {
color: rgba(255, 255, 255, 0.90);
diff --git a/static/js/index.js b/static/js/index.js
index 0a5d3d09..5232948b 100644
--- a/static/js/index.js
+++ b/static/js/index.js
@@ -13,6 +13,7 @@ function attachListeners() {
$('.resolutionMenu li').on('click', saveResolution);
$('.framerateMenu li').on('click', saveFramerate);
$('#bitrateSlider').on('input', e => changeBitrate(e.target.value)); // input occurs every notch you slide
+ $('#bitrateInput').on('input', e => changeBitrate(e.target.value));
$("#remoteAudioEnabledSwitch").on('click', saveRemoteAudio);
$('#optimizeGamesSwitch').on('click', saveOptimize);
$('#addHostCell').on('click', addHost);
@@ -76,6 +77,8 @@ function changeBitrate(value) {
slider.MaterialSlider.change(value)
var field = document.querySelector('#bitrateField')
field.innerText = value + "Mbps"
+ var input = document.querySelector('#bitrateInput')
+ input.value = value;
// Second, save to storage
storeData('bitrate', value, null)
window.currentBitrate = value; // DEBUG: This is meant for debugging
@@ -961,8 +964,8 @@ function onWindowLoad() {
// load stored bitrate prefs
chrome.storage.sync.get('bitrate', function(previousValue) {
- $('#bitrateSlider')[0].MaterialSlider.change(previousValue.bitrate != null ? previousValue.bitrate : '10');
- updateBitrateField();
+ var value = previousValue.bitrate != null ? previousValue.bitrate : '10'
+ changeBitrate(value)
});
}
}
From 6b683d02de3f1dae5ec639a62f5c8bce12d3cf24 Mon Sep 17 00:00:00 2001
From: Jorys Paulin
Date: Sat, 21 Jul 2018 11:49:24 +0200
Subject: [PATCH 03/14] Added Resolution class
---
static/js/index.js | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/static/js/index.js b/static/js/index.js
index 5232948b..2c5994de 100644
--- a/static/js/index.js
+++ b/static/js/index.js
@@ -86,6 +86,51 @@ function changeBitrate(value) {
return value
}
+/**
+ * Resolution - Represents a resolution
+ */
+class Resolution {
+
+ /**
+ * constructor - Creates a new Resolution object
+ *
+ * @param {Number} width Resolution width
+ * @param {Number} height Resolution height
+ * @param {String} name Resolution name
+ * @return {Object} The corresponding object
+ */
+ constructor(width, height, name = null) {
+ this.width = width
+ this.height = height
+ if(name === null)
+ this.name = this.height + 'p'
+ else
+ this.name = name
+ }
+
+ /**
+ * getObject - Returns the corresponding object
+ *
+ * @return {type} description
+ */
+ getObject() {
+ return { width, height, name } = this
+ }
+
+ /**
+ * getChildren - Returns an item
+ *
+ * @return {HTMLElement} The chooser
+ */
+ getChildren() {
+ var child = document.createElement('li')
+ child.className = 'mdl-menu__item'
+ child.dataset.value = this.width + ':' + thids.height
+ child.innerText = this.name
+ return child
+ }
+}
+
function changeUiModeForNaClLoad() {
$('#main-navigation').children().hide();
$("#main-content").children().not("#listener, #naclSpinner").hide();
From a628043a47c557b6b3b08f3b307a5ba9d513e03e Mon Sep 17 00:00:00 2001
From: Jorys Paulin
Date: Sat, 21 Jul 2018 12:09:06 +0200
Subject: [PATCH 04/14] Added customResolutions
---
static/js/index.js | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/static/js/index.js b/static/js/index.js
index 2c5994de..73d3c71d 100644
--- a/static/js/index.js
+++ b/static/js/index.js
@@ -963,6 +963,23 @@ function onWindowLoad() {
loadWindowState();
if (chrome.storage) {
+ // Load stored customResolutions prefs
+ chrome.storage.sync.get('customResolutions', function(previousValue) {
+ if (previousValue.customResolutions != null) {
+ previousValue.customResolutions.forEach(item => {
+ console.log(item);
+ var child = document.createElement('li')
+ child.className = 'mdl-menu__item'
+ child.dataset.value = item.width + ':' + item.height
+ child.innerText = item.name||item.height + 'p'
+ $(child).on('click', saveResolution);
+ document.querySelector('.resolutionMenu').appendChild(child)
+ })
+ } else {
+ console.info('No custom resolutions found')
+ }
+ });
+
// load stored resolution prefs
chrome.storage.sync.get('resolution', function(previousValue) {
if (previousValue.resolution != null) {
From ea4488304e5e150227088fe88e3b70ee92398557 Mon Sep 17 00:00:00 2001
From: Jorys Paulin
Date: Sat, 21 Jul 2018 13:23:55 +0200
Subject: [PATCH 05/14] Added JSDoc to ALL functions
---
static/js/index.js | 133 +++++++++++++++++++++++++++++++++++++++++----
1 file changed, 121 insertions(+), 12 deletions(-)
diff --git a/static/js/index.js b/static/js/index.js
index 73d3c71d..3c2da105 100644
--- a/static/js/index.js
+++ b/static/js/index.js
@@ -6,7 +6,9 @@ var api; // `api` should only be set if we're in a host-specific screen. on the
var isInGame = false; // flag indicating whether the game stream started
var windowState = 'normal'; // chrome's windowState, possible values: 'normal' or 'fullscreen'
-// Called by the common.js module.
+/**
+ * attachListeners - Gets called to attach listeners. Called by the common.js module.
+ */
function attachListeners() {
changeUiModeForNaClLoad();
@@ -23,6 +25,9 @@ function attachListeners() {
chrome.app.window.current().onMaximized.addListener(fullscreenChromeWindow);
}
+/**
+ * fullscreenChromeWindow - Fullscreens the chrome window
+ */
function fullscreenChromeWindow() {
// when the user clicks the maximize button on the window,
// FIRST restore it to the previous size, then fullscreen it to the whole screen
@@ -34,6 +39,11 @@ function fullscreenChromeWindow() {
chrome.app.window.current().fullscreen();
}
+/**
+ * loadWindowState - Loads the window state: windowed, fullscreen...
+ *
+ * @return {Void} If chrome.storage is not avaliable
+ */
function loadWindowState() {
if (!chrome.storage) {
return;
@@ -51,6 +61,9 @@ function loadWindowState() {
});
}
+/**
+ * onFullscreened - Gets called when window is fullscreened
+ */
function onFullscreened() {
if (!isInGame && windowState == 'normal') {
storeData('windowState', 'fullscreen', null);
@@ -58,6 +71,9 @@ function onFullscreened() {
}
}
+/**
+ * onBoundsChanged - Gets called when window's bounds changed
+ */
function onBoundsChanged() {
if (!isInGame && windowState == 'fullscreen') {
storeData('windowState', 'normal', null);
@@ -97,7 +113,7 @@ class Resolution {
* @param {Number} width Resolution width
* @param {Number} height Resolution height
* @param {String} name Resolution name
- * @return {Object} The corresponding object
+ * @return {NvHTTP} The corresponding object
*/
constructor(width, height, name = null) {
this.width = width
@@ -131,6 +147,11 @@ class Resolution {
}
}
+/**
+ * changeUiModeForNaClLoad - Changes the view to NaCL loading
+ *
+ * @return {type} description
+ */
function changeUiModeForNaClLoad() {
$('#main-navigation').children().hide();
$("#main-content").children().not("#listener, #naclSpinner").hide();
@@ -138,12 +159,18 @@ function changeUiModeForNaClLoad() {
$('#naclSpinner').css('display', 'inline-block');
}
+/**
+ * startPollingHosts - Start polling the hosts
+ */
function startPollingHosts() {
for (var hostUID in hosts) {
beginBackgroundPollingOfHost(hosts[hostUID]);
}
}
+/**
+ * stopPollingHosts - Stops polling the hosts
+ */
function stopPollingHosts() {
for (var hostUID in hosts) {
stopBackgroundPollingOfHost(hosts[hostUID]);
@@ -185,6 +212,11 @@ function restoreUiAfterNaClLoad() {
});
}
+/**
+ * beginBackgroundPollingOfHost - Starts the polling of the host
+ *
+ * @param {NvHTTP} host The host object
+ */
function beginBackgroundPollingOfHost(host) {
var el = document.querySelector('#hostgrid-' + host.serverUid)
if (host.online) {
@@ -225,6 +257,11 @@ function beginBackgroundPollingOfHost(host) {
}
}
+/**
+ * stopBackgroundPollingOfHost - Stops the background polling of the host
+ *
+ * @param {NvHTTP} host The host object
+ */
function stopBackgroundPollingOfHost(host) {
console.log('%c[index.js, backgroundPolling]', 'color: green;', 'Stopping background polling of host ' + host.serverUid + '\n', host, host.toString()); //Logging both object (for console) and toString-ed object (for text logs)
window.clearInterval(activePolls[host.serverUid]);
@@ -249,6 +286,11 @@ function snackbarLogLong(givenMessage) {
document.querySelector('#snackbar').MaterialSnackbar.showSnackbar(data);
}
+/**
+ * moduleDidLoad - Gets called when the NaCL module is loaded
+ *
+ * @return {type} description
+ */
function moduleDidLoad() {
// load the HTTP cert and unique ID if we have one.
chrome.storage.sync.get('cert', function(savedCert) {
@@ -303,7 +345,14 @@ function moduleDidLoad() {
});
}
-// pair to the given NvHTTP host object. Returns whether pairing was successful.
+/**
+ * pairTo - description
+ *
+ * @param {NvHTTP} nvhttpHost The host object
+ * @param {Function} onSuccess Callback on success
+ * @param {Function} onFailure Callback on faillure
+ * @return {Void}
+ */
function pairTo(nvhttpHost, onSuccess, onFailure) {
if (!pairingCert) {
snackbarLog('ERROR: cert has not been generated yet. Is NaCl initialized?');
@@ -360,6 +409,11 @@ function pairTo(nvhttpHost, onSuccess, onFailure) {
});
}
+/**
+ * hostChosen - Gets called when a host is chosen
+ *
+ * @param {NvHTTP} host The host object
+ */
function hostChosen(host) {
if (!host.online) {
@@ -420,8 +474,12 @@ function addHost() {
});
}
-
-// host is an NvHTTP object
+/**
+ * addHostToGrid - description
+ *
+ * @param {NvHTTP} host The host object
+ * @param {Boolean} ismDNSDiscovered Whether or not host was mDNS discovered
+ */
function addHostToGrid(host, ismDNSDiscovered) {
var outerDiv = $("
", {
@@ -538,7 +596,11 @@ function sortTitles(list, sortOrder) {
});
}
-// show the app list
+/**
+ * showApps - Shows the app list view
+ *
+ * @param {NvHTTP} host The host object
+ */
function showApps(host) {
if (!host || !host.paired) { // safety checking. shouldn't happen.
console.log('%c[index.js, showApps]', 'color: green;', 'Moved into showApps, but `host` did not initialize properly! Failing.');
@@ -632,7 +694,9 @@ function showApps(host) {
showAppsMode();
}
-// set the layout to the initial mode you see when you open moonlight
+/**
+ * showHostsAndSettingsMode - Changes the view to list hosts and settings (initial view)
+ */
function showHostsAndSettingsMode() {
console.log('%c[index.js]', 'color: green;', 'Entering "Show apps and hosts" mode');
$("#main-navigation").show();
@@ -648,6 +712,9 @@ function showHostsAndSettingsMode() {
startPollingHosts();
}
+/**
+ * showAppsMode - Changes the view to list apps
+ */
function showAppsMode() {
console.log('%c[index.js]', 'color: green;', 'Entering "Show apps" mode');
$('#backIcon').show();
@@ -676,9 +743,13 @@ function showAppsMode() {
stopPollingHosts();
}
-
-// start the given appID. if another app is running, offer to quit it.
-// if the given app is already running, just resume it.
+/**
+ * startGame - Start the given appID. If another app is running, offer to quit it. If the given app is already running, just resume it.
+ *
+ * @param {NvHTTP} host description
+ * @param {Number} appID The ID of the app to start
+ * @return {type} description
+ */
function startGame(host, appID) {
if (!host || !host.paired) {
console.error('%c[index.js, startGame]', 'color: green;', 'Attempted to start a game, but `host` did not initialize properly. Host object: ', host);
@@ -787,6 +858,9 @@ function startGame(host, appID) {
});
}
+/**
+ * playGameMode - Change the view to streaming mode
+ */
function playGameMode() {
console.log('%c[index.js, playGameMode]', 'color:green;', 'Entering play game mode');
isInGame = true;
@@ -802,6 +876,9 @@ function playGameMode() {
}
// Maximize the size of the nacl module by scaling and resizing appropriately
+/**
+ * fullscreenNaclModule - Fullscreens the NaCL module
+ */
function fullscreenNaclModule() {
var streamWidth = $('#selectResolution').data('value').split(':')[0];
var streamHeight = $('#selectResolution').data('value').split(':')[1];
@@ -819,6 +896,9 @@ function fullscreenNaclModule() {
module.style.paddingTop = ((screenHeight - module.height) / 2) + "px";
}
+/**
+ * stopGameWithConfirmation - Stops the game after user confirmation
+ */
function stopGameWithConfirmation() {
if (api.currentGame === 0) {
snackbarLog('Nothing was running');
@@ -845,6 +925,12 @@ function stopGameWithConfirmation() {
}
}
+/**
+ * stopGame - Stops the currently running game
+ *
+ * @param {NvHTTP} host The host object
+ * @param {Function} callbackFunction The callback function
+ */
function stopGame(host, callbackFunction) {
isInGame = false;
@@ -885,6 +971,9 @@ function storeData(key, data, callbackFunction) {
chrome.storage.sync.set(obj, callbackFunction);
}
+/**
+ * saveResolution - Saves the option for resolution to storage
+ */
function saveResolution() {
var chosenResolution = $(this).data('value');
$('#selectResolution').text($(this).text()).data('value', chosenResolution);
@@ -892,6 +981,9 @@ function saveResolution() {
updateDefaultBitrate();
}
+/**
+ * saveOptimize - Saves the option for optimisations to storage
+ */
function saveOptimize() {
// MaterialDesignLight uses the mouseup trigger, so we give it some time to change the class name before
// checking the new state
@@ -902,6 +994,9 @@ function saveOptimize() {
}, 100);
}
+/**
+ * saveFramerate - Saves the option for framerate to storage
+ */
function saveFramerate() {
var chosenFramerate = $(this).data('value');
$('#selectFramerate').text($(this).text()).data('value', chosenFramerate);
@@ -909,15 +1004,19 @@ function saveFramerate() {
updateDefaultBitrate();
}
-
-
// storing data in chrome.storage takes the data as an object, and shoves it into JSON to store
// unfortunately, objects with function instances (classes) are stripped of their function instances when converted to a raw object
// so we cannot forget to revive the object after we load it.
+/**
+ * saveHosts - Saves the hosts to storage
+ */
function saveHosts() {
storeData('hosts', hosts, null);
}
+/**
+ * saveRemoteAudio - Saves the option for remote audio to storage
+ */
function saveRemoteAudio() {
// MaterialDesignLight uses the mouseup trigger, so we give it some time to change the class name before
// checking the new state
@@ -928,6 +1027,11 @@ function saveRemoteAudio() {
}, 100);
}
+/**
+ * updateDefaultBitrate - Updates the bitrate according to the resolution and framerate
+ *
+ * @return {Void}
+ */
function updateDefaultBitrate() {
var res = $('#selectResolution').data('value');
var frameRate = $('#selectFramerate').data('value').toString();
@@ -955,6 +1059,11 @@ function updateDefaultBitrate() {
}
}
+/**
+ * onWindowLoad - Gets clalled when the main window loads
+ *
+ * @return {type} description
+ */
function onWindowLoad() {
console.log('%c[index.js]', 'color: green;', 'Moonlight\'s main window loaded');
// don't show the game selection div
From b377813789e7af379e25df8b0ad1a9008937a592 Mon Sep 17 00:00:00 2001
From: Jorys Paulin
Date: Sat, 21 Jul 2018 13:53:00 +0200
Subject: [PATCH 06/14] Removed some Jquery
---
static/js/index.js | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/static/js/index.js b/static/js/index.js
index 3c2da105..064dcd83 100644
--- a/static/js/index.js
+++ b/static/js/index.js
@@ -11,17 +11,20 @@ var windowState = 'normal'; // chrome's windowState, possible values: 'normal' o
*/
function attachListeners() {
changeUiModeForNaClLoad();
-
+ // Streaming controls handlers
$('.resolutionMenu li').on('click', saveResolution);
$('.framerateMenu li').on('click', saveFramerate);
- $('#bitrateSlider').on('input', e => changeBitrate(e.target.value)); // input occurs every notch you slide
- $('#bitrateInput').on('input', e => changeBitrate(e.target.value));
$("#remoteAudioEnabledSwitch").on('click', saveRemoteAudio);
$('#optimizeGamesSwitch').on('click', saveOptimize);
- $('#addHostCell').on('click', addHost);
- $('#backIcon').on('click', showHostsAndSettingsMode);
- $('#quitCurrentApp').on('click', stopGameWithConfirmation);
- $(window).resize(fullscreenNaclModule);
+ // Inputs handlers
+ document.querySelector('#bitrateSlider').oninput = e => changeBitrate(e.target.value)
+ document.querySelector('#bitrateInput').oninput = e => changeBitrate(e.target.value)
+ // Controls handler
+ document.querySelector('#addHostCell').onclick = () => addHost()
+ document.querySelector('#backIcon').onclick = () => showHostsAndSettingsMode()
+ document.querySelector('#quitCurrentApp').onclick = () => stopGameWithConfirmation()
+ // Resize handlers
+ window.onresize = () => fullscreenNaclModule()
chrome.app.window.current().onMaximized.addListener(fullscreenChromeWindow);
}
@@ -964,6 +967,13 @@ function stopGame(host, callbackFunction) {
});
}
+/**
+ * storeData - Stores data into chrome.storage.sync
+ *
+ * @param {String} key The key for the storage
+ * @param {Object|String|Number} data The data to store
+ * @param {Function} callbackFunction The callback function
+ */
function storeData(key, data, callbackFunction) {
var obj = {};
obj[key] = data;
@@ -1076,7 +1086,6 @@ function onWindowLoad() {
chrome.storage.sync.get('customResolutions', function(previousValue) {
if (previousValue.customResolutions != null) {
previousValue.customResolutions.forEach(item => {
- console.log(item);
var child = document.createElement('li')
child.className = 'mdl-menu__item'
child.dataset.value = item.width + ':' + item.height
From 61c43cdf20cbdb53b5ae954fa643c5e2afd2d765 Mon Sep 17 00:00:00 2001
From: Jorys Paulin
Date: Sat, 21 Jul 2018 16:38:36 +0200
Subject: [PATCH 07/14] Started localizing
---
_locales/en/messages.json | 38 ++++++++++++++++++++++++++++
_locales/fr/messages.json | 38 ++++++++++++++++++++++++++++
manifest.json | 9 ++++---
static/js/index.js | 52 +++++++++++++++++----------------------
4 files changed, 104 insertions(+), 33 deletions(-)
create mode 100644 _locales/en/messages.json
create mode 100644 _locales/fr/messages.json
diff --git a/_locales/en/messages.json b/_locales/en/messages.json
new file mode 100644
index 00000000..6627e3e9
--- /dev/null
+++ b/_locales/en/messages.json
@@ -0,0 +1,38 @@
+{
+ "loading_plugin": {
+ "message": "Loading Moonlight plugin..."
+ },
+ "loading_apps": {
+ "message": "Loading apps..."
+ },
+ "stopping_game": {
+ "message": "Stopping $1"
+ },
+ "error": {
+ "message": "Error"
+ },
+ "cert_error": {
+ "message": "Cert has not been generated yet. Is NaCl initialized?"
+ },
+ "busy_error": {
+ "message": "Your computer is busy. Stop streaming to pair"
+ },
+ "pair_error": {
+ "message": "Failed to pair with $1"
+ },
+ "remove_host": {
+ "message": "Remove host"
+ },
+ "delete_host": {
+ "message": "Are you sure you want to delete $1?"
+ },
+ "add_host": {
+ "message": "Add host"
+ },
+ "gamelist_empty": {
+ "message": "Your game list is empty"
+ },
+ "game_running": {
+ "message": "$1 is already running. Would you like to quit? All unsaved progress will be lost"
+ }
+}
diff --git a/_locales/fr/messages.json b/_locales/fr/messages.json
new file mode 100644
index 00000000..41664b15
--- /dev/null
+++ b/_locales/fr/messages.json
@@ -0,0 +1,38 @@
+{
+ "loading_plugin": {
+ "message": "Chargement du plugin..."
+ },
+ "loading_apps": {
+ "message": "Chargement des applications..."
+ },
+ "stopping_game": {
+ "message": "Arrêt de $1"
+ },
+ "error": {
+ "message": "Erreur"
+ },
+ "cert_error": {
+ "message": "Le certificat n'a pas été généré. Est-ce que NaCL est activé?"
+ },
+ "busy_error": {
+ "message": "Votre ordinateur est occupé. Arrêter de streamer pour appareiller"
+ },
+ "pair_error": {
+ "message": "Impossible d'appareiller $1"
+ },
+ "remove_host": {
+ "message": "Supprimer l'ordinateur"
+ },
+ "delete_host": {
+ "message": "Voulez-vous vraiement enlever $1?"
+ },
+ "add_host": {
+ "message": "Ajouter un ordinateur"
+ },
+ "gamelist_empty": {
+ "message": "Votre liste d'applications est vide"
+ },
+ "game_running": {
+ "message": "$1 est en cours d'execution. Voulez-vous quitter? Toute progression non enregistrée sera perdue"
+ }
+}
diff --git a/manifest.json b/manifest.json
index 30eebd5c..16c5175f 100644
--- a/manifest.json
+++ b/manifest.json
@@ -4,11 +4,12 @@
"short_name": "Moonlight",
"version": "0.9.0",
"description": "Open-source client for NVIDIA GameStream",
+ "default_locale": "en",
"icons": {
"128": "icons/icon128.png",
"48": "icons/icon48.png",
"32": "icons/icon32.png",
- "16": "icons/icon16.png"
+ "16": "icons/icon16.png"
},
"app": {
"background": {
@@ -29,9 +30,9 @@
"power",
"overrideEscFullscreen", {
"socket": [
- "tcp-connect",
- "resolve-host",
- "udp-bind:*:*",
+ "tcp-connect",
+ "resolve-host",
+ "udp-bind:*:*",
"udp-send-to:*:*"
] }
],
diff --git a/static/js/index.js b/static/js/index.js
index 064dcd83..856eaa4a 100644
--- a/static/js/index.js
+++ b/static/js/index.js
@@ -158,7 +158,7 @@ class Resolution {
function changeUiModeForNaClLoad() {
$('#main-navigation').children().hide();
$("#main-content").children().not("#listener, #naclSpinner").hide();
- $('#naclSpinnerMessage').text('Loading Moonlight plugin...');
+ $('#naclSpinnerMessage').text(chrome.i18n.getMessage('loading_plugin'));
$('#naclSpinner').css('display', 'inline-block');
}
@@ -358,7 +358,7 @@ function moduleDidLoad() {
*/
function pairTo(nvhttpHost, onSuccess, onFailure) {
if (!pairingCert) {
- snackbarLog('ERROR: cert has not been generated yet. Is NaCl initialized?');
+ snackbarLog(chrome.i18n.getMessage('cert_error'));
console.warn('%c[index.js]', 'color: green;', 'User wants to pair, and we still have no cert. Problem = very yes.');
onFailure();
return;
@@ -379,7 +379,7 @@ function pairTo(nvhttpHost, onSuccess, onFailure) {
var randomNumber = String("0000" + (Math.random() * 10000 | 0)).slice(-4);
var pairingDialog = document.querySelector('#pairingDialog');
- $('#pairingDialogText').html('Please enter the number ' + randomNumber + ' on the GFE dialog on the computer. This dialog will be dismissed once complete');
+ pairingDialog.innerText = 'Please enter the number ' + randomNumber + ' on the GFE dialog on the computer. This dialog will be dismissed once complete'
pairingDialog.showModal();
$('#cancelPairingDialog').off('click');
@@ -390,10 +390,11 @@ function pairTo(nvhttpHost, onSuccess, onFailure) {
console.log('%c[index.js]', 'color: green;', 'Sending pairing request to ' + nvhttpHost.hostname + ' with random number' + randomNumber);
nvhttpHost.pair(randomNumber).then(function(paired) {
if (!paired) {
+ var pairingDialogText = document.querySelector('#pairingDialogText')
if (nvhttpHost.currentGame != 0) {
- $('#pairingDialogText').html('Error: ' + nvhttpHost.hostname + ' is busy. Stop streaming to pair.');
+ pairingDialogText.innerText = chrome.i18n.getMessage('busy_error')
} else {
- $('#pairingDialogText').html('Error: failed to pair with ' + nvhttpHost.hostname + '.');
+ pairingDialogText.innerText = chrome.i18n.getMessage('pair_error', nvhttpHost.hostname)
}
console.log('%c[index.js]', 'color: green;', 'Failed API object:', nvhttpHost, nvhttpHost.toString()); //Logging both the object and the toString version for text logs
onFailure();
@@ -404,7 +405,7 @@ function pairTo(nvhttpHost, onSuccess, onFailure) {
pairingDialog.close();
onSuccess();
}, function(failedPairing) {
- snackbarLog('Failed pairing to: ' + nvhttpHost.hostname);
+ snackbarLog(chrome.i18n.getMessage('pair_error', nvhttpHost.hostname));
console.error('%c[index.js]', 'color: green;', 'Pairing failed, and returned:', failedPairing);
console.error('%c[index.js]', 'color: green;', 'Failed API object:', nvhttpHost, nvhttpHost.toString()); //Logging both the object and the toString version for text logs
onFailure();
@@ -457,7 +458,7 @@ function addHost() {
// try to pair if they continue
$('#continueAddHost').off('click');
$('#continueAddHost').on('click', function() {
- var inputHost = $('#dialogInputHost').val();
+ var inputHost = document.querySelector('#dialogInputHost').value;
var _nvhttpHost = new NvHTTP(inputHost, myUniqueid, inputHost);
pairTo(_nvhttpHost, function() {
@@ -483,15 +484,13 @@ function addHost() {
* @param {NvHTTP} host The host object
* @param {Boolean} ismDNSDiscovered Whether or not host was mDNS discovered
*/
-function addHostToGrid(host, ismDNSDiscovered) {
-
- var outerDiv = $("