window object in NodeJS of SSR got both 'not defined' or 'already been declared' - node.js

I am migrating an Angular 6 project to Angular Universal project(SSR). In my project, I need to access window object in order to get "navigator", "location", etc... I am using the following method to polyfill window in Server side. But it is not working.
try {
console.log(window);
} catch (window) {
console.log('Server side window.');
window = {
location: {
replace: () => {},
protocol: 'https'
},
navigator: {
userAgent: '',
appVersion: ''
},
scrollTo: () => {},
open: () => {},
localStorage: {}
};
console.log('Server side window.', window);
}
What is the best way to handle the window object properly on the server side for the server-side rendering web site? I got following confusion errors. It said 'window is not defined' or 'has been declared'. How to use window object in NodeJS?
> console.log(window);
ReferenceError: window is not defined
> let window = 1
SyntaxError: Identifier 'window' has already been declared

The problem with this piece of code is that window is specified as exception identifier in try..catch, basically:
try {
console.log(window);
} catch (window) {
// window instanceof ReferenceError
window = {...};
// window is redefined in this block scope
}
This will work in loose mode:
try {
console.log(window);
} catch (err) {
window = {...};
}
But will result in another ReferenceError in strict mode. It should be instead:
try {
console.log(window);
} catch (err) {
global.window = {...};
}
And a proper way to detect window is:
if (typeof window === 'undefined') {
global.window = {...};
}
This code is limited to browser and Node.js; it will result in an error in a worker.

Related

Unchecked runtime.lastError: No tab with <id>, Chrome Extension

I don't understand why i recieve this error
Error
This code works
chrome.tabs.onUpdated.addListener(handleUrls);
function handleUrls(tabId, { changeInfo }, tab) {
const isOauthTokenPage = tab.url?.match(CONFIG.OAUTH_TOKEN_PAGE_PATTERN);
if (isOauthTokenPage) {
chrome.tabs.remove(tabId);
}
}
But why i get this error?
I tried chrome.tabs.onUpdated.removeListener before and after chrome.tabs.remove(tabId), tried chrome.tabs.query to get "actual" tabId
So it's trigger more than once
To avoid it
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
// check url state
if (!changeInfo.url) return;
// your code...
if ((tab.url).match(CONFIG.OAUTH_TOKEN_PAGE_PATTERN)) {
// won't invoke onUpdated several times
chrome.tabs.remove(tabId);
}
});

Stop callback chain and send notification beforeSave method ApostropheCMS

I'm trying to prevent the user to save a piece if it doesn't achieve some requirements.
Currently I'm doing it like this:
self.beforeSave = function(req, piece, options, callback) {
let success = true;
let error = "";
if (Array.isArray(piece._subevents) && piece._subevents.length) {
success = self.checkDateAndTimeCompabilitiyWithChildren(piece);
}
if (!success) {
self.apos.notify(req, "Check the compatibility between parent event and subevents", { type: "error" });
error = "Subevents are not compatible with parent event";
}
callback(error);
};
This works but the problem is it shows 2 errors notifications (the default and my custom), 1 because of callback(error) and 1 because of apos.notify.
Any idea how to stop the item of being saved and only show my notification?
Thanks in advance.
UPDATE 1:
As Tom pointed out, my code looks like this now:
// lib/modules/events/public/js/editor-modal.js
apos.define('events-editor-modal', {
extend: 'apostrophe-pieces-editor-modal',
construct: function(self, options) {
self.getErrorMessage = function(err) {
if (err === 'incompatible') {
apos.notify('A message suitable for this case.', { type: 'error' });
} else {
apos.notify('A generic error message.', { type: 'error' });
}
};
}
});
// lib/modules/events/index.js
var superPushAssets = self.pushAssets;
self.pushAssets = function() {
superPushAssets();
self.pushAsset("script", "editor-modal", { when: "user" });
};
self.beforeSave = async function(req, piece, options, callback) {
return callback("incompatible")
};
For testing purposes I'm just returning the error in beforeSave. The problem is that an exception is being thrown in the browser console and the modal is not properly rendered again. Here's a screenshot about what I'm talking:
I'm trying to debug it and understand what's happening but no clue yet.
In your server-side code:
self.beforeSave = function(req, piece, options, callback) {
let success = true;
if (Array.isArray(piece._subevents) && piece._subevents.length) {
success = self.checkDateAndTimeCompabilitiyWithChildren(piece);
}
if (!success) {
return callback('incompatible');
}
return callback(null);
};
And on the browser side:
// in lib/modules/my-pieces-module/public/js/editor-modal.js
apos.define('my-pieces-module-editor-modal', {
extend: 'apostrophe-pieces-editor-modal',
construct: function(self, options) {
self.getErrorMessage = function(err) {
if (err === 'incompatible') {
return 'A message suitable for this case.';
} else {
return 'A generic error message.';
}
};
}
});
If the error reported by the callback is a string, it is passed to the browser. The browser can then recognize that case and handle it specially. 'my-pieces-module-editor-modal' should be substituted with the name of your pieces module followed by -editor-modal.

nativescript-audio plugin does not function on ios

I have succesfully implemented the nativescript-audio plugin on android. I am using plain JS in my project. When i run it on ios i get the following error.
NSURLErrorDomain Code= -1002 "unsupported url".
I get this error with most of the examples that i found on the web (including the following , which works perfectly on android).
var ns_audio = require("nativescript-audio");
var player = new ns_audio.TNSPlayer();
var playerOptions = {
audioFile: "http://www.noiseaddicts.com/samples_1w72b820/2514.mp3",
loop: false,
completeCallback: function () {
console.log('completePlayer')
},
errorCallback: function (errorObject) {
console.log(JSON.stringify(errorObject));
},
infoCallback: function (args) {
console.log(JSON.stringify(args));
}
};
player.playFromUrl(playerOptions)
.then(function (res) {
console.log(res);
})
.catch(function () {
console.log("didn't work...");
})
It looks like recording works (no errors, and the correct responses, although i cannot test if the file has been correctly created...) But playback gives this error. Any idea ?
I have created a plain JS playground for you. I have tested the mp3 URL that you have provided in the the post and that works fine on ios.
Have a play with that and see if you are missing something. Here is
function pageLoaded(args) {
var page = args.object;
const player = new audio.TNSPlayer();
const playerOptions = {
audioFile: 'http://www.noiseaddicts.com/samples_1w72b820/2514.mp3',
loop: false,
completeCallback: function () {
console.log('finished playing');
},
errorCallback: function (errorObject) {
console.log(JSON.stringify(errorObject));
},
infoCallback: function (args) {
console.log(JSON.stringify(args));
}
};
player
.playFromUrl(playerOptions)
.then(function (res) {
console.log(res);
})
.catch(function (err) {
console.log('something went wrong...', err);
});
page.bindingContext = homeViewModel;
}
Recording and Playback with the nativescript-audio plugin (for iOS) are both working now!. My first problem was that i needed to record to .caf (not .mp3) so i used
if(isAndroid)
{
extention = ".mp3";
}
else
{
extention = ".caf";
}
before i record the audio file....
Also i ran in a stupid oversight which is easy to miss....
i created my code from the above mentioned example, but because i play the sound that is recorded to a .caf file. i needed to use playFromFile and not playFromUrl as the example uses.
( thats what caused the error : NSURLErrorDomain Code= -1002 "unsupported url".)
player
.playFromFile(playerOptions)
.then(function (res) {
hopefully this point of attention can save someone a headache !

RTCMulticonnection room join keeps throwing error : Session-Descriptions not found. Rechecking

I'm using RTCMulticonnection MultiRTC script to capture and stream multiple user cameras.
I guess, If any user refresh page then session keeps alive in background even I've added page unload event
window.onbeforeunload = function() {
rtcMultiConnection.close();
};
my problem is that joining a room after refresh keeps throwing error/warning message Session-Descriptions not found. Rechecking...
Why session description not found? I've checked RTCMulticonnection js and this error is throwing from below function.
function joinSession(session, joinAs) {
if (isString(session)) {
connection.skipOnNewSession = true;
}
console.log(session);
console.log(joinAs);
if (!rtcMultiSession) {
log('Signaling channel is not ready. Connecting...');
// connect with signaling channel
initRTCMultiSession(function() {
log('Signaling channel is connected. Joining the session again...');
setTimeout(function() {
joinSession(session, joinAs);
}, 1000);
});
return;
}
// connection.join('sessionid');
if (isString(session)) {
if (connection.sessionDescriptions[session]) {
session = connection.sessionDescriptions[session];
} else
return setTimeout(function() {
log('Session-Descriptions not found. Rechecking..');
joinSession(session, joinAs);
}, 1000);
}
// connection.join('sessionid', { audio: true });
if (joinAs) {
return captureUserMedia(function() {
session.oneway = true;
joinSession(session);
}, joinAs);
}
if (!session || !session.userid || !session.sessionid) {
error('missing arguments', arguments);
var error = 'Invalid data passed over "connection.join" method.';
connection.onstatechange({
userid: 'browser',
extra: {},
name: 'Unexpected data detected.',
reason: error
});
throw error;
}
if (!connection.dontOverrideSession) {
connection.session = session.session;
}
var extra = connection.extra || session.extra || {};
// todo: need to verify that if-block statement works as expected.
// expectations: if it is oneway streaming; or if it is data-only connection
// then, it shouldn't capture user-media on participant's side.
if (session.oneway || isData(session)) {
rtcMultiSession.joinSession(session, extra);
} else {
captureUserMedia(function() {
rtcMultiSession.joinSession(session, extra);
});
}
}
Upgraded my application with RTCMulticonnection version v3, also used socket.io instead of WebSocket, earlier I was using WebSocket.

How to Get Window Variable Using WebdriverIO

I am trying to run webdriverio with PhantomJS/Chrome to load a page and then grab the window object for use with other scripts. For some reason I am unable to get the window object. Everytime I get, I end up seeing output like this:
Title is: XXXXX
{ state: 'pending' }
Using the following script:
var webdriverio = require('webdriverio');
var options = {
desiredCapabilities: {
browserName: 'chrome',
logLevel: 'verbose'
}
};
var client = webdriverio.remote(options);
client
.init()
.url('https://xxxx.com')
.waitUntil(function () {
return client.execute(function () {
return Date.now() - window.performance.timing.loadEventEnd > 40000;
}).then(function (result) {
console.log(window);
return window;
});
})
.end();
Does anyone know how I can fix my code so that the window object is returned to my NodeJS console app after the page is completely loaded?
Thanks!
Window is an object in the browser's DOM, so it's only available inside of the 'execute' function. If you wanted access to it, you could return it from your 'execute' function:
return client.execute(function () {
return window;
}).then(function (result) {
console.log(result);
});
This work as well:
browser.execute('return window');

Resources