I am trying to modify a web application we have and I'm not sure if I can do what is being requested. My boss wants to be able to click a link from an email and have our internal company web application go straight to a page identified at the end of a provided URL.
If I click on the link below the first time, it goes to the index page of our web application. If I leave the web application open and click on the link again, it goes to the correct page identified at the end of the URL.
http://mycompanyweb.com/handbook/mycompanyprocess/#/rt/softwate/9.13_UpdateSDP
I've tried adding an init(), thinking that is where the application goes first in the lifecycle and I only see this part of the URL at that point (http://mycompanyweb.com/handbook/mycompanyprocess/). This leads me to believe that the browser is stripping everything off after the # when it first opens. Is that correct? Is there something I can do to get our web application to go directly to the document the first time a user clicks on the link, without the web application open?
http://mycompanyweb.com/handbook/mycompanyprocess/ - Base URL
#/rt - Used by our javascript engine to determine which path to take
(dev or production).
/software/9.13_UpdateSDP - Logical path to a web page named 6.034_UpdateSDP.htm
Our engine that determines where to route based on the URL. I assume that the second time a link is clicked that it goes to the correct page is because the engine has been loaded (provided the browser is left open when clicked a second time).
$(document).ready(function () {
// Define the routes.
Path.map("#/:program").to(function () {
var program = this.params['program'];
if (program == "search") {
$("#mainContent").load("search.html");
}
else {
$("#mainContent").load("views/onepageprocess.html");
}
$("#subheader").html("");
$("#headerLevelTwoBreadcrumbLink").html("");
}).enter(setPageActions);
Path.map("#/:program/:swimlane").to(function () {
localStorage.removeItem("SearchString");
var swimlane = this.params['swimlane'];
var view = "views/" + swimlane + ".html";
$("#mainContent").load(view);
}).enter(setPageActions);
// Sends all links to the level three view and updates the breadcrumb.
Path.map("#/:program/:swimlane/:page").to(function () {
var page = this.params['page'];
var url = "views/levelthree/" + page.replace("", "") + ".htm";
var levelThreeTitle = "";
$.get(url)
.done(function () {
// Nothing here at this time...
}).fail(function () {
url = "views/levelthree/badurlpage.htm";
levelThreeTitle = "Page Unavailable";
}).always(function (data) {
$("#subheader").html("");
level_three_breadcrumb = "views/breadcrumbs/breadcrumb_link.html";
$("#headerLevelTwoBreadcrumbLink").load(level_three_breadcrumb);
$("#headerLevelThreeBreadcrumb").html("");
$('#headerLevelThreeBreadcrumb').append('<img src="images/Chevron.gif" />');
if (data.status != "404") {
$("#headerLevelThreeBreadcrumb").append(retrieveStorageItem("LevelThreeSubheader"));
}
$("#mainContent").load(url);
});
}).enter(setPageActions);
// Set a "root route". User will be automatically re-directed here. The definition
// below tells PathJS to load this route automatically if one isn't provided.
Path.root("#/rt");
// Start the path.js listener.
Path.listen();
});
Is there something I can do to get our web application to go directly to the document the first time a user clicks on the link, without the web application open?
If anyone runs into something like this, I found out that my company's servers were stripping anything after the # in the URL at authentication. I will be modifying my app to not use hash tags in the URL to fix it.
Related
the code below checks whether a url is loaded and then logs to the console. I would like to know if there is simple, clean method to check if a page is loaded from bfcache or http cache? Firefox documentation states that the load event should not be triggered if I go from URL A to B and then hit the back button to URL A, but this is not my experience, both load and PageShow is logged regardless, does anyone know why?
var tabs = require("sdk/tabs");
function onOpen(tab) {
tab.on("pageshow", logPageShow);
tab.on("load", logLoading);
}
function logPageShow(tab) {
console.log(tab.url + " -- loaded (maybe from bfcache?) ");
}
function logLoading(tab) {
console.log(tab.url + " -- loaded (not from bfcache) ");
}
tabs.on('open', onOpen);
I am not sure whether there is any purposeful API for that but a workaround that came to mind is to check value of the performance.timing.responseEnd - performance.timing.requestStart. If it is <= 5 then most likely it is HTTP or back-forward cache. Otherwise, it is a download from the web.
A way to recognize a return to the page through a back button instead of opening up a clean URL is to use history API. For example:
// on page load
var hasCameBack = window.history && window.history.state && window.history.state.customFlag;
if (!hasComeBack) {
// most likely, user has come by following a hyperlink or entering
// a URL into browser's address bar.
// we flag the page's state so that a back/forward navigation
// would reveal that on a comeback-kind of visist.
if (window.history) {
window.history.replaceState({ customFlag: true }, null, null);
}
}
else {
// handle the comeback visit situation
}
See also Manipulating the browser history article at MDN.
I want to use $location to navigate a self-contained comments section on a normal statically loaded page, but it seems to break the back back button.
The problem comes when I've navigated to a few pages using $location, then click on an external link. It goes to that link, but when I hit back, it changes the URL to the last one but doesn't actually change the page (i.e. it stays on the external page). If I then keep on clicking back, it changes the URL (so the url history is fine), but it doesn't actually load up the page from that url until I get to the first one that I've visited (if that makes sense...). So, for example:
So, navigating the app:
www.example.com - loads up my page with the comments
www.example.com?page=2 - uses $location and loads the new comments correctly
www.example.com?page=3 - uses $location and loads the new comments correctly
www.externalexamplepage.com - navigates correctly to the page.
back - changes the address to www.example.com?page=3 but stays on www.externalexamplepage.com
back - changes the address to www.example.com?page=2 but stays on www.externalexamplepage.com
back - changes the address to www.example.com and loads up the page correctly.
So, how can I get it to not break the back button? This is what I've got in my comments directive:
$scope.$on('$locationChangeStart', function(e, newUrl) {
// If moving off current page...
if ($scope.changingCommentsPage === false) {
$window.location.href = newUrl;
}
});
$scope.$on('$locationChangeSuccess', function() {
// Get current urlParams
var urlParams = $location.search();
// Get new comments if page has changed
if ($scope.page != urlParams.page || typeof urlParams.page === "undefined") {
$scope.changingCommentsPage = false;
$scope.page = urlParams.page ? urlParams.page : 1;
if ($scope.page < 1) return;
// Get comments
getComments($scope.model.page);
}
});
I was asked to take a look at what should be a simple problem with one of our web pages for a small dashboard web app. This app just shows some basic state info for underlying backend apps which I work heavily on. The issues is as follows:
On a page where a user can input parameters and request to view a report with the given user input, a button invokes a JS function which opens a new page in the browser to show the rendered report. The code looks like this:
$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
window.open('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>');
}
});
The page that is then opened has the following code which is called from Page_Load:
rptViewer.ProcessingMode = ProcessingMode.Remote
rptViewer.AsyncRendering = True
rptViewer.ServerReport.Timeout = CInt(WebConfigurationManager.AppSettings("ReportTimeout")) * 60000
rptViewer.ServerReport.ReportServerUrl = New Uri(My.Settings.ReportURL)
rptViewer.ServerReport.ReportPath = "/" & My.Settings.ReportPath & "/" & Request("Report")
'Set the report to use the credentials from web.config
rptViewer.ServerReport.ReportServerCredentials = New SQLReportCredentials(My.Settings.ReportServerUser, My.Settings.ReportServerPassword, My.Settings.ReportServerDomain)
Dim myCredentials As New Microsoft.Reporting.WebForms.DataSourceCredentials
myCredentials.Name = My.Settings.ReportDataSource
myCredentials.UserId = My.Settings.DatabaseUser
myCredentials.Password = My.Settings.DatabasePassword
rptViewer.ServerReport.SetDataSourceCredentials(New Microsoft.Reporting.WebForms.DataSourceCredentials(0) {myCredentials})
rptViewer.ServerReport.SetParameters(parameters)
rptViewer.ServerReport.Refresh()
I have omitted some code which builds up the parameters for the report, but I doubt any of that is relevant.
The problem is that, when the user clicks the show report button, and this new page opens up, depending on the types of parameters they use the report could take quite some time to render, and in the mean time, the original page becomes completely unresponsive. The moment the report page actually renders, the main page begins functioning again. Where should I start (google keywords, ReportViewer properties, etc) if I want to fix this behavior such that the other page can load asynchronously without affecting the main page?
Edit -
I tried doing the follow, which was in a linked answer in a comment here:
$.ajax({
context: document.body,
async: true, //NOTE THIS
success: function () {
window.open(Address);
}
});
this replaced the window.open call. This seems to work, but when I check out the documentation, trying to understand what this is doing I found this:
The .context property was deprecated in jQuery 1.10 and is only maintained to the extent needed for supporting .live() in the jQuery Migrate plugin. It may be removed without notice in a future version.
I removed the context property entirely and it didnt seem to affect the code at all... Is it ok to use this ajax call in this way to open up the other window, or is there a better approach?
Using a timeout should open the window without blocking your main page
$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
setTimeout(function() {
window.open('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>');
}, 0);
}
});
This is a long shot, but have you tried opening the window with a blank URL first, and subsequently changing the location?
$("#btnShowReport").click(function(){
If (CheckSession()) {
var pop = window.open ('', 'showReport');
pop = window.open ('<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>', 'showReport');
}
})
use
`$('#btnShowReport').click(function () {
document.getElementById("Error").innerHTML = "";
var exists = CheckSession();
if (exists) {
window.location.href='<%=Url.Content("~/Reports/Launch.aspx?Report=Short&Area=1") %>';
}
});`
it will work.
I have a ASP.net MVC web application which consists of several pages. The requirement is like this:
when users are using the application, suppose user is in page 7, suddenly user navigates away from the application by typing a external internet URL say Google.com.
Now when user presses the back button of the browser, Instead of bringing him back to page 7, we need to redirect him to Page 0 which is the landing page of the application.
Is there any way to achieve this? we have a base controller which gets executed every time a page loads as well as a master page (aspx). Can we do something there so that this behavior can be implemented in all the pages?
I think the best solution is to use iframe and switch between your steps inside of iframe. It would be quite easy to do, because you don't need to redesign your application. Anytime when user tries to switch to other url and come back, the iframe will be loaded again from the first step.
Be sure to disable caching on every step of your application. You can do this by applying NoCache attribute to your controller's actions:
public class NoCache : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.SetNoStore();
base.OnResultExecuting(filterContext);
}
}
There is 2 case over here
First is browser in online mode, in this case you have to store your last page get request in session, if user hit back button it will re initiate get request for that page again you can trap it and send them to landing page, You have to take care that get request for page happen only once other action must be post.
Second is browser in offline mode, in this case you have to take care that your response should not put any cache foot print in browser, there are many code example you can found on net for this purpose.
I can offer the following idea:
When user press <a href='external url' onclick='clearHistory'>link</a>
You can save in browser history of the desired url:
<script>
function clearHistory()
{
var reternUrl = getReternUrl();
History.pushState({}, null, reternUrl);
}
</script>
more about history.js
Edit: ok, then handle beforeunload event:
$(window).on('beforeunload', function () {
var reternUrl = getReternUrl();
History.pushState({}, null, reternUrl);
});
EDIT: Shortened and slightly changed code to better answer exact question (based on first comment to this answer)
Addition to answer above about editing the browser history for the case where the user types the external URL in the browser address bar.
You could try to detect url change as posted in How to detect URL change in JavaScript.
Example of this using jquery (taken and edited slightlyfrom post linked to above):
For newer browsers:
$(window).bind('hashchange', function() {
/* edit browser history */
});
For older browsers:
function callback(){
/* edit browser history */
}
function hashHandler(callback){
this.oldHash = window.location.hash;
this.Check;
var that = this;
var detect = function(){
if(that.oldHash!=window.location.hash){
callback("HASH CHANGED - new hash" + window.location.hash);
that.oldHash = window.location.hash;
}
};
this.Check = setInterval(function(){ detect() }, 100);
}
hashHandler(callback); //start detecting (callback will be called when a change is detected)
I'll get back to you on bookmarks (still need to check that out).
I'm wrapping a web app in a Windows Store app shell using a x-ms-webview. This works fine, but I have one problem. I use PayPal and since PayPal doesn't allow to be iframed I need to open PayPal in a new browser window.
On regular browsers this isn't a problem. The window open and when the user returns from PayPal I can a callback on "opener" and update the users account.
But when doing this in a Windows Store app the window.open triggers IE to launch. The problem is to return to my app and let it know that the user finished the transaction.
My first idea was just to use a URI activation. This kind of works, but I having trouble knowing if the PayPal page was launch from a regular browser or an app. I also think it is confusing for the user to be taken to another app to make the purchase.
I would prefer to have the window open in my app, but I'm not sure how I would open open a new x-ms-webview as a modal window overlapping existing webview.
What is the best way to communicate from the current web view and the app?
Can I use postMessage to send messages between the app and the x-ms-webview even though the src of the web view is a http hosted site?
Thank you for your help.
I found a solution to this.
First, you will need to use a https url for the embedded site. The reason for this is that the solution include postMessage and invokeScriptAsync.
First, my markup in my app looks something like this to have one webview for the app and one web view for the PayPal popup.
<x-ms-webview id="webview" src="https://myapp"></x-ms-webview>
<div id="paypalContainer">
<div class="paypal-header"><button id="paypalClose" type="reset">Close</button></div>
<div class="paypal-body"><x-ms-webview id="paypalWebView" src="about:blank"></x-ms-webview></div>
</div>
Then, when the web app is ready to use PayPal, I use window.external.notify to send a message to the Windows Store app.
if (window.external && 'notify' in window.external) {
window.external.notify(JSON.stringify({ action: 'paypal' }));
}
The windows store app listens for Script Notify events and displays the paypalWebView.
webview.addEventListener("MSWebViewScriptNotify", scriptNotify);
function scriptNotify(e) {
var data = JSON.parse(e.value);
if (data.action === "paypal") {
var loading = document.getElementById("loading-indicator");
var container = document.getElementById("paypalContainer");
var paypalWebView = document.getElementById("paypalWebView");
var paypalClose = document.getElementById("paypalClose");
if (paypalWebView.src === "about:blank") {
paypalWebView.addEventListener('MSWebViewNavigationCompleted', function (e) {
loading.classList.remove('loading');
var successUrl = '/paypal/success';
if (event.target.src.indexOf(successUrl) !== -1) {
var operation = webview.invokeScriptAsync("updateUser");
operation.oncomplete = function () {
(new Windows.UI.Popups.MessageDialog("Your account is refreshed", "")).showAsync().done();
};
operation.start();
}
});
paypalWebView.addEventListener('MSWebViewNavigationStarting', function (e) {
console.log("Started loading");
loading.classList.add('loading');
});
paypalClose.addEventListener('click', function () {
container.classList.remove("visible");
});
}
paypalWebView.src = "https://myapp/paypal/";
container.classList.add("visible");
}
}
So, basically, when the script notify event fires, I parse the sent json string to an object and check what kind of action it is. If it's the first time I run this I setup some naviation event handlers that check if the web view reach the Success page. If we have, I use incokeScriptAsync to let the web app know that we're done so it can refresh the user account the new payment.
I think you can use a similar solution for authentication and just check your your return URL after authenticating.
Hope this helps!