I have created a webpage to write an Arduino code and after that i would like to save the code on the pc, so i use new Blob to save the file and the extension is .ino,, but when i go to the created file i got these messages
Could not create the sketch
Failed to open sketch: 'direction for the file'
I would like to know How to save .ino file
var textToSaveAsBlob = new Blob([encodeURIComponent(arduinoSource)], {type:'data:text/ino;charset=utf-8,'});
var datenow = Date.now();
var fileNameToSaveAs = "arduino_code" +datenow+ ".ino";
saveAs(textToSaveAsBlob, fileNameToSaveAs);
You can use data URIs inside anchor element to generate your download. Browser support varies though, check out Wikipedia description.
For example, the following function takes in your filename and code and generates a download. The way it works is that it creates an anchor element in your DOM, defines charset and content type of your file, appends your code, launches a click event on the anchor element to generate download and then destroys the element.
function download(filename, code) {
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(code));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
I have written the following snippet to generate your required functionality, added a bit of Arduino style CSS as well. Hope it helps!
function download(filename, code) {
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(code));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
var dateNow = Date.now();
var fileName = 'ArduinoCode';
document.getElementById("arduino-file-name").innerHTML = fileName;
document.getElementById("download-code").addEventListener("click", function() {
var arduinoCode = document.getElementById("arduino-code").value;
var fileNameFull = fileName + "-" + dateNow + ".ino";
download(fileNameFull, arduinoCode);
}, false);
.arduino-menu-bar {
background-color: #006468;
padding: 10px;
}
.arduino-menu-bar--footer {
display: block;
height: 10px;
background-color: #4db7bb;
}
#download-code {
border: none;
color: #4db7bb;
font-size: 30px;
cursor: pointer;
}
#download-code:hover {
color: #7ac4c7;
}
.arduino-files-bar {
background-color: #4db7bb;
padding: 5px 5px 0 5px;
}
.open-file-title {
background-color: #fff;
padding: 5px 15px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
display: inline-block;
color: #006468;
font-family: Arial, Helvetica, sans-serif;
}
#arduino-code {
font-family: 'Fira Code', monospace;
outline: none;
display: block;
width: 100%;
height: 250px;
border: 0px;
font-size: 14px;
resize: none;
}
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css">
<link href="https://fonts.googleapis.com/css?family=Fira+Code&display=swap" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css">
<div class="arduino-code-container">
<div class="arduino-menu-bar">
<i id="download-code" class="fas fa-cloud-download-alt"></i>
</div>
<div class="arduino-files-bar">
<div id="arduino-file-name" class="open-file-title"></div>
</div>
<textarea id="arduino-code">
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
</textarea>
<div class="arduino-menu-bar arduino-menu-bar--footer"></div>
</div>
Related
I'm working on a portfolio project - which should use jquery - part of the task is to set and get text via localstorage - which I can do in Javascript but I breaks when attempting to refactor in jquery.
I found an elegantly simple javascript codepen, which has all the features I want. But when I refactor into jquery it loses funtionality - I can't save the text to local storage (I get null) and I can't copy the text to a different Div.
This is the HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Local Test</title>
</head>
<body>
<div class="content-output"></div>
<textarea class="content-input" placeholder="Your text here"></textarea>
<button class="save-button">Save</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="./script.js"></script>
</body>
</html>
This is simple CSS from the JS code pen:
* {
font-size: 16px;
font-family: sans-serif;
}
body {
padding: 1rem;
font-family: sans-serif;
}
.content-output {
float: left;
box-sizing: border-box;
background: #f9f9f9;
padding: 0.5rem;
width: calc(50% - 1rem);
height: 10rem;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
color: #202020;
}
.content-input {
float: left;
box-sizing: border-box;
margin-left: 2rem;
padding: 0.5rem;
width: calc(50% - 1rem);
height: 10rem;
border: 1px solid #505050;
resize: none;
}
.save-button {
/* -webkit-appearance: none; */
border: 0;
background: #0088ff;
padding: 0.5rem 1rem;
border-radius: 3px;
color: #fff;
margin-top: 1rem;
float: right;
cursor: pointer;
}
Here is the JS which works:
var input_textarea = document.querySelector(".content-input");
var output_div = document.querySelector(".content-output");
var save_button = document.querySelector(".save-button");
save_button.addEventListener("click", updateOutput);
output = localStorage.getItem("content");
input = localStorage.getItem("content");
console.log(output);
output_div.textContent = output;
function updateOutput() {
console.log("clicked button");
localStorage.setItem("content", input_textarea.value);
output_div.textContent = input_textarea.value;
}
And here is the jquery which doesn't work:
var input_textarea = $(".content-input");
var output_div = $(".content-output");
var save_button = $(".save-button");
save_button.on("click", updateOutput);
output_div.textContent = localStorage.getItem("content");
input_textarea.value = localStorage.getItem(("content"));
function updateOutput(event) {
event.preventDefault();
localStorage.setItem("content", input_textarea.value);
output_div.textContent = input_textarea.value;
}
I'm running out of ideas and searches - probably a typo but I cant find it . I've tried text() which was the advice 6 years ago. JSON.stringify and parse don't help because it's just a string.
I'm hoping someone has done some refactoring and spots the differences - I've even run this in the console but I can only add the text to localstorage manually: localstorage.setItem('content', 'help')
Thanks in advance
The problem is that you are trying to select a array, get the value of that array, and output to another array. I think jquery does that when you select a class, (because there could be more than one of them). Simple solution to this..
var input_textarea = $(".content-input")[0];
console.log(input_textarea)
var output_div = $(".content-output")[0];
var save_button = $(".save-button");
save_button.on("click", updateOutput);
output_div.textContent = localStorage.getItem("content");
input_textarea.value = localStorage.getItem(("content"));
function updateOutput(event) {
console.log('hello')
event.preventDefault();
localStorage.setItem("content", input_textarea.value);
output_div.textContent = input_textarea.value;
}
Found it: val() to set and text() to get.
var input_textarea = $(".content-input");
var output_div = $(".content-output");
var save_button = $(".save-button");
save_button.on("click", updateOutput);
// input_textarea.value = localStorage.getItem(("content"));
function updateOutput(event) {
event.preventDefault();
localStorage.setItem("content", input_textarea.val());
output_div.text(localStorage.getItem("content"));
}
this post helped: How to save the value of textarea to localstorage then display it in the same textarea
This is my Fiddle: https://jsfiddle.net/e6b5hdow/2/
const links = document.querySelectorAll('[href$=".jpg"], [href$=".png"], [href$=".mp4"], [href$=".avi"], [href$=".jpeg"], [href$=".mkv"], [href$=".csv"]');
links.forEach(link => link.classList.add('download-button'));
$('.name').prepend($("<div class='download-ui-container'><div class='start-download'>Starting Download..</div><div class='download-progress-container'><div class='download-progress'></div></div><a class='save-file'>Save File</a></div>"));
var _OBJECT_URL;
$(document).on('click', '.download-button', function(event) {
var request = new XMLHttpRequest();
fileDownload = $(this).attr('href');
var _t = $(this);
request.addEventListener('readystatechange', function(e) {
if (request.readyState == 2 && request.status == 200) {
_t.parents('td').find('.start-download').css('display', 'block');
_t.parents('td').find('.download-button').hide();
} else if (request.readyState == 3) {
_t.parents('td').find('.download-progress-container').css('display', 'block');
_t.parents('td').find('.start-download').hide()
} else if (request.readyState == 4) {
_OBJECT_URL = URL.createObjectURL(request.response);
var fileName = fileDownload.split("/")
fileName = fileName[fileName.length - 1]
var downloadLink = document.createElement('a');
console.log(downloadLink);
downloadLink.href = _OBJECT_URL;
downloadLink.download = fileName;
// document.body.appendChild(downloadLink);
downloadLink.click();
_t.parents('td').find('.download-button').css('display', 'block');
_t.parents('td').find('.download-progress-container').hide();
_t.parents('td').find('.save-file').click();
setTimeout(function() {
window.URL.revokeObjectURL(_OBJECT_URL);
_t.parents('td').find('.download-button').css('display', 'block');
_t.parents('td').find('.save-file').css('display', 'hide');
}, 60 * 1000);
}
});
request.addEventListener('progress', function(e) {
var percent_complete = (e.loaded / e.total) * 100;
_t.parents('td').find('.download-progress').css('width', percent_complete + '%');
});
request.responseType = 'blob';
request.open('get', fileDownload);
request.send();
return false;
});
.demo-container {
width: 400px;
margin: 60px auto;
}
.download-button {
background-color: white;
color: #2980b9;
border: 2px solid #2980b9;
font-family: inherit;
outline: none;
min-width: 100px;
padding: 10px;
font-size: inherit;
border-radius: 2px;
cursor: pointer;
display: block;
margin: 0 auto;
}
.start-download {
text-align: center;
display: none;
}
.download-progress-container {
border: 1px solid #cccccc;
padding: 4px;
display: none;
height: 20px;
}
.download-progress {
background-color: #2980b9;
display: inline-block;
height: 100%;
}
.save-file {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<table>
<tr>
<td class="name">
First link, large file
</td>
</tr>
<tr>
<br><br><br>
<td class="name">
Second link small file
</td>
</tr>
</table>
Here, I am trying to download the file using Ajax and show progress bar. It works perfectly but one problem.
If the first link file is big, and second link file is small.
Then if someone clicks on the first link and file starts downloading and
then immediately clicks on second link and file downloads because of small size, and first link file is still downloading.
After the first link click file is downloaded, it saves with the file with name of second file.
Reproducing steps:
Click on first link
Click on second link
If second link file downloads first, then the name of first link file is same as of second file link
I think, when I call the function again, the filename variable, it gets overwritten something.
Is it possible to use request header instead of filename?
Basically, what I need is.
A way to prevent the overwrite of variable name, when a function is called two times with different parameters, and the function called first time, takes longer to execute, and function called second time, executes within 1 sec.
just replace
fileDownload = $(this).attr('href');
with
var fileDownload = $(this).attr('href');
so that your variable is not considered global by javascript
In Anki, I have a note type where one card is effectively a cloze deletion, however I am using other cards at the same time, with the cloze deletion field in it. I've tried to use javascript to replace everything within two '\'s and it appears to work in the preview when editing, but when the card appears during normal use, only the first line appears as plain text. I'm using the desktop linux program for editing, but would also like to be able to use it in AnkiDroid.
So the question is: what's the problem and how can I fix it?
Front Template:
<script>
function showDef() {
document.getElementById("def").innerHTML = '{{Bedeutung 1}}'.replace(/^[^\/]+\/\*!?/, '').replace(/\*\/[^\/]+$/, '');
};
var initial = false;
var beispiel = (function () {/*{{Beispiel 1}}*/}).toString().replace(/^[^\/]+\/\*!?/, '').replace(/\*\/[^\/]+$/, '');
var splitBeispiel = beispiel.split('\\');
document.write(splitBeispiel[0] + "<n id='cloze'>[...]</n>" + splitBeispiel[2]);
</script>
<p onclick="showDef()" id="def">Click to show definition</p>
Styling:
.card {
font-family: arial;
font-size: 20px;
text-align: center;
color: black;
background-color: white;
}
#cloze {
font-family: arial;
font-size: 25px;
text-align: center;
color: blue;
background-color: white;
}
#def {
font-family: arial;
font-size: 15px;
text-align: center;
color: green;
background-color: white;
}
#beispiel {
font-family: arial;
font-size: 15px;
text-align: center;
color: orange;
background-color: white;
}
Back Template:
<script>
var initial = false;
var beispiel = (function () {/*{{Beispiel 1}}*/}).toString().replace(/^[^\/]+\/\*!?/, '').replace(/\*\/[^\/]+$/, '');
var splitBeispiel = beispiel.split('\\');
document.write(splitBeispiel[0] + "<n id='cloze'>" + splitBeispiel[1] +"</n>" + splitBeispiel[2]);
</script>
<hr id=answer>
{{Singular Nominativ}}
The 'Beispiel 1' field in the following example is "ein kirchlicher, ein \gesetzlicher\ Feiertag"
Screenshot of editor preview:
Screenshot of test:
I guess, you should look for the solution here.
Avoid using document.write in your templates and use document.getElementById("HTMLidToReplace").innerHTML = '<b>' + your_var + '</b>';, for example. Hope it helps.
I have written a script to add a Pinterest button to most images on my site. The issue is that when someone has the Chrome Pin it extension enabled in their browser, the "pin it" button shows up twice for the user.
Is there anyway, in JavaScript, to check if the user has this extension enabled in their browser?
(function($) {
$(function() {
$('.container img').each(function() {
if ($(this).parent('a')) {
var $permalink = $(this).parent('a').attr('href');
}
else {
var $permalink = $(location).attr('href');
}
var $permalink = $(location).attr('href'),
$title = $('h1.product_name').text() || $('h2.header');
var $linkhtml = $('<a/>', {
'class':'pin-it-button pinme',
'html': '<img src="//assets.pinterest.com/images/pidgets/pinit_fg_en_rect_gray_20.png" />',
'count-layout': 'horizontal',
'style': 'cursor:pointer; position:absolute; bottom:30px; left:0; border:0 none; opacity: 0.4;',
'href': 'http://pinterest.com/pin/create/button/?url=' + $permalink + '&media=' + $(this).attr('src') + '&description=' + $title
});
if ($(this).parent('a')) {
$(this).addClass('pinme').parent('a').after($linkhtml);
}
else {
$(this).addClass('pinme').after($linkhtml);
}
$('.pinme').hover(
function() {
if ($(this).hasClass('pin-it-button')) {
console.log('hello');
$(this).css('opacity', '1');
}
else {
$(this).parent().siblings('.pin-it-button').css('opacity', '1');
}
}, function() {
if ($(this).hasClass('pin-it-button')) {
$(this).css('opacity', '0.4');
}
else {
$(this).parent().siblings('.pin-it-button').css('opacity', '0.4');
}
}
);
});
});
})(jQuery);
The new Pinterest extension (2017)
injects a <span> hover button directly under <body:
<span style="border-radius: 3px;
text-indent: 20px;
width: auto;
padding: 0px 4px 0px 0px;
text-align: center;
font-style: normal;
font-variant: normal;
font-weight: bold;
font-stretch: normal;
font-size: 11px;
line-height: 20px;
font-family: "Helvetica Neue", Helvetica, sans-serif;
color: rgb(255, 255, 255);
background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMzBweCIgd2lkdGg9IjMwcHgiIHZpZXdCb3g9Ii0xIC0xIDMxIDMxIj48Zz48cGF0aCBkPSJNMjkuNDQ5LDE0LjY2MiBDMjkuNDQ5LDIyLjcyMiAyMi44NjgsMjkuMjU2IDE0Ljc1LDI5LjI1NiBDNi42MzIsMjkuMjU2IDAuMDUxLDIyLjcyMiAwLjA1MSwxNC42NjIgQzAuMDUxLDYuNjAxIDYuNjMyLDAuMDY3IDE0Ljc1LDAuMDY3IEMyMi44NjgsMC4wNjcgMjkuNDQ5LDYuNjAxIDI5LjQ0OSwxNC42NjIiIGZpbGw9IiNmZmYiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxIj48L3BhdGg+PHBhdGggZD0iTTE0LjczMywxLjY4NiBDNy41MTYsMS42ODYgMS42NjUsNy40OTUgMS42NjUsMTQuNjYyIEMxLjY2NSwyMC4xNTkgNS4xMDksMjQuODU0IDkuOTcsMjYuNzQ0IEM5Ljg1NiwyNS43MTggOS43NTMsMjQuMTQzIDEwLjAxNiwyMy4wMjIgQzEwLjI1MywyMi4wMSAxMS41NDgsMTYuNTcyIDExLjU0OCwxNi41NzIgQzExLjU0OCwxNi41NzIgMTEuMTU3LDE1Ljc5NSAxMS4xNTcsMTQuNjQ2IEMxMS4xNTcsMTIuODQyIDEyLjIxMSwxMS40OTUgMTMuNTIyLDExLjQ5NSBDMTQuNjM3LDExLjQ5NSAxNS4xNzUsMTIuMzI2IDE1LjE3NSwxMy4zMjMgQzE1LjE3NSwxNC40MzYgMTQuNDYyLDE2LjEgMTQuMDkzLDE3LjY0MyBDMTMuNzg1LDE4LjkzNSAxNC43NDUsMTkuOTg4IDE2LjAyOCwxOS45ODggQzE4LjM1MSwxOS45ODggMjAuMTM2LDE3LjU1NiAyMC4xMzYsMTQuMDQ2IEMyMC4xMzYsMTAuOTM5IDE3Ljg4OCw4Ljc2NyAxNC42NzgsOC43NjcgQzEwLjk1OSw4Ljc2NyA4Ljc3NywxMS41MzYgOC43NzcsMTQuMzk4IEM4Ljc3NywxNS41MTMgOS4yMSwxNi43MDkgOS43NDksMTcuMzU5IEM5Ljg1NiwxNy40ODggOS44NzIsMTcuNiA5Ljg0LDE3LjczMSBDOS43NDEsMTguMTQxIDkuNTIsMTkuMDIzIDkuNDc3LDE5LjIwMyBDOS40MiwxOS40NCA5LjI4OCwxOS40OTEgOS4wNCwxOS4zNzYgQzcuNDA4LDE4LjYyMiA2LjM4NywxNi4yNTIgNi4zODcsMTQuMzQ5IEM2LjM4NywxMC4yNTYgOS4zODMsNi40OTcgMTUuMDIyLDYuNDk3IEMxOS41NTUsNi40OTcgMjMuMDc4LDkuNzA1IDIzLjA3OCwxMy45OTEgQzIzLjA3OCwxOC40NjMgMjAuMjM5LDIyLjA2MiAxNi4yOTcsMjIuMDYyIEMxNC45NzMsMjIuMDYyIDEzLjcyOCwyMS4zNzkgMTMuMzAyLDIwLjU3MiBDMTMuMzAyLDIwLjU3MiAxMi42NDcsMjMuMDUgMTIuNDg4LDIzLjY1NyBDMTIuMTkzLDI0Ljc4NCAxMS4zOTYsMjYuMTk2IDEwLjg2MywyNy4wNTggQzEyLjA4NiwyNy40MzQgMTMuMzg2LDI3LjYzNyAxNC43MzMsMjcuNjM3IEMyMS45NSwyNy42MzcgMjcuODAxLDIxLjgyOCAyNy44MDEsMTQuNjYyIEMyNy44MDEsNy40OTUgMjEuOTUsMS42ODYgMTQuNzMzLDEuNjg2IiBmaWxsPSIjYmQwODFjIj48L3BhdGg+PC9nPjwvc3ZnPg==") 3px 50% / 14px 14px no-repeat rgb(189, 8, 28);
position: absolute;
opacity: 1;
z-index: 8675309;
display: none;
cursor: pointer;
border: none;
-webkit-font-smoothing: antialiased;
top: 240px;
left: 110px;
">Save</span>
So a simple check would be:
var pin = document.querySelector('body > span[style*="8675309"][style*="rgb(189, 8, 28)"]')
Or you can check for the entire background base64 string which contains the P logo.
Old answer for the old PinIt extension:
Examining a page with Pin It extension installed we can see that it adds its own attribute to <body>:
<body data-pinterest-extension-installed="cr1.39.1">
It's easy to determine the presence of the attribute in js:
if (document.body.dataset.pinterestExtensionInstalled) {
console.log("Pin It extension detected!");
}
Note that the attribute is added after the page has been loaded so you can't check it right in DOMContentLoaded event handler; make a pause with setInterval or use MutationObserver:
Content script with "run_at": "document_end" or "document_idle" (the default mode):
var PinItInstalled = undefined;
new MutationObserver(function(mutations) {
PinItInstalled = document.body.dataset.pinterestExtensionInstalled;
this.disconnect();
}).observe(document.body, {
attributes: true,
attributeFilter: ["data-pinterest-extension-installed"]
});
Content script with "run_at": "document_start":
var PinItInstalled = undefined;
document.addEventListener("DOMContentLoaded", function() {
new MutationObserver(function(mutations) {
PinItInstalled = document.body.dataset.pinterestExtensionInstalled;
this.disconnect();
}).observe(document.body, {
attributes: true,
attributeFilter: ["data-pinterest-extension-installed"]
});
});
P.S. Don't forget to test what happens if the Pin It extension's option to show its button on hover is disabled.
While detecting the presence of the extension or pinit.js on the page may be worthwhile, the easier solution is to simply add the data-pin-no-hover attribute to your images. This will tell the extension to ignore the images.
<img src="whatevz" data-pin-no-hover="true" />
There really isn't any reason to care if it is installed or not if the data-pin attribute is set.
The other option is to not create your own hover buttons, but use pinit.js that creates the hover buttons for you. See the docs.
<script
type="text/javascript"
async defer
data-pin-hover="true"
src="//assets.pinterest.com/js/pinit.js"
></script>
I have styled filed upload button and added preview image before upload... basically everything works as a charm in all browsers except IE...
Now to bring you my idea closer it looks like:
http://postimage.org/gallery/22cvzh2g/bcd61d61/
Is there a reason why image isn't showing in IE? I tried in IE9, but I just get the path, while the $('#background-preview').removeClass('hidden'); seems not to be working as it's not removing class hidden...
...also in IE and Opera as file path you will note C:/fakepath/etc... while in FireFox, Chrome and normal browsers it displays just file name. Any help is highly appreciated!
Now in header I have:
<script>
function clearFileInput() {
var oldInput = document.getElementById("upload-bg");
var newInput = document.createElement("input");
newInput.type = "file";
newInput.id = oldInput.id;
newInput.name = oldInput.name;
newInput.onchange = oldInput.onchange;
newInput.className = oldInput.className;
newInput.style.cssText = oldInput.style.cssText;
// copy any other relevant attributes
oldInput.parentNode.replaceChild(newInput, oldInput);
$('#background-preview').addClass('hidden');
var oldInput1 = document.getElementById("FileField");
var newInput2 = document.createElement("input");
newInput2.type = "text";
newInput2.id = oldInput1.id;
newInput2.className = oldInput1.className;
newInput2.style.cssText = oldInput1.style.cssText;
oldInput1.parentNode.replaceChild(newInput2, oldInput1);
}
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#background-image')
.attr('src', e.target.result)
.width(250)
.height(170);
$('#background-preview').removeClass('hidden');
};
reader.readAsDataURL(input.files[0]);
}
}
In body section where actual button is:
<div id="FileUpload">
<input id="upload-bg" type='file' onchange="readURL(this);getElementById('FileField').value = getElementById('upload-bg').value;" />
<div id="BrowserVisible"><input type="text" id="FileField" /></div>
</div>
<div id="background-preview" class="hidden"><img id="background-image" src="#" alt="Bad Image File !" /> </div>
And the CSS that takes care for the customizing file input is:
#FileUpload {
position:relative;
height: 50px;
}
#BrowserVisible {
margin: 5px 0px 5px 0px;
position: absolute;
top: 0px;
left: 0px;
z-index: 1;
background:url(images/button-browse.png) 100% 0px no-repeat;
height:42px;
width:290px;
}
#FileField {
border: 1px solid #BDBDBD;
font-size: 13px;
height: 40px;
margin: 0;
padding: 0;
width: 215px;
}
#upload-bg {
position:relative;
width:290px;
height:43px;
text-align: right;
-moz-opacity:0;
filter:alpha(opacity: 0);
opacity: 0;
z-index: 2;
}
#clear-bg-upload {
position: absolute;
top: 0px;
right: 0px;
width: 16px;
height: 16px;
background: url(images/icon-delete-input.png) top center no-repeat;
}
#background-preview {
border: solid 1px #ccc;
padding: 5px;
position: relative;
display: inline-block;
border-radius: 5px;
-o-border-radius: 5px;
-icab-border-radius: 5px;
-khtml-border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
}
#background-preview.hidden {
display: none;
}
#background-preview img {
margin: 0px auto;
display: block;
max-height: 140px;
max-width: 180px;
width: auto;
}
----------------------------- EDITED -------------------------------
Ok, I went to different approach via Ajax (using) upload and all is wonderful... I just can't figure how to send field value only. Right now it's sent like form, but is there a way to trigger send only the field. Right now it's warped in #FileUploadForm, but I want to use this within a form and since forms can't be nested... I am kind of stuck... except having two forms like I have now, but I would like that file upload filed to be sent like it is now, just without having to wrap it in it's own form.
This is script I am using:
function showRequest(formData, jqForm, options) {
var fileToUploadValue = $('#fileToUpload').fieldValue();
if (!fileToUploadValue[0]) {
$('#result').html('Please select a file.');
return false;
}
$("#loading").show();
return true;
}
function showResponse(data, statusText) {
$("#loading").hide();
if (statusText == 'success') {
var msg = data.error.replace("##", "<br />");
if (data.img != '') {
$('#result').removeClass('hiddenmessage');
$('#result').html('<img src="uploads/thumbs/' + data.img + '" /> ');
// $('#message').html('Click here');
// $('#FileUploadForm').html('');
} else {
$('#result').removeClass('hiddenmessage');
$('#result').html(msg);
}
} else {
$('#result').removeClass('hiddenmessage');
$('#result').html('Unknown error!');
}
}
function StartFileUpload() {
$('#message').html('');
$('#FileUploadForm').ajaxSubmit({
beforeSubmit: showRequest,
success: showResponse,
url: 'upload.php',
dataType: 'json'
});
return false;
}
$('#fileToUpload').live('change', function () {
StartFileUpload();
});
Let's start with paths — in HTML/JS, you can't get full path to attached file due to security concerns. All you can get is file name.
Usually the best approach is to upload file to server with JavaScript when user selects file and then grab preview from that server. You could provide some "delete" button which would enable users to remove pics they uploaded by mistake.
This would enforce deep changes in your application. I recommend File Uploader plugin. Writing your own solution from scratch will be very painful because it requires many hacks for different browsers.