PDA

View Full Version : Image file upload field with preview extension



teddyjas
7 Jul 2009, 5:39 AM
Hi guys,

I have created a simple extension for ExtJS for image file upload field extension for my own use which enables you to:
- validate image file extension (gif, jpeg & png)
- preview the image on the fly
- enable resizing on the fly
- get the image width and height

The extension is created on ExtJS 2.2, I have not tried using the ExtJS 3.0 yet :).

Currently the extension works on IE and Firefox/Mozilla.

http://www.jasin.biz/wp-includes/js/tinymce/plugins/wordpress/img/trans.gifIE Note: IE7 and above requires you to add the website url as an authorised sites to allow you to preview the image.
You can do this in Tools > Internet options > Security > Trusted sites > Sites

Here's the extension source code:


/**
* @class Ext.ux.form.ImageField
* @extends Ext.form.TextField
* This is a image file upload field
* @license: LGPLv3
* @author: Teddy A Jasin
* @constructor
* Creates a image field
* @param {Object} config Configuration options
* @version 1.0.0
*/

Ext.namespace("Ext.ux", "Ext.ux.form");
Ext.apply(Ext.form.VTypes, {
Image: function(v) {
v = v.replace(/^\s|\s$/g, ""); //trims string
if (v.match(/([^\/\\]+)\.(gif|png|jpg|jpeg)$/i) )
return true;
else
return false;
},
ImageText: 'Must be a valid image: gif,jpg,png,jpeg'
});

Ext.ux.form.Imagefield = Ext.extend(Ext.form.TextField, {
inputType:'file',
validationEvent:'all',
previewImage: true,
//only aplied of previewImage is true
forceUpload:false, //if set to true it will upload the image first to allow preview, if false will detect by browser and use upload when necessary
resizable:true,
//only applied if resizable is true
preserveRatio:true,
resizeHandles:'se',
pinned:true,
//if browser preview not supported, supply file upload url which return img path
imgPreviewUrl:'imgPreview.php',

initComponent : function(){
Ext.ux.form.Imagefield.superclass.initComponent.call(this);
this.on('blur',this.setPreview,this);
},

afterRender : function(){
Ext.ux.form.Imagefield.superclass.afterRender.call(this);
if (this.previewImage && !this.preview){
this.previewId = this.getId()+'-preview';
this.preview = Ext.DomHelper.insertAfter(this.getEl(),
{tag:'div',cls:'x-imagefield-preview',children:[
{tag:'div',children:[
{tag:'span',html:'',id:this.previewId+'-width',style:'margin:10px;'},
{tag:'span',html:'',id:this.previewId+'-height',style:'margin:10px;'}
]}
]}
);
this.maxPreviewWidth = Ext.get(this.preview).getWidth();
}

},

validateValue: function(value){
this.vtype = 'Image';
var valid=Ext.ux.form.Imagefield.superclass.validateValue.call(this,value);

return valid;
},

setPreview: function(){
if (Ext.isEmpty(this.getValue()) || !this.previewImage) return false;
if (this.preview && this.isValid() && !this.forceUpload){
if (!this.forceUpload){
//use browser preview if available
Ext.DomHelper.insertFirst(this.preview,{tag:'img',src:'images/spinner.gif',alt:'preview',id:this.previewId,style:'max-width:'+this.maxPreviewWidth+'px;'});
var previewImg = Ext.getDom(this.previewId);
if (Ext.isGecko3){
var file = this.getEl().dom.files[0];
previewImg.src = file.getAsDataURL();
this.updatePreviewSize();
this.setResizable();
}
else if (Ext.isIE){
if (!Ext.isIE6){
//non ie 6 requires sites to be added to trusted sites
previewImg.alt='If you are unable to view the image, ensure the site url is added to the trusted site';
}
var file = this.getValue();
previewImg.src = 'file://'+file;
this.updatePreviewSize();
this.setResizable();
}
else{
this.processUpload();
}
}else
this.processUpload();
}
},

processUpload: function(){
(function(){
Ext.Ajax.request({
form: this.ownerCt.getForm().id,
url: this.imgPreviewUrl,
isUpload: true,
method:'POST',
params: {'imagename':this.getId()},
success:function(action){
try {
var jsonData = Ext.util.JSON.decode(action.responseText);
}
catch (err) {
var jsonData = false;
}
if(jsonData && jsonData.success === true){
Ext.getDom(this.previewId).src=jsonData.preview;
this.updatePreviewSize();
this.setResizable();
}
},
scope:this
});
}).defer(100,this);
},

updatePreviewSize: function(){
var widthDom = Ext.getDom(this.previewId+'-width');
var heightDom = Ext.getDom(this.previewId+'-height');
var previewSize = Ext.fly(this.previewId).getSize();

widthDom.innerHTML = 'width:'+previewSize.width+'px';
this.previewWidth = previewSize.width;
heightDom.innerHTML = 'height:'+previewSize.height+'px';
this.previewHeight = previewSize.height;

this.validate();
},

setResizable:function(){
if (this.resizable)
this.updateResizer();
},

updateResizer:function(){
if (this.resizer)
this.resizer.destroy(true);

if(this.preview){
//had to do this as if image is not in browser cache, it will cause the image size not properly rendered
(function(){
this.resizer = new Ext.Resizable(this.previewId, {
handles: this.resizeHandles,
maxWidth:this.maxPreviewWidth,
pinned: this.pinned,
preserveRatio:this.preserveRatio,
wrap:true
});
this.resizer.on("resize",this.updatePreviewSize,this);
}).defer(100,this);
}
},

getPreviewSize:function(){
return {'width':this.previewWidth,'height':this.previewHeight};
}
});
Ext.reg('imagefield', Ext.ux.form.Imagefield);
Demo site:http://www.jasin.biz/playground/imagefield.html
(http://www.jasin.biz/playground/imagefield.html)
The extension stills need lots of torture testing and improvements, do help me improving it :)
hope this extension will help someone out there :). If anyone can point me the properties of file upload field for safari and chrome do let me know... thanks!.

moegal
7 Jul 2009, 6:14 AM
I tried your demo and I cannot see it working in FF2+. This looks like it would be a real handy extension.

In FF I get this.getEl().dom.files has no properties

In IE I see the image once I have added the site to my trusted sites.

Thanks, Marty

teddyjas
7 Jul 2009, 6:13 PM
ugh thats ugly!
i tested that on FF3 thinking will be working on FF2... dang!
have to find the workaround... thankss!

moegal
8 Jul 2009, 4:59 AM
no problem. Who would have thought 2 and 3 would be that different.
Marty

teddyjas
10 Jul 2009, 7:37 AM
code updated...
I think there's no way to get the file in firefox 2 due to security issue.
So need to force to upload first then preview...

you will need server side script to accept the preview image file and move to a directory and return the json format containing path of the image file on server.

here's the code I use for my preview in php:



<?php
/*
* sample preview php file to accept the upload image for preview
* returning json syntax {success:boolean [,preview:str of image temp path]}
*/
$return = array();
//tempdir
$tempdir="temp/";
$uploadfile = $tempdir . basename($_FILES[$_POST['imagename']]['name']);
if(!move_uploaded_file($_FILES[$_POST['imagename']]['tmp_name'], $uploadfile)) {
$return['success']=false;
} else {
$return['success']=true;
$return['preview']=$uploadfile;
}
echo json_encode($return);
?>

now the drawback is that it uploads the whole form to the server side file first, hopefully someone can give me pointer on how to submit that field only not the rest?

It still not working for safari yet, can anyone point me what's the event for file type input in safari to make this work??

mystix
11 Jul 2009, 1:30 AM
now the drawback is that it uploads the whole form to the server side file first, hopefully someone can give me pointer on how to submit that field only not the rest?


create a new throwaway <form> using DomHelper, clone the file field into that throwaway <form>, then submit it.
after submitting, remove the throwaway <form> from the DOM.

teddyjas
11 Jul 2009, 7:38 AM
create a new throwaway <form> using DomHelper, clone the file field into that throwaway <form>, then submit it.
after submitting, remove the throwaway <form> from the DOM.

mystix, I have tried that before.
the file field can be cloned, but the value user chosen cant be copied to the cloned field... it throws security error...
I've googled it... u can't set the file field value.
If can I also think it would be greatest security hole, the javascript can set the local file and send to the website without user knowing...:-?

mystix
11 Jul 2009, 7:48 AM
ok, how about we change that approach a little...

create a throwaway <form> using DomHelper, move the file input field into the throwaway <form>, submit the throwaway <form>, move the file input field back to its original location, then remove the throwaway <form> from the DOM.

teddyjas
11 Jul 2009, 8:27 AM
yeah thot of that too, but didn't try as I thought it would cos the form to flicker as in the field will be moved and back again, doesnt feel good to the user view.
anyway let me try first..

mystix
11 Jul 2009, 10:19 AM
yeah thot of that too, but didn't try as I thought it would cos the form to flicker as in the field will be moved and back again, doesnt feel good to the user view.
anyway let me try first..

you could "wrap" the file upload field with the new throwaway <form> instead of moving it. just a thought.

teddyjas
17 Jul 2009, 1:52 AM
you could "wrap" the file upload field with the new throwaway <form> instead of moving it. just a thought.

mystix, I haven't try your previous suggestion, tomorrow probably as its weekend :)
anyway what you meant by throwaway form?

mystix
17 Jul 2009, 2:01 AM
mystix, I haven't try your previous suggestion, tomorrow probably as its weekend :)
anyway what you meant by throwaway form?

a single-use, plain-old html <form> element.

israeldelahoz
26 Jan 2010, 8:42 AM
it doesnt support any web kit browser like chrome and safary,and.. how can i get the preview with out clicking the component again,I mean when i choose the file,
ohh,I almoust forgot ,great job

jphillips
15 Jul 2010, 12:31 PM
Can someone point me to an example that is using the ImageField? Also, has anyone used it with Ext 3.0.x successfully?

edwin.deloso
31 Jan 2011, 12:17 AM
Hi,

This demo site http://www.jasin.biz/playground/imagefield.html is not working. Do you have the updated demo site?

Thanks,
Edwin