<package>
<job id="Phonebook">
<script language="JScript" src="usage.js"/>
<script id="UsageDemo" language="JScript">
// Core functions
function main()
{
init();
var args = WScript.Arguments;
if (args.length < 1)
{
myWSH.ShowUsage();
WScript.Quit();
}
switch (args(0))
{
case "-A" :
case "-a" :
if (args.length < 3)
{
myWSH.ValError(
"Adding to the phonebook requires both a name and a phone number.");
WScript.Quit();
}
WScript.Echo(args(1) + " has been added to your phonebook");
break;
case "-D" :
case "-d" :
if (args.length < 2)
{
myWSH.ValError("Deleting from the phonebook requires a name.");
WScript.Quit();
}
WScript.Echo(args(1) + " has been deleted from your phonebook");
break;
case "-L" :
case "-l" :
WScript.Echo("Phone: " + genPhone());
break;
case "-h" :
case "-H" :
case "/h" :
case "\\h":
case "-?" :
case "/?" :
case "\\?":
case "?" :
myWSH.ShowUsage();
break;
}
}
function init()
{
myWSH.AddParameter(ptFlag, "-H", "Show this message and quit", true, 1, 1);
myWSH.AddParameter(ptFlag, "-A", "Adds a Name", false, 2, 2);
myWSH.AddParameter(ptString, "name", "The name to process", true, 2, 5);
myWSH.AddParameter(ptPhoneNum, "num", "The phone number", true, 2, 6);
myWSH.AddParameter(ptFlag, "-D", "Deletes a Name", false, 3, 3);
myWSH.AddParameter(ptFlag, "-L", "Looks up a Name (default)", false, 3, 4);
myWSH.AddParameter(ptString, "name", "The name to process", true, 3, 5);
myWSH.fConsoleRequired = false;
myWSH.strUsageDefault = "-H";
myWSH.Validate();
}
function genPhone()
{
var str = "";
for (var i = 0; i < 12; i++)
{
if (3 == i || 7 == i)
{
str += "-";
}
else
if (0 == i || 4 == i)
{
str += new String(Math.floor(Math.random() * 8) + 2);
// First nums shouldn't be 0 or 1
}
else
{
str += new String(Math.floor(Math.random() * 10));
}
}
return str;
}
// Let's run this puppy!
main();
</script>
</job>
</package>
Figure 2 Handling Standard Streams
<package>
<job id="js">
<script language="JScript" src="menus.js"/>
<script language="JScript" src="..\Example 1\usage.js"/>
<script language="JScript">
// Declare globals
var MainMenu;
var AddMenu;
var DelMenu;
var LookupMenu;
var dataObj;
// Core functions
function main()
{
init();
MainMenu.Activate();
}
function init()
{
myWSH.fConsoleRequired = true;
myWSH.Validate();
init_MainMenu();
init_AddMenu();
init_DelMenu();
init_LookupMenu();
dataObj = new DataObj();
}
// Create the menus
function init_AddMenu()
{
AddMenu = new Menu("Add a Name",
"Phonebook",
AddMenuInit,
"Items marked with a * are required but not completed");
AddMenu.AddItem("N", "Enter the name", AddMenuGetName);
AddMenu.AddItem("P", "Enter the phone number", getPhone);
AddMenu.AddItem("A", "Enter the street address", getAddress);
AddMenu.AddItem("C", "Enter the city", getCity);
AddMenu.AddItem("S", "Enter the state", getState);
AddMenu.AddItem("Z", "Enter the zip code", getZip);
AddMenu.AddItem("Q", "Quit and Save data", AddMenuSaveData);
AddMenu.AddItem("X", "Cancel (Data will not be saved)", cancel);
}
function init_DelMenu()
{
DelMenu = new Menu("Delete a Name", "Phonebook");
DelMenu.AddItem("N", "Enter a name to delete", DelMenuGetName);
DelMenu.AddItem("Q", "Quit to Main Menu", cancel);
}
function init_LookupMenu()
{
LookupMenu = new Menu("Lookup a Name", "Phonebook");
LookupMenu.AddItem("N", "Enter a name to lookup", LookupMenuGetName);
LookupMenu.AddItem("Q", "Quit to Main Menu", cancel);
}
function init_MainMenu()
{
MainMenu = new Menu("Main Menu", "Phonebook");
MainMenu.AddItem("A", "Add a Name", DoAddMenu);
MainMenu.AddItem("D", "Delete a Name", DoDelMenu);
MainMenu.AddItem("L", "Lookup a Name", DoLookupMenu);
MainMenu.AddItem("Q", "Quit Phonebook", cancel);
}
// AddMenu Specific functions
function AddMenuInit()
{
AddMenu.MarkItem("N");
AddMenu.MarkItem("P");
}
function AddMenuGetName()
{
dataObj.name = getInput("Enter the name: ");
if (dataObj.name != "")
{
return "unmark";
}
return "mark";
}
function AddMenuSaveData()
{
if (AddMenu.MarkedItems())
{
WScript.StdOut.WriteLine("There are still required fields that are blank");
return true;
}
WScript.StdOut.WriteLine(dataObj.name + " has been added to the phonebook.");
return false;
}
// DelMenu Specific functions
function DelMenuGetName()
{
dataObj.name = getInput("Enter the name: ");
if (dataObj.name != "")
{
WScript.StdOut.WriteLine(dataObj.name + " has been removed from the phonebook");
}
return true;
}
// LookupMenu Specific functions
function LookupMenuGetName()
{
dataObj.name = getInput("Enter the name: ");
if (dataObj.name != "")
{
WScript.StdOut.WriteLine(dataObj.name + "'s phone number is " + genPhone());
}
return true;
}
// MainMenu Specific functions
// Note: By calling these here, rather than doing direct calls to the Activate
// functions, we can safely create the menus in any order. We also gain local
// control if we quit out of the Main Menu or not - something we need.
function DoAddMenu()
{
AddMenu.Activate();
return true;
}
function DoDelMenu()
{
DelMenu.Activate();
return true;
}
function DoLookupMenu()
{
LookupMenu.Activate();
return true;
}
// General Menu Functions
function getPhone()
{
dataObj.phone = getInput("Enter the phone number: ");
if (dataObj.phone != "")
{
return "unmark";
}
return "mark";
}
function getAddress()
{
dataObj.address = getInput("Enter the street address: ");
}
function getCity()
{
dataObj.city = getInput("Enter the city: ");
}
function getState()
{
dataObj.state = getInput("Enter the state: ");
}
function getZip()
{
dataObj.zip = getInput("Enter the zip code: ");
}
function cancel()
{
return false;
}
// Data
// Data Handler
function DataObj()
{
this.name = "";
this.phone = "";
this.address = "";
this.city = "";
this.state = "";
this.zip = "";
}
// Utilities
function getInput(prompt, val)
{
var notdone = true;
var data;
while (notdone)
{
WScript.StdOut.WriteLine();
WScript.StdOut.Write(prompt);
data = WScript.StdIn.ReadLine();
if (null != val)
{
if (val(data))
{
notdone = false;
}
else
{
WScript.StdOut.WriteLine("Error - Invalid Data");
WScript.StdOut.Write("Try again? (Y/N) > ");
var yn = WScript.StdIn.Read();
if (yn.toUpperCase() == "N")
{
data = "";
notdone = false;
}
}
}
else
{
notdone = false;
}
}
return data;
}
function genPhone()
{
var str = "";
for (var i = 0; i < 12; i++)
{
if (3 == i || 7 == i)
{
str += "-";
}
else
if (0 == i || 4 == i)
{
// First nums shouldn't be 0 or 1
str += new String(Math.floor(Math.random() * 8) + 2);
}
else
{
str += new String(Math.floor(Math.random() * 10));
}
}
return str;
}
// Let's run this puppy!
main();
</script>
</job>
</package>
Figure 3 Phonebook with GUI
<?XML version="1.0"?>
<package>
<job id="js">
<comment>
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Program: PhoneBook3
Author : Michael Whalen
Date : August 27, 1999
This is the PhoneBook3 Example, written for Microsoft Internet
Developer Magazine. There are two other examples written for the
same article, but they are not as complete as this one. This example
contains primitive data handling methods, a simple entry form and
it demonstrates more of the XML syntax needed for WSF files.
An even more complete implementation of this program would use a
more flexible database system - an XML text file, for instance.
However, for the sake of simplicity, this code uses a simple text
file with hardcoded data positions.
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
</comment>
<comment>****** FILE NAMES ******</comment>
<resource id="sDataFileName">phonebook3.dat</resource>
<resource id="sHTMLFileName">phonebook3.htm</resource>
<comment>****** ERROR MESSAGES ******</comment>
<resource id="errMissingName">You must enter a name</resource>
<resource id="errMissingPhone">You must enter a phone number</resource>
<resource id="errMissingAddress">You must enter an address</resource>
<resource id="errMissingCity">You must enter a city</resource>
<resource id="errMissingState">You must enter a state</resource>
<resource id="errMissingZip">You must enter a zip code</resource>
<resource id="errInvalidStateLen">State field should be 2 letters long</resource>
<resource id="errInvalidZipLen">Zip code should be 5 numbers long</resource>
<comment>****** TITLES ******</comment>
<resource id="ttlMain">Enter data now</resource>
<resource id="ttlStored">Data stored</resource>
<resource id="ttlCleared">Data cleared</resource>
<resource id="ttlRestored">Data has been restored</resource>
<resource id="ttlRecordNum">Record number </resource>
<resource id="ttlNewRecord">New record added at end of list</resource>
<resource id="ttlDelRecord">Record deleted</resource>
<resource id="ttlErrDirty">Error: Data has changed - Accept or Cancel changes first</resource>
<resource id="ttlErrInvalid">Invalid data entered - </resource>
<comment>****** MISC ******</comment>
<resource id="defColor">Blue.... No! Yellaaaaaaaaaaaaaaaaaaaaaaa</resource>
<script language="JScript">
<![CDATA[
// Declare Globals
var fso, ie, doc, keep_going;
var data;
var rootdir;
var errmessage;
var datafile;
var htmlfile;
// Core Functions
function main()
{
init();
ie.Navigate(rootdir + htmlfile);
while (keep_going)
{
WScript.Sleep(100);
}
}
function init()
{
fso = WScript.CreateObject("Scripting.FileSystemObject");
ie = WScript.CreateObject("InternetExplorer.Application", "ie_");
// Initialize our form
ie.AddressBar = false;
ie.FullScreen = false;
ie.MenuBar = false;
ie.Resizable = false;
ie.StatusBar = false;
ie.ToolBar = false;
// Set the size
ie.Height = 270;
ie.Width = 780;
// Get file paths
rootdir = WScript.ScriptFullName;
rootdir = rootdir.substring(0, rootdir.lastIndexOf("\\") + 1);
datafile = getResource("sDataFileName");
htmlfile = getResource("sHTMLFileName");
// Don't stop
keep_going = true;
}
// Data Object
function DataObj(fin)
{
this.name = "";
this.phone = "";
this.address = "";
this.city = "";
this.state = "";
this.zip = "";
this.color = "";
if (null != fin)
{
this.LoadData(fin);
}
}
function DataObj_Validate()
{
// All fields are required - make sure they're all there first
// We're gonna fudge on the color though....
if ("" == this.name){
errormsg = getResource("errMissingName");
return false;
}
if ("" == this.phone){
errormsg = getResource("errMissingPhone");
return false;
}
if ("" == this.address){
errormsg = getResource("errMissingAddress");
return false;
}
if ("" == this.city){
errormsg = getResource("errMissingCity");
return false;
}
if ("" == this.state){
errormsg = getResource("errMissingState");
return false;
}
if ("" == this.zip){
errormsg = getResource("errMissingZip");
return false;
}
if ("" == this.color){
this.color = getResource("defColor");
}
// Okay... the fields are there... now let's check validity.
// State should be two letters
if (2 != this.state.length)
{
// If we want to get fancier, we probably should check that it's actually
// a legal state code.
errormsg = getResource("errInvalidStateLen");
return false;
}
// Zip should be 5 characters
if (5 != this.zip.length)
{
// If we want to get fancier, we could cross check this with the state and
// city, or even fill them in based on the zip...
// we'd need a database of zip codes, of course
errormsg = getResource("errInvalidZipLen");
return false;
}
// Everything we care about is good, let's return true
return true;
}
DataObj.prototype.Validate = DataObj_Validate;
function DataObj_LoadData(fin)
{
var InputString = fin.ReadLine();
var InputArray = InputString.split(";");
this.name = InputArray[0].UnEncode();
this.phone = InputArray[1].UnEncode();
this.address = InputArray[2].UnEncode();
this.city = InputArray[3].UnEncode();
this.state = InputArray[4].UnEncode();
this.zip = InputArray[5].UnEncode();
this.color = InputArray[6].UnEncode();
}
DataObj.prototype.LoadData = DataObj_LoadData;
function DataObj_StoreData(fout)
{
var OutputArray = new Array(
this.name.Encode(),
this.phone.Encode(),
this.address.Encode(),
this.city.Encode(),
this.state.Encode(),
this.zip.Encode(),
this.color.Encode());
var OutputString = OutputArray.join(";");
fout.WriteLine(OutputString);
}
DataObj.prototype.StoreData = DataObj_StoreData;
function DataObj_LoadDialog()
{
// Copy from dialog
doc.all.txtName.value = this.name;
doc.all.txtPhone.value = this.phone;
doc.all.txtAddr.value = this.address;
doc.all.txtCity.value = this.city;
doc.all.txtState.value = this.state;
doc.all.txtZip.value = this.zip;
doc.all.txtColor.value = this.color;
}
DataObj.prototype.LoadDialog = DataObj_LoadDialog;
function DataObj_StoreDialog()
{
// Store the old values
var old = new DataObj();
old.Copy(this);
// Copy from dialog
this.name = doc.all.txtName.value;
this.phone = doc.all.txtPhone.value;
this.address = doc.all.txtAddr.value;
this.city = doc.all.txtCity.value;
this.state = doc.all.txtState.value;
this.zip = doc.all.txtZip.value;
this.color = doc.all.txtColor.value;
// Are they good?
if (!this.Validate())
{
// Bad data - restore data and return
this.Copy(old);
return false;
}
return true;
}
DataObj.prototype.StoreDialog = DataObj_StoreDialog;
function DataObj_Copy(from)
{
this.name = from.name;
this.phone = from.phone;
this.address = from.address;
this.city = from.city;
this.state = from.state;
this.zip = from.zip;
this.color = from.color;
}
DataObj.prototype.Copy = DataObj_Copy;
// Data Handler Object
function DataHandler()
{
this.Data = new Array();
this.CurRecord = 0;
this.Dirty = false;
}
function DataHandler_ReadData()
{
if (!fso.FileExists(rootdir + datafile))
return;
var fin = fso.OpenTextFile(rootdir + datafile);
while (!fin.AtEndOfStream)
{
this.Data[this.Data.length] = new DataObj(fin);
}
fin.Close();
}
DataHandler.prototype.ReadData = DataHandler_ReadData;
function DataHandler_SaveData()
{
var fout = fso.OpenTextFile(rootdir + datafile, 2);
for (var i = 0; i < this.Data.length; i++)
{
this.Data[i].StoreData(fout);
}
fout.Close();
}
DataHandler.prototype.SaveData = DataHandler_SaveData;
function DataHandler_LoadDialog()
{
this.Data[this.CurRecord].LoadDialog();
}
DataHandler.prototype.LoadDialog = DataHandler_LoadDialog;
function DataHandler_StoreDialog()
{
if (this.Data[this.CurRecord].StoreDialog())
{
this.Dirty = false;
return true;
}
return false;
}
DataHandler.prototype.StoreDialog = DataHandler_StoreDialog;
function DataHandler_NextRecord()
{
if (this.CurRecord < this.Data.length - 1)
{
this.CurRecord++;
}
}
DataHandler.prototype.NextRecord = DataHandler_NextRecord;
function DataHandler_PreviousRecord()
{
if (this.CurRecord > 0)
{
this.CurRecord--;
}
}
DataHandler.prototype.PreviousRecord = DataHandler_PreviousRecord;
function DataHandler_FirstRecord()
{
this.CurRecord = 0;
}
DataHandler.prototype.FirstRecord = DataHandler_FirstRecord;
function DataHandler_FinalRecord()
{
this.CurRecord = this.Data.length - 1;
}
DataHandler.prototype.FinalRecord = DataHandler_FinalRecord;
function DataHandler_NewRecord()
{
this.Data[this.Data.length] = new DataObj();
this.FinalRecord();
}
DataHandler.prototype.NewRecord = DataHandler_NewRecord;
function DataHandler_DelRecord()
{
if (1 == this.Data.length)
{
// Clear the data
var obj = this.Data[0];
obj.name = "";
obj.phone = "";
obj.addr = "";
obj.city = "";
obj.state = "";
obj.zip = "";
obj.color = "";
obj.LoadDialog();
return;
}
if (this.CurRecord == this.Data.length - 1)
{
// Simple amputation
this.Data.length--;
this.CurRecord--;
return;
}
for (var i = this.CurRecord; i < this.Data.length - 1; i++)
{
this.Data[i].Copy(this.Data[i + 1]);
}
this.Data.length--;
}
DataHandler.prototype.DelRecord = DataHandler_DelRecord;
// IE Events
function ie_DocumentComplete()
{
// Let's create some data, shall we?
data = new DataHandler();
data.ReadData();
// Set up the document - title, events, etc.
doc = ie.Document;
doc.title = getResource("ttlMain");
// Button Events
doc.all.btnAccept.onclick = btnAccept_OnClick;
doc.all.btnClear.onclick = btnClear_OnClick;
doc.all.btnCancel.onclick = btnCancel_OnClick;
doc.all.btnFirst.onclick = btnFirst_OnClick;
doc.all.btnPrevious.onclick = btnPrevious_OnClick;
doc.all.btnNew.onclick = btnNew_OnClick;
doc.all.btnDelete.onclick = btnDelete_OnClick;
doc.all.btnNext.onclick = btnNext_OnClick;
doc.all.btnFinal.onclick = btnFinal_OnClick;
// Text Box Events
doc.all.txtName.onchange = txtBoxOnChange;
doc.all.txtPhone.onchange = txtBoxOnChange;
doc.all.txtAddr.onchange = txtBoxOnChange;
doc.all.txtState.onchange = txtBoxOnChange;
doc.all.txtCity.onchange = txtBoxOnChange;
doc.all.txtZip.onchange = txtBoxOnChange;
doc.all.txtColor.onchange = txtBoxOnChange;
// What if there's no data?
if (data.Data.length < 1)
{
data.AddRecord();
}
data.CurRecord = 0;
data.LoadDialog();
// Show the world our creation
ie.Visible = true;
}
function ie_OnQuit()
{
keep_going = false;
data.SaveData();
}
// Button Events
function btnAccept_OnClick()
{
if (!data.StoreDialog())
{
doc.title = getResource("ttlErrInvalid") + errormsg;
}
else
{
doc.title = getResource("ttlStored");
}
}
function btnClear_OnClick()
{
// Clear the dialog
doc.all.txtName.value = "";
doc.all.txtPhone.value = "";
doc.all.txtAddr.value = "";
doc.all.txtCity.value = "";
doc.all.txtState.value = "";
doc.all.txtZip.value = "";
doc.all.txtColor.value = "";
doc.title = "Data Cleared";
}
function btnCancel_OnClick()
{
data.LoadDialog();
doc.title = getResource("ttlRestored");
}
function btnFirst_OnClick()
{
if (data.Dirty)
{
doc.title = getResource("ttlErrDirty");
return;
}
data.FirstRecord();
data.LoadDialog();
doc.title = getResource("ttlRecordNum") + (data.CurRecord + 1);
}
function btnPrevious_OnClick()
{
if (data.Dirty)
{
doc.title = getResource("ttlErrDirty");
return;
}
data.PreviousRecord();
data.LoadDialog();
doc.title = getResource("ttlRecordNum") + (data.CurRecord + 1);
}
function btnNew_OnClick()
{
if (data.Dirty)
{
doc.title = getResource("ttlErrDirty");
return;
}
data.NewRecord();
data.LoadDialog();
doc.title = getResource("ttlNewRecord");
}
function btnDelete_OnClick()
{
data.DelRecord();
data.LoadDialog();
doc.title = getResource("ttlDelRecord");
}
function btnNext_OnClick()
{
if (data.Dirty)
{
doc.title = getResource("ttlErrDirty");
return;
}
data.NextRecord();
data.LoadDialog();
doc.title = getResource("ttlRecordNum") + (data.CurRecord + 1);
}
function btnFinal_OnClick()
{
if (data.Dirty)
{
doc.title = getResource("ttlErrDirty");
return;
}
data.FinalRecord();
data.LoadDialog();
doc.title = getResource("ttlRecordNum") + (data.CurRecord + 1);
}
// Text Box Events
function txtBoxOnChange()
{
data.Dirty = true;
doc.title = getResource("ttlMain");
}
// String Extensions
function String_Encode()
{
return this.replace(new RegExp("#","g"), "#0").replace(new
RegExp(";","g"),
"#1");
}
String.prototype.Encode = String_Encode;
function String_UnEncode()
{
return this.replace(new RegExp("#1","g"), ";").replace(new
RegExp("#0","g"), "#");
}
String.prototype.UnEncode = String_UnEncode;
// Let's run this puppy!
main();
]]>
</script> </job> </package>
Figure 4 Scripting Internet Explorer
Events
|
Description
|
BeforeNavigate2
|
This fires before the WebBrowser is about to navigate to a new site. If you have a page with links, you can use this event to validate the data before the next page loads, even canceling the load if the data doesn’t pass.
|
DocumentComplete
|
Fires when the page is fully loaded and displayed. At this point, it’s safe to modify the page.
|
DownloadBegin
|
If you have a complicated page that takes a while to load, throw up a progress dialog when this event fires.
|
DownloadComplete
|
Kill that progress dialog from the DownloadBegin event.
|
OnQuit
|
The browser quit, so the dialog is finished. Get your script moving again.
|
Methods |
Description
|
Navigate
|
Directs the browser to a page. This is a basic command that you’ll need every time.
|
Stop
|
Stops everything without quitting. Good for progress dialogs when the main page finishes faster than expected.
|
Quit
|
Stops everything and quits. Good for getting out of the program when the user cancels the operation.
|
Properties
|
Description
|
Height, Width
|
Control the size of the dialog.
|
Top, Left
|
Control the placement of the dialog.
|
Visible
|
The browser control is initially invisible by default. You’ll need this property to show your work.
|
AddressBar, MenuBar, StatusBar, ToolBar
|
These aren’t needed by most dialogs, but the status bar can be useful.
|
FullScreen
|
For those really big forms.
|
Resizable
|
For those really big forms that want to stay big, or the really small ones that want to stay small.
|