4月24日
Debugging Gadgets can be a little frustrating, not only whilst coding; but also when trying to get useful feedback from users who've reported issues.
The simplest way to achieve this, is to log debug entries out to a file. In the example below, we check to see if "debug.txt" exists in the Gadget folder and if it does write debugging information to it.
The first step is to see if the file exists and open it. In the following code, we create a BOOLEAN variable "bDebug" which we can use later to output more detailed information, beyond simply errors:
var bDebug = oFSO.FileExists(gadgetPath+"\\debug.txt");
try{
if (bDebug)
var debugLogFile = oFSO.OpenTextFile(gadgetPath+"\\debug.txt", 2);
} catch(err) {bDebug = false; debugLog("Open debug.txt error: "+err.name+" - "+err.message)}
//log a debug entry
function debugLog(str) {
try{
System.Debug.outputString(str);
if (bDebug) debugLogFile.WriteLine(str);
} catch(err) {}
}
It's good practice to get into the habit of wrapping all your functions in a try/catch loop, to prevent Runtime errors from popping up:
try{
// your code
} catch (err) {debugLog(err.name+ " - "+err.message)}
It's also a good idea to put in tracking information, so you know where you are in the code. For example:
if(bDebug) debugLog("Register ActiveX");
if(bDebug) debugLog(" trying HKCU");
if (!activateXDLL("HKCU")) {
if(bDebug) debugLog(" trying HKLM");
if (!activateDLL("HKLM"))
debugLog("Error creating ActiveX object");
}
To enable "debug mode", simply create a blank text file in your Gadget folder called "debug.txt".
Personally, I put this code into all Gadgets and leave "debug.txt" out of the Gadget package. When a user reports an issue, I ask them to create the file and eMail it back to me once they've reproduced the problem.
Whilst your developing your code, I'd also advise running Microsoft's Debug View; which will allow you to watch all debug entries as they occur.
In a future article, I'll detail how to write out debugging information from VB and C++ ActiveX DLL's.
Allowing drag/drop
First, you need to set up the HTML events to allow drag/drop. By default they're disabled, so you need to allow them. You do this by cancelling two drag events on the <BODY> tag:
<BODY
ondragenter="java script:event.returnValue = false"
ondragover="java script:event.returnValue = false"
>
The next thing you need to do, is set up a function to handle the drag/drop action. This is also done on the <BODY> tag with the ondrop event. In this example, the function is fileDragDropped(), so your final <BODY> tag should be:
<BODY
ondragenter="java script:event.returnValue = false"
ondragover="java script:event.returnValue = false"
ondrop="fileDragDropped"
>
Handling File drag/drop from Explorer
Files are passed through event.dataTransfer as an object with a collection of items inside. To extract each entry you need to use System.Shell.itemFromFileDrop(<object>, <n>). To avoid errors, you need to loop whilst the object is not null.
function fileDragDropped() {
var sFile;
for (var i=0; System.Shell.itemFromFileDrop(event.dataTransfer, i) != null; i++)
{
// get the file name and path
sFile = System.Shell.itemFromFileDrop(event.dataTransfer, i).path;
// do something with sFile
}
}
Trapping for certain file types
In most cases, you'll want to handle only certain file types. So you need to check the file extension and ignore files that are not supported. The best way to do this is through a string that contains all your supported extensions, you then check if the file extension is in that string. supportedFileTypes contains all your extensions padded with a space either side, to stop it catching truncated extensions (eg ".doc" but not ".document"). In this example, we're checking for .doc, .xls and .ppt files:
var supportedFileTypes = " .doc .xls .ppt ";
function fileDragDropped() {
var sFile, sFiletype;
for (var i=0; System.Shell.itemFromFileDrop(event.dataTransfer, i) != null; i++)
{
// get the file name and path
sFile = System.Shell.itemFromFileDrop(event.dataTransfer, i).path;
// get the extension
sFiletype = " " + sFile.substring(sFile.lastIndexOf(".")).toLowerCase() + " ";
if (supportedFileTypes.indexOf(sFiletype) > -1) {
// do something with sFile
}
}
}
Handling URL drag/drop from Internet Explorer
Internet Explorer passes information slightly differently, URL's are passed as text, so you need to change the code slightly to handle these. The URL you end up with is a string and to ensure we don't pick up files being drag/dropped, we need to check if that string is null:
function fileDragDropped() {
var url = event.dataTransfer.getData("text");
if (url != null) {
// do something with the url
}
}
Putting it all together
Combining both IE and file/drag drop together, your final function will be:
var supportedFileTypes = " .doc .xls .ppt ";
function fileDragDropped() {
var sFile, sFiletype;
// is it a URL from IE?
var url = event.dataTransfer.getData("text");
if (url != null) {
// do something with the url
} else {
for (var i=0; System.Shell.itemFromFileDrop(event.dataTransfer, i) != null; i++)
{
// get the file name and path
sFile = System.Shell.itemFromFileDrop(event.dataTransfer, i).path;
// get the extension
sFiletype = " " + sFile.substring(sFile.lastIndexOf(".")).toLowerCase() + " ";
// is the extension supported
if (supportedFileTypes.indexOf(sFiletype) > -1) {
//do something with sFile
}
}
}
}