I'm developing an application for both mobile and desktop browsers. I'm wondering if there is anyway to detect if a browser supports file uploading. I'm looking specifically for feature detection and not browser detection. Is there any way to find out?
Server-side or client side is fine.
Thanks
client side javascript:
<input type="file" name="file" value="" id="fileUploadField1">
<script type="text/javascript" charset="utf-8">
if (document.getElementById('fileUploadField1').disabled)
{ document.write('your device does not allow uploads'); }
else
{ document.write('your device does allow uploads'); }
</script>
You might be interested to read this article about current input type=file support on mobile and how to detect it: http://viljamis.com/blog/2012/file-upload-support-on-mobile/ (the detection is currently tested to be working on ~120 different mobile browser/mobile OS combinations).
Basically, we are just using similar detection as Modernizr does, but use UA detection as a backup to filter out those mobile browsers that falsely report support (there really doesn’t seem to be any other way to detect it reliably than using these both, feature detection and browser detection).
You can use Modernizr framework with forms-fileinput extension. Give it a try.
if Modernizr.fileinput
// you can use file inputs
Visit the Modernizr download page and check the forms-fileinput extension (expand the "Non-core detects" section).
Modernizr now supports a check for whether or not file uploads are supported.
From: What is the best way to check if user can upload files?
if(Modernizr.fileinput) {
//file input available!
} else {
//No file input :(
}
If you're worried about the size of this library, you can always get one component at a time - http://modernizr.com/download/ ... or you can just copy the code they use: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/forms/fileinput.js
if(navigator.userAgent.match(/(Android (1.0|1.1|1.5|1.6|2.0|2.1))|(Windows Phone (OS 7|8.0))|(XBLWP)|(ZuneWP)|(w(eb)?OSBrowser)|(webOS)|(Kindle\/(1.0|2.0|2.5|3.0))/)) {
return false;
}
var elem = createElement('input');
elem.type = 'file';
return !elem.disabled;
Related
I am loading an <iframe> in my HTML page and trying to access the elements within it using JavaScript, but when I try to execute my code, I get the following error:
SecurityError: Blocked a frame with origin "http://www.example.com" from accessing a cross-origin frame.
How can I access the elements in the frame?
I am using this code for testing, but in vain:
$(document).ready(function() {
var iframeWindow = document.getElementById("my-iframe-id").contentWindow;
iframeWindow.addEventListener("load", function() {
var doc = iframe.contentDocument || iframe.contentWindow.document;
var target = doc.getElementById("my-target-id");
target.innerHTML = "Found it!";
});
});
Same-origin policy
You can't access an <iframe> with different origin using JavaScript, it would be a huge security flaw if you could do it. For the same-origin policy browsers block scripts trying to access a frame with a different origin.
Origin is considered different if at least one of the following parts of the address isn't maintained:
protocol://hostname:port/...
Protocol, hostname and port must be the same of your domain if you want to access a frame.
NOTE: Internet Explorer is known to not strictly follow this rule, see here for details.
Examples
Here's what would happen trying to access the following URLs from http://www.example.com/home/index.html
URL RESULT
http://www.example.com/home/other.html -> Success
http://www.example.com/dir/inner/another.php -> Success
http://www.example.com:80 -> Success (default port for HTTP)
http://www.example.com:2251 -> Failure: different port
http://data.example.com/dir/other.html -> Failure: different hostname
https://www.example.com/home/index.html:80 -> Failure: different protocol
ftp://www.example.com:21 -> Failure: different protocol & port
https://google.com/search?q=james+bond -> Failure: different protocol, port & hostname
Workaround
Even though same-origin policy blocks scripts from accessing the content of sites with a different origin, if you own both the pages, you can work around this problem using window.postMessage and its relative message event to send messages between the two pages, like this:
In your main page:
const frame = document.getElementById('your-frame-id');
frame.contentWindow.postMessage(/*any variable or object here*/, 'https://your-second-site.example');
The second argument to postMessage() can be '*' to indicate no preference about the origin of the destination. A target origin should always be provided when possible, to avoid disclosing the data you send to any other site.
In your <iframe> (contained in the main page):
window.addEventListener('message', event => {
// IMPORTANT: check the origin of the data!
if (event.origin === 'https://your-first-site.example') {
// The data was sent from your site.
// Data sent with postMessage is stored in event.data:
console.log(event.data);
} else {
// The data was NOT sent from your site!
// Be careful! Do not use it. This else branch is
// here just for clarity, you usually shouldn't need it.
return;
}
});
This method can be applied in both directions, creating a listener in the main page too, and receiving responses from the frame. The same logic can also be implemented in pop-ups and basically any new window generated by the main page (e.g. using window.open()) as well, without any difference.
Disabling same-origin policy in your browser
There already are some good answers about this topic (I just found them googling), so, for the browsers where this is possible, I'll link the relative answer. However, please remember that disabling the same-origin policy will only affect your browser. Also, running a browser with same-origin security settings disabled grants any website access to cross-origin resources, so it's very unsafe and should NEVER be done if you do not know exactly what you are doing (e.g. development purposes).
Google Chrome
Mozilla Firefox
Safari
Opera: same as Chrome
Microsoft Edge: same as Chrome
Brave: same as Chrome
Microsoft Edge (old non-Chromium version): not possible
Microsoft Internet Explorer
Complementing Marco Bonelli's answer: the best current way of interacting between frames/iframes is using window.postMessage, supported by all browsers
Check the domain's web server for http://www.example.com configuration for X-Frame-Options
It is a security feature designed to prevent clickJacking attacks,
How Does clickJacking work?
The evil page looks exactly like the victim page.
Then it tricked users to enter their username and password.
Technically the evil has an iframe with the source to the victim page.
<html>
<iframe src='victim-domain.example'/>
<input id="username" type="text" style="display: none;"/>
<input id="password" type="text" style="display: none;"/>
<script>
//some JS code that click jacking the user username and input from inside the iframe...
<script/>
<html>
How the security feature work
If you want to prevent web server request to be rendered within an iframe add the x-frame-options
X-Frame-Options DENY
The options are:
SAMEORIGIN: allow only to my own domain render my HTML inside an iframe.
DENY: do not allow my HTML to be rendered inside any iframe
ALLOW-FROM https://example.com/: allow specific domain to render my HTML inside an iframe
This is IIS config example:
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="SAMEORIGIN" />
</customHeaders>
</httpProtocol>
The solution to the question
If the web server activated the security feature it may cause a client-side SecurityError as it should.
For me i wanted to implement a 2-way handshake, meaning:
- the parent window will load faster then the iframe
- the iframe should talk to the parent window as soon as its ready
- the parent is ready to receive the iframe message and replay
this code is used to set white label in the iframe using [CSS custom property]
code:
iframe
$(function() {
window.onload = function() {
// create listener
function receiveMessage(e) {
document.documentElement.style.setProperty('--header_bg', e.data.wl.header_bg);
document.documentElement.style.setProperty('--header_text', e.data.wl.header_text);
document.documentElement.style.setProperty('--button_bg', e.data.wl.button_bg);
//alert(e.data.data.header_bg);
}
window.addEventListener('message', receiveMessage);
// call parent
parent.postMessage("GetWhiteLabel","*");
}
});
parent
$(function() {
// create listener
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
eventer(messageEvent, function (e) {
// replay to child (iframe)
document.getElementById('wrapper-iframe').contentWindow.postMessage(
{
event_id: 'white_label_message',
wl: {
header_bg: $('#Header').css('background-color'),
header_text: $('#Header .HoverMenu a').css('color'),
button_bg: $('#Header .HoverMenu a').css('background-color')
}
},
'*'
);
}, false);
});
naturally you can limit the origins and the text, this is easy-to-work-with code
i found this examlpe to be helpful:
[Cross-Domain Messaging With postMessage]
There is a workaround, actually, for specific scenarios.
If you have two processes running on the same domain but different ports, the two Windows can interact without limitations. (i.e. localhost:3000 & localhost:2000). To make this work, each window needs to change their domain to the shared origin:
document.domain = 'localhost'
This also works in the scenario that you are working with different subdomains on the same second-level domain, i.e. you are on john.site.example trying to access peter.site.example or just site.example
document.domain = 'site.example'
By explicitily setting document.domain; the browser will ignore the hostname difference and the Windows can be treated as coming from the 'same-origin'. Now, in a parent window, you can reach into the iframe: frame.contentWindow.document.body.classList.add('happyDev')
If you have control over the content of the iframe - that is, if it is merely loaded in a cross-origin setup such as on Amazon Mechanical Turk - you can circumvent this problem with the <body onload='my_func(my_arg)'> attribute for the inner html.
For example, for the inner html, use the this html parameter (yes - this is defined and it refers to the parent window of the inner body element):
<body onload='changeForm(this)'>
In the inner html :
function changeForm(window) {
console.log('inner window loaded: do whatever you want with the inner html');
window.document.getElementById('mturk_form').style.display = 'none';
</script>
I experienced this error when trying to embed an iframe and then opening the site with Brave. The error went away when I changed to "Shields Down" for the site in question. Obviously, this is not a full solution, since anyone else visiting the site with Brave will run into the same issue. To actually resolve it I would need to do one of the other things listed on this page. But at least I now know where the problem lies.
I would like to add Java Spring specific configuration that can effect on this.
In Web site or Gateway application there is a contentSecurityPolicy setting
in Spring you can find implementation of WebSecurityConfigurerAdapter sub class
contentSecurityPolicy("
script-src 'self' [URLDomain]/scripts ;
style-src 'self' [URLDomain]/styles;
frame-src 'self' [URLDomain]/frameUrl...
...
.referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)
Browser will be blocked if you have not define safe external contenet here.
Open the start menu
Type windows+R or open "Run
Execute the following command.
chrome.exe --user-data-dir="C://Chrome dev session" --disable-web-security
I created a webview (BrowserComponent) and added a listener:
BComp.addWebEventListener(BrowserComponent.onMessage, e->{
Display.getInstance().callSerially(()->{
Dialog.show("Message", (String)e.getSource(), "OK", null);
});
});
Then, in the JavaScript of the embedded website, I called cn1PostMessage and postMesage. This works well in the simulator! But when building the application, on Android, it does nothing (cn1PostMessage is undefined and postMessage is not received by the main program).
var msg = "test";
if(window.cn1PostMessage) {
window.cn1PostMessage(msg);
} else {
window.parent.postMessage(msg, '*');
// Tried: window.postMessage(msg, '*');
// Tried: window.top.postMessage(msg, '*');
}
What can I do?
Thanks!
I just tried building the BrowserComponentPostMessageSample, and it seemed to work fine on my Galaxy S8, Android 8.
If you're finding that window.cn1PostMessage is undefined, then either there was a javascript error in page load that prevented that callback from being installed, or your code is running before the CodenameOne initialization code has run.
I have just added support for the "android.webContentsDebuggingEnabled" display property, which will make the app's web views debuggable using Chrome's remote development tools. This will make it easier for your to track down such issues. See usage example:
Display.getInstance().setProperty("android.webContentsDebuggingEnabled", "true");
This will be available in Friday's update (Dec. 6/19).
In the mean time, I recommend starting with the BrowserComponentPostMessageSample and modifying it to suit your needs from there.
Alternatively, if you can post a test case to demonstrate the issue, I can look at it.
I am currently developing a Meteor React app, which is using the ostrio:files package to store audio files in a collection named Files. In another (regular mongo) collection, I am using the following code in the transform function to "join" the document with the link to the audio file:
transform: function(doc){
let curAudio = doc.audio;
let audioFile = Files.collection.findOne({_id: curAudio.file_id});
if(audioFile){
curAudio.audioLink = Files.link(audioFile);
curAudio.audioLength = audioFile.meta.length;
curAudio.audioSize = audioFile.size;
doc.audio = curAudio;
}
return doc;
}
This seems to work just fine, as the resulting audio.audioLink is something like
http://localhost:3000/cdn/storage/files/8Q7WwEXyJSkNWwFQa/original/8Q7WwEXyJSkNWwFQa.m4a
But when I try to do something like this
<audio controls preload="none" style={{width: "480px"}}>
<source src={track.audioLink} type="audio/mp4"/>
<p>Your browser does not support HTML5 audio.</p>
</audio>
To be able to play the file, everything works until I click the play button of the HTML5 player. Then, chrome outputs to the console, that the server returned 404 when the file was supposed to be loaded. I tested putting the link into the adress bar, here the server response is just
File Not Found :(
Does anyone have an idea how to fix this?
I found the answer:
My local Ubuntu installation was apparently configured to store uploaded files in /tmp, which didn't caus problems until I restarted the system or cleared my temporary files otherwise. Having the server recreate the DB fixed the problem.
console.log(Ext.os.Name)
prints the name for OS("Windows"==>in windows machine) for all browser,
But I want to know there is anyway to get the current Platform("chrome","safari","firefox","windows","ios","ios-classic") value based upon the theme currently loaded by sencha.
Because i need configure some of my component based on the browser also.
I dont need Browser name or os name, i need the platform variable used
by sencha framework. like when we using the ios6 it will take the
platform parameter as ios-classic we also pass the platform parameter
in link like http://cdn.sencha.com/touch/sencha-touch-2.3.1a/built-examples/kitchensink/index.html?platform=ios-classic# or
http://cdn.sencha.com/touch/sencha-touch-2.3.1a/built-examples/kitchensink/index.html?platform=windows# this will load the ios6 and windows theme respectively even we use any kind of browser in any OS.
you can use Ext.browser
console.log(Ext.browser.name);
console.log(Ext.browser.version);
Ext.device will not work for browser as it works only for native packing.
you can get what theme is applied by using Ext.theme.name
Ext.theme.name
getting platform for them is not directly provided in Sencha Touch. you can check implementation for that in sencha\app\microloader
I found the following configurations on http://docs-origin.sencha.com/extjs/4.2.2/#!/api/Ext , from that what i have observed is, we can't find the browser's name but we can check whether it is chrome or else like that...
example :
console.log(Ext.isWindows);
true //because i am working in windows
chromeVersion
firefoxVersion
ieVersion
isChrome
isFF10
isFF3_0
isFF3_5
isFF3_6
isFF4
isFF5
isGecko
isGecko10
isGecko3
isGecko4
isGecko5
isIE
isIE10
isIE10m
isIE10p
isIE11
isIE11m
isIE11p
isIE6
isIE7
isIE7m
isIE7p
isIE8
isIE8m
isIE8p
isIE9
isIE9m
isIE9p
isLinux
isMac
isOpera
isOpera10_5
isSafari
isSafari2
isSafari3
isSafari4
isSafari5
isSafari5_0
isWebKit
isWindows
name
operaVersion
safariVersion
In Sencha Touch 2.3 the Ext.device.Device singleton will give you information on the platform and the Ext.device.Browser will give you information on the browser.
Joomla has a feature where it loads the a minified javascript file and the uncompressed version when the site is in debug mode.
I have named both my files correctly and am include it as follows:
JHtml::_('script', JUri::root() . 'path_to_file/jquery-sortable.js');
When I put the site in debug mode, it does not load the uncompressed file.
However, If I use the following instead, it works fine:
JHtml::_('script', 'path_to_file/jquery-sortable.js');
Now I'm not sure whether this is a bug in Joomla or not, but I cannot find any information online regarding this. I would like to use JURI::root() in the path.
Does anyone have any information on this?
Indeed, if the script URL begins with http, the code that is responsible for including the uncompressed version (i.e, remove the min. segment if such exists or add -uncompressed otherwise) is ignored.
The source for this behavior:
JHtml::includeRelativeFiles() in libraries/cms/html/html.php:298
protected static function includeRelativeFiles($folder, $file, $relative, $detect_browser, $detect_debug)
{
// If http is present in filename
if (strpos($file, 'http') === 0)
{
$includes = array($file);
}
else
//process the script sourch.
}
...
}
Most of the script files, including frameworks, are included as relative paths. I guess that this behavior is meant to prevent remote resources from getting 404ed.