I have developed a windows 10 universal app using Html,css and JS. For allowing inline scripts i am using ms-appx-web context and has set ms-appx-web:///login.html as start page in manifest.
Whenever I open my app in windows 10 mobile it works fine but if I switch to another app and then go to app again by selecting it from windows app list. Then it instead of resuming app from saved state it restarts it.
(function () {
"use strict";
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState === activation.ApplicationExecutionState.terminated) {
}
if (WinJS.Application.sessionState.url) {
localStorage.setItem("UserName", WinJS.Application.sessionState.name);
window.location = WinJS.Application.sessionState.url;
}
args.setPromise(WinJS.UI.processAll().then(function () {
}));
}
};
app.oncheckpoint = function (args) {
var location = window.location.href;
var name = localStorage.getItem("UserName");
WinJS.Application.sessionState.name = name;
WinJS.Application.sessionState.url = location;
};
Windows.UI.WebUI.WebUIApplication.addEventListener("resuming", function (args) {
if (WinJS.Application.sessionState) {
window.location = WinJS.Application.sessionState.url;
localStorage.setItem("UserName", WinJS.Application.sessionState.name);
}
}, false);
Windows.UI.WebUI.WebUIApplication.addEventListener("suspending", function (args) {
var location = window.location.href;
var name = localStorage.getItem("UserName");
WinJS.Application.sessionState.name = name;
WinJS.Application.sessionState.url = location;
}, false);
app.start();
})();
Can anyone suggest me what am I doing wrong?
I changed my app.onactivated event in main.js
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
} else {
}
args.setPromise(WinJS.UI.processAll());
var name = Windows.Storage.ApplicationData.current.roamingSettings.values["name"];
var url = Windows.Storage.ApplicationData.current.roamingSettings.values["url"];
if (name) {
localStorage.setItem("UserName", name);
}
if (url) {
window.location.href = url;
}
}
};
But it stops running on window.location.href = url; line.
What i am trying to do is store username and current url on suspending event and want to restore it on resume event (when user opens app from app list which is already running.)
but if I switch to another app and then go to app again by selecting it from windows app list. Then it instead of resuming app from saved state it restarts it.
I think you are not using Single-Page Navigation for your app.
Please refer to Single-page navigation: the recommended model:
The script context is destroyed and must be initialized again. The app might receive system events but not handle them because the script context is being destroyed and reinitialized.
So the script context is already destroyed after you navigated to other page.
To fix the problem, the best solution is to make your app a single paged application. And navigate pages using PageControl. You can refer to Quickstart: Using single-page navigation to get started.
Update:
but when I use window.location.href for redirecting in main.js it closes app.
It's because you are using it in WinJS script. When you are leaving the page WinJS script context will be destroyed and thus executing the codes inside crash the app. To fix this you can use windows lifecycle API instead:
var roaming=Windows.Storage.ApplicationData.current.roamingSettings;
Windows.UI.WebUI.WebUIApplication.addEventListener("activated", function (args) {
if (args.detail[0].kind === activation.ActivationKind.launch) {
if (roaming.values["currentUri"]) {
window.location.href = roaming.values["currentUri"];
}
}
});
Windows.UI.WebUI.WebUIApplication.addEventListener("suspending", function (args) {
roaming.values["currentUri"] = window.location.href;
roaming.values["UserName"] = evt.srcElement.value;
//save the other information of the page here
});
Windows.UI.WebUI.WebUIApplication.addEventListener("resuming", function (args) {
var roam = Windows.Storage.ApplicationData.current.roamingSettings;
if (roam) {
if (roam["currentUri"])
{
window.location.href = roam["currentUri"];
}
}
}, false);
You can also refer to my demo.
Notes: If you don't use WinJS at all, just remove the reference. Loading WinJS library on every page is not efficient.
I have changed my main.js as :
(function () {
"use strict";
//No need of WinJS
var activation = Windows.ApplicationModel.Activation;
var roaming = Windows.Storage.ApplicationData.current.roamingSettings;
// For App Start Up
Windows.UI.WebUI.WebUIApplication.addEventListener("activated", function (args) {
if (args.detail[0].kind === activation.ActivationKind.launch) {
if (roaming.values["currentUri"]) {
if (roaming.values["UserName"])
{
localStorage.setItem("UserName", roaming.values["UserName"]);
window.location.href = roaming.values["currentUri"];
}
}
}
});
// For App Suspension
Windows.UI.WebUI.WebUIApplication.addEventListener("suspending", function (args) {
roaming.values["currentUri"] = window.location.href;
roaming.values["UserName"] = localStorage.getItem("UserName");
});
// For Resuming App
Windows.UI.WebUI.WebUIApplication.addEventListener("resuming", function (args) {
var roam = Windows.Storage.ApplicationData.current.roamingSettings;
if (roam) {
if (roam.values["currentUri"]) {
localStorage.setItem("UserName", roam.values["UserName"]);
window.location.href = roam.values["currentUri"];
}
}
}, false);
// not working backpressed event
Windows.UI.WebUI.WebUIApplication.addEventListener("backpressed", function (args) {
// to do
}, false);})();
Everything is working fine. But I dont know how to add back key press event without using winjs.
Can anyone suggest me?
How to add back key press event without winjs?
Related
i'm having difficulties trying to open up links in phonegap's (cordova's) inAppBrowser.
I need to be able to make it so the IAB can open both local phonegap links (file:///android_assets/www/example.html) and online links (https://www.google.com for instance)
I have achieved this so far by creating an object in index.js which creates an initiate IAB object, and then for every call from there onwards I was thinking that I could just open that link.
I've found a number of problems, for example when I try to use window.location = some_url it will change the index.html page to that some_url and hence my attached JS no longer works.
I've tried injecting a window.location from my index.html's JS into the IAB document however that breaks down when trying to fetch a local file
My current method is causing a memory leak because it's continuously opening IAB objects which I'm then having difficulties closing because ...
Using the .close() method on an IAB object shows (according to Chrome's Remote Devices view) that it doesn't actually delete the IAB window but rather turns it into an about:new tab
Heres my current code for the JS which is called in index.js (im sorry i know there's a lot of redundant code!)
var interceptor = {
// library dictionary object of <K,V> pairs in the form of <current page, desired page>
// insert your k,v pairs here:
library: {
'login/signup.php': 'example.html', //test data
'calendar/view.php': 'example.html',
'course/view.php?id=10': 'example.html'
},
// origin dictionary
// dictionary for redirecting from the phonegap page to the moodle page
// must be explicit in your page names and avoid duplication
// e.g. use full path notation -> full/path/to/file.html not file.html
origin: {
'current/attempt': ['example1.html', 'example2.html', 'course/index.php'] //test data
},
history_stack: [],
// stack of all current windows
browser_windows: [],
is_back: 'false',
windows: 0,
redirect_flag: false,
first: true,
currentWindow: null,
currentLocalFile: null,
get_origin: function() {
return this.origin;
},
get_library: function() {
return this.library;
},
// interceptor constructor
initialize: function(old_ref = null, default_url = config.moodleURL, android = true) {
// interval for checking our back flag
// the scope changes when you enter the anonymous closure and this changes. this is a hack for that
var self = this;
var ref;
console.log('default url: ' + default_url);
// check for android
if ((android) && (self.windows < 1)) {
// self.browser_windows[0] = cordova.InAppBrowser.open(default_url, '_blank', 'location=no,zoom=no');
ref = cordova.InAppBrowser.open(default_url, '_blank', 'location=yes,zoom=no');
self.first = false;
}
// otherwise iOS
else if ((!android) && (self.windows < 1)) {
// self.browser_windows[0] = cordova.InAppBrowser.open(default_url, '_blank', 'location=no,zoom=no,suppressesIncrementalRendering');
ref = cordova.InAppBrowser.open(default_url, '_blank', 'location=no,zoom=no,suppressesIncrementalRendering');
// self.browser_windows.push(ref);
self.first = false;
} else {
old_ref =
// old_ref = cordova.InAppBrowser.open(default_url, '_blank', 'location=yes,zoom=no');
ref = old_ref;
}
self.windows++;
var library_dictionary = this.get_library();
var origin_dictionary = this.get_origin();
var redirect_URL;
ref.addEventListener('loadstart', function(event) {
// push current page to histoy stack
self.history_stack.push(event.url);
// check to see if an element of one of our origin arrays is in the URL
for (var origin_list in origin_dictionary) {
if (event.url.includes(origin_list)) self.redirect_flag = true;
for (var elements in origin_dictionary[origin_list]) {
// if it is raise a flag and store the key that its array maps to
if ((event.url.includes(origin_dictionary[origin_list][elements])) && (self.redirect_flag)) {
redirect_URL = origin_list;
self.redirect_flag = false;
var temp_previous_pages = self.history_stack;
var temp_element;
// pop elements of stack until empty
while (temp_previous_pages.length !== 0) {
temp_element = temp_previous_pages.pop();
// if we find an element in the stack (our URL history) that matches the key that our array mapped to
if (temp_element.indexOf(redirect_URL) !== -1) {
// redirect and break from loop
self.initialize(ref, temp_element, android);
break;
}
}
}
}
}
for (var key in library_dictionary) {
if (event.url.includes(key)) {
self.initialize(ref, library_dictionary[key], android);
break;
}
}
});
ref.addEventListener('loadstop', function() {
// when we've finished loading our page set up an interval every 2.5 seconds to check
// if we've been signalled to change pages
console.log('here');
var is_back_interval = setInterval(function() {
ref.executeScript({
code: "localStorage.getItem('is_back')"
}, function(values) {
if (values[0] === 'true') {
// if we have been signalled then remove that signal from our html or moodle page
ref.executeScript({
code: "localStorage.setItem('is_back', '')"
});
// get 3rd last since the last will be the current page as will the 2nd last
prev_page = self.history_stack[self.history_stack.length - 3];
self.initialize(ref, prev_page, android);
}
});
}, 2500);
});
}
};
and heres index.js
var app = {
// Application Constructor
initialize: function() {
this.bindEvents();
},
// Bind Event Listeners
//
// Bind any events that are required on startup. Common events are:
// 'load', 'deviceready', 'offline', and 'online'.
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
// deviceready Event Handler
//
// The scope of 'this' is the event. In order to call the 'receivedEvent'
// function, we must explicitly call 'app.receivedEvent(...);'
onDeviceReady: function() {
app.receivedEvent('deviceready');
},
// Update DOM on a Received Event
receivedEvent: function(id) {
if (window.device.platform === "iOS"){
interceptor.initialize(config.moodleURL, false);
} else {
interceptor.initialize();
}
}
};
example.html: https://gist.github.com/anonymous/28a78ab0879878d7a9dac8eb89544cda
This is my main.js
(function () {
"use strict";
//No need of WinJS
var activation = Windows.ApplicationModel.Activation;
var roaming = Windows.Storage.ApplicationData.current.roamingSettings;
// For App Start Up
Windows.UI.WebUI.WebUIApplication.addEventListener("activated", function (args) {
if (args.detail[0].kind === activation.ActivationKind.launch) {
if (roaming.values["currentUri"]) {
if (roaming.values["UserName"])
{
localStorage.setItem("UserName", roaming.values["UserName"]);
window.location.href = roaming.values["currentUri"];
}
}
}
});
// For App Suspension
Windows.UI.WebUI.WebUIApplication.addEventListener("suspending", function (args) {
roaming.values["currentUri"] = window.location.href;
roaming.values["UserName"] = localStorage.getItem("UserName");
});
// For Resuming App
Windows.UI.WebUI.WebUIApplication.addEventListener("resuming", function (args) {
var roam = Windows.Storage.ApplicationData.current.roamingSettings;
if (roam) {
if (roam.values["currentUri"]) {
localStorage.setItem("UserName", roam.values["UserName"]);
window.location.href = roam.values["currentUri"];
}
}
}, false);
// not working backpressed event
Windows.UI.WebUI.WebUIApplication.addEventListener("backpressed", function (args) {
// to do
}, false);})();
I need to add back key press event for windows phone without using winjs library?
Can anyone suggest me?
I am using ms-appx-web context in my app. I dont want to use winjs library.
I need to add back key press event for windows phone without using winjs library?
The backpressed event should be attached to Windows.Phone.UI.Input.HardwareButtons but not Windows.UI.WebUI.WebUIApplication.
If you refer to HardwareButtons.BackPressed and HardwareButtons, you will find the backpressed event is used like this:
var hardwareButtons = Windows.Phone.UI.Input.HardwareButtons;
function onBackPressed(eventArgs) { /* Your code */ }
// addEventListener syntax
hardwareButtons.addEventListener("backpressed", onBackPressed);
hardwareButtons.removeEventListener("backpressed", onBackPressed);
And since you are not making a Single Page Application. This event should be attached on every new page's JS codes.
Update: If you want to know your current device programmatically, you can use the following if-statement:
if (deviceInfo.operatingSystem.toLowerCase() == "windowsphone")
{
//do your windows phone logic
} else if (deviceInfo.operatingSystem.toLowerCase() == "windows")
{
//do your windows logic
}
I used this-
var flag = Windows.Foundation.Metadata.ApiInformation.isTypePresent("Windows.Phone.UI.Input.HardwareButtons");
if (flag) {
var hardwareButtons = Windows.Phone.UI.Input.HardwareButtons;
hardwareButtons.addEventListener("backpressed", onBackPressed);
}
It worked for me well!
This is undoubtedly a stupid problem where I'm just doing something simple wrong.
I have a page with several directives, loading their templates and controllers. All of which is working fine except for this one.
Using the controller as model, this. is the same as $scope.. So in my controller I have:
var self = this;
this.states = { showControls: false, showVideo: false }
this.showVideo = function() { self.states.showVideo = true; }
this.showControls = function() { self.states.showControls = true; }
$scope.$on(Constants.EVENT.START_WEBCAM, self.showVideo)
$scope.$on(Constants.EVENT.VIDEO_SUCCESS, self.showControls)
In the view I have a button to reveal this part of the view and subsequently request access to your webcam. Clicking the button broadcasts an event with $rootScope.$broadcast from the parent controller.
When the user grants access to the webcam (handled in the directive's link function) it broadcasts another event the same way.
Both methods are triggered by listening with $scope.$on, and both methods fire as they should. However, the showVideo method successfully updates its associated state property, and the showControls method does not. What am I doing wrong?
Using the debug tool it looks like states.showControls is being set to true, but this change isn't reflected in the view, and adding a watcher to the states object doesn't detect any change at this point either. It does when I set showVideo.
EDIT
This part is in the directive:
if (Modernizr && Modernizr.prefixed('getUserMedia', navigator)) {
userMedia = Modernizr.prefixed('getUserMedia', navigator);
}
var videoSuccess = function(stream) {
// Do some stuff
$rootScope.$broadcast(Constants.EVENT.VIDEO_SUCCESS);
}
scope.$on(Constants.EVENT.START_WEBCAM, function() {
if (MediaStreamTrack && MediaStreamTrack.getSources) {
MediaStreamTrack.getSources(function(sourceInfo) {
var audio = null;
var video = null;
_.each(sourceInfo, function(info, i) {
if (info.kind === "audio") {
audio = info.id;
} else if (info.kind === "video") {
video = info.id;
} else {
console.log("random unknown source: ", info);
}
});
if (userMedia) { userMedia(getReqs(), videoSuccess, error); }
});
}
});
i've got a pretty simple Javascript for redirecting a specific URL to an app in Google-Play-Store/iOS-Store or show an URL for desktop users depending on the client's opersting system. For the ios case the redirect is not being executed, can anyone explain what the problem is? (alert before redirect is being executed properly!)
var playStoreUrl = "https://play.google.com/store/apps/details?id=xyz",
appStoreUrl = "https://itunes.apple.com/de/app/gxyz/id123456789?mt=8",
desktopUrl = "http://www.xyz.de/apps/";
var isMobile = {
Android: function() {
return navigator.userAgent.match(/Android/i);
},
iOS: function() {
return navigator.userAgent.match(/iPhone|iPad|iPod/i);
}
};
if ( isMobile.Android() ) {
alert('os: android!');
window.location.href = playStoreUrl;
}
else if(isMobile.iOS()) {
alert('os: ios!');
window.location.href = appStoreUrl;
}
else {
alert('os: desktop!');
window.location.href = desktopUrl;
}
Solution: don't use the "?mt=8" parameter in the iOS-Appstore-Link and the redirect will work (and open the Appstore-App on your device)
I'm writing a firefox plugin and keeping track of each page's workers in an array. Apart from a bit of fancy footwork required to manage this array (as described here https://bugzilla.mozilla.org/show_bug.cgi?id=686035 and here Addon SDK - context-menu and page-mod workers) everything is working properly. One issue I'm having is that when listening to the tabs pageshow event (or the worker's own pageshow event for that matter), the callback seems to fire before the worker is actually ready. When retrieving the page's corresponding worker in the callback and using it to try to send a message to the content script, I'm receiving the error The page is currently hidden and can no longer be used until it is visible again. Normally, I'd just use a setTimeout and grit my teeth, but this isn't available for add-ons. What's a suitable workaround? The code for the main part of the add-on is below:
var { ToggleButton } = require('sdk/ui/button/toggle');
var panels = require('sdk/panel');
var tabs = require('sdk/tabs');
var self = require('sdk/self');
var pageMods = require('sdk/page-mod');
var ss = require('sdk/simple-storage');
var workers = [];
ss.storage.isPluginActive = ss.storage.isPluginActive || false;
var button = ToggleButton({
id: 'tomorrowww',
label: 'Tomorowww',
icon: {
'16': './icon-16.png',
'32': './icon-32.png',
'64': './icon-64.png'
},
onChange: handleButtonChange
});
var panel = panels.Panel({
contentURL: self.data.url('panel.html'),
contentScriptFile: self.data.url('panel-script.js'),
onHide: handlePanelHide,
width: 342,
height: 270
});
panel.port.on('panel-ready', handlePanelReady);
panel.port.on('plugin-toggled', handlePluginToggled);
panel.port.on('link-clicked', handleLinkClicked);
pageMods.PageMod({
include: ['*'],
contentScriptFile: [self.data.url('CancerDOMManager.js'), self.data.url('content-script.js')],
contentStyleFile: self.data.url('content-style.css'),
onAttach: function (worker) {
addWorker(worker);
sendActiveState(ss.storage.isPluginActive);
}
});
// move between tabs
tabs.on('activate', function () {
sendActiveState();
});
// this actually fires before the worker's pageshow event so isn't useful as the workers array will be out of sync
//tabs.on('pageshow', function () {
// sendActiveState();
//});
function addWorker (worker) {
if(workers.indexOf(worker) > -1) {
return;
}
worker.on('detach', handleWorkerDetach);
worker.on('pageshow', handleWorkerShown);
worker.on('pagehide', handleWorkerHidden);
workers.push(worker);
}
function handleWorkerDetach () {
removeWorker(this, true);
}
function handleWorkerShown () {
addWorker(this);
// back / forward page history
// trying to send the state here will trigger the page hidden error
sendActiveState();
}
function handleWorkerHidden () {
removeWorker(this);
}
function removeWorker (worker, removeEvents) {
var index = workers.indexOf(worker);
removeEvents = removeEvents || false;
if(index > -1) {
if(removeEvents) {
worker.removeListener('detach', handleWorkerDetach);
worker.removeListener('pageshow', handleWorkerShown);
worker.removeListener('pagehide', handleWorkerHidden);
}
workers.splice(index, 1);
}
}
function getWorkersForCurrentTab () {
var i;
var tabWorkers = [];
i = workers.length;
while(--i > -1) {
if(workers[i].tab.id === tabs.activeTab.id) {
tabWorkers.push(workers[i]);
}
}
return tabWorkers;
}
function handlePanelReady () {
setActive(ss.storage.isPluginActive);
}
function setActive (bool) {
ss.storage.isPluginActive = bool;
panel.port.emit('active-changed', bool);
sendActiveState();
}
function sendActiveState () {
var tabWorkers = getWorkersForCurrentTab();
var i = tabWorkers.length;
while(--i > -1) {
tabWorkers[i].port.emit('toggle-plugin', ss.storage.isPluginActive);
}
}
function handleButtonChange (state) {
if(state.checked) {
panel.show({
position: button
});
}
}
function handlePanelHide () {
button.state('window', {checked: false});
}
function handleLinkClicked (url) {
if(panel.isShowing) {
panel.hide();
}
tabs.open(url);
}
function handlePluginToggled (bool) {
if(panel.isShowing) {
panel.hide();
}
setActive(bool);
}
try using contentScriptWhen: "start" in the page-mod
I was dealing with a similar problem. I think I have it working the way I want now by putting the listener in the content script instead of the addon script. I listen for the event on the window, I then emit a message from my content script to my addon script, my addon script then sends a message back to the content script with the information needed from the addon script.
In my code, I am working on update the preferences in the content script to ensure that the tab always has the most up to date settings when they are changed, only the addon script can listen to the prefs change event.
This particular snippet will listen for when the page is navigated to from history (i.e., back or forward button), will inform the addon script, the addon script will get the most up to date preferences, and then send them back to a port listening in the content script.
Content script:
window.onpageshow = function(){
console.log("onpageshow event fired (content script)");
self.port.emit("triggerPrefChange", '');
};
Addon Script (e.g., main.js:
worker.port.on("triggerPrefChange", function() {
console.log("Received request to triggerPrefChange in the addon script");
worker.port.emit("setPrefs", prefSet.prefs);
});
Since the event is being fired from the DOM event, the page must be shown. I am not sure if listening to the pageshow event in the addon script is doing what we think.