I have a c# MVC project with some jQuery driven interface. Some actions are performed with a $.post().
Sometimes, the site would be deployed to the root of the domain (e.g. www.mydomain.com) and sometimes it would be deployed in a folder (e.g. www.mydomain.com/Super).
I want to make posts to controllers relative to the location of the view that the user is accessing. However, the user may access the view both with and without an ending /, so i need to cater for both scenarios to avoid weird requests to www.mydomain.com/Super//somecontroller.
Currently, i have a function that does the following:
function getlocation() {
var loc = "";
if (location.pathname != "/") {
loc = (window.location.href.match("/$")) ? window.location.href : window.location.href + "/";
}
return loc;
}
Ultimately, this looks pretty ugly to me. Besides, every time i want to make a post or insert a relative URL when parsing data, i have to insert the result of that function before the actual URL which contributes to tag soup.
What is the best way to approach this?
I think your code is not ugly, but you can look to Backbone.js code:
url: function() {
var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError();
if (this.isNew()) return base;
return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id);
},
This is a case of me not asking the question correctly.
The problem as i had it is best solved using Url.Action() method from the UrlHelper.
Related
I'm trying to tidy up the analysis in Google Analytics by removing query strings from the URL, but this has split into three requirements;
I want to remove query strings from being displayed in the GA analysis.
Campaign UTMs still need to work.
Stop any PII gathered in a UTM from hitting GA.
I've found a number of JavaScript methods (attached below) that will do task 3, but I don't know whether this implementation will affect tasks 1 and 2.
This leads to my question;
Will the JavaScript method stop all query strings from hitting GA entirely, and therefore break my campaign UTMs?
Thanks for your help!
JavaScript attached below
function() {
var params = ['name', 'email'];
var a = document.createElement('a');
var param,
qps,
iop,
ioe
i;
a.href = {{Page URL}};
if (a.search) {
qps = '&' + a.search.replace('?', '') + '&';
for (i = 0; i < params.length; i++) {
param = params[i];
iop = qps.indexOf('&' + param + '=');
if(iop > -1) {
ioe = qps.indexOf('&', iop + 1);
qps = qps.slice(0, iop) + qps.slice(ioe, qps.length);
}
}
a.search = qps.slice(1, qps.length - 1);
}
return a.href;
}
If you update the page location in the DOM with the result of a function like this (window.location={{clean URL}}) you would naturally cause a lot of problems by causing reloading.
If you use the result of this function to set UA parameters relating to page and referrer, then it affects nothing that isn't related to those parameters in the hits. For example, you would want to clean the page field which is not just on page hits:
Things like utm parameters are extracted from normal DOM/BOM (for example window.location) and sent as separate parameters and are not calculated from page related parameters later on the server side unless you are doing extraction yourself in Analytic's custom filters.
Also you may use Google Analytics built-in mechanics to drop URL parameters through setting up Exclude URL Query Parameters in View settings. Docs are here: https://support.google.com/analytics/answer/1010249?hl=en
No JS Required.
I am developing an Ember.js application whose initial page resides at:
https://localhost:8443/
I want to perform a redirect from JavaScript to the following location if the user is authenticated:
https://localhost:8443/admin
To do this, I write code as follows:
App.ApplicationRoute = Ember.Route.extend({
model: function () {
var that = this,
session = this.get('session'),
sessionService = this.get('services').session();
return sessionService.getStatus().then(function (sessionStatus) {
session.setProperties(sessionStatus);
if (/^\/[signup]|[forgotPassword]/.test(that.router.get('url'))) return;
if (!session.get('authenticated'))
that.transitionTo('signin');
else
window.location.href = window.location.origin + '/admin';
});
}
});
However, when I do perform this, the page browses to:
https://localhost/admin
I also tried location.assign() with the same result.
Why does setting location.href or location.assign() remove the port-number from the URL? Is this something that the Ember.js Router would be doing?
Any other way I can accomplish this?
You have to look at the documentation for the Location object to see why. Essentially, there's ways to get every part of the URL and you just happen to be using the wrong one. Try one of these:
window.location.href = window.location.host + '/admin';
Or, more preferably:
window.location.href = '/admin';
The second way is nice because it allows you to forget about the base URL altogether and just worry about the relative path you need.
Also, Ember.js doesn't affect this kind of functionality at all, you're just dealing with the Javascript browser API.
I'm developing a site that is heavily reliant on javascript for browser history manipulation and only uses one actual page file. I want the script to run a function whenever the user hits the base url of the site, but I'm not sure what method is appropriate. Figured I could make a quick comparison of the current window location, but what if the user types in www instead of http://, or none of them. Something tells me this should be really easy.
if (window.location.href == 'http://mysite.com') {
console.log('you hit the base url, yay');
myFunction();
}
It sounds like you want to isolate the path part of the URL.
function isHomePage() {
return window.location.pathname === '/' || window.location.pathname === '';
}
That should cover your bases, even if the URL is something like
https://www2.example.com:443/#hash
window.location.href always includes the protocol, so there's no issue if the user omits that when typing in the URL.
If by base url, you mean there is no path component or hash fragment, you can check for this as follows:
if (window.location.pathname==='/' && window.location.hash==="") {
console.log('you hit the base url, yay');
myFunction();
}
JavaScript can access the current URL in parts. For this URL:
http://mysite.com/example/index.html
window.location.protocol = "http"
window.location.host = "mysite.com"
window.location.pathname = "example/index.html"
Make it sure to use the host property
if (window.location.host === 'mysite.com') {
console.log('you hit the base url, yay');
myFunction();
}
first timer here so be nice :3.
I am attempting to write a jQuery function that rewrites Amazon URL's to include affiliate tags, similar to what StackExchange does but with a twist.
The main differences is that I am attempting to the user to their closest Amazon Store - e.g. amazon.de - for german visitors. Due to Amazon's ASIN's differing in some countries I first want to check the new link, if it 404's I obviously don't want to direct my visitor there [1]
Here is my code that selects links to amazon.com, grabs the ASIN number and writes a shortlink to the product including the affiliate tag.
var tld_table = {'GB' : ".co.uk",'DE' : ".de",'CN' : ".cn",'AU' : ".ca",'IT' : ".it",'FR' : ".fr",'CA' : ".ca",'JP' : ".jp",};
var country = $.cookie("CountryCode");
//$.cookie by http://plugins.jquery.com/files/jquery.cookie.js.txt
var tld = tld_table[country] || '.com';
var regex = RegExp("http://www.amazon.com/([\\w-]+/)?(dp|gp/product)/(\\w+/)?(\\w{10})");
$('a[href*="amazon.com"]').each(function(){
var url = $(this).attr('href');
m = url.match(regex);
if (m) { //if ASIN found
var ASIN = m[4];
var shorturl = "http://www.amazon"+tld+"/dp/" + ASIN + "?tag="+ affTag[tld];
//http test for 404
//if 404 do not rewrite
//else $(this).attr('href',shorturl);
}
});
This works fine and will re-write the URL's but when I introduce ajax into the equation the script fails to rewrite any URL's.
EDIT
$('a[href*="amazon.com"]').each(function(){
var url = $(this).attr('href');
m = url.match(regex);
if (m) { //if ASIN found http://www.amazon.com/dp/B003DZ1Y8Q/?tag=derp
var ASIN = m[4];
var ajaxCall = $.get('ASIN.php?ASIN='+ASIN+'&tld='+tld+'&tag='+affTags[tld], function(data) {
var newlink = data;
console.log('New Link: '+newlink)
$(this).attr('href',newlink); //does not rewrite
})
ajaxCall.success(function() {
if(newlink != '404'){
$(this).attr('href',newlink);//does not rewrite
}
})
}
});
Above is the code I am attempting to use currently, ASIN.php builds & requests the new link, opens it using php's cURL and returns either a new link or '404'.
I think $(this) is failing to reference the link correctly, but I have no idea why.
The error says it all: is not allowed by Access-Control-Allow-Origin
It basically means that your javascript is not allowed to retrieve any URL outside of your domain. You can fix this by rewriting your ajax request to a local PHP script that checks the url.
It has something to do with http://en.wikipedia.org/wiki/Same_origin_policy
you can also use apache mod_proxy
ProxyPass /mirror/foo/ http://foo.com/
Then you can call the url /mirror/foo/ on your domain and it will pass the request to the forwarding remote url.
This is a common way of overcoming cross-domain browser restrictions.
http://httpd.apache.org/docs/1.3/mod/mod_proxy.html#proxypass
I'm currently using the following function to 'convert' a relative URL to an absolute one:
function qualifyURL(url) {
var a = document.createElement('a');
a.href = url;
return a.href;
}
This works quite well in most browsers but IE6 insists on returning the relative URL still! It does the same if I use getAttribute('href').
The only way I've been able to get a qualified URL out of IE6 is to create an img element and query it's 'src' attribute - the problem with this is that it generates a server request; something I want to avoid.
So my question is: Is there any way to get a fully qualified URL in IE6 from a relative one (without a server request)?
Before you recommend a quick regex/string fix I assure you it's not that simple. Base elements + double period relative urls + a tonne of other potential variables really make it hell!
There must be a way to do it without having to create a mammoth of a regex'y solution??
How strange! IE does, however, understand it when you use innerHTML instead of DOM methods.
function escapeHTML(s) {
return s.split('&').join('&').split('<').join('<').split('"').join('"');
}
function qualifyURL(url) {
var el= document.createElement('div');
el.innerHTML= 'x';
return el.firstChild.href;
}
A bit ugly, but more concise than Doing It Yourself.
As long as the browser implements the <base> tag correctly, which browsers tend to:
function resolve(url, base_url) {
var doc = document
, old_base = doc.getElementsByTagName('base')[0]
, old_href = old_base && old_base.href
, doc_head = doc.head || doc.getElementsByTagName('head')[0]
, our_base = old_base || doc_head.appendChild(doc.createElement('base'))
, resolver = doc.createElement('a')
, resolved_url
;
our_base.href = base_url || '';
resolver.href = url;
resolved_url = resolver.href; // browser magic at work here
if (old_base) old_base.href = old_href;
else doc_head.removeChild(our_base);
return resolved_url;
}
Here's a jsfiddle where you can experiment with it: http://jsfiddle.net/ecmanaut/RHdnZ/
You can make it work on IE6 just cloning the element:
function qualifyURL(url) {
var a = document.createElement('a');
a.href = url;
return a.cloneNode(false).href;
}
(Tested using IETester on IE6 and IE5.5 modes)
I found on this blog another method that really looks like #bobince solution.
function canonicalize(url) {
var div = document.createElement('div');
div.innerHTML = "<a></a>";
div.firstChild.href = url; // Ensures that the href is properly escaped
div.innerHTML = div.innerHTML; // Run the current innerHTML back through the parser
return div.firstChild.href;
}
I found it a little more elegant, not a big deal.
URI.js seems to solve the issue:
URI("../foobar.html").absoluteTo("http://example.org/hello/world.html").toString()
See also http://medialize.github.io/URI.js/docs.html#absoluteto
Not testeed with IE6, but maybe helpful for others searching to the general issue.
I actually wanted an approach to this that didn't require modifying the original document (not even temporarily) but still used the browser's builtin url parsing and such. Also, I wanted to be able to provide my own base (like ecmanaught's answer). It's rather straightforward, but uses createHTMLDocument (could be replaced with createDocument to be a bit more compatible possibly):
function absolutize(base, url) {
d = document.implementation.createHTMLDocument();
b = d.createElement('base');
d.head.appendChild(b);
a = d.createElement('a');
d.body.appendChild(a);
b.href = base;
a.href = url;
return a.href;
}
http://jsfiddle.net/5u6j403k/
This solution works in all browsers.
/**
* Given a filename for a static resource, returns the resource's absolute
* URL. Supports file paths with or without origin/protocol.
*/
function toAbsoluteURL (url) {
// Handle absolute URLs (with protocol-relative prefix)
// Example: //domain.com/file.png
if (url.search(/^\/\//) != -1) {
return window.location.protocol + url
}
// Handle absolute URLs (with explicit origin)
// Example: http://domain.com/file.png
if (url.search(/:\/\//) != -1) {
return url
}
// Handle absolute URLs (without explicit origin)
// Example: /file.png
if (url.search(/^\//) != -1) {
return window.location.origin + url
}
// Handle relative URLs
// Example: file.png
var base = window.location.href.match(/(.*\/)/)[0]
return base + url
However, it doesn't support relative URLs with ".." in them, like "../file.png".
This is the function I use to resolve basic relative URLs:
function resolveRelative(path, base) {
// Absolute URL
if (path.match(/^[a-z]*:\/\//)) {
return path;
}
// Protocol relative URL
if (path.indexOf("//") === 0) {
return base.replace(/\/\/.*/, path)
}
// Upper directory
if (path.indexOf("../") === 0) {
return resolveRelative(path.slice(3), base.replace(/\/[^\/]*$/, ''));
}
// Relative to the root
if (path.indexOf('/') === 0) {
var match = base.match(/(\w*:\/\/)?[^\/]*\//) || [base];
return match[0] + path.slice(1);
}
//relative to the current directory
return base.replace(/\/[^\/]*$/, "") + '/' + path.replace(/^\.\//, '');
}
Test it on jsfiddle: https://jsfiddle.net/n11rg255/
It works both in the browser and in node.js or other environments.
I found this blog post that suggests using an image element instead of an anchor:
http://james.padolsey.com/javascript/getting-a-fully-qualified-url/
That works to reliably expand a URL, even in IE6. But the problem is that the browsers that I have tested will immediately download the resource upon setting the image src attribute - even if you set the src to null on the next line.
I am going to give bobince's solution a go instead.
If url does not begin with '/'
Take the current page's url, chop off everything past the last '/'; then append the relative url.
Else if url begins with '/'
Take the current page's url and chop off everything to the right of the single '/'; then append the url.
Else if url starts with # or ?
Take the current page's url and simply append url
Hope it works for you
If it runs in the browser, this sort of works for me..
function resolveURL(url, base){
if(/^https?:/.test(url))return url; // url is absolute
// let's try a simple hack..
var basea=document.createElement('a'), urla=document.createElement('a');
basea.href=base, urla.href=url;
urla.protocol=basea.protocol;// "inherit" the base's protocol and hostname
if(!/^\/\//.test(url))urla.hostname=basea.hostname; //..hostname only if url is not protocol-relative though
if( /^\//.test(url) )return urla.href; // url starts with /, we're done
var urlparts=url.split(/\//); // create arrays for the url and base directory paths
var baseparts=basea.pathname.split(/\//);
if( ! /\/$/.test(base) )baseparts.pop(); // if base has a file name after last /, pop it off
while( urlparts[0]=='..' ){baseparts.pop();urlparts.shift();} // remove .. parts from url and corresponding directory levels from base
urla.pathname=baseparts.join('/')+'/'+urlparts.join('/');
return urla.href;
}