By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
432,369 Members | 950 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,369 IT Pros & Developers. It's quick & easy.

Gmail - dynamic Add Attachment - Reverse Engineering

P: n/a
I've been trying to imitate / reverse engineer the add attachment
feature in gmail composer. I managed to do it to say about 80% but its
giving me trouble in IE on WinXP-Sp2. I am using PHP to do the upload.
It works well on Firefox/DeerPark, but in IE, the file selected just
vanishes. You can verify it by commenting the lines marked "//IE
Trouble". Commenting those lines will remove IE specific code, except
the el.click() whick sends the Click event to the newly added file
upload input element.
Please someone help me.
_________________________
Here is the code
-------------------------
<?
include_once('../modules/file_*upload/lib_upload.php');
?>

<script language="JavaScript">

function Table_AddRow(tblName, pos)
{
if(typeof(pos) == 'undefined')
pos = '_LAST_';
var tbl = document.getElementById(tblNam*e);
switch(pos)
{
case '_LAST_':
pos = tbl.rows.length;
default:
pos = parseInt(pos, 10);
if(isNaN(pos))
{
pos = 0;
}
else if (pos > tbl.rows.length)
{
pos = tbl.rows.length;
}
}
var today = new Date();
var rowID = tblName + today.getTime() + tbl.rows.length;
var row = tbl.insertRow(pos);
if(document.all) row.style.display = 'none';
//IE Trouble
var cellRight = row.insertCell(row.length);
cellRight.setAttribute('id', rowID);
var el = document.createElement('input'*);
el.setAttribute('type', 'FILE');
el.setAttribute('name', 'upload_files[]');
if(document.all) el.style.display = 'none';
//IE Trouble
cellRight.appendChild(el);
if(document.all)
{
//IE Trouble
el.click();
if(el.value == '')
//IE Trouble
{
//IE Trouble
DeleteCurRow(row);
//IE Trouble
}
//IE Trouble
else
//IE Trouble
{
//IE Trouble
row.style.display = '';
//IE Trouble
var fn = document.createElement("strong*");
//IE Trouble
fn.innerHTML = el.value;
//IE Trouble
cellRight.appendChild(fn);
//IE Trouble
}
//IE Trouble
}
var spc = document.createElement("span")*;
spc.innerHTML = "&nbsp;";
cellRight.appendChild(spc);
var aa = document.createElement("a");
aa.setAttribute('href', 'javascript:;');
var clickName = new
Function("Table_DeleteRowByID(*'"+tblName+"','"+ro wID+"')");
aa.onclick = clickName;
aa.innerHTML = "remove";
cellRight.appendChild(aa);

}
function Table_DeleteRow(x)
{
while (x.tagName.toLowerCase() !='tr')
{
if(x.parentElement)
x=x.parentElement;
else if(x.parentNode)
x=x.parentNode;
else
return;
}
var rowNum=x.rowIndex;
while (x.tagName.toLowerCase() !='table')
{
if(x.parentElement)
x=x.parentElement;
else if(x.parentNode)
x=x.parentNode;
else
return;
}
x.deleteRow(rowNum);
}
function Table_DeleteRowByIndex(tblName*, row)
{
var tbl = document.getElementById(tblNam*e);
x.deleteRow(row);
}
function Table_DeleteRowByID(tblName, rowID)
{
var tbl = document.getElementById(tblNam*e);
var row = document.getElementById(rowID)*;
while (row.tagName.toLowerCase() !='tr')
{
if(row.parentElement)
row = row.parentElement;
else if(row.parentNode)
row = row.parentNode;
else
return;
}
var rowNum = row.rowIndex;
tbl.deleteRow(rowNum);
}
</script>

<form method="post" enctype="multipart/form-data">
<table id="tblSample" border="0" cellspacing="2"
cellpadding="2">
<tr id="tblSample_row0">
<td><a href="javascript:;"
onClick="Table_AddRow('tblSamp*le', 0); return false;">Add
File</a></td>
</tr></table><input type="hidden" name="MAX_FILE_SIZE"
value="512000"><input type=submit>
</form>
<?php
if($REQUEST_METHOD == "POST")
{
$newNames = array();
if(($newFile = UploadFile('upload_files', '.', 1, $newNames,
array('application/x-zip-compr*essed', 'application/zip'))) === false)

{
?><font color=red><b>Upload of <?= sizeof($APP_ERR)?>
file(s) failed.</font><br><strong>Erro*r: </strong><?
print_r($APP_ERR)?><?
}
else
{
?><font color=green><b><?= sizeof($newNames)?> file(s)
uploaded.<br></font>&nbsp;&nbs*p;&nbsp;New filename: <?
print_r($newNames) ?><?
}
}
?>

_________________________
lib_upload.php
-------------------------
sorry for the un-pro coding, one of my
early creations, not well maintained
-------------------------
function UploadFile($name, $path, $mandatory = 0, &$newName,
$mimeAllowed = array())
{
global $APP_ERR;
global $HTTP_POST_FILES;
global $PATH_TRANSLATED;
global $HTTP_POST_VARS;
global $UPLOAD_MAX_FILESIZE;

$UPLOAD_MAX_FILESIZE = get_cfg_var('upload_max_filesize');
$x = substr($UPLOAD_MAX_FILESIZE, -1);
switch($x)
{
case 'T':
$x = 1099511627776;
break;
case 'G':
$x = 1073741824;
break;
case 'M':
$x = 1048576;
break;
case 'K':
$x = 1024;
break;
default:
$x = 1;
break;
}
$UPLOAD_MAX_FILESIZE = intval($UPLOAD_MAX_FILESIZE) * $x;
$scrMaxSize = intval($HTTP_POST_VARS['MAX_FILE_SIZE']);
$UPLOAD_MAX_FILESIZE = $scrMaxSize < $UPLOAD_MAX_FILESIZE?
$scrMaxSize: $UPLOAD_MAX_FILESIZE;
unset($x, $scrMaxSize);

if(isset($name) && isset($path))
{
$APP_ERR = NULL;

set_time_limit(60);
$MimeType = array(
'application/x-drm' => 'dnp',
'image/x-tiff' => 'tif',
'image/x-targa' => 'tga',
'image/x-quicktime' => 'qti',
'image/x-png' => 'png',
'image/x-pict' => 'pic',
'image/pict' => 'pic',
'image/x-macpaint' => 'mac',
'image/x-photoshop' => 'psd',
'image/x-sgi' => 'sgi',
'application/x-rtsp' => 'rts',
'audio/vnd.qcelp' => 'qcp',
'video/flc' => 'flc',
'application/asx' => 'asx',
'audio/x-rmf' => false,
'audio/rmf' => false,
'audio/midi' => 'mid',
'audio/nspaudio' => 'lma',
'audio/x-nspaudio' => 'lma',
'text/xml' => 'xml',
'audio/wav64' => 'w64',
'application/x-cnet-vsl' => 'vsl',
'text/iuls' => 'uls',
'application/x-shockwave-flash' => 'swf',
'application/vnd.ms-pki.stl' => 'stl',
'application/vnd.ms-pki.certstore' => 'sst',
'application/futuresplash' => 'spl',
'application/forge' => 'sfw',
'audio/sfa' => 'sfa',
'audio/x-sd2' => 'sd2',
'text/scriptlet' => false,
'application/vnd.adobe.asset-catalog' => 'sac',
'audio/x-pn-realaudio-plugin' => 'rpm',
'application/rat-file' => 'rat',
'application/pics-rules' => 'prf',
'application/vnd.ms-pki.pko' => 'pko',
'audio/pca' => 'pca',
'application/pkcs7-signature' => 'p7s',
'application/x-pkcs7-certreqresp' => 'p7r',
'application/pkcs7-mime' => 'p7m',
'application/x-pkcs7-certificates' => 'p7b',
'application/x-pkcs12' => 'p12',
'application/pkcs10' => 'p10',
'audio/ogg' => 'ogg',
'application/x-mmxp' => 'mxp',
'audio/mid' => 'mid',
'application/msaccess' => 'mdb',
'application/x-troff-man' => 'man',
'image/pjpeg' => 'jfif',
'application/x-iphone' => 'iii',
'image/x-icon' => 'ico',
'Icon Library' => 'icl',
'text/webviewhtml' => 'htt',
'text/x-component' => 'htc',
'application/hta' => 'hta',
'application/vnd.fdf' => 'fdf',
'message/rfc822' => 'eml',
'video/x-dv' => 'dv',
'application/x-speedbit-daf' => 'daf',
'application/x-ctm' => 'ctm',
'text/css' => 'css',
'application/pkix-crl' => 'crl',
'application/x-x509-ca-cert' => 'cer',
'application/x-cdf' => 'cdf',
'application/vnd.ms-pki.seccat' => 'cat',
'image/bmp' => false,
'text/h323' => '323',
'application/x-vpeg005' => 'vpg',
'application/vnd.rn-realsystem-rjt' => 'rjt',
'audio/blue-matter-song' => 'bmt',
'text/blue-matter-content-ref' => 'bmr',
'audio/blue-matter-offer' => 'bmo',
'audio/x-liquid-file' => 'la1',
'application/x-laplayer-reg' => 'lar',
'audio/x-liquid-secure' => 'lavs',
'audio/x-la-lqt' => 'lqt',
'audio/x-la-lms' => 'lmsff',
'audio/x-mei-aac' => 'acp',
'text/vnd.rn-realtext3d' => 'r3t',
'audio/x-pn-aiff' => 'aif',
'audio/x-pn-au' => 'au',
'audio/x-pn-windows-pcm' => 'wav',
'audio/x-pn-windows-acm' => 'wav',
'audio/x-pn-wav' => 'wav',
'audio/wav' => 'wav',
'application/vnd.rn-realsystem-rmj' => 'rmj',
'application/vnd.rn-realmedia-vbr' => 'rmvb',
'video/vnd.rn-realvideo-secure' => 'rms',
'audio/x-realaudio-secure' => 'rms',
'application/vnd.rn-realaudio-secure' => 'rms',
'application/vnd.rn-realmedia-secure' => 'rms',
'audio/x-musicnet-download' => 'mnd',
'audio/x-musicnet-stream' => 'mns',
'application/vnd.rn-realsystem-rom' => 'rom',
'application/vnd.rn-realsystem-r1m' => 'r1m',
'video/x-mpg' => 'mpa',
'audio/mp2' => 'mp2',
'audio/mp1' => 'mp1',
'video/mpg' => 'mpg',
'audio/rn-mpeg' => 'mpga',
'audio/mpeg' => 'mpga',
'application/x-sdp' => 'sdp',
'application/sdp' => 'sdp',
'image/vnd.rn-realpix' => 'rp',
'text/vnd.rn-realtext' => 'rt',
'image/vnd.rn-realflash' => 'rf',
'video/vnd.rn-realvideo' => 'rv',
'application/vnd.rn-realmedia' => 'rm',
'audio/x-realaudio' => 'ra',
'audio/vnd.rn-realaudio' => 'ra',
'application/vnd.rn-realsystem-rjs' => 'rjs',
'application/vnd.rn-realsystem-rmx' => 'rmx',
'application/vnd.rn-rn_music_package' => 'rmp',
'application/vnd.rn-realplayer' => 'rnx',
'application/vnd.rn-rsml' => 'rsml',
'application/streamingmedia' => 'ssm',
'application/smil' => 'smi',
'audio/mpegurl' => 'm3u',
'audio/mpg' => 'mpg',
'audio/mp3' => 'mp3',
'audio/x-mpg' => 'mpg',
'audio/x-mp3' => 'mp3',
'audio/scpls' => 'pls',
'audio/x-scpls' => 'pls',
'video/x-ms-wvx' => 'wvx',
'video/x-ms-wmv' => 'wmv',
'video/x-ms-wm' => 'wm',
'video/x-ms-asf' => false,
'video/x-mpeg2a' => 'mp2',
'video/x-mpeg' => 'mpe',
'video/x-ivf' => 'ivf',
'video/msvideo' => 'avi',
'video/avi' => 'avi',
'midi/mid' => 'mid',
'audio/x-ms-wma' => 'wma',
'audio/x-ms-wax' => 'wax',
'audio/x-mpegurl' => 'm3u',
'audio/x-midi' => 'mid',
'application/pps' => 'pps',
'application/pot' => 'pot',
'application/ppt' => 'ppt',
'application/xlc' => 'xlc',
'application/msexcel' => 'xls',
'audio/aiff' => 'aif',
'application/x-compress' => 'z',
'application/wordperfect5.1' => 'wpd',
'application/vnd.lotus-screencam' => 'scm',
'application/vnd.lotus-organizer' => 'org',
'application/vnd.lotus-freelance' => 'pre',
'application/vnd.lotus-wordpro' => 'lwp',
'application/vnd.ms-schedule' => 'sch',
'application/vnd.ms-powerpoint' => false,
'application/vnd.ms-access' => false,
'application/vnd.ms-excel' => false,
'application/msword' => 'doc',
'application/x-pkcs7-crl' => 'crl',
'application/pre-encrypted' => 'enc',
'application/x-pkcs7-signature' => 'p7s',
'application/x-pkcs7-mime' => 'p7m',
'application/x-javascript-config' => 'jsc',
'application/x-ns-proxy-autoconfig' => 'pac',
'application/x-javascript' => 'js',
'application/x-perl' => 'pl',
'application/x-tcl' => 'tcl',
'application/x-sh' => 'sh',
'application/x-csh' => 'csh',
'application/postscript' => false,
'application/octet-stream' => false,
'application/java-archive' => 'jar',
'application/x-cpio' => 'cpio',
'application/x-gtar' => 'gtar',
'application/x-tar' => 'tar',
'application/x-shar' => 'shar',
'application/x-zip-compressed' => 'zip',
'application/x-stuffit' => 'sit',
'application/mac-binhex40' => 'hqx',
'video/x-msvideo' => 'avi',
'video/quicktime' => false,
'video/x-mpeg2' => 'mpv2',
'video/mpeg' => 'mpg',
'audio/x-pn-realaudio' => 'ram',
'audio/x-mpeg' => 'mpga',
'audio/x-wav' => 'wav',
'audio/x-aiff' => 'aif',
'audio/basic' => 'snd',
'application/fractals' => 'fif',
'image/ief' => 'ief',
'image/png' => 'png',
'image/x-photo-cd' => 'pcd',
'image/x-MS-bmp' => 'bmp',
'image/x-rgb' => 'rgb',
'image/x-portable-pixmap' => 'ppm',
'image/x-portable-graymap' => 'pgm',
'image/x-portable-bitmap' => 'pbm',
'image/x-portable-anymap' => 'pnm',
'image/x-xwindowdump' => 'xwd',
'image/x-xpixmap' => 'xpm',
'image/x-xbitmap' => 'xbm',
'image/x-cmu-raster' => 'ras',
'image/tiff' => 'tif',
'image/jpeg' => 'jpg',
'image/gif' => 'gif',
'text/x-vcard' => 'vcf',
'application/x-texinfo' => 'texinfo',
'application/x-dvi' => 'dvi',
'application/x-latex' => 'latex',
'application/x-tex' => 'tex',
'application/pdf' => 'pdf',
'application/rtf' => 'rtf',
'application/zip' => 'zip',
'text/html' => 'htm',
'text/plain' => 'txt'
);

if(substr($path, 0, 1) != '/')
$path = dirname($PATH_TRANSLATED).'/'.$path;
$path .= substr($path, -1) != '/'? '/': '';

list($usec, $sec) = explode(' ', microtime());
list(, $usec) = explode('.', $usec);
$fnBase = $sec.$usec;

$errStat = count($APP_ERR);
for($i = 0; $i < sizeof($HTTP_POST_FILES[$name]['name']); $i++)
{
if(empty($HTTP_POST_FILES[$name]['name'][$i]))
{
if(is_array($mandatory) && $mandatory[$i])
$APP_ERR[$i] = 'File was not uploaded.';
}

if((sizeof($mimeAllowed) > 0) &&
!in_array($HTTP_POST_FILES[$name]['type'][$i], $mimeAllowed))
{
$APP_ERR[$i] = 'File type not allowed.';
}

if(!empty($HTTP_POST_FILES[$name]['name'][$i]) &&
isset($MimeType[$HTTP_POST_FILES[$name]['type'][$i]]))
{
if(!isset($newName[$i])) $newName[$i] = "$fnBase$i";

if(false === strrchr($newName[$i], '.'))
{
$newName[$i] .= '.';
$newName[$i] .= $MimeType[$HTTP_POST_FILES[$name]['type'][$i]] ===
false
? substr($HTTP_POST_FILES[$name]['name'][$i],
strrpos($HTTP_POST_FILES[$name]['name'][$i], '.'))
: $MimeType[$HTTP_POST_FILES[$name]['type'][$i]];
}
continue;
}
else
{
$APP_ERR[$i] = 'Unknown file type.';
}
unset($newName[$i]);
}

if($errStat == count($APP_ERR) && (!is_array($mandatory) &&
$mandatory === count($newName)))
{
for($i = 0; $i < sizeof($HTTP_POST_FILES[$name]['name']); $i++)
{
if(false ===
move_uploaded_file($HTTP_POST_FILES[$name]['tmp_name'][$i],
$path.$newName[$i]))
{
$APP_ERR[$i] = true;
unset($newName[$i]);
continue;
}
}
}

return sizeof($APP_ERR) > 0 ? false: $newName;
}
}

Aug 3 '05 #1
Share this Question
Share on Google+
7 Replies


P: n/a
JavaScriptRocks wrote:
I've been trying to imitate / reverse engineer the add attachment
feature in gmail composer. I managed to do it to say about 80% but its
giving me trouble in IE on WinXP-Sp2. I am using PHP to do the upload.
It works well on Firefox/DeerPark, but in IE, the file selected just
vanishes. You can verify it by commenting the lines marked "//IE
Trouble". Commenting those lines will remove IE specific code, except
the el.click() whick sends the Click event to the newly added file
upload input element.
Please someone help me.
_________________________
Here is the code
-------------------------
<?
include_once('../modules/file_*upload/lib_upload.php');
?>

<script language="JavaScript">
language is depreciated, type is required.

function Table_AddRow(tblName, pos)
{
if(typeof(pos) == 'undefined')
pos = '_LAST_';
var tbl = document.getElementById(tblNam*e);
switch(pos)
{
case '_LAST_':
pos = tbl.rows.length;
default:
pos = parseInt(pos, 10);
if(isNaN(pos))
{
pos = 0;
}
else if (pos > tbl.rows.length)
{
pos = tbl.rows.length;
}
}
That appears to be an inordinate amount of code just to check 'pos'.
Given that you pass 'pos' from your own code, how about:

function Table_AddRow(tblName, pos) {
var tbl = document.getElementById(tblNam*e);
var rlen = tbl.length;
if ( pos > rlen || pos < 0 ) pos = -1;

If 'pos' is not a valid index to the table, it will be set to -1 so that
the new row will be appended as the last row (which is what I think
your code is doing). I would also guess that any feature testing for
getElementById) is done up front before the rest of the script is attempted.

var today = new Date();
var rowID = tblName + today.getTime() + tbl.rows.length;

var row = tbl.insertRow(pos);
if(document.all) row.style.display = 'none';
//IE Trouble
What is the point of testing document.all? If you want to see if the
style object is supported, test that:

if ( row.style) row.style.display = 'none';

It would also be better to do it once and deal with it once.
var cellRight = row.insertCell(row.length);
cellRight.setAttribute('id', rowID);
Simpler to access the cell attributes directly. And since you know that
the row has a length of zero (you just created it):

var cellRight = row.insertCell(0);
cellRight.id = rowID;

Which makes me think 'rowID' should be 'cellID'.


var el = document.createElement('input'*);
el.setAttribute('type', 'FILE');
el.setAttribute('name', 'upload_files[]');
accessing attribute directly is simpler:

el.type = 'file';
el.name = 'upload_files[]';
if(document.all) el.style.display = 'none';
//IE Trouble
cellRight.appendChild(el);

if(document.all)
{
//IE Trouble
el.click();
el is type 'file', which does not have a 'click' method:

<URL:http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-2651361>
if(el.value == '')
//IE Trouble
{
//IE Trouble
DeleteCurRow(row);
Where is 'DeleteCurRow' defined?
//IE Trouble
}
//IE Trouble
else
//IE Trouble
{
//IE Trouble
row.style.display = '';
//IE Trouble
var fn = document.createElement("strong*");
//IE Trouble
fn.innerHTML = el.value;
//IE Trouble
cellRight.appendChild(fn);
Mixing of DOM methods with innerHTML can be unreliable - it is likely
better to use one or the other. Since tables are involved, say stick to
DOM:

fn.appendChild(document.createTextNode( el.value ));
cellRight.appendChild(fn);
//IE Trouble
}
//IE Trouble
}
var spc = document.createElement("span")*;
spc.innerHTML = "&nbsp;";
Same here:

spc.appendChild(document.createTextNode('\u00A0')) ;

where \u00A0 will insert a non-breaking space.
cellRight.appendChild(spc);
var aa = document.createElement("a");
aa.setAttribute('href', 'javascript:;');
var clickName = new
Function("Table_DeleteRowByID(*'"+tblName+"','"+ro wID+"')");
aa.onclick = clickName;
You start using the javascript pseudo protocol in the HREF attribute
then use an onclick. Why use an 'a' element at all? Why not a span
with an onclick or an input button?

You may also be having issues with closures here with references to
tblName and rowID (I didn't test it but it seems likely).

You could use (see below):

aa.onclick = function() { Table_DeleteRowByID( rowID ); }

Provided the issue with closure is dealt with.
aa.innerHTML = "remove";
aa.appendChild(document.createTextNode('remove'));
cellRight.appendChild(aa);
}
function Table_DeleteRow(x)
{
while (x.tagName.toLowerCase() !='tr')
{
if(x.parentElement)
x=x.parentElement;
else if(x.parentNode)
x=x.parentNode;
else
return;
More efficient:
while ( x.parentNode && 'tr' != x.nodeName.toLowerCase() ) {
x = x.parentNode;
}
}
var rowNum=x.rowIndex;
while (x.tagName.toLowerCase() !='table')
{
if(x.parentElement)
x=x.parentElement;
else if(x.parentNode)
x=x.parentNode;
else
return;
}
x.deleteRow(rowNum);

All of the above can be replaced with:

if ( 'tr' == x.nodeName.toLowerCase() ) {
x.parentNode.removeChild( x );
}

But this function is not used anyway.

}
function Table_DeleteRowByIndex(tblName*, row)
{
var tbl = document.getElementById(tblNam*e);
x.deleteRow(row);
}
Does not appear to be used.


function Table_DeleteRowByID(tblName, rowID)
{
var tbl = document.getElementById(tblNam*e);
var row = document.getElementById(rowID)*;
while (row.tagName.toLowerCase() !='tr')
{
if(row.parentElement)
row = row.parentElement;
else if(row.parentNode)
row = row.parentNode;
else
return;
}
var rowNum = row.rowIndex;
tbl.deleteRow(rowNum);
}
Presuming you want to delete the row with a particular ID, then the
above can be replaced with:

function Table_DeleteRowByID( rowID ) {
var row = document.getElementById( rowID );
if ( row ) row.parentNode.removeChild( row );
}

Which can be used as a generic method to delete any element with an id:

function deleteElementById( elID ) {
var el = document.getElementById( elID );
if ( el ) el.parentNode.removeChild( el );
}



</script>

[...]
--
Rob
Aug 4 '05 #2

P: n/a
Thanks for the reply.

I am actually a beginner in JavaScript DOM scripting. Was putting
together some scripts found on internet and making them to work in the
way I want (my way of expanding my knowledge of JavaScript).

After reading your reply, I feel that I have failed to convey my aim in
my posting. I am actually trying to mimic the gmail's attachment GUi
element. If you look at it, in IE, it doesnt show the actual browse
button, instead it just shows the file name that you have added, along
with a remove link. I wanted to mimic it exactly. Thats why I had to
put those if(document.all) checkings.

I need some time to put together the changes that you have suggested
and will post the resulting code.
RobG wrote:
JavaScriptRocks wrote:
I've been trying to imitate / reverse engineer the add attachment
feature in gmail composer. I managed to do it to say about 80% but its
giving me trouble in IE on WinXP-Sp2. I am using PHP to do the upload.
It works well on Firefox/DeerPark, but in IE, the file selected just
vanishes. You can verify it by commenting the lines marked "//IE
Trouble". Commenting those lines will remove IE specific code, except
the el.click() whick sends the Click event to the newly added file
upload input element.
Please someone help me.
_________________________
Here is the code
-------------------------
<?
include_once('../modules/file_*upload/lib_upload.php');
?>

<script language="JavaScript">


language is depreciated, type is required.

function Table_AddRow(tblName, pos)
{
if(typeof(pos) == 'undefined')
pos = '_LAST_';
var tbl = document.getElementById(tblNam*e);
switch(pos)
{
case '_LAST_':
pos = tbl.rows.length;
default:
pos = parseInt(pos, 10);
if(isNaN(pos))
{
pos = 0;
}
else if (pos > tbl.rows.length)
{
pos = tbl.rows.length;
}
}


That appears to be an inordinate amount of code just to check 'pos'.
Given that you pass 'pos' from your own code, how about:

function Table_AddRow(tblName, pos) {
var tbl = document.getElementById(tblNam*e);
var rlen = tbl.length;
if ( pos > rlen || pos < 0 ) pos = -1;

If 'pos' is not a valid index to the table, it will be set to -1 so that
the new row will be appended as the last row (which is what I think
your code is doing). I would also guess that any feature testing for
getElementById) is done up front before the rest of the script is attempted.

var today = new Date();
var rowID = tblName + today.getTime() + tbl.rows.length;

var row = tbl.insertRow(pos);
if(document.all) row.style.display = 'none';
//IE Trouble


What is the point of testing document.all? If you want to see if the
style object is supported, test that:

if ( row.style) row.style.display = 'none';

It would also be better to do it once and deal with it once.
var cellRight = row.insertCell(row.length);
cellRight.setAttribute('id', rowID);


Simpler to access the cell attributes directly. And since you know that
the row has a length of zero (you just created it):

var cellRight = row.insertCell(0);
cellRight.id = rowID;

Which makes me think 'rowID' should be 'cellID'.


var el = document.createElement('input'*);
el.setAttribute('type', 'FILE');
el.setAttribute('name', 'upload_files[]');


accessing attribute directly is simpler:

el.type = 'file';
el.name = 'upload_files[]';
if(document.all) el.style.display = 'none';
//IE Trouble
cellRight.appendChild(el);

if(document.all)
{
//IE Trouble
el.click();


el is type 'file', which does not have a 'click' method:

<URL:http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-2651361>
if(el.value == '')
//IE Trouble
{
//IE Trouble
DeleteCurRow(row);


Where is 'DeleteCurRow' defined?
//IE Trouble
}
//IE Trouble
else
//IE Trouble
{
//IE Trouble
row.style.display = '';
//IE Trouble
var fn = document.createElement("strong*");
//IE Trouble
fn.innerHTML = el.value;
//IE Trouble
cellRight.appendChild(fn);


Mixing of DOM methods with innerHTML can be unreliable - it is likely
better to use one or the other. Since tables are involved, say stick to
DOM:

fn.appendChild(document.createTextNode( el.value ));
cellRight.appendChild(fn);
//IE Trouble
}
//IE Trouble
}
var spc = document.createElement("span")*;
spc.innerHTML = "&nbsp;";


Same here:

spc.appendChild(document.createTextNode('\u00A0')) ;

where \u00A0 will insert a non-breaking space.
cellRight.appendChild(spc);
var aa = document.createElement("a");
aa.setAttribute('href', 'javascript:;');
var clickName = new
Function("Table_DeleteRowByID(*'"+tblName+"','"+ro wID+"')");
aa.onclick = clickName;


You start using the javascript pseudo protocol in the HREF attribute
then use an onclick. Why use an 'a' element at all? Why not a span
with an onclick or an input button?

You may also be having issues with closures here with references to
tblName and rowID (I didn't test it but it seems likely).

You could use (see below):

aa.onclick = function() { Table_DeleteRowByID( rowID ); }

Provided the issue with closure is dealt with.
aa.innerHTML = "remove";


aa.appendChild(document.createTextNode('remove'));
cellRight.appendChild(aa);
}
function Table_DeleteRow(x)
{
while (x.tagName.toLowerCase() !='tr')
{
if(x.parentElement)
x=x.parentElement;
else if(x.parentNode)
x=x.parentNode;
else
return;


More efficient:
while ( x.parentNode && 'tr' != x.nodeName.toLowerCase() ) {
x = x.parentNode;
}
}
var rowNum=x.rowIndex;
while (x.tagName.toLowerCase() !='table')
{
if(x.parentElement)
x=x.parentElement;
else if(x.parentNode)
x=x.parentNode;
else
return;
}
x.deleteRow(rowNum);


All of the above can be replaced with:

if ( 'tr' == x.nodeName.toLowerCase() ) {
x.parentNode.removeChild( x );
}

But this function is not used anyway.

}
function Table_DeleteRowByIndex(tblName*, row)
{
var tbl = document.getElementById(tblNam*e);
x.deleteRow(row);
}


Does not appear to be used.


function Table_DeleteRowByID(tblName, rowID)
{
var tbl = document.getElementById(tblNam*e);
var row = document.getElementById(rowID)*;
while (row.tagName.toLowerCase() !='tr')
{
if(row.parentElement)
row = row.parentElement;
else if(row.parentNode)
row = row.parentNode;
else
return;
}
var rowNum = row.rowIndex;
tbl.deleteRow(rowNum);
}


Presuming you want to delete the row with a particular ID, then the
above can be replaced with:

function Table_DeleteRowByID( rowID ) {
var row = document.getElementById( rowID );
if ( row ) row.parentNode.removeChild( row );
}

Which can be used as a generic method to delete any element with an id:

function deleteElementById( elID ) {
var el = document.getElementById( elID );
if ( el ) el.parentNode.removeChild( el );
}



</script>

[...]


--
Rob


Aug 4 '05 #3

P: n/a
Many Thanks RobG

I have updated the code with your suggestions.
But its still not working the way I want it to.

As you had said,
el is type 'file', which does not have a 'click' method:


but how Gmail does it??!! Thats what I want.
Here in this case, it accepts the click() event but it acts funny.

__________________________________________

<?
include_once('lib_upload.php');
?>
<SCRIPT type="text/javascript">

function DynUploads_Add(tblName, pos)
{
var tbl = document.getElementById(tblName);
var rowLen = tbl.rows.length;

pos = parseInt(pos, 10);
pos = (pos >= 0 || pos < rowLen)? pos: pos = -1;

var today = new Date();
var uploadID = tblName + today.getTime() + tbl.rows.length;

var row = tbl.insertRow(pos);
// cosmetic: specific to IE - Hide row till user selects a file
if(document.all) row.style.display = 'none';

var cellRight = row.insertCell(row.length);
cellRight.id = uploadID;

var el = document.createElement('input');
el.type = 'FILE';
el.name = 'upload_files[]';
// cosmetic: specific to IE - Hide control for ever, Gmail style
if(document.all) el.style.display = 'none';

cellRight.appendChild(el);

// cosmetic: specific to IE
// Instead of the text box and Browse button of the upload form
element
// hide the form element and show its value.
if(document.all)
{
el.click();
if(el.value == '')
{
DeleteCurRow(row);
}
else
{
row.style.display = '';
var fn = document.createElement("strong");
fn.appendChild(document.createTextNode( el.value ));
cellRight.appendChild(fn);
}
}

// cosmetic: just for space
cellRight.appendChild(document.createTextNode('\u0 0A0'));

var aa = document.createElement("a");
aa.href = 'javascript:;';
aa.onclick = function() { DynUploads_DeleteByID(tblName, uploadID); };
aa.appendChild(document.createTextNode('remove'));
cellRight.appendChild(aa);
}

function DynUploads_Delete(x)
{
while ( x.parentNode && 'tr' != x.nodeName.toLowerCase() ) {
x = x.parentNode;
}

if ( 'tr' == x.nodeName.toLowerCase() ) {
x.parentNode.removeChild( x );
}
}

function DynUploads_DeleteByIndex(tblName, row)
{
var tbl = document.getElementById(tblName);
x.deleteRow(row);
}

function DynUploads_DeleteByID(tblName, uploadID)
{
var row = document.getElementById(uploadID);
if(row) row.parentNode.removeChild(row);
}

</script>

<form method="post" enctype="multipart/form-data">
<table id="tblSample" border="0" cellspacing="2" cellpadding="2">
<tr id="tblSample_row0">
<td><a href="javascript:;" onClick="DynUploads_Add('tblSample', 1);
return false;">Add File</a></td>
</tr></table><input type="hidden" name="MAX_FILE_SIZE"
value="512000"><input type=submit>
</form>

Aug 7 '05 #4

P: 2
Actually the code to reproduce Gmail's dynamic file attachment forms is a lot easier than you're making it out to be. I have just recently made a very small example of the code required to generate all the necessary elements. :)

try this - A working example and sourcecode.
Aug 10 '05 #5

P: 1
Great contribution, Gavin. I've been itchin' to reverse-engineer Gmail add attachment script, but ran across this forum first :).

There is a sligt error in your script, though. When you remove a file input from your div tags, you decrement the form_count variable and then check to see if it equals 0 to change the more link to show the appropriate text:

Expand|Select|Wrap|Line Numbers
  1. //remove file attachment form and associated elements
  2. function remove(remove_form_num)
  3. {
  4.     //decrease the form count
  5.     form_count--;
  6.  
  7.     //remove < input > element attachment
  8.     document.getElementById('content').removeChild(document.getElementById('child_attachment_' + remove_form_num));
  9.     //remove < span > element text
  10.     document.getElementById('content').removeChild(document.getElementById('child_attachment_text_' + remove_form_num));
  11.     //remove < img > element image
  12.     document.getElementById('content').removeChild(document.getElementById('child_attachment_img_' + remove_form_num));
  13.  
  14.     //if all forms are removed, change text back to "Attach a file"
  15.     if (form_count == 0)
  16.     {
  17.                document.getElementById('more').innerHTML = 'Attach a file';
  18.     }
  19. }
This gets you into a little bind if you remove any element other than the last one, because if you do, you end up with two input boxes with the same name! If you look at gmails code, they use an always incremented value for their input names. So a better way to do it is to check if "content" has any children with the "hasChildNodes" method:

Expand|Select|Wrap|Line Numbers
  1. //remove file attachment form and associated elements
  2. function remove(remove_form_num)
  3. {
  4.     //remove < input > element attachment
  5.     document.getElementById('content').removeChild(document.getElementById('child_attachment_' + remove_form_num));
  6.     //remove < span > element text
  7.     document.getElementById('content').removeChild(document.getElementById('child_attachment_text_' + remove_form_num));
  8.     //remove < img > element image
  9.     document.getElementById('content').removeChild(document.getElementById('child_attachment_img_' + remove_form_num));
  10.  
  11.     //if all forms are removed, change text back to "Attach a file"
  12.     if (document.getElementById('content').hasChildNodes)
  13.     {
  14.                document.getElementById('more').innerHTML = 'Attach a file';
  15.     }
  16. }
--Jon
-----------
http://witmatix.com
-----------


Actually the code to reproduce Gmail's dynamic file attachment forms is a lot easier than you're making it out to be. I have just recently made a very small example of the code required to generate all the necessary elements. :)

try this - A working example and sourcecode.
Aug 17 '05 #6

P: 2
I'm having trouble getting this to work. For some reason PHP is not seeing the newly created form elements upon POST. To test I print out the $_POST Array to see what elements posted. Before you freakout and say, type=file are a part of the files array, I know so I've also added a text box for a description of the file. Here is my function:
Expand|Select|Wrap|Line Numbers
  1. function addVideo(form){
  2.   currentVids = parseInt(form.addVids.value);
  3.   var new_attachment = document.createElement('input');
  4.   var new_description = document.createElement('input');
  5.   var ln_break = document.createElement('br');
  6.   new_description.setAttribute('id', 'addVid' + currentVids+ 'Description');
  7.   new_description.setAttribute('type', 'text');
  8.   new_description.setAttribute('size', '32');
  9.   new_attachment.setAttribute('id', 'addVid' + currentVids);
  10.   new_attachment.setAttribute('type', 'file');
  11.   document.getElementById('addVids').appendChild(ln_break);
  12.   document.getElementById('addVids').appendChild(new_description);
  13.   document.getElementById('addVids').appendChild(ln_break);
  14.   document.getElementById('addVids').appendChild(new_attachment);
  15.   form.addVids.value = currentVids + 1;
  16. }
I'm a little confused about this, and a little irritated, if anyone can help me figure out why the descriptions aren't being appended to the post array it would be greatly appreciated.
Aug 31 '05 #7

P: 2
I realized my mistake, I forgot to add the name attribute to the elements. :D
Sep 2 '05 #8

This discussion thread is closed

Replies have been disabled for this discussion.