jquery to get/set href protocol - javascript

I have some relative links on my site that need to enforce https even if the current page is http (so I can't just use //links).
I'm guessing there is a pretty easy way for jQuery to retrieve the href upon click, and then set the page location to match the link that was clicked prepended with the HTTPS protocol?
Thanks in advance!

To get the protocol:
document.location.protocol;
to set the protocol:
document.location.protocol = 'https:';

You need a url joining helper function (the one below is modified from another answer I gave). Complete code, assuming you add class="httpsLink" to the special <a> links:
var urlJoin = function(base, relative)
{
// See if there is already a protocol on this
if (relative.indexOf("://") != -1)
return relative;
// See if this is protocol-relative
if (relative.indexOf("//") == 0)
{
var protocolIndex = base.indexOf("://");
return base.substr(0, protocolIndex+1) + relative;
}
// We need to split the domain and the path for the remaining options
var protocolIndexEnd = base.indexOf("://") + 3;
if (base.indexOf("/", protocolIndexEnd) == -1) // append slash if passed only http://bla.com
base += "/";
var endDomainIndex = base.indexOf("/", protocolIndexEnd);
var domain = base.substr(0, endDomainIndex);
var path = base.substr(endDomainIndex);
if (path.lastIndexOf("/") != path.length-1) // trim off any ending file name
path = path.substr(0, path.lastIndexOf("/")+1);
// See if this is site-absolute
if (relative.indexOf("/") == 0)
{
return domain + relative;
}
// See if this is document-relative with ../
while (relative.indexOf("../") == 0)
{
relative = relative.substr(3);
if (path.length > 1)
{
var secondToLastSlashIndex = path.substr(0, path.length-1).lastIndexOf("/");
path = path.substr(0, secondToLastSlashIndex+1);
}
}
// Finally, slap on whatever ending is left
return domain + path + relative;
};
$('a.httpsLink').click(function(e){
e.preventDefault();
location.href = urlJoin(location.href, $(this).attr('href')).split('http://').join('https://');
});
This will work with any type of links, be they absolute or relative.

If you're getting all of the links on a page (unlikely) you can use a global selector:
$('a').click(function(e) {
location.href = this.attr('href').replace("http://", "https://");
});
If you need to be more selective, you can apply a custom class selector to get only certain ones (this class would then have to be applied to those links):
$('.outsideLinkClass').click(function(e) {
location.href = this.attr('href').replace("http://", "https://");
});
Edit:
After re-reading my answer a little, it occurred to me that the simple replace option might not work if you're using internal links that are based off relative urls. In such a case you will need to make the assignment code a little more involved to ensure that you're modifying a full url and not just trusting to the replace.
Edit 2:
An idea for a more robust protocol replacement:
$('.outsideLinkClass').click(function(e) {
var baseUrl = window.location.pathname.substring(0, window.location.pathname.indexOf('/'));
location.href = baseUrl.replace("http://", "https://") + this.attr('href');
});
The code above is untested so you will possibly have to tweak the line that assigns the baseUrl variable to get it right, but this should make it possible.

Related

Javascript how to narrow down suitable URL in the if statment

I am trying to develop a Javascript code which will suit my website. Here is my code:
jQuery('.hestia-title').click(function() {
var link;
link = location.href;
if (link = "http://www.puslapioguru.eu" || "https://www.puslapioguru.eu" || "www.puslapioguru.eu") {
var element_to_scroll_to = jQuery('.second-title')[0];
console.log("Viskas veikia");
element_to_scroll_to.scrollIntoView();
} else {
window.location.href = "http://www.puslapioguru.eu/";
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
This code should determine on what open page it is run, but I encounter a problem with the if statement:
if (link="http://www.puslapioguru.eu" || "https://www.puslapioguru.eu" || "www.puslapioguru.eu")
I want that the if statement would run only if the specific URL would be opened, but now it even runs if the opened page URL is "http://www.puslapioguru.eu/temu-portfolio/". Can someone please help me with this problem?
Each part of || (or &&) has to equate to true/false by itself, ie:
if ((true|false) || (true||false))
so, rather than just use a string, you need to provide something to compare with, in each of the parts around the ||
Secondly, in javascript, if you are comparing a value you need to use == or ===, not =. This gives,
link = location.href;
if (link == "http://www.puslapioguru.eu"
|| link == "https://www.puslapioguru.eu"
|| link == "www.puslapioguru.eu") {
You can make this more flexible, but these are the essential issues with your if.
In this case you might want just location.host instead of location.href as .href is the entire address including any page path or parameters while .host already removes the https:// etc parts for you:
link = location.host;
if (link == "www.puslapioguru.eu") {
Either use a Regular Expression
/^https?:\/\/(?:www\.)?puslapioguru\.eu$/i.test(link); // Exactly on this
// OR
/^https?:\/\/(?:www\.)?puslapioguru\.eu(?:$|\/)/i.test(link); // Any path on this
Or use Array methods to test for your options
const permittedSiteList = [
'http://www.puslapioguru.eu',
'https://www.puslapioguru.eu',
'www.puslapioguru.eu'
];
permittedSiteList.includes(link); // eactly one of these
// OR
permittedSiteList.some(
domain => (link + '/').toLowerCase().startsWith(domain + '/')
); // Any path
If you choose one of these, I also recommend abstracting the RegExp or the Array outside the condition so it is more readable; i.e. the if's condition looks like
if (permittedSiteRegExp.test(link)) {
// ...
}
// OR
if (permittedSiteList.includes(link)) {
// ...
}
// OR in the Array + any path case, also the test function
const isThisDomain = domain => (link + '/').toLowerCase().startsWith(domain + '/');
if (permittedSiteList.some(isThisDomain)) {
// ...
}
Currently, you're performing an assignment in your if statement so you'll get unexpected behaviour

regex detect url and prepend http:// [duplicate]

This question already has answers here:
Adding http:// to all links without a protocol
(4 answers)
Closed 8 years ago.
I would like to detect url's that are entered in a text input. I have the following code which prepends http:// to the beginning of what has been entered:
var input = $(this);
var val = input.val();
if (val && !val.match(/^http([s]?):\/\/.*/)) {
input.val('http://' + val);
}
How would I go about adapting this to only append the http:// if it contains a string followed by a tld? At the moment if I enter a string for example:
Hello. This is a test
the http:// will get appended to hello, even though it's not a url. Any help would be greatly appreciated.
This simple function works for me. We don't care about the real existence of a TLD domain to gain speed, rather we check the syntax like example.com.
Sorry, I've forgotten that VBA trim() is not intrinsic function in js, so:
// Removes leading whitespaces
function LTrim(value)
{
var re = /\s*((\S+\s*)*)/;
return value.replace(re, "$1");
}
// Removes ending whitespaces
function RTrim(value)
{
var re = /((\s*\S+)*)\s*/;
return value.replace(re, "$1");
}
// Removes leading and ending whitespaces
function trim(value)
{
return LTrim(RTrim(value));
}
function hasDomainTld(strAddress)
{
var strUrlNow = trim(strAddress);
if(strUrlNow.match(/[,\s]/))
{
return false;
}
var i, regex = new RegExp();
regex.compile("[A-Za-z0-9\-_]+\\.[A-Za-z0-9\-_]+$");
i = regex.test(strUrlNow);
regex = null;
return i;
}
So your code, $(this) is window object, so I pass the objInput through an argument, using classical js instead of jQuery:
function checkIt(objInput)
{
var val = objInput.value;
if(val.match(/http:/i)) {
return false;
}
else if (hasDomainTld(val)) {
objInput.value = 'http://' + val;
}
}
Please test yourself: http://jsfiddle.net/SDUkZ/8/
The best solution i have found is to use the following regex:
/\.[a-zA-Z]{2,3}/
This detects the . after the url, and characters for the extension with a limit of 2/3 characters.
Does this seem ok for basic validation? Please let me know if you see any problems that could arise.
I know that it will detect email address's but this wont matter in this instance.
You need to narrow down your requirements first as URL detection with regular expressions can be very tricky. These are just a few situations where your parser can fail:
IDNs (госуслуги.рф)
Punycode cases (xn--blah)
New TLD being registered (.amazon)
SEO-friendly URLs (domain.com/Everything you need to know about RegEx.aspx)
We recently faced a similar problem and what we ended up doing was a simple check whether the URL starts with either http://, https://, or ftp:// and prepending with http:// if it doesn't start with any of the mentioned schemes. Here's the implementation in TypeScript:
public static EnsureAbsoluteUri(uri: string): string {
var ret = uri || '', m = null, i = -1;
var validSchemes = ko.utils.arrayMap(['http', 'https', 'ftp'], (i) => { return i + '://' });
if (ret && ret.length) {
m = ret.match(/[a-z]+:\/\//gi);
/* Checking against a list of valid schemes and prepending with "http://" if check fails. */
if (m == null || !m.length || (i = $.inArray(m[0].toLowerCase(), validSchemes)) < 0 ||
(i >= 0 && ret.toLowerCase().indexOf(validSchemes[i]) != 0)) {
ret = 'http://' + ret;
}
}
return ret;
}
As you can see, we're not trying to be smart here as we can't predict every possible URL form. Furthermore, this method is usually executed against field values we know are meant to be URLs so the change of misdetection is minimal.
Hope this helps.

Check if a string starts with http using Javascript

I've been searching all over for an answer to this and all of the answers I've found haven't been in JavaScript.
I need a way, in javascript, to check if a string starts with http, https, or ftp. If it doesn't start with one of those I need to prepend the string with http://. indexOf won't work for me I don't think as I need either http, https or ftp. Also I don't want something like google.com/?q=http://google.com to trigger that as being valid as it doesn't start with an http whereas indexOf would trigger that as being true (if I'm not entirely mistaken).
The closest PHP regex I've found is this:
function addhttp($url) {
if (!preg_match("~^(?:f|ht)tps?://~i", $url)) {
$url = "http://" . $url;
}
return $url;
}
Source: How to add http if its not exists in the url
I just don't know how to convert that to javascript. Any help would be greatly appreciated.
export const getValidUrl = (url = "") => {
let newUrl = window.decodeURIComponent(url);
newUrl = newUrl.trim().replace(/\s/g, "");
if(/^(:\/\/)/.test(newUrl)){
return `http${newUrl}`;
}
if(!/^(f|ht)tps?:\/\//i.test(newUrl)){
return `http://${newUrl}`;
}
return newUrl;
};
Tests:
expect(getValidUrl('https://www.test.com')).toBe('https://www.test.com');
expect(getValidUrl('http://www.test.com')).toBe('http://www.test.com');
expect(getValidUrl(' http : / / www.test.com')).toBe('http://www.test.com');
expect(getValidUrl('ftp://www.test.com')).toBe('ftp://www.test.com');
expect(getValidUrl('www.test.com')).toBe('http://www.test.com');
expect(getValidUrl('://www.test.com')).toBe('http://www.test.com');
expect(getValidUrl('http%3A%2F%2Fwww.test.com')).toBe('http://www.test.com');
expect(getValidUrl('www . test.com')).toBe('http://www.test.com');
This should work:
var pattern = /^((http|https|ftp):\/\/)/;
if(!pattern.test(url)) {
url = "http://" + url;
}
jsFiddle
var url = "http://something.com"
if( url.indexOf("http") == 0 ) {
alert("yeah!");
} else {
alert("No no no!");
}
Non-Regex declarative way:
const hasValidUrlProtocol = (url = '') =>
['http://', 'https://', 'ftp://'].some(protocol => url.startsWith(protocol))
This should work:
var re = /^(http|https|ftp)/
Refining previous answers a bit more, I used new RegExp(...) to avoid messy escapes, and also added an optional s.
var pattern = new RegExp('^(https?|ftp)://');
if(!pattern.test(url)) {
url = "http://" + url;
}
var pattern = new RegExp('^(https?|ftp)://');
console.log(pattern.test('http://foo'));
console.log(pattern.test('https://foo'));
console.log(pattern.test('ftp://foo'));
console.log(pattern.test('bar'));
Best readability I'd say is to use .startsWith('theString').
The code below checks for both http://, https:// and ftp:// and sets okUrl to a boolean true if any of them comply, by using the || which means or.
When you know if the url contains none of those strings, then just just add http:// to the start of the string either with literals (${})
let url = 'google.com'
const urlOK = url.startsWith('http://') || url.startsWith('https://') || url.startsWith('ftp://')
if (!urlOk) url = `http://${url}`
// => 'http://google.com'
or with simple string concat, which can be done in various ways, for example:
url = 'http://' + url
Read more about it, and test it, here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith

How to extract the hostname portion of a URL in JavaScript

Is there a really easy way to start from a full URL:
document.location.href = "http://aaa.bbb.ccc.com/asdf/asdf/sadf.aspx?blah"
And extract just the host part:
aaa.bbb.ccc.com
There's gotta be a JavaScript function that does this reliably, but I can't find it.
Suppose that you have a page with this address: http://sub.domain.com/virtualPath/page.htm.
Use the following in page code to achieve those results:
Property
Result
window.location.host
sub.domain.com:8080 or sub.domain.com:80
window.location.hostname
sub.domain.com
window.location.protocol
http:
window.location.port
8080 or 80
window.location.pathname
/virtualPath
window.location.origin
http://sub.domain.com (Might include :port too*****)
Update: about the .origin
***** As the ref states, browser compatibility for window.location.origin is not clear. I've checked it in chrome and it returned http://sub.domain.com:port if the port is anything but 80, and http://sub.domain.com if the port is 80.
Special thanks to #torazaburo for mentioning that to me.
You could concatenate the location protocol and the host:
var root = location.protocol + '//' + location.host;
For a url, let say 'http://stackoverflow.com/questions', it will return 'http://stackoverflow.com'
The accepted answer didn't work for me since wanted to be able to work with any arbitary url's, not just the current page URL.
Take a look at the URL object:
var url = new URL("http://aaa.bbb.ccc.com/asdf/asdf/sadf.aspx?blah");
url.protocol; // "http:"
url.hostname; // "aaa.bbb.ccc.com"
url.pathname; // "/asdf/asdf/sadf.aspx"
url.search; // "?blah"
Use document.location object and its host or hostname properties.
alert(document.location.hostname); // alerts "stackoverflow.com"
There are two ways. The first is a variant of another answer here, but this one accounts for non-default ports:
function getRootUrl() {
var defaultPorts = {"http:":80,"https:":443};
return window.location.protocol + "//" + window.location.hostname
+ (((window.location.port)
&& (window.location.port != defaultPorts[window.location.protocol]))
? (":"+window.location.port) : "");
}
But I prefer this simpler method (which works with any URI string):
function getRootUrl(url) {
return url.toString().replace(/^(.*\/\/[^\/?#]*).*$/,"$1");
}
Let's suppose you have this url path:
http://localhost:4200/landing?query=1#2
So, you can serve yourself by the location values, as follow:
window.location.hash: "#2"
​
window.location.host: "localhost:4200"
​
window.location.hostname: "localhost"
​
window.location.href: "http://localhost:4200/landing?query=1#2"
​
window.location.origin: "http://localhost:4200"
​
window.location.pathname: "/landing"
​
window.location.port: "4200"
​
window.location.protocol: "http:"
window.location.search: "?query=1"
Now we can conclude you're looking for:
window.location.hostname
Try
document.location.host
or
document.location.hostname
use
window.location.origin
and for: "http://aaa.bbb.ccc.ddd.com/sadf.aspx?blah"
you will get: http://aaa.bbb.ccc.ddd.com/
There is another hack I use and never saw in any StackOverflow response :
using "src" attribute of an image will yield the complete base path of your site.
For instance :
var dummy = new Image;
dummy.src = '$'; // using '' will fail on some browsers
var root = dummy.src.slice(0,-1); // remove trailing '$'
On an URL like http://domain.com/somesite/index.html,
root will be set to http://domain.com/somesite/.
This also works for localhost or any valid base URL.
Note that this will cause a failed HTTP request on the $ dummy image.
You can use an existing image instead to avoid this, with only slight code changes.
Another variant uses a dummy link, with no side effect on HTTP requests :
var dummy = document.createElement ('a');
dummy.href = '';
var root = dummy.href;
I did not test it on every browser, though.
Check this:
alert(window.location.hostname);
this will return host name as www.domain.com
and:
window.location.host
will return domain name with port like www.example.com:80
For complete reference check Mozilla developer site.
I know this is a bit late, but I made a clean little function with a little ES6 syntax
function getHost(href){
return Object.assign(document.createElement('a'), { href }).host;
}
It could also be writen in ES5 like
function getHost(href){
return Object.assign(document.createElement('a'), { href: href }).host;
}
Of course IE doesn't support Object.assign, but in my line of work, that doesn't matter.
I would like to specify something. If someone want to get the whole url with path like I need, can use:
var fullUrl = window.location.protocol + "//" + window.location.hostname + window.location.pathname;
Regex provides much more flexibility.
//document.location.href = "http://aaa.bbb.ccc.com/asdf/asdf/sadf.aspx?blah
//1.
var r = new RegExp(/http:\/\/[^/]+/);
var match = r.exec(document.location.href) //gives http://aaa.bbb.ccc.com
//2.
var r = new RegExp(/http:\/\/[^/]+\/[^/]+/);
var match = r.exec(document.location.href) //gives http://aaa.bbb.ccc.com/asdf
My solution works in all web browsers including Microsoft Internet Explorer and doesn't use any regular expression, it's inspired of Noah Cardoza and Martin Konecny solutions:
function getHostname(href) {
if (typeof URL === 'object') {
// workaround for MS IE 11 (Noah Cardoza's solution but without using Object.assign())
var dummyNode = document.createElement('a');
dummyNode.href = href;
return dummyNode.hostname;
} else {
// Martin Konecny's solution
return new URL(href).hostname;
}
}
You can split the URL string using /
const exampleURL = "Https://exampleurl.com/page1/etc/etc"
const URLsplit = exampleURL.split("/")
console.log(URLsplit)
console.log(URLsplit[2])
Result. exampleurl.com

How can I get file extensions with JavaScript?

See code:
var file1 = "50.xsl";
var file2 = "30.doc";
getFileExtension(file1); //returns xsl
getFileExtension(file2); //returns doc
function getFileExtension(filename) {
/*TODO*/
}
Newer Edit: Lots of things have changed since this question was initially posted - there's a lot of really good information in wallacer's revised answer as well as VisioN's excellent breakdown
Edit: Just because this is the accepted answer; wallacer's answer is indeed much better:
return filename.split('.').pop();
My old answer:
return /[^.]+$/.exec(filename);
Should do it.
Edit: In response to PhiLho's comment, use something like:
return (/[.]/.exec(filename)) ? /[^.]+$/.exec(filename) : undefined;
return filename.split('.').pop();
Edit:
This is another non-regex solution that I think is more efficient:
return filename.substring(filename.lastIndexOf('.')+1, filename.length) || filename;
There are some corner cases that are better handled by VisioN's answer below, particularly files with no extension (.htaccess etc included).
It's very performant, and handles corner cases in an arguably better way by returning "" instead of the full string when there's no dot or no string before the dot. It's a very well crafted solution, albeit tough to read. Stick it in your helpers lib and just use it.
Old Edit:
A safer implementation if you're going to run into files with no extension, or hidden files with no extension (see VisioN's comment to Tom's answer above) would be something along these lines
var a = filename.split(".");
if( a.length === 1 || ( a[0] === "" && a.length === 2 ) ) {
return "";
}
return a.pop(); // feel free to tack .toLowerCase() here if you want
If a.length is one, it's a visible file with no extension ie. file
If a[0] === "" and a.length === 2 it's a hidden file with no extension ie. .htaccess
This should clear up issues with the slightly more complex cases. In terms of performance, I think this solution is a little slower than regex in most browsers. However, for most common purposes this code should be perfectly usable.
The following solution is fast and short enough to use in bulk operations and save extra bytes:
return fname.slice((fname.lastIndexOf(".") - 1 >>> 0) + 2);
Here is another one-line non-regexp universal solution:
return fname.slice((Math.max(0, fname.lastIndexOf(".")) || Infinity) + 1);
Both work correctly with names having no extension (e.g. myfile) or starting with . dot (e.g. .htaccess):
"" --> ""
"name" --> ""
"name.txt" --> "txt"
".htpasswd" --> ""
"name.with.many.dots.myext" --> "myext"
If you care about the speed you may run the benchmark and check that the provided solutions are the fastest, while the short one is tremendously fast:
How the short one works:
String.lastIndexOf method returns the last position of the substring (i.e. ".") in the given string (i.e. fname). If the substring is not found method returns -1.
The "unacceptable" positions of dot in the filename are -1 and 0, which respectively refer to names with no extension (e.g. "name") and to names that start with dot (e.g. ".htaccess").
Zero-fill right shift operator (>>>) if used with zero affects negative numbers transforming -1 to 4294967295 and -2 to 4294967294, which is useful for remaining the filename unchanged in the edge cases (sort of a trick here).
String.prototype.slice extracts the part of the filename from the position that was calculated as described. If the position number is more than the length of the string method returns "".
If you want more clear solution which will work in the same way (plus with extra support of full path), check the following extended version. This solution will be slower than previous one-liners but is much easier to understand.
function getExtension(path) {
var basename = path.split(/[\\/]/).pop(), // extract file name from full path ...
// (supports `\\` and `/` separators)
pos = basename.lastIndexOf("."); // get last position of `.`
if (basename === "" || pos < 1) // if file name is empty or ...
return ""; // `.` not found (-1) or comes first (0)
return basename.slice(pos + 1); // extract extension ignoring `.`
}
console.log( getExtension("/path/to/file.ext") );
// >> "ext"
All three variants should work in any web browser on the client side and can be used in the server side NodeJS code as well.
function getFileExtension(filename)
{
var ext = /^.+\.([^.]+)$/.exec(filename);
return ext == null ? "" : ext[1];
}
Tested with
"a.b" (=> "b")
"a" (=> "")
".hidden" (=> "")
"" (=> "")
null (=> "")
Also
"a.b.c.d" (=> "d")
".a.b" (=> "b")
"a..b" (=> "b")
There is a standard library function for this in the path module:
import path from 'path';
console.log(path.extname('abc.txt'));
Output:
.txt
So, if you only want the format:
path.extname('abc.txt').slice(1) // 'txt'
If there is no extension, then the function will return an empty string:
path.extname('abc') // ''
If you are using Node, then path is built-in. If you are targetting the browser, then Webpack will bundle a path implementation for you. If you are targetting the browser without Webpack, then you can include path-browserify manually.
There is no reason to do string splitting or regex.
function getExt(filename)
{
var ext = filename.split('.').pop();
if(ext == filename) return "";
return ext;
}
var extension = fileName.substring(fileName.lastIndexOf('.')+1);
If you are dealing with web urls, you can use:
function getExt(filepath){
return filepath.split("?")[0].split("#")[0].split('.').pop();
}
getExt("../js/logic.v2.min.js") // js
getExt("http://example.net/site/page.php?id=16548") // php
getExt("http://example.net/site/page.html#welcome.to.me") // html
getExt("c:\\logs\\yesterday.log"); // log
Demo: https://jsfiddle.net/squadjot/q5ard4fj/
var parts = filename.split('.');
return parts[parts.length-1];
function file_get_ext(filename)
{
return typeof filename != "undefined" ? filename.substring(filename.lastIndexOf(".")+1, filename.length).toLowerCase() : false;
}
Code
/**
* Extract file extension from URL.
* #param {String} url
* #returns {String} File extension or empty string if no extension is present.
*/
var getFileExtension = function (url) {
"use strict";
if (url === null) {
return "";
}
var index = url.lastIndexOf("/");
if (index !== -1) {
url = url.substring(index + 1); // Keep path without its segments
}
index = url.indexOf("?");
if (index !== -1) {
url = url.substring(0, index); // Remove query
}
index = url.indexOf("#");
if (index !== -1) {
url = url.substring(0, index); // Remove fragment
}
index = url.lastIndexOf(".");
return index !== -1
? url.substring(index + 1) // Only keep file extension
: ""; // No extension found
};
Test
Notice that in the absence of a query, the fragment might still be present.
"https://www.example.com:8080/segment1/segment2/page.html?foo=bar#fragment" --> "html"
"https://www.example.com:8080/segment1/segment2/page.html#fragment" --> "html"
"https://www.example.com:8080/segment1/segment2/.htaccess?foo=bar#fragment" --> "htaccess"
"https://www.example.com:8080/segment1/segment2/page?foo=bar#fragment" --> ""
"https://www.example.com:8080/segment1/segment2/?foo=bar#fragment" --> ""
"" --> ""
null --> ""
"a.b.c.d" --> "d"
".a.b" --> "b"
".a.b." --> ""
"a...b" --> "b"
"..." --> ""
JSLint
0 Warnings.
Fast and works correctly with paths
(filename.match(/[^\\\/]\.([^.\\\/]+)$/) || [null]).pop()
Some edge cases
/path/.htaccess => null
/dir.with.dot/file => null
Solutions using split are slow and solutions with lastIndexOf don't handle edge cases.
// 获取文件后缀名
function getFileExtension(file) {
var regexp = /\.([0-9a-z]+)(?:[\?#]|$)/i;
var extension = file.match(regexp);
return extension && extension[1];
}
console.log(getFileExtension("https://www.example.com:8080/path/name/foo"));
console.log(getFileExtension("https://www.example.com:8080/path/name/foo.BAR"));
console.log(getFileExtension("https://www.example.com:8080/path/name/.quz/foo.bar?key=value#fragment"));
console.log(getFileExtension("https://www.example.com:8080/path/name/.quz.bar?key=value#fragment"));
i just wanted to share this.
fileName.slice(fileName.lastIndexOf('.'))
although this has a downfall that files with no extension will return last string.
but if you do so this will fix every thing :
function getExtention(fileName){
var i = fileName.lastIndexOf('.');
if(i === -1 ) return false;
return fileName.slice(i)
}
"one-liner" to get filename and extension using reduce and array destructuring :
var str = "filename.with_dot.png";
var [filename, extension] = str.split('.').reduce((acc, val, i, arr) => (i == arr.length - 1) ? [acc[0].substring(1), val] : [[acc[0], val].join('.')], [])
console.log({filename, extension});
with better indentation :
var str = "filename.with_dot.png";
var [filename, extension] = str.split('.')
.reduce((acc, val, i, arr) => (i == arr.length - 1)
? [acc[0].substring(1), val]
: [[acc[0], val].join('.')], [])
console.log({filename, extension});
// {
// "filename": "filename.with_dot",
// "extension": "png"
// }
There's also a simple approach using ES6 destructuring:
const path = 'hello.world.txt'
const [extension, ...nameParts] = path.split('.').reverse();
console.log('extension:', extension);
function extension(fname) {
var pos = fname.lastIndexOf(".");
var strlen = fname.length;
if (pos != -1 && strlen != pos + 1) {
var ext = fname.split(".");
var len = ext.length;
var extension = ext[len - 1].toLowerCase();
} else {
extension = "No extension found";
}
return extension;
}
//usage
extension('file.jpeg')
always returns the extension lower cas so you can check it on field change
works for:
file.JpEg
file (no extension)
file. (noextension)
This simple solution
function extension(filename) {
var r = /.+\.(.+)$/.exec(filename);
return r ? r[1] : null;
}
Tests
/* tests */
test('cat.gif', 'gif');
test('main.c', 'c');
test('file.with.multiple.dots.zip', 'zip');
test('.htaccess', null);
test('noextension.', null);
test('noextension', null);
test('', null);
// test utility function
function test(input, expect) {
var result = extension(input);
if (result === expect)
console.log(result, input);
else
console.error(result, input);
}
function extension(filename) {
var r = /.+\.(.+)$/.exec(filename);
return r ? r[1] : null;
}
I'm sure someone can, and will, minify and/or optimize my code in the future. But, as of right now, I am 200% confident that my code works in every unique situation (e.g. with just the file name only, with relative, root-relative, and absolute URL's, with fragment # tags, with query ? strings, and whatever else you may decide to throw at it), flawlessly, and with pin-point precision.
For proof, visit: https://projects.jamesandersonjr.com/web/js_projects/get_file_extension_test.php
Here's the JSFiddle: https://jsfiddle.net/JamesAndersonJr/ffcdd5z3/
Not to be overconfident, or blowing my own trumpet, but I haven't seen any block of code for this task (finding the 'correct' file extension, amidst a battery of different function input arguments) that works as well as this does.
Note: By design, if a file extension doesn't exist for the given input string, it simply returns a blank string "", not an error, nor an error message.
It takes two arguments:
String: fileNameOrURL (self-explanatory)
Boolean: showUnixDotFiles (Whether or Not to show files that begin with a dot ".")
Note (2): If you like my code, be sure to add it to your js library's, and/or repo's, because I worked hard on perfecting it, and it would be a shame to go to waste. So, without further ado, here it is:
function getFileExtension(fileNameOrURL, showUnixDotFiles)
{
/* First, let's declare some preliminary variables we'll need later on. */
var fileName;
var fileExt;
/* Now we'll create a hidden anchor ('a') element (Note: No need to append this element to the document). */
var hiddenLink = document.createElement('a');
/* Just for fun, we'll add a CSS attribute of [ style.display = "none" ]. Remember: You can never be too sure! */
hiddenLink.style.display = "none";
/* Set the 'href' attribute of the hidden link we just created, to the 'fileNameOrURL' argument received by this function. */
hiddenLink.setAttribute('href', fileNameOrURL);
/* Now, let's take advantage of the browser's built-in parser, to remove elements from the original 'fileNameOrURL' argument received by this function, without actually modifying our newly created hidden 'anchor' element.*/
fileNameOrURL = fileNameOrURL.replace(hiddenLink.protocol, ""); /* First, let's strip out the protocol, if there is one. */
fileNameOrURL = fileNameOrURL.replace(hiddenLink.hostname, ""); /* Now, we'll strip out the host-name (i.e. domain-name) if there is one. */
fileNameOrURL = fileNameOrURL.replace(":" + hiddenLink.port, ""); /* Now finally, we'll strip out the port number, if there is one (Kinda overkill though ;-)). */
/* Now, we're ready to finish processing the 'fileNameOrURL' variable by removing unnecessary parts, to isolate the file name. */
/* Operations for working with [relative, root-relative, and absolute] URL's ONLY [BEGIN] */
/* Break the possible URL at the [ '?' ] and take first part, to shave of the entire query string ( everything after the '?'), if it exist. */
fileNameOrURL = fileNameOrURL.split('?')[0];
/* Sometimes URL's don't have query's, but DO have a fragment [ # ](i.e 'reference anchor'), so we should also do the same for the fragment tag [ # ]. */
fileNameOrURL = fileNameOrURL.split('#')[0];
/* Now that we have just the URL 'ALONE', Let's remove everything to the last slash in URL, to isolate the file name. */
fileNameOrURL = fileNameOrURL.substr(1 + fileNameOrURL.lastIndexOf("/"));
/* Operations for working with [relative, root-relative, and absolute] URL's ONLY [END] */
/* Now, 'fileNameOrURL' should just be 'fileName' */
fileName = fileNameOrURL;
/* Now, we check if we should show UNIX dot-files, or not. This should be either 'true' or 'false'. */
if ( showUnixDotFiles == false )
{
/* If not ('false'), we should check if the filename starts with a period (indicating it's a UNIX dot-file). */
if ( fileName.startsWith(".") )
{
/* If so, we return a blank string to the function caller. Our job here, is done! */
return "";
};
};
/* Now, let's get everything after the period in the filename (i.e. the correct 'file extension'). */
fileExt = fileName.substr(1 + fileName.lastIndexOf("."));
/* Now that we've discovered the correct file extension, let's return it to the function caller. */
return fileExt;
};
Enjoy! You're Quite Welcome!:
Try this:
function getFileExtension(filename) {
var fileinput = document.getElementById(filename);
if (!fileinput)
return "";
var filename = fileinput.value;
if (filename.length == 0)
return "";
var dot = filename.lastIndexOf(".");
if (dot == -1)
return "";
var extension = filename.substr(dot, filename.length);
return extension;
}
If you are looking for a specific extension and know its length, you can use substr:
var file1 = "50.xsl";
if (file1.substr(-4) == '.xsl') {
// do something
}
JavaScript reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substr
I just realized that it's not enough to put a comment on p4bl0's answer, though Tom's answer clearly solves the problem:
return filename.replace(/^.*?\.([a-zA-Z0-9]+)$/, "$1");
For most applications, a simple script such as
return /[^.]+$/.exec(filename);
would work just fine (as provided by Tom). However this is not fool proof. It does not work if the following file name is provided:
image.jpg?foo=bar
It may be a bit overkill but I would suggest using a url parser such as this one to avoid failure due to unpredictable filenames.
Using that particular function, you could get the file name like this:
var trueFileName = parse_url('image.jpg?foo=bar').file;
This will output "image.jpg" without the url vars. Then you are free to grab the file extension.
function func() {
var val = document.frm.filename.value;
var arr = val.split(".");
alert(arr[arr.length - 1]);
var arr1 = val.split("\\");
alert(arr1[arr1.length - 2]);
if (arr[1] == "gif" || arr[1] == "bmp" || arr[1] == "jpeg") {
alert("this is an image file ");
} else {
alert("this is not an image file");
}
}
I'm many moons late to the party but for simplicity I use something like this
var fileName = "I.Am.FileName.docx";
var nameLen = fileName.length;
var lastDotPos = fileName.lastIndexOf(".");
var fileNameSub = false;
if(lastDotPos === -1)
{
fileNameSub = false;
}
else
{
//Remove +1 if you want the "." left too
fileNameSub = fileName.substr(lastDotPos + 1, nameLen);
}
document.getElementById("showInMe").innerHTML = fileNameSub;
<div id="showInMe"></div>
A one line solution that will also account for query params and any characters in url.
string.match(/(.*)\??/i).shift().replace(/\?.*/, '').split('.').pop()
// Example
// some.url.com/with.in/&ot.s/files/file.jpg?spec=1&.ext=jpg
// jpg
return filename.replace(/\.([a-zA-Z0-9]+)$/, "$1");
edit: Strangely (or maybe it's not) the $1 in the second argument of the replace method doesn't seem to work... Sorry.
fetchFileExtention(fileName) {
return fileName.slice((fileName.lastIndexOf(".") - 1 >>> 0) + 2);
}
Wallacer's answer is nice, but one more checking is needed.
If file has no extension, it will use filename as extension which is not good.
Try this one:
return ( filename.indexOf('.') > 0 ) ? filename.split('.').pop().toLowerCase() : 'undefined';
Don't forget that some files can have no extension, so:
var parts = filename.split('.');
return (parts.length > 1) ? parts.pop() : '';

Categories

Resources