folks!
I'm trying to run an HTML app in Trigger.io. This app calls ajax to load some data from a PHP page. At this moment, I authenticate the user and start the session. After this, I have to call another PHP page. So, I check for the session started, and I found that the session is not active anymore. The second call is made right after the first one.
This happens when I try to run the app from the Trigger.io ToolKit, using iOS Simulator ( I'm using a Mac - OS X Mountain Lion ). When I test the same app in the Safari, it works perfectly: my PHP server recognizes the session started earlier, and the second page is loaded by ajax.
Is there any parameter I have to set? Or Trigger.io does not support PHP sessions?
Thank you.
Marcio
You should use forge.request.ajax(params) to make ajax requests, this is because of cross domain restrictions, as Forge apps are loaded as file:// urls on iOS.
forge.ajax.request takes a similar input to jQuery's $.ajax so you can easily switch between them if you want to use the same code on a website as well as in your Forge app.
More documentation is available in our docs: http://docs.trigger.io/en/v1.4/modules/request.html#ajax
#Connorhd , thank you so much for helping!
First of all, I do an ajax request to "app_authUser.php" to authenticate user. Then, if Ok, I do another ajax request to "app_loadFeed.php" to load data from server.
In the first ajax request, I pass, in the post parameters, the user data ( login and password ) to authenticate the user on database. The first command I call on the php file "app_authUser.php" is "session_start()", as follow:
CODE FOR "app_authUser.php" ON THE SERVER SIDE:
<?php
session_start();
// Just for test;
$idSession = session_id();
echo $idSession;
/*
Test user authenticate. If ok, then I assign idUser to $_SESSION['idUser'] variable.
*/
if( $loginOk == true ){
$_SESSION[ 'idUser' ] = $User->idUser;
}
?>
In the code above, the user is authenticated and $_SESSION['idUser'] is correctly initiated. In the second ajax request, I test if the variable $_SESSION[ 'idUser' ] is set. That's the point: it isn't set anymore. Again, I call "session_start()" at first:
CODE FOR "app_loadFeed.php" ON THE SERVER SIDE:
<?php
session_start();
// Just for test;
$idSession = session_id();
echo $idSession;
if( isset( $_SESSION[ 'idUser' ] ) ){
/* Load data from database to return to user.... */
echo ...
}
else{
echo '0';
}
?>
The test above always return false when I call my app from Trigger.io compiler. But, when I call my app from Safari, it always returns true.
I found out that the function "session_id()" returns different values in both ajax requests when the call is made from app running on Trigger.io compiler, but the same value when app is running on Sarari:
Example:
Requests from Trigger.io:
First request: echo $idSession returns "m7dbsv7qqem92os39lv5ao2ta1"
Second request: echo $idSession returns "h49pble06n7ao9pum06kt4dph0"
Requests from Safari:
First request: echo $idSession returns "2cbhin1185fm5ehvbb15k6n0b1"
Second request: echo $idSession returns "2cbhin1185fm5ehvbb15k6n0b1"
That means the session isn't the same at the first example. Why does this happen?
I'm not using forge.request.ajax in my app. That's my ajax code, in my javascript:
<script>
function openAjax()
{
try
{
var ajax = new XMLHttpRequest();
}
catch(e)
{
try
{
var ajax = new ActiveXObject("Msxml2.XMLHTTP");
}
catch(ee)
{
try
{
var ajax = new ActiveXObject("Microsoft.XMLHTTP");
}
catch(eee)
{
var ajax = false;
alert("Seu navegador não suporta AJAX!")
}
}
}
return ajax;
}
// This is the function called at second time, just after I authenticate my user and have session opened.
function loadFeed(){
var url = CT_URLBase + 'app_loadFeed.php'; // CT_URLBase = 'http://192.168.1.100/' in my local environment.
var parameters = '';
var ajax = openAjax();
ajax.open('POST', url, true);
ajax.setRequestHeader('Content-type', 'application/x-www-form-urlencoded; charset=iso-8859-1');
ajax.onreadystatechange = function(){
if (ajax.readyState == 4){
if (ajax.status == 200){
var retorno = ajax.responseText;
if( retorno != '0' ){
/* Return OK!!! */
}
else{
/* Error: return is 0 (zero), that means session is not started.
}
}
}
}
ajax.send(parameters);
}
</script>
What most makes me in a misunderstanding is that the same code works perfectly in Safari, but not in Trigger.io.
By the way, I visited your website, connorhd.co.uk ! Great job! It's a great place to find "Interesting stuff"! Congratulations!
Thank you so much for your help!!!
Marcio Clume
Related
I see that this question is similar to another question (webView:didFailLoadWithError -1004: Could not connect to the server while connecting google plus in Phonegap ios) , but somehow different because I've gone over the code line-by-line and it is doing the samething, but it is still not working for me. Perhaps also because I am on different versions: iOS 9.3.2 on an iPhone 5S), Cordova 6.1.1, and cordova-plugin-inappbrowser 1.3.0.
My code works well on my Android, but not on the iPhone. Code is as follows:
var googleapi = {
authorize: function(options) {
var deferred = $.Deferred();
var authUrl = GOOGLE_CLIENT_API_URL + $.param({
client_id: options.client_id,
redirect_uri: options.redirect_uri,
response_type: 'code',
scope: options.scope
});
console.log("authUrl: " + authUrl);
var authWindow = window.open(authUrl, "_blank", "location=no,toolbar=no"); // for iOS add 'toolbar=no'
//The recommendation is to use the redirect_uri "urn:ietf:wg:oauth:2.0:oob"
//which sets the authorization code in the browser's title. However, we can't
//access the title of the InAppBrowser.
//
//Instead, we pass a bogus redirect_uri of "http://localhost", which means the
//authorization code will get set in the url. We can access the url in the
//loadstart and loadstop events. So if we bind the loadstart event, we can
//find the authorization code and close the InAppBrowser after the user
//has granted us access to their data.
//
// To clear the authorization, go to https://accounts.google.com/IssuedAuthSubTokens.
$(authWindow).on('loadstart', function(e) {
var url = e.originalEvent.url;
var code = /\?code=(.+)$/.exec(url);
var error = /\?error=(.+)$/.exec(url);
if(code || error) {
authWindow.close();
}
if (code) {
//Exchange the authorization code for an access token
$.post('https://accounts.google.com/o/oauth2/token', {
code: code[1],
client_id: options.client_id,
client_secret: options.client_secret,
redirect_uri: options.redirect_uri,
grant_type: 'authorization_code'
}).done(function(data) {
// use the token we got back from oauth to setup the api.
gapi.auth.setToken(data);
// load the drive api.
loadDriveApi();
deferred.resolve(data);
}).fail(function(response) {
console.log("Posting code to Google failed. No OAuth token will be returned.");
deferred.reject(response.responseJSON);
});
} else if (error) {
//The user denied access to the app
console.log("Error retrieving code from Google.");
deferred.reject({
error: error[1]
});
}
});
return deferred.promise();
}
};
function checkAuth() {
if(device.platform === 'browser') {
console.log("calling gapi.auth.authorize()");
gapi.auth.authorize(
{
'client_id' : CLIENT_ID,
'scope' : SCOPES.join(' '),
'immediate' : true
}, handleAuthResult);
} else {
// because this is called only after deviceready(), InAppBrowser is initialized by now:
console.log("using the InAppBrowser plugin to authenticate.");
window.open = cordova.InAppBrowser.open;
googleapi.authorize(
{
'client_id' : CLIENT_ID,
'client_secret' : CLIENT_SECRET,
'redirect_uri' : REDIRECT_URI,
'scope' : SCOPES.join(' ')
}, handleAuthResult);
}
}
/**
* Handle response from authorization server.
*
* #param {Object} authResult Authorization result.
*/
function handleAuthResult(authResult) {
var authMenuItem = document.getElementById("menuitemenablegoogledrivebackup");
if (authResult && !authResult.error) {
// If already authorized, change menu option to allow user to deny Authorization
authMenuItem.innerHTML = l("Disable Google Drive Backup");
loadDriveApi();
} else {
alert("Authorization Error: " + authResult.error);
console.log("inside handleAuthResult, authResult.error: " + authResult.error);
// Show auth menu item, allowing the user to initiate authorization
authMenuItem.innerHTML = l("Enable Google Drive Backup");
// use the InAppBrowser to display the authorization window:
// var authWindow = window.open(authUrl, '_blank', 'location=no,toolbar=no');
// or?
// gapi.auth.authorize(
// {
// client_id: CLIENT_ID,
// scope: SCOPES.join(' '),
// immediate: false
// }, handleAuthResult)
}
}
/**
* Load Drive API client library.
*/
function loadDriveApi() {
try {
gapi.client.load('drive', 'v2', null).then(function(resp) {
console.log("Google Drive API v2 loaded successfully.");
}, function(reason) {
alert('Google Drive API v2 FAILED to load: ' + reason.result.error.message);
console.log('Google Drive aPI v2 FAILED to load: ' + reason.result.error.message);
});
} catch(err) {
alert(err.message);
console.log("Google Drive API v2 FAILED to load. Exception: " + err.message);
}
}
From debugging, I see that the Android version calls the window.open() call, which goes through the loadstart handler first once, with the original URL, but it contains no code, and no error, so it just passes through. Then the redirect_url comes up, on a second call to the loadstart handler (is this by the InAppBrowser?) but this time it has the shorter redirect_url with the code appended, so the code is then successfully used to get the token on the "$.post" call. However, on iOS, there is no second call to the loadstart handler.
When I run it in the Chrome debugger, I get no errors, just silent failure. In the XCode debugger, I get errors as follows:
2016-06-09 20:47:27.014 APass2[675:398271] Setting the WebView's frame
to {{0, 0}, {320, 524}} 2016-06-09 20:47:27.015 APass2[675:398271]
Setting the WebView's frame to {{0, 0}, {320, 568}} 2016-06-09
20:47:27.026 APass2[675:398271] THREAD WARNING: ['InAppBrowser'] took
'39.259033' ms. Plugin should use a background thread. 2016-06-09
20:47:27.749 APass2[675:398271] webView:didFailLoadWithError - -1004:
Could not connect to the server. 2016-06-09 20:47:28.955
APass2[675:398271] ERROR Internal navigation rejected -
not set for
url='https://content.googleapis.com/static/proxy.html?jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.en.joG9nQvYxYQ.O%2Fm%3D__features__%2Fam%3DAQ%2Frt%3Dj%2Fd%3D1%2Frs%3DAGLTcCPyXDgCg_S7GlvvvMpztuAZ6V0pEA#parent=file%3A%2F%2F&rpctoken=1268129019'
None of my success or fail callbacks is called.
Please help!!! I'm totally at a loss now.
Thanks,
Edward
First of all, by looking at the InAppBrowser documentation, I learned that there is also a "loaderror" event. Only on iOS, the call to the inAppBrowser.open() was resulting in "loaderror" handler being called. Inside the "loaderror" handler, I was also able to grab the url, just as the original code did on "loadstart". Debugging simultaneously in Chrome and Safari I was able to see that the url was exactly the same in the "loaderror" as in the "loadstart" handler, and the parsing for code and error worked exactly the same way. So, in the first cut, I hacked it that way and got to the next phase (success - sort of). Then I hit another error related to <access-navigation>. Googling that much more, I found that there is a configuration setting available in config.xml in the root of your project.
Lots more Googling pointed me at someone who said to use <allow-navigation href="*" />
Clearly, I was unhappy with that broad a security hole.
So, the bottom line is that I needed to add the urls that the Google api needs to access to the config.xml file as follows:
<allow-navigation href="https://accounts.google.com/*" />
<allow-navigation href="https://content.googleapis.com/*" />
I still need to clean up the code, and probably simplify the error handling in the "loaderror" handler, but I have got it working now!
Most frustrating of all is that this setting is not necessary at all on Android, so I had no reason to suspect this was the problem.
Thank you to those of you who took the time to look at this!
Edward
I'm developing iOS app using ionic framework and I have one problem when I try to call web service by using 3G network.
here is my service in UserService:
function getUserStat(user_id){
var request = $http({ method: "get",
url: "http://www.example.com/user.php",
params: {
action: "stat",
user_id:user_id
},
data: {
}
});
return(request.then(handleSuccess, handleError));
}
function handleError( response ) {
// The API response from the server should be returned in a
// nomralized format. However, if the request was not handled by the
// server (or what not handles properly - ex. server error), then we
// may have to normalize it on our end, as best we can.
if (!angular.isObject( response.data ) || !response.data.message) {
return( $q.reject("An unknown error occurred.") );
}
// Otherwise, use expected error message.
return( $q.reject( response.data.message ) );
}
// I transform the successful response, unwrapping the application data
// from the API response payload.
function handleSuccess( response ) {
return( response.data );
}
the getUserStat() function will return json back.
here is my controller
UserService.getUserStat($scope.user_id).then(function(data){
alert("Result: " + JSON.stringify(data));
});
in my control I just show the json.
I build this code to my iPhone and test it over WIFI network, everything work fine. If i update the serverside, UserService.getUserStat in controller will show update. but the problem is when I test it on 3G network, iPhone always show the old json returned from the server (even I change server side data).
any idea to solve this problem?
Thank you
I had a similar problem when I tried to upload a camera photo to my data server.when i tested the app on my local WIFI it worked perfectly but when I tested it outside i noticed it fails to upload the file. eventualy the problem was that since the internet outside is much slower the app moved to another view without finish the upload action.
so for example if your controller looks something like this:
.controller('Ctrl1', function(webService, $scope, $state) {
UserService.getUserStat($scope.user_id).then(function(data){
alert("Result: " + JSON.stringify(data));
});
$state.go('app.posts');
});
it should be like this:
.controller('Ctrl1', function(webService, $scope, $state) {
UserService.getUserStat($scope.user_id).then(function(data){
alert("Result: " + JSON.stringify(data));
})
.finally(function() {
$state.go('app.posts');
});
});
I am creating a firefox addon using the SDK. My goal is simple, to intercept a specific iframe and load my own HTML page (packaged as a resource with my addon) instead of the content that was requested originally.
So far I have the following code:
var httpRequestObserver =
{
observe: function(subject, topic, data)
{
var httpChannel, requestURL;
if (topic == "http-on-modify-request") {
httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
requestURL = httpChannel.URI.spec;
var newRequestURL, i;
if (/someurl/.test(requestURL)) {
var ioService = Cc["#mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
httpChannel.redirectTo(ioService.newURI(self.data.url('pages/test.html'), undefined, undefined));
}
return;
}
}
};
var observerService = Cc["#mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
observerService.addObserver(httpRequestObserver, "http-on-modify-request", false);
This code works in that it detects the proper iframe loading and does the redirect correctly. However, I get the following error:
Security Error: Content at http://url.com may not load or link to
jar:file:///.../pages/test.html.
How can I get around this limitation?
actually man i was really over thinking this.
its already solved when I changed to using loadContext. Now when you get loadContext you get the contentWindow of whatever browser element (tab browser, or frame or iframe) and then just abort the http request like you are doing and then loadContext.associatedWindow.document.location = self.data('pages/tests.html');
done
ill paste the code here removing all the private stuff. you might need the chrome.manifest ill test it out and paste the code back here
Cu.import('resource://gre/modules/Services.jsm');
var httpRequestObserver = {
observe: function (subject, topic, data) {
var httpChannel, requestURL;
if (topic == "http-on-modify-request") {
httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
requestURL = httpChannel.URI.spec;
var newRequestURL, i;
if (/someurl/.test(requestURL)) {
var goodies = loadContextGoodies(httpChannel);
if (goodies) {
httpChannel.cancel(Cr.NS_BINDING_ABORTED);
goodies.contentWindow.location = self.data.url('pages/test.html');
} else {
//dont do anything as there is no contentWindow associated with the httpChannel, liekly a google ad is loading or some ajax call or something, so this is not an error
}
}
return;
}
}
};
Services.obs.addObserver(httpRequestObserver, "http-on-modify-request", false);
//this function gets the contentWindow and other good stuff from loadContext of httpChannel
function loadContextGoodies(httpChannel) {
//httpChannel must be the subject of http-on-modify-request QI'ed to nsiHTTPChannel as is done on line 8 "httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);"
//start loadContext stuff
var loadContext;
try {
var interfaceRequestor = httpChannel.notificationCallbacks.QueryInterface(Ci.nsIInterfaceRequestor);
//var DOMWindow = interfaceRequestor.getInterface(Components.interfaces.nsIDOMWindow); //not to be done anymore because: https://developer.mozilla.org/en-US/docs/Updating_extensions_for_Firefox_3.5#Getting_a_load_context_from_a_request //instead do the loadContext stuff below
try {
loadContext = interfaceRequestor.getInterface(Ci.nsILoadContext);
} catch (ex) {
try {
loadContext = subject.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
} catch (ex2) {}
}
} catch (ex0) {}
if (!loadContext) {
//no load context so dont do anything although you can run this, which is your old code
//this probably means that its loading an ajax call or like a google ad thing
return null;
} else {
var contentWindow = loadContext.associatedWindow;
if (!contentWindow) {
//this channel does not have a window, its probably loading a resource
//this probably means that its loading an ajax call or like a google ad thing
return null;
} else {
var aDOMWindow = contentWindow.top.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
var gBrowser = aDOMWindow.gBrowser;
var aTab = gBrowser._getTabForContentWindow(contentWindow.top); //this is the clickable tab xul element, the one found in the tab strip of the firefox window, aTab.linkedBrowser is same as browser var above //can stylize tab like aTab.style.backgroundColor = 'blue'; //can stylize the tab like aTab.style.fontColor = 'red';
var browser = aTab.linkedBrowser; //this is the browser within the tab //this is where the example in the previous section ends
return {
aDOMWindow: aDOMWindow,
gBrowser: gBrowser,
aTab: aTab,
browser: browser,
contentWindow: contentWindow
};
}
}
//end loadContext stuff
}
NOTE: Now try this first, I didn't test it yet, if you get a security error when it tries to redirect then create a chrome.manifest file and put it in the root directory. If it throws a security error than you definitely need a chrome.manifest file and that will without question fix it up. I'll test this myself later tonight when I get some time.
The chrome.manifest should look like this:
content kaboom-data ./resources/kaboom/data/ contentaccessible=yes
Then in the code way above change the redirect line from goodies.contentWindow.location = self.data.url('pages/test.html'); to goodies.contentWindow.location = 'chrome://kaboom-data/pages/test.html');.
see this addon here: https://addons.mozilla.org/en-US/firefox/addon/ghforkable/?src=search
in the chrome.manifest file we set the contentaccessible parameter to yes
you dont need sdk for this addon. its so simple, just ocpy paste that into a bootstrap skeleton as seen here:
Bootstrap With Some Features, Like chrome.manifest which you will need
Bootstrap Ultra Basic
if you want to really do a redirect of a page to your site, maybe you want to make a custom about page? if you would like ill throw togather a demo for you on making a custom about page. you can see a bit hard to understand demo here
posting my trials here so it can help all:
trail 1 failed - created chrome.manifest file with contents content kaboom-data resources/kaboom/data/ contentaccessible=yes
var myuri = Services.io.newURI('chrome://kaboom-data/content/pages/test.html', undefined, undefined);
httpChannel.redirectTo(myuri);
Error Thrown
Security Error: Content at http://digg.com/tools/diggthis/confirm? may
not load or link to
jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4RtC8vdvPagpQ#jetpack.xpi!/resources/kaboom/data/pages/test.html.
trial 2 failed - created resource in bootstrap.js
alias.spec =
file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4RtC8vdvPagpQ#jetpack.xpi
alias updated to spec:
jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4RtC8vdvPagpQ#jetpack.xpi!/
let resource = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
let alias = Services.io.newFileURI(data.installPath);
Cu.reportError('alias.spec = ' + alias.spec);
if (!data.installPath.isDirectory()) {
alias = Services.io.newURI("jar:" + alias.spec + "!/", null, null);
Cu.reportError('alias updated to spec: ' + alias.spec);
}
resource.setSubstitution("kaboom_data", alias);
...
var myuri = Services.io.newURI('resource://kaboom_data/resources/kaboom/data/pages/test.html', undefined, undefined);
httpChannel.redirectTo(myuri);
Error Thrown
Security Error: Content at http://digg.com/tools/diggthis/confirm? may
not load or link to
jar:file:///C:/Documents%20and%20Settings/SONY%20VAIO/Application%20Data/Mozilla/Firefox/Profiles/vr10qb8s.default/extensions/jid1-g4RtC8vdvPagpQ#jetpack.xpi!/resources/kaboom/data/pages/test.html.
CONCLUSION
in both trials above it was the weirdest thing, it wouldnt show the resource or chrome path in the security error thrown but it would give the full jar path. Leading me to believe that this has something to do with redirectTo function.
The solution that did work was your solution of
var gBrowser = utils.getMostRecentBrowserWindow().gBrowser;
var domWin = httpChannel.notificationCallbacks.getInterface(Ci.nsIDOMWindow);
var browser = gBrowser.getBrowserForDocument(domWin.document);
//redirect
browser.loadURI(self.data.url('pages/test.html'));
however I changed this to use loadContext instead of this method because it is the recommended way. also gBrowser to getMostRecentBrowserWindow will fail if the url load is slow and in that time the user swithces to another tab or window
I also changed to use Services.jsm as you had imported Cu anyways. Using Services.jsm is super fast not even blink fast. Its just a pointer.
Im still working on trying to the redirectTo method working its really bothering me. The changes I made are to my local copy.
Have you considered turning your local HTML file into a data URL and loading that?
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
i am trying to accomplish a two way communication request response in my firefox sidebar extension, i have a file named event.js this resides on the content side, i have another file called sidebar.js file which is residing in the xul. I am able to communicate from event.js to sidebar.js file using the dispatchEvent method. my event in turn raises a XMLHttpRequest in sidebar.js file which hits the server and sends back the response. Now, here i am unable to pass the response to the event.js file. I want the response to be accessed in the event.js file. Till now i have achieved only one way communication. Please help me in getting the two way communication.
Code is as follows:
// event.js file
// This event occurs on blur of the text box where i need to save the text into the server
function saveEvent() {
var element = document.getElementById("fetchData");
element.setAttribute("urlPath", "http://localhost:8080/event?Id=12");
element.setAttribute("jsonObj", convertToList);
element.setAttribute("methodType", "POST");
document.documentElement.appendChild(element);
var evt = document.createEvent("Events");
evt.initEvent("saveEvent", true, true);
element.dispatchEvent(evt);
//Fetching the response over here by adding the listener
document.addEventListener("dispatchedResponse", function (e) { MyExtension.responseListener(e); }, false, true);
}
var MyExtension = {
responseListener: function (evt) {
receivedResponse(evt.target.getAttribute("responseObject"));
}
}
function receivedResponse(event) {
alert('response: ' + event);
}
// sidebar.js file
window.addEventListener("load", function (event) {
var saveAjaxRequest = function (urlPath, jsonObj, methodType, evtTarget) {
var url = urlPath;
var request = Components.classes["#mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest);
request.onload = function (aEvent) {
window.alert("Response Text: " + aEvent.target.responseText);
saveResponse = aEvent.target.responseText;
//here i am again trying to dispatch the response i got from the server back to the origin, but unable to pass it...
evtTarget.setAttribute("responseObject", saveResponse);
document.documentElement.appendChild(evtTarget);
var evt = document.createEvent("dispatchedRes"); // Error line "Operation is not supported" code: "9"
evt.initEvent("dispatchedResponse", true, false);
evtTarget.dispatchEvent(evt);
};
request.onerror = function (aEvent) {
window.alert("Error Status: " + aEvent.target.status);
};
//window.alert(methodType + " " + url);
request.open(methodType, url, true);
request.send(jsonObj);
};
this.onLoad = function () {
document.addEventListener("saveEvent", function (e) { MyExtension.saveListener(e); }, false, true);
}
var MyExtension =
{
saveListener: function (evt) {
saveAjaxRequest(evt.target.getAttribute("urlPath"), evt.target.getAttribute("jsonObj"), evt.target.getAttribute("methodType"), evt.originalTarget);
}
};
});
Why are you moving your fetchData element into the sidebar document? You should leave it where it is, otherwise your content code won't be able to receive the event. Also, use the content document to create the event. Finally, document.createEvent() parameter for custom events should be "Events". So the code after your //here i am again trying comment should look like:
evtTarget.setAttribute("responseObject", saveResponse);
var evt = evtTarget.ownerDocument.createEvent("Events");
evt.initEvent("dispatchedResponse", true, false);
evtTarget.dispatchEvent(evt);
Please note however that your code as you show it here is a huge security vulnerability - it allows any website to make any HTTP requests and get the result back, so it essentially disables same-origin policy. At the very least you need to check that the website talking to you is allowed to do it (e.g. it belongs to your server). But even then it stays a security risk because server response could be altered (e.g. by an attacker on a public WLAN) or your server could be hacked - and you would be giving an attacker access to sensitive data (for example he could trigger a request to mail.google.com and if the victim happens to be logged in he will be able to read all email data). So please make this less generic, only allow requests to some websites.