Failed to add saved page to menu bar - wrapper application using electron - electron

I recently follow a project electron on geeksforgeeks: https://www.geeksforgeeks.org/create-a-geeksforgeeks-wrapper-application-using-electron/
Here is its code on Github https://github.com/sayantanm19/geeksforgeeks-desktop/blob/master/index.js
The function appenItemToMenu doesn't work, which means I could save pages offline but the savedpagelist on menu bar is always empty ...
Could you try it on your machine and point out the bug?
function appendItemToMenu(filename) {
curr_menu = Menu.getApplicationMenu()
.getMenuItemById("saved").submenu
curr_menu.append(
new MenuItem({
label: path.basename(filename, '.html'),
click() {
console.log('Saved page opened')
win.loadFile(savedFolder + path.basename(filename))
}
}))
}

function appendItemToMenu(filename) {
const newMenu = Menu.getApplicationMenu()
curr_menu = newMenu.getMenuItemById('saved').submenu
curr_menu.append(
new MenuItem({
label: path.basename(filename, '.html'),
click() {
console.log('Saved page opened')
win.loadFile(savedFolder + path.basename(filename))
}
}))
Menu.setApplicationMenu(newMenu)
}
Update the application menu after change. Any dynamic change or append Item not allowed.

Related

Electron: Minimize the application when launched after computer is restarted

I am using node-auto-launch to launch my application after computer is restarted. This application is only for windows. I want this application by default to be launched minimized as it works in the background. HOw can I achieve this?
let bizAnalystAutoLauncher = new AutoLaunch({
name: 'BizAnalystDesktop'
});
bizAnalystAutoLauncher.enable();
bizAnalystAutoLauncher.isEnabled()
.then(function (isEnabled: boolean) {
if (isEnabled) {
return;
}
bizAnalystAutoLauncher.enable();
})
.catch(function (err: any) {
// handle error
console.log(err);
});
I don't want the application to be hidden. The application icon should be visible in the system tray in the taskbar.
So you want to have some kind of "minimize to tray" behaviour.
Initialize your app the usual way but instead of mainWindow.show() you call mainWindow.minimize() after initializing the mainWindow, then add EventListeners for the mainWiondw's minimize and restore events to hide or show the taskbar icon for your app via mainWindow.setSkipTaskbar():
...
mainWindow.on('restore', () => {
mainWindow.setSkipTaskbar(false)
})
mainWindow.on('minimize', () => {
mainWindow.setSkipTaskbar(true)
})
...
Add a Tray menu like in the documentation but make sure you add a menu item to restore the app window, otherwise you will end up with an app that is not accessible after it is minimized:
...
const trayMenu = Menu.buildFromTemplate([
{
label: 'Show',
click: () => {
mainWindow.restore()
}
},
{
label: 'Quit',
role: 'quit'
}
])
tray.setContextMenu(trayMenu)
...
The way I would do it is I would create a shortcut in the start menu Programs > startup with an argument instead of using node-auto-launch. Then when the app runs check for that argument in process.argv.
So to create a start menu shortcut with an argument of startMinimized you can use this module called windows-shortcuts
require('windows-shortcuts').create(
'%APPDATA%/Microsoft/Windows/Start Menu/Programs/Startup/myApp.lnk', {
target: process.execPath,
args: 'startMinimized',
icon: 'path/to/icon'
}, function (err) {
if (err) {
throw Error(err);
}
}
);
Then you could write some script like this to minimize the window at startup:
var startMinimized = false;
if (process.argv[2] && process.argv[2].indexOf('startMinimized') != -1) {
startMinimized = true;
}
var mainWindow = new BrowserWindow({show: !startMinimized});
if (startMinimized) {
mainWindow.minimize();
}
process.argv is an array of arguments the app starts with. The first one is the .exe path. The second is the squirrel argument.

ngCordova InAppBrowser plugin freeze app on iOS but no on Android

I am currently using, IONIC v1.0.0, AngularJs and ngCordova v0.1.23-alpha on IOS and Android.
I have come across an issue with my login view freezing up.
It happens after opening InAppBrowser and hitting "back to app" (close button caption used for IOS to get back) is freezes my login view disabling the ability to touch on the whole screen and making me unable to login. It only happens if I call InAppBrowser when starting the app, if I use it during the app life cycle (after login in), it doesn't do it.
Here are some of my code pieces
In app.js:
angular.module('MyApp', ['ionic', 'MyApp', 'ngCordova', 'mainController', 'loginController', 'pascalprecht.translate', 'ngStorage', 'ngSanitize', 'ngAnimate', 'ngTouch', 'ngCookies', 'ngLocale', 'testController'])
In mainController I have Factory:
.factory('customMainFunction', function ($rootScope, $ionicLoading, $ionicScrollDelegate, $ionicPopup,
$timeout, $localStorage, $location, $ionicHistory, $window, $cordovaInAppBrowser) {
var Token = "";
return {
openBrowser: function (link) {
var options = {
location: 'yes',
clearcache: 'yes',
toolbar: 'yes',
closebuttoncaption: 'Back to App'
};
document.addEventListener("deviceready", function () {
$cordovaInAppBrowser.open(link, '_blank', options)
.then(function (event) {
// success
})
.catch(function (event) {
// error
});
}, false);
$rootScope.$on('$cordovaInAppBrowser:loadstart', function (e, event) {
//console.log(event);
var url = "";
var positionNumber;
var res;
url = event.url;
positionNumber = url.search("ssoToken=");
res = url.substr(Number(positionNumber)+9);
/*positionNumber = url.search("module=");
res = url.substr(Number(positionNumber)+6);*/
if(url !== "" && positionNumber >= 0 && res.length > 0) {
$rootScope.$broadcast('ssoToken', { token: res });
$cordovaInAppBrowser.close();
}
});
$rootScope.$on('$cordovaInAppBrowser:loadstop', function (e, event) {
console.log("loadstop");
//console.log(event);
// insert CSS via code / file
//$cordovaInAppBrowser.insertCSS({
// code: ''
//});
// insert Javascript via code / file
//$cordovaInAppBrowser.executeScript({
// file: ''
//});
});
$rootScope.$on('$cordovaInAppBrowser:loaderror', function (e, event) {
});
$rootScope.$on('$cordovaInAppBrowser:exit', function (e, event) {
});
}
}
})
If anybody has encounter such issue please let me know what can be done to resolve it. Any question or clarifications let me know. Thanks in advance.
Found the issue of my own problem. Basically the problem is related to Threading. Look for Threading. How did I find out about it? On XCode I was able to see a message saying:
THREAD WARNING: ['InAppBrowser'] took '108.12' ms. Plugin should use a
background thread
There are two ways to solve this (I believe):
1- Using background threading (just like the message states). Please refer to:
How to run cordova plugins in the background?
2- Wrap the openBrowser function call (in my case) in a setTimeout. That will delay the call until the thread is done and UI won't be blocked. Once done (in my case) it opened the inAppBrowser and when I hit "Back to app" UI was not block at all.
Hope this helps someone out there.

Control firefox tabs

I'm working on a firefox extension, until now I was working with XUL browser, to control the user navigation across web sites and save the visited pages, but the browser is limited, I tried a simple google search, when I click on some result, it won't be displayed in the browser.
One idea is to move the xul application to Dialog and control the actual firefox tabs.
But I have no idea how to do this.
(per your comment....)
To create an addon that logs TAB 'load' events, create a bootstrapped (restartless) addon:
bootstrap.js (The JavaScript file containing your 'privileged' code)
install.rdf (an XML file describing your addon to Firefrox)
To build the addon, simply place both files inside the top-level (no folders!) of a ZIP file with the file extension .xpi. To install the addon, navigate to about:addons then from the tools menu, click Install from file, find your XPI, open it, then after a short delay choose Install.
In install.rdf put something like this:
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>youraddonname#yourdomain</em:id>
<em:type>2</em:type>
<em:name>Name of your addon</em:name>
<em:version>1.0</em:version>
<em:bootstrap>true</em:bootstrap>
<em:description>Describe your addon.</em:description>
<em:creator>Your name</em:creator>
<!-- Firefox Desktop -->
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>4.0.*</em:minVersion>
<em:maxVersion>29.0.*</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>
You need to implement two mandatory JavaScript functions in the bootstrap.js:
startup() - called when you install the addon, and when your browser starts up.
shutdown() - called when you uninstall the addon, and when your browser shuts down.
You should call all of the 'privileged' code from startup(). For hygiene, you can (and probably should) also implement install() and uninstall() functions.
Start by implementing the following code in bootstrap.js:
const Cc = Components.classes;
const Ci = Components.interfaces;
let consoleService = Cc["#mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService);
let wm = Cc["#mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator);
function LOG(msg) {
consoleService.logStringMessage("EXTENSION: "+msg);
}
function startup() {
try {
LOG("starting up...");
let windows = wm.getEnumerator("navigator:browser");
while (windows.hasMoreElements()) {
let chromeWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
WindowListener.setupBrowserUI(chromeWindow);
}
wm.addListener(WindowListener);
LOG("done startup.");
} catch (e) {
LOG("error starting up: "+e);
}
}
function shutdown() {
try {
LOG("shutting down...");
let windows = wm.getEnumerator("navigator:browser");
while (windows.hasMoreElements()) {
let chromeWindow = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
WindowListener.tearDownBrowserUI(chromeWindow);
}
wm.addListener(WindowListener);
LOG("done shutdown.");
} catch (e) {
LOG("error shutting down: "+e);
}
}
Basically, that calls WindowListener.setupBrowserUI() for each current & future window of your web-browser. WindowListener is defined as follows:
var WindowListener = {
setupBrowserUI: function(chromeWindow) {
chromeWindow.gBrowser.addEventListener('load', my_load_handler, true);
},
tearDownBrowserUI: function(chromeWindow) {
chromeWindow.gBrowser.removeEventListener('load', my_load_handler, true);
},
onOpenWindow: function(xulWindow) {
let chromeWindow = xulWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
chromeWindow.addEventListener("load", function listener() {
chromeWindow.removeEventListener("load", listener, false);
var domDocument = chromeWindow.document.documentElement;
var windowType = domDocument.getAttribute("windowtype");
if (windowType == "navigator:browser")
WindowListener.setupBrowserUI(chromeWindow);
}, false);
},
onCloseWindow: function(chromeWindow) { },
onWindowTitleChange: function(chromeWindow, newTitle) { }
};
That sets up an event listener for the OpenWindow event, and in turn installs an event listener for load events in the TabBrowser of each ChromeWindow. The load event handler is defined as:
var my_load_handler = function (evt) {
try {
var browserEnumerator = wm.getEnumerator("navigator:browser");
while (browserEnumerator.hasMoreElements()) {
var browserWin = browserEnumerator.getNext();
var tabbrowser = browserWin.gBrowser;
var numTabs = tabbrowser.browsers.length;
for (var index = 0; index < numTabs; index++) {
var currentBrowser = tabbrowser.getBrowserAtIndex(index);
var domWindow = currentBrowser.contentWindow.wrappedJSObject;
if (!domWindow.hasOwnProperty('__logged_this_window__')) {
LOG("TAB loaded:");
LOG(" URL: "+domWindow.location.href);
LOG(" TITLE: "+domWindow.title)
domWindow.__logged_this_window__ = 1;
}
}
}
} catch (e) {
LOG(e);
}
}
So basically, if there's a load event on any of the TabBrowser elements in Firefox, that function will run. It'll enumerate all of the Firefox windows, and all of those windows' tabs (Browser elements). The trick is that when a page reloads all the custom properties on a "content" DomWindow are lost, so we check to see if a custom property is present. If not, then we log details of the TAB's content page.

Phonegap app won't reopen after close (Failed to load webpage with error: CDVWebViewDelegate: Navigation started when state=1)

I'm building an app for iOS using Phonegap and I've run into some problems. The app runs fine on both a simulator and real device until I close the app using the multi-tasking shutdown (double tap home button sequence..)
Upon reopening the app I find that it becomes unresponsive and you can't interact with it in any way. I've spent a fair amount of time trying to debug this and I've had no joy.
Error wise I have been getting the error Failed to load webpage with error: CDVWebViewDelegate: Navigation started when state=1 appear in the xcode console. After lots of googling it seems that this is caused due to hash tags within the URLs (something that I'm using for scrolling down to links both on the same and different pages). Most of the suggestions recommend updating phonegap/cordova to the latest version. I was previously on 2.8 and I went up to 2.9 and it still didn't work, i'm now on 3 and i'm still getting the same issues.
I've checked the cordova git and updated my CDVWebViewDelegate.m file several times with supposed fixes, nothing seems to work. I had a previous version of the app working on earlier versions of Cordova/Phonegap but I've recently upgraded and i'd rather not downgrade to get it to work..
I should probably note that I'm using zepto for my ajax calls and not JQM, for the hash tag scrolling i'm using the following code (figured this may help given it seems to be a hash issue..)
Hash Change function
// Ajax
var wrap = $('#contentScroller .scroller')
// get href
$('a.ajax').click(function () {
location.hash = $(this).attr('href').match(/(^.*)\./)[1]
return false
})
// load page
function hashChange() {
var page = location.hash.slice(1)
if (page != "" && window.location.hash) {
wrap.hide();
spinner.spin(target);
//setTimeout(function () {
wrap.load('pages/' + page + ".html .page-wrapper")
contentScroller.scrollTo(0,0);
refreshScroll();
//}, 1500);
snapper.close();
$(menuBtn).removeClass('active');
}else{
wrap.hide();
spinner.spin(target);
//setTimeout(function () {
wrap.load('pages/Welcome.html .page-wrapper')
refreshScroll();
//}, 1500);
snapper.close();
$(menuBtn).removeClass('active');
}
}
// check for hash change
if ("onhashchange" in window) {
$(window).on('hashchange', hashChange).trigger('hashchange')
} else { // lame browser
var lastHash = ''
setInterval(function () {
if (lastHash != location.hash)
hashChange()
lastHash = location.hash
contentScroller.scrollTo(0,0);
}, 100)
}
Scrolling
$(document)
.on('ajaxStart', function () {
wrap.hide();
})
.on('ajaxStop', function () {
//wrap.show();
})
.on('ajaxSuccess', function () {
//setTimeout(function () {
spinner.stop();
wrap.fadeIn(700);
refreshScroll();
//}, 1000);
// Local storage scrollTo
var storage = window.localStorage;
var url = window.location.href.substr(window.location.href.lastIndexOf("/") + 1);
$('a.scroll-link').click(function (event) {
event.preventDefault();
url = url.replace('home.html?firstrun#', "");
url = url.replace(url, url+".html");
var myHref = $(this).attr('href');
if (url == myHref) {
var sameScroll = $(this).attr('data-scroll-same-page');
sameScroll = sameScroll.replace(sameScroll, "a#" + sameScroll);
contentScroller.scrollToElement(sameScroll, 1500);
} else {
var diffScroll = $(this).attr("data-scroll-diff-page");
storage.setItem("key", diffScroll);
//Alter value for iScroll
var value = window.localStorage.getItem("key");
value = value.replace(value, "a#" + value);
location.hash = $(this).attr('href').match(/(^.*)\./)[1]
$(window).on('hashchange', hashChange).trigger('hashchange')
// Scroll to element after .5 second
setTimeout(function () {
contentScroller.scrollToElement(value, 1500);
return false;
}, 2000)
// Clear local storage to prevent scrolling on page reload
localStorage.clear();
}
Sample link
<a href="IndexOfTerms.html" class="ajax scroll-link" data-scroll-diff-page="First_year_allowance">
this will then pass the attr "first_year_allowance" through to the IndexOfTerms pages and then scroll down to the element that has that id
Can anybody shed some light on how I might be able to fix this? It's really starting to annoy me so I'd quite like to get a fix pretty sharpish!
Note: Libraries used: iScroll, Zepto, fastclick, snapjs, spinjs
Thanks!

External link in WinJS, iframe or not, doesnt matter

I work on a Windows 8 app, and from a page that I use link hystory for running back and forward through the app, I also have 3 or 4 links to external websites(eg: facebook or my site). I tried to run them in iframe, or also to make them open in the default browser like simple links. Both method resulted in an error in base.js that says it can't handle my error (!?) I searched a lot before asking here. I watched msdn sample that works just fine, but if i copy what I need in my app results in the same error. I I use it from another page where I dont have forward history, it works, but i really need it on the front page. Any ideeas? Thank you very much.
LE:
This is my items.js code: ( for the items.html page )
(function () {
"use strict";
var appViewState = Windows.UI.ViewManagement.ApplicationViewState;
var ui = WinJS.UI;
ui.Pages.define("/pages/items/items.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
var listView = element.querySelector(".itemslist").winControl;
listView.itemDataSource = Data.groups.dataSource;
listView.itemTemplate = element.querySelector(".itemtemplate");
listView.oniteminvoked = this._itemInvoked.bind(this);
this._initializeLayout(listView, Windows.UI.ViewManagement.ApplicationView.value);
listView.element.focus();
WinJS.Utilities.query("a").listen("click", this.linkClickEventHandler, false);
},
// This function updates the page layout in response to viewState changes.
updateLayout: function (element, viewState, lastViewState) {
/// <param name="element" domElement="true" />
var listView = element.querySelector(".itemslist").winControl;
if (lastViewState !== viewState) {
if (lastViewState === appViewState.snapped || viewState === appViewState.snapped) {
var handler = function (e) {
listView.removeEventListener("contentanimating", handler, false);
e.preventDefault();
}
listView.addEventListener("contentanimating", handler, false);
var firstVisible = listView.indexOfFirstVisible;
this._initializeLayout(listView, viewState);
if (firstVisible >= 0 && listView.itemDataSource.list.length > 0) {
listView.indexOfFirstVisible = firstVisible;
}
}
}
},
linkClickEventHandler: function (eventInfo) {
eventInfo.preventDefault();
var link = eventInfo.target;
WinJS.Navigation.navigate(link.href);
},
// This function updates the ListView with new layouts
_initializeLayout: function (listView, viewState) {
/// <param name="listView" value="WinJS.UI.ListView.prototype" />
if (viewState === appViewState.snapped) {
listView.layout = new ui.ListLayout();
} else {
listView.layout = new ui.GridLayout();
}
},
_itemInvoked: function (args) {
var groupKey = Data.groups.getAt(args.detail.itemIndex).key;
WinJS.Navigation.navigate("/pages/split/split.html", { groupKey: groupKey });
}
});
})();
And from items.html I have different types of links: some of them links to other application pages, from where I can return with history buttons back/forward and some of them are links to external page. Simple link.These links crashes my app with the error that I mentioned below. If I erase the next line:
WinJS.Utilities.query("a").listen("click", this.linkClickEventHandler, false);
from my js script, external links works, but I dont have anymore history buttons in my others's app pages.
You are trying to use the navigation framework to navigate to an external URI. It's usually meant to be used within the application's local context and pages that can contain 'fragments' to load up into your main nav control.
I wouldn't hook anchor tags with your function call, instead in your linkClickEventHandler I would do the following to only hook your internal links
WinJS.Utilities.query(".nav").listen("click", linkClickEventHandler, false);
in turn your internal links would be
click me
This approach only hooks the navigation framework into your internal links. Another approach is to inspect the 'this.href' in your handler and if it contains http:// or https:// then call window.open instead

Resources