Why does 'window.location.href' not work as expected when set as a variable outside an exported function? - hyperlink

Below I've shared two code snippets: the first works, the second does not. In both instances, the user clicks a share button which is supposed to copy the link to the clipboard. The first copies the current window link correctly every time. The second only copies the current window link if the window is reloaded after the first load.
Please explain why this isn't working as expected, and if there is a solution to the second code snippet, please provide it.
First code snippet
export const ShareGroup = ({ link = window.location.href, callback = () => null }) => {
const handleCopyLink = () => {
if ('window' in globalThis) {
const cb = navigator.clipboard
cb.writeText(link).then(() => alert('Link copied to clipboard'))
}
callback()
}
Second code snippet
let currentPage = ''
if ('window' in globalThis) {
currentPage = window.location.href
}
export const ShareGroup = ({ link = currentPage, callback = () => null }) => {
const handleCopyLink = () => {
if ('window' in globalThis) {
const cb = navigator.clipboard
cb.writeText(link).then(() => alert('Link copied to clipboard'))
}
callback()
}
Interestingly in the second code snippet, if there's a console.log(${link}) within the export function, the console.log correctly displays the link that's supposed to be copied, but the actual link that's copied to the clipboard isn't correct. Really odd behavior.
Again, with the second code snippet, if the page is reloaded after the initial load then the functionality works as expected.

Related

Focus tab and change page with service worker

We need a little help with a service worker. What we want to do is to click on notification, to execute service worker code and to check if the site is yet opened in a tab: if the site is not opened, we want to open a new tab and to navigate to a predefined url, if it is opened, we want to focus tab and then to navigate to a predefined path of the site.
We tried the code below but it doesn't work, cause we get some errors such as 'the service worker is not the active one' and so on.
Any help is really appreciated
Thanks
event.waitUntil(clients.matchAll({type: 'window' }).then(function (clientList) {
let openNewWindow = true;
for (let i = 0; i < clientList.length; i++) {
const client = clientList[i];
if (client.url.includes('localhost') && 'focus' in client) {
openNewWindow = false;
client.focus()
.then(function (client2)
{ return client.navigate(openUrl)});
// });
}
}
if (openNewWindow) {
return clients.openWindow(openUrl);
}
}));
I don't know if you still need a solution, but we did it like this.
After click, we look for the right registration by a lookup. Because our solution has many different customers, and there can be multiple registrations.
When we found it, we send a message. Somewhere else we have a listener on those messages to handle the rounting with the angular app.
If there is no tab opened, we use winClients.openWindow(url)
self.addEventListener('notificationclick', event => handleClick (event));
const handleClick = async (event) => {
const data = event.notification.data
const winClients = clients;
const action = event.action;
event.notification.close();
event.waitUntil(
clients.matchAll({includeUncontrolled: true, type: 'window'}).then(clients => {
let found = false;
let url = data.fallback_url;
if (action === 'settings') {
url = data.actions.settings;
}
clients.every(client => {
if (client.url.includes(data.lookup)) {
found = true;
client.focus();
client.postMessage({action: 'NOTIFICATION_CLICK', message_id: data.message_id, navigate_url: url});
return false;
}
return true;
});
if (!found) {
winClients.openWindow(url);
}
})
);
};

control Electron instances

Wanted to check how many instances are running and control the number of instances running in one exe electron bundle. Let us say I wanted to allow only three instances running for the one exe bundle. I am not able to do this.
Current Behavior:
Only one and remaining can block. Or open for any number of instances. We need to control only three instances running, not more than that.
Example:
const { app } = require('electron')
let myWindow = null
const gotTheLock = app.requestSingleInstanceLock()
if (!gotTheLock) {
app.quit()
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (myWindow) {
if (myWindow.isMinimized()) myWindow.restore()
myWindow.focus()
}
})
// Create myWindow, load the rest of the app, etc...
app.on('ready', () => {
})
}
You can try with the following code to know how many windows have been opened.
const count = BrowserWindow.getAllWindows().length;
To check visible windows, you can try the following code
let count = BrowserWindow.getAllWindows()
.filter(b => {
return b.isVisible()
}).length
Once you get the number of instances, based upon the condition for number of instance, ie. if it is more than 3, you can quit using app.quit().
You can make each instance write to a file (increment a counter for example) when the instance starts and when it exits. (decrement the counter). You should check that file to see if the maximum number of instances are running
import { app } from "electron";
import path from "path";
import fs from "fs";
const MAX_APP_INSTANCES = 3;
const INSTANCE_COUNT_FILE_PATH = path.join(
app.getPath("userData"),
"numOfInstances"
);
// utils to read/write number of instances to a file
const instanceCountFileExists = () => fs.existsSync(INSTANCE_COUNT_FILE_PATH);
const readInstanceCountFile = () =>
parseInt(fs.readFileSync(INSTANCE_COUNT_FILE_PATH, "utf-8"));
const writeInstanceCountFile = (value) =>
fs.writeFileSync(INSTANCE_COUNT_FILE_PATH, value);
const incInstanceCountFile = () => {
const value = readInstanceCountFile() + 1;
writeInstanceCountFile(value.toString());
};
const decInstanceCountFile = () => {
const value = readInstanceCountFile() - 1;
writeInstanceCountFile(value.toString());
};
// logic needed to only allow a certain number of instances to be active
if (instanceCountFileExists() && readInstanceCountFile() >= MAX_APP_INSTANCES) {
app.quit();
} else {
if (!instanceCountFileExists()) {
writeInstanceCountFile("1");
} else {
incInstanceCountFile();
}
app.on("quit", () => decInstanceCountFile());
}
Note: this is solution is somewhat hacky. For example, the quit event is not guaranteed to fire when the Electron app exits

How to use ipcRender inside executeJavascript?

I tried just simply putting the ipcRenderer message inside of executeJavascript but it returned
ipcRenderer is not defined
my ipcRender is defined using window.ipcRenderer:
const { ipcRenderer, remote } = require('electron');
window.ipcRenderer = ipcRenderer;
//and then
remote.getCurrentWebContents().executeJavaScript(`settingsDiv.addEventListener('click', function() { ipcRenderer.send('test','ayy'); } );`)
This is loaded as a preloaded script for a webpage.
There is no need to take that path on a preload.
Something like this should work instead:
const { ipcRenderer } = require('electron');
document.addEventListener('DOMContentLoaded', (event) => {
const settingsDiv = document.querySelector('<?>'); // replace <?> with your selector for that div element
settingsDiv.addEventListener('click', () => {
ipcRenderer.send('test', 'ayy');
});
}
(the preload runs first, then the page is rendered. So we have to wait until the DOM content is loaded and the div is available)

"CS0162: Warning as Error: Unreachable code detected" on Razor View

I have the following code within a script tag on my razor view:
self.regions = [];
#foreach(var region in Model.OperationRegions)
{
<text>
self.regions.push({
regionid: '#region.Region_Id',
regionname: '#region.Title',
selected: ko.observable(#(Model.RegionsList.Contains(region.Region_Id).ToString().ToLower()))
});
</text>
}
self.categories = [];
#foreach(var category in Model.Categories)
{
<text>
self.categories.push({
categoryid: '#category.Category_Id',
title: '#category.Title'
});
</text>
}
For clarity, the code outside of the foreach loops and within the text tags are Javascript and the purpose of the razor code is to populate my Javascript arrays with data from the server.
When I run this I am currently getting a server error saying "CS0162: Warning as Error: Unreachable code detected"
The error is thrown on the second "foreach" in the snippet.
Surprisingly I couldn't find another question referring to this error message on an MVC razor page so I'm posting this here.
My question is why is that line of code considered to be unreachable? I will update this question if I find anything else on my page to be relevant to the issue as I try to debug.
The error has disappeared now. I had renamed a property of my model and not recompiled before trying to load the page again. Recompiling made the error go away. I have no idea how the root cause translated to the error message shown but its fixed now in any case.
This is an extremely poor way to handle this. There's no need to build an array piece by piece like this. Just convert your list to JSON.
self.regions = #Html.Raw(Json.Encode(Model.OperationRegions.Select(region => new {
regionid = region.Region_Id,
regionname = region.Title,
selected = Model.RegionsList.Contains(region.Region_Id)
})));
The only thing this can't handle is making selected an observable. However, you can simply loop through the array and fix this:
for (var i = 0; i < self.regions.length; i++) {
self.regions[i].selected = ko.observable(self.regions[i].selected);
}
However, the better approach is to use another view model:
var OperationRegionViewModel = function (data) {
var self = {};
self.regionid = ko.observable(data.regionid);
self.regionname = ko.observable(data.regionname);
self.selected = ko.observable(data.selected);
return self;
};
Then, you can just do something like:
var regions = #Html.Raw(Json.Encode(Model.OperationRegions.Select(region => new {
regionid = region.Region_Id,
regionname = region.Title,
selected = Model.RegionsList.Contains(region.Region_Id)
})));
self.regions = $.map(regions, new OperationRegionViewModel);
Or, even better build your JSON all at once:
var json = #Html.Raw(Json.Encode(new {
regions = Model.OperationRegions.Select(r => new { ... }),
categories = Model.Categories.Select(c => new { ... }),
// etc
});
Then, inject this all into your view model:
var viewModel = (function (json) {
// other stuff
self.regions = $.map(json.regions, new OperationRegionViewModel);
self.categories = $.map(json.categories, new CategoryViewModel);
// etc
})(json);

Previous and current selected options in Prototype

How can I get the previously selected option from a <select> in prototype so I can "rollback" the selection should anything fail in the script ?
You cannot do this directly with prototype, but here is a class to handle "rollbackable" selects:
var UndoableSelect = Class.create({
_$select: null,
_selectedValue : null,
_lastSelectedValue: null,
initialize: function(elementOrId)
{
this._$select = $(elementOrId);
this._lastSelectedIndex = this._$select.selectedIndex;
this._selectedIndex = this._lastSelectedIndex;
this._$select.observe('change', this._changeHandler.bind(this));
},
undoLastSelection: function()
{
this._$select.selectedIndex = this._lastSlectedIndex;
this._selectedIndex = this._lastSelectedIndex;
},
_changeHandler: function(event)
{
this._lastSelectedIndex = this._selectedIndex;
this._selectedIndex = this._$select.selectIndex;
}
});
That you can use like that:
// this one line under has to be called only once per page load (where there is the select of course):
var theSelect = new UndoableSelect('id_of_the_select');
$('id_of_the_select').observe('change', function(event)
{
// your code, if you need to rollback, do this:
theSelect.undoSelection();
});
Sorry not so much explanation but I don't have much time now. I just wrote the code without testing so if any problem let me know and I'll be back on it with more time to fix it ;-)

Resources