Hi Matteo,
Teo wrote: -
I would like to sort the elements of a <SELECT> element.
Later RobG wrote: -
Because the NodeList interface doesn't implement it, a HTML collection
isn't a javascript Array. Your function should include loading the
options into an array first, then sort them and finally re-position
them in the collection.
I never new that; but it makes me feel better. I had previously (see below)
had to unload an options collection into an array to sort it, purely (or so
I thought at the time) to get around the problem of my having a "header" row
at option[0]. The fact that the exercise had to be undertaken regardless is
strangely comforting.
Anyway, FWIW there is an example of just such select-list-sorting below. If
you look at the jobList SELECT list you'll see that the onclick event calls
the showDetails() function. If the selectedIndex is zero (they clicked on
the "header" row) then I first check that there's more than one row to sort
and then I pop-up a <div> to ask them what key (select list column) to sort
on. (Could this be done with x/y pixel co-ords for the click?) I then unload
the options[] collection (except for element [0]) into a JavaScript array
and sort it before loading it back into the select-list. (FYI If they
clicked on a row other than the "header" I drill-down into a details
screen/frame)
Hope it helps 'cos (at least to me) it sounds relevant to what you're trying
to do. (Sorry to reproduce the whole thing so soon after posting it to
another question but cut/pasting would take some time and then I'd probably
miss out a bit, or it wouldn't make sense out of context. Either way it's
diskspace not trees so just don't print it all
Cheers Richard Maher
PS. The code also contains RobG's suggestion (or my dodgy implementation of
it
of using node-cloning to speed up performance when tearing down a
select-list before repopulating it. Thanks again Rob.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"
http://www.w3.org/TR/html4/loose.dtd">
<html>
<meta name="author" content="Richard Maher"/>
<meta name="description" content="VMS Queue lookup example"/>
<meta http-equiv="Page-Enter"
content="revealtrans(duration=1.5,transition=13)"/>
<head>
<style>
body
{
color: Black;
background-color: White;
font-family: Times;
font-size: 16px;
font-weight: normal;
font-style: normal;
margin-left: 5px;
margin-right: 5px;
text-align: left;
}
select#jobList option
{
white-space: pre;
}
select#queList option
{
white-space: pre;
}
.header
{
color: Turquoise;
font-size: 22px;
font-weight: bold;
}
.credits
{
color: Turquoise;
font-family: Georgia;
}
.waiting
{
width: 100%;
text-align: right;
font-family: Georgia;
font-size: 150%;
font-weight: bold;
}
.greenScreen
{
color: Lime;
background-color: Black;
font-family: Fixed-Width, Monospace;
white-space: pre;
}
.revLeft
{
background-color: AliceBlue;
color: Black;
font-family: Fixed-Width, Monospace;
font-weight: normal;
font-size: 14px;
text-align: left;
}
.revRight
{
background-color: AliceBlue;
color: Black;
font-family: Fixed-Width, Monospace;
font-weight: normal;
font-size: 14px;
text-align: right;
}
.floater
{
position: absolute;
z-index: 1000;
visibility: hidden;
left: 83px;
top: 123px;
padding: 0px;
font-family: Fixed-Width, Monospace;
font-weight: normal;
font-size: 14px;
}
.sortPanel
{
background-color: AliceBlue;
color: blue;
border: thin ridge blue;
position: absolute;
z-index: 1000;
visibility: hidden;
left: 455px;
top: 242px;
width: 115px;
height: 170px;
margin: 5px;
padding: 0px;
}
.sortHead
{
text-align: center;
color: Black;
font-size: 16px;
font-weight: bold;
}
.options
{
font-family: Fixed-Width, Monospace;
font-weight: normal;
font-size: 14px;
background-color: AliceBlue;
color: Black;
white-space: pre;
}
</style>
<script type="text/javascript" src="common.js"></script>
<script type="text/javascript">
function msgField(name, offset, length)
{
this.name = name;
this.offset = offset;
this.length = length;
}
var field = new Array(5);
field[0] = new msgField("entryNumber", 0, 10);
field[1] = new msgField("jobName" , 11, 39);
field[2] = new msgField("jobStatus" , 51, 15);
field[3] = new msgField("queName" , 67, 31);
field[4] = new msgField("queType" , 99, 10);
field[5] = new msgField("queStatus" , 110, 10);
var msgGetInfo = "10";
var jobInfo = "11";
var msgQueName = "40";
var jobByQue = "60";
var queName = "41";
var eofInfo = "99";
var eofLen = 3;
var jobMsgLen = 115;
var queNameLen = 31;
var msgQue = "";
var lastMsgQue = "";
var spaceFill = " ";
var zeroFill = "0000000000";
var maxRows = "00000"; //Unlimited
var maxReadTime = 10000;
var waitInterval = 700;
var sortKey = 0;
var sortIndex = 0;
var optIndex = 0;
var strA = "";
var strB = "";
var alertMsg = "Error retrieving job entry information:\n";
var timeoutMsg = "Request timeout has expired.<br />" +
"Increase the timeout value if server is under load."
var rc;
var outPad;
var ok;
var msgEntry;
var intId;
var abortBackColor;
var sendBackColor;
var abortValue;
var cancelCount;
var closureType;
var target;
var waitCount;
var waitColors;
var waitText;
var bytesIn;
var queList;
var quePopUp;
var eventTarget;
var radioTarget;
var labelTarget;
var labels;
var labelIndex;
var sortBy;
var exitSort;
var selectClone;
var swapClone;
var evt;
var keyCode;
function load()
{
selectRef = document.getJobs.jobList;
selectClone = selectRef.cloneNode(true);
queList = document.queOptions.queList;
waitColors = new Array("blue","lime","yellow","orange","red");
waitText = document.getElementById("stallMsg");
quePopUp = document.getElementById("queInfo");
labels = document.getElementsByTagName("label");
sortBy = document.getElementById("sortBy");
exitSort = document.getElementById("r7");
try
{
chan = parent.cornucopiae.chan;
chan.setTimeout(maxReadTime);
document.getJobs.queName.focus();
}
catch(err)
{
return false;
}
}
function lockDown()
{
document.getJobs.send.disabled=true;
sendBackColor = document.getJobs.send.style.backgroundColor;
document.getJobs.send.style.backgroundColor="Silver";
document.getJobs.send.blur();
document.getJobs.queName.disabled=true;
document.getJobs.entryNumber.disabled=true;
document.getJobs.jobList.disabled=true;
abortValue=document.getJobs.reqAbort.value;
abortBackColor = document.getJobs.reqAbort.style.backgroundColor;
document.getJobs.reqAbort.style.backgroundColor="Red";
document.getJobs.reqAbort.disabled=false;
cancelCount = zeros;
return true;
}
function openUp()
{
document.getJobs.reqAbort.disabled=true;
document.getJobs.reqAbort.style.backgroundColor=abortBackColor;
document.getJobs.reqAbort.value=abortValue;
document.getJobs.send.style.backgroundColor=sendBackColor;
document.getJobs.send.disabled=false;
document.getJobs.queName.disabled=false;
document.getJobs.entryNumber.disabled=false;
if (selectRef.options.length > 1)
document.getJobs.jobList.disabled=false;
document.getJobs.queName.focus();
return true;
}
function sendOOB(OOBchar)
{
if (document.getJobs.reqAbort.disabled)
{
alert("Request already complete.");
return;
}
cancelCount++
chan.sendUrgentData(OOBchar);
document.getJobs.reqAbort.value="Aborts Sent " + String(cancelCount);
document.getJobs.reqAbort.blur();
return;
}
function enter(nextfield,e)
{
evt = e || window.event;
try
{
target = evt.srcElement.name;
}
catch (err)
{
target = evt.target.name;
}
if (evt.type == "keypress")
{
keyCode = evt.which || evt.keyCode;
if ((keyCode == 8) ||
(keyCode == 9) ||
(keyCode == 45) ||
(keyCode == 46) ||
(keyCode == 37) ||
(keyCode == 39))
return true;
else
if (keyCode == 13)
{
nextfield.focus();
return false;
}
else
{
if ((target == "entryNumber") &&
(keyCode < 48 || keyCode > 57))
return false;
else
return true;
}
}
}
function selectQue()
{
if ((queList.selectedIndex >= queList.length) ||
(queList.selectedIndex == -1))
{
document.getJobs.queName.focus();
return true;
}
document.getJobs.queName.value =
queList.options[queList.selectedIndex].text.rTrim();
document.getJobs.send.focus();
return true;
}
function queLookup()
{
msgQue = document.getJobs.queName.value.toUpperCase();
if (msgQue == lastMsgQue)
return true;
lastMsgQue = msgQue;
quePopUp.style.visibility="hidden";
if (msgQue.rTrim() == "")
return true;
queList.size = 2;
queList.length = zeros;
outPad = spaceFill.substring(0, (spaceFill.length - msgQue.length));
chan.sendMessage(msgQueName.concat(msgQue,outPad));
recType = recvAndGet(recTypeLen);
if (!recType)
return;
while (recType == queName)
{
if (chan.readMessage(queNameLen) == queNameLen)
msgQue = chan.getString(0,queNameLen);
else
return true;
queList.options[queList.length] = new Option (msgQue, msgQue);
recType = recvAndGet(recTypeLen);
}
if (recType == errorInfo)
{
if (chan.readMessage() < errLenLen)
reportError("Error receiving Error Length from server");
return true;
}
if (recType != eofInfo)
{
reportError("Invalid recType " + recType + " received from
server");
return true;
}
if (queList.length == zeros)
return true;
if (queList.length == 1 && lastMsgQue.rTrim() == msgQue.rTrim())
return true;
if (queList.length > 2)
if (queList.length < 7)
queList.size=queList.length;
else
queList.size=7;
queList.selectedIndex = -1;
quePopUp.style.visibility="visible";
return true;
}
function jobLookup()
{
msgQue = document.getJobs.queName.value.toUpperCase();
msgEntry = document.getJobs.entryNumber.value;
if (msgEntry.length > zeros && parseInt(msgEntry,10) == zeros)
msgEntry = "";
if (msgEntry.length != zeros && msgQue.rTrim() != "")
{
alert("Please enter a Queue Name or a Job Entry Number, but not
both.");
return true;
}
lockDown();
document.getJobs.recCount.value = 0;
outPad = "";
ok = true;
msgEntry = "";
selectRef.size = 1;
swapClone = selectClone.cloneNode(true);
selectRef.parentNode.replaceChild(swapClone, selectRef);
selectRef = document.getJobs.jobList;
if (msgQue.rTrim() == "")
{
msgEntry = document.getJobs.entryNumber.value;
outPad = zeroFill.substring(0, (zeroFill.length -
msgEntry.length));
chan.sendMessage(msgGetInfo.concat(outPad,msgEntry,maxRows));
}
else
{
outPad = spaceFill.substring(0, (spaceFill.length -
msgQue.length));
chan.sendMessage(jobByQue.concat(msgQue,outPad));
}
waitCount = 0
chan.setTimeout(waitInterval);
dclAST("getResponse()");
return true;
}
function getResponse()
{
bytesIn = chan.readMessage(recTypeLen);
if (bytesIn == 0)
{
if (waitCount == waitColors.length)
{
reportError(timeoutMsg);
return;
}
else
{
if (waitText.innerHTML == "")
{
waitText.style.color = waitColors[waitCount];
waitText.innerHTML = "Waiting. . .";
waitCount++
}
else
{
waitText.innerHTML = "";
}
dclAST("getResponse()");
return;
}
}
if (bytesIn != recTypeLen)
{
reportError("Error receiving reply from server 1");
return;
}
waitText.innerHTML = "";
chan.setTimeout(maxReadTime);
recType = chan.getString(0,recTypeLen);
if (recType == jobInfo)
{
rc = 1;
dclAST("processJobs()");
}
else
{
if (recType == errorInfo)
{
dclAST("processError()");
}
else
{
reportError("Unknown message type " + recType);
return;
}
}
return;
}
function processError()
{
if (chan.readMessage() < errLenLen)
{
reportError("Error receiving Error Length from server");
return;
}
errMsgLen = parseInt(chan.getString(0,errLenLen),10);
alert(alertMsg + chan.getString(errLenLen,errMsgLen));
openUp();
return;
}
function processJobs()
{
if (chan.readMessage(jobMsgLen) != jobMsgLen)
{
alert ("Error receiving Job Information from server");
return;
}
if (cancelCount == zeros)
{
document.getJobs.recCount.value = rc;
jobMsg = chan.getString(0,10) + "|" +
chan.getString(10,39) + "|" +
chan.getString(49,15) + "|" +
chan.getString(64,31) + "|" +
chan.getString(95,10) + "|" +
chan.getString(105,10);
selectRef.options[selectRef.options.length] = new Option (jobMsg,
jobMsg);
rc++;
if (rc < 6)
selectRef.size = rc;
}
if (chan.readMessage(recTypeLen) != recTypeLen)
{
reportError("Error receiving reply from server 2");
return;
}
recType = chan.getString(0,recTypeLen);
if (recType == jobInfo)
{
dclAST("processJobs()");
return;
}
if (selectRef.length != 1)
selectRef.selectedIndex = -1;
openUp();
if (recType != eofInfo)
{
reportError("Error receiving reply from server 3");
return;
}
if (chan.readMessage(eofLen) != eofLen)
{
reportError("Error receiving reply from server 4");
return;
}
closureType = chan.getString(0,eofLen);
if (closureType == "CAN" || cancelCount != zeros)
alert("Request curtailed\nby operator.");
else
if (closureType != "EOF")
reportError("Error receiving reply from server 5");
return;
}
function showDetails()
{
if (selectRef.selectedIndex == zeros)
{
selectRef.options[zeros].selected=false;
selectRef.selectedIndex = -1;
if(selectRef.length < 3)
alert("Nothing to Sort.")
else
{
sortBy.style.visibility="visible";
exitSort.checked=true;
exitSort.focus();
}
return false;
}
parent.entry_details.getReady();
parent.document.getElementById("main").rows="30px,0px,*";
return true;
}
function menuMove(e)
{
evt = e || window.event;
eventTarget = eventTarget=evt.srcElement || evt.currentTarget;
if (eventTarget.type == "radio")
{
radioTarget = eventTarget;
for (labelIndex = 0; labelIndex < labels.length; labelIndex++)
if (labels[labelIndex].htmlFor == radioTarget.id)
{
labelTarget=labels[labelIndex];
break;
}
}
else
{
labelTarget = eventTarget;
radioTarget = document.getElementById(labelTarget.htmlFor)
}
if (evt.type == "mouseover")
{
labelTarget.style.color = "turquoise";
radioTarget.checked = true;
}
if (evt.type == "mouseout")
labelTarget.style.color = "blue";
return true;
}
function sortIt(keyField)
{
var sortScratch = new Array();
sortScratch.length = selectRef.length - 1;
for (sortIndex=0; sortIndex<sortScratch.length; sortIndex++)
sortScratch[sortIndex] = selectRef.options[sortIndex + 1].value;
sortKey = keyField;
sortScratch.sort(colCompare);
optIndex = 1;
for (sortIndex in sortScratch)
{
selectRef.options[optIndex].value = sortScratch[sortIndex];
selectRef.options[optIndex].text = sortScratch[sortIndex];
optIndex++;
}
return;
}
function colCompare(a,b)
{
strA =
a.substr(field[sortKey].offset,field[sortKey].length).toUpperCase();
strB =
b.substr(field[sortKey].offset,field[sortKey].length).toUpperCase();
if (strA < strB)
return -1;
if (strA > strB)
return 1;
return zeros;
}
function hideQues()
{
if (quePopUp.style.visibility != "hidden")
quePopUp.style.visibility="hidden";
return;
}
</script>
</head>
<body onload="load()">
<br /><span class="header">Example Client for Tier3 DEMO Application
Server on VMS<br /></span>
<br /><hr><br />
<form name="getJobs">
<div style="font-size: 14px">
Queue Name:
<input
type="text"
class="revLeft"
style="text-transform: uppercase"
onkeypress="return enter(document.getJobs.entryNumber, event)"
onkeyup="return queLookup()"
name="queName"
maxlength=31
size=31
title="Enter the Queue Name [Wildcards '*' and '%' are
permitted]"
/>
Job Entry Number:
<input
type="text"
class="revRight"
onfocus="hideQues();"
onkeypress="return enter(document.getJobs.send, event)"
name="entryNumber"
maxlength=10
size=10
dir="rtl"
title="Enter the Job Entry Number [Default is All My Jobs]"
/>
<input
type="button"
style="background-color:Turquoise; color:Black;"
onfocus="hideQues();"
onclick="jobLookup()"
name="send"
value="Get Job Info."
title="Get results from Tier3 Server"
/>
Jobs Found:
<input
type="text"
class="revRight"
name="recCount"
readonly="readonly"
value="0"
size=5
title="Number of matching jobs found in last request"
/>
<input
type="button"
onclick="sendOOB(33);"
name="reqAbort"
value="Abort Request"
disabled="disabled"
title="Send an Abort request to the server"
/>
<br /><br />
</div>
<div style="height:90px; font-size: 14px;">
<select
name="jobList"
id="jobList"
disabled="disabled"
onfocus="hideQues();"
onclick="return showDetails()"
class="greenScreen">
<option
id="lovHdr"
style="color:Black; background-color:Turquoise;"
Entry Nbr-|Job Name-------------------------------|Job
Status-----|Queue Name---------------------|Queue Type|Status----</o
ption>
</select>
</div>
</form>
<div style="overflow:auto; height:180px;"><p>
This is an example of a browser-based, html and JavaScript,
client interacting with a VMS hosted Application Server in
a connection-oriented and context-rich Tier3 environment.<br /><br />
You would have noticed that, when this page was initially displayed,
you were immediately prompted for your VMS Username and Password.
Once authorization is successful your credentials, and an accompanying
Persona, are automatically made available to your 3GL User Action
Routines each time their Server Process is chosen to perform work on
behalf of the client. In this example, the user only gets to see those
Print and Batch jobs that they have privileges to view. You can find
the corresponding server code for this example (demo_uars.cob) in your
t3$examples directory.<br /><br />
Your Tier3 session and server connection are terminated when you change
web pages or refresh this page.</p></div>
<hr><br />
<span class="credits">
"Tier3" is a registered trademark of Tier3 Software Ltd<br />
"CornuCopiae" is a trademark of Richard Maher<br /></span>
<div class="waiting" id="stallMsg"></div>
<div
id="queInfo"
class="floater"
style="visibility: hidden"<form name="queOptions">
<select name="queList" class="options" onclick="return
selectQue()"></select>
</form>
</div>
<div
id="sortBy"
class="sortPanel"<form
name="sortMenu"
style="font-size: 14px; margin-bottom: 0px;"<div class="sortHead">Sort By</div>
<input
type="radio"
name="sortKey"
id="r1"
class="sortButton"
onmouseover="menuMove(event)"
onmouseout ="menuMove(event)"
onmousedown="sortIt(0)"
/>
<label for="r1"
onmouseover="menuMove(event)"
onmouseout="menuMove(event)"
onmousedown="sortIt(0)"
Entry Number</label><br />
<input
type="radio"
name="sortKey"
id="r2"
class="sortButton"
onmouseover="menuMove(event)"
onmouseout="menuMove(event)"
onmousedown="sortIt(1)"
/>
<label for="r2"
onmouseover="menuMove(event)"
onmouseout="menuMove(event)"
onmousedown="sortIt(1)"
<input
type="radio"
name="sortKey"
id="r3"
class="sortButton"
onmouseover="menuMove(event)"
onmouseout="menuMove(event)"
onmousedown="sortIt(2)"
/>
<label for="r3"
onmouseover="menuMove(event)"
onmouseout="menuMove(event)"
onmousedown="sortIt(2)"
<input
type="radio"
name="sortKey"
id="r4"
class="sortButton"
onmouseover="menuMove(event)"
onmouseout="menuMove(event)"
onmousedown="sortIt(3)"
/>
<label for="r4"
onmouseover="menuMove(event)"
onmouseout="menuMove(event)"
onmousedown="sortIt(3)"
<input
type="radio"
name="sortKey"
id="r5"
class="sortButton"
onmouseover="menuMove(event)"
onmouseout="menuMove(event)"
onmousedown="sortIt(4)"
/>
<label for="r5"
onmouseover="menuMove(event)"
onmouseout="menuMove(event)"
onmousedown="sortIt(4)"
<input
type="radio"
name="sortKey"
id="r6"
class="sortButton"
onmouseover="menuMove(event)"
onmouseout="menuMove(event)"
onmousedown="sortIt(5)"
/>
<label for="r6"
onmouseover="menuMove(event)"
onmouseout="menuMove(event)"
onmousedown="sortIt(5)"
Queue Status</label><br />
<input
type="radio"
name="sortKey"
id="r7"
checked="checked"
class="sortButton"
onmouseover="menuMove(event)"
onmouseout="menuMove(event)"
onclick="document.getJobs.queName.focus()"
onblur='sortBy.style.visibility="hidden"'
/>
<label for="r7"
onmouseover="menuMove(event)"
onmouseout="menuMove(event)"
</form>
</div>
</body>
</html>