Annotation of zogiLib/js/dllib.js, revision 1.9

1.2       casties     1: /* Copyright (C) 2003,2004 IT-Group MPIWG, WTWG Uni Bern and others
1.1       casties     2:  
                      3: This program is free software; you can redistribute it and/or
                      4: modify it under the terms of the GNU General Public License
                      5: as published by the Free Software Foundation; either version 2
                      6: of the License, or (at your option) any later version.
                      7:  
                      8: This program is distributed in the hope that it will be useful,
                      9: but WITHOUT ANY WARRANTY; without even the implied warranty of
                     10: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     11: GNU General Public License for more details.
                     12:  
                     13: You should have received a copy of the GNU General Public License
                     14: along with this program; if not, write to the Free Software
                     15: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
                     16:  
1.2       casties    17: Authors:
                     18:   Christian Luginbuehl, 01.05.2003 (first version)
                     19:   DW 24.03.2004 (Changed for digiLib in Zope)
1.8       casties    20:   Robert Casties, 14.7.2006
1.1       casties    21: 
1.2       casties    22:   ! Requires baselib.js !
1.1       casties    23: 
                     24: */
                     25: 
1.5       casties    26: 
                     27: function identify() {
1.6       casties    28:         // used for identifying a digilib instance
                     29:         // Relato uses that function - lugi
                     30:         return "Digilib 0.6";
1.5       casties    31: }
                     32: 
1.1       casties    33: 
                     34: /*
                     35:  * more parameter handling
                     36:  */
                     37: 
                     38: function parseArea() {
                     39:     // returns area Rectangle from current parameters
                     40:     return new Rectangle(getParameter("wx"), getParameter("wy"), getParameter("ww"), getParameter("wh"));
                     41: }
                     42: 
                     43: function setParamFromArea(rect) {
                     44:     // sets digilib wx etc. from rect
                     45:     setParameter("wx", cropFloat(rect.x));
                     46:     setParameter("wy", cropFloat(rect.y));
                     47:     setParameter("ww", cropFloat(rect.width));
                     48:     setParameter("wh", cropFloat(rect.height));
                     49:     return true;
                     50: }
                     51: 
                     52: function parseTrafo(elem) {
                     53:     // returns Transform from current dlArea and picsize
                     54:     var picsize = getElementRect(elem);
                     55:     var trafo = new Transform();
                     56:     // subtract area offset and size
                     57:     trafo.concat(getTranslation(new Position(-dlArea.x, -dlArea.y)));
                     58:     trafo.concat(getScale(new Size(1/dlArea.width, 1/dlArea.height)));
                     59:     // scale to screen size
                     60:     trafo.concat(getScale(picsize));
                     61:     trafo.concat(getTranslation(picsize));
                     62:     // rotate
                     63:     //trafo.concat(getRotation(- getParameter("rot"), new Position(0.5*picsize.width, 0.5*picsize.height)));
                     64:     // mirror
                     65:     //if (hasFlag("hmir")) {
                     66:     //trafo.m00 = - trafo.m00;
                     67:     //}
                     68:     //if (hasFlag("vmir")) {
                     69:     //trafo.m11 = - trafo.m11;
                     70:     //}
                     71:     return trafo;
                     72: }
                     73: 
                     74: 
                     75: function parseMarks() {
                     76:     // returns marks array from current parameters
                     77:     var marks = new Array();
                     78:     var ma;
                     79:     var mk = getParameter("mk");
                     80:     if (mk.indexOf(";") >= 0) {
1.6       casties    81:         // old format with ";"
                     82:         ma = mk.split(";");
1.1       casties    83:     } else {
1.6       casties    84:         ma = mk.split(",");
1.1       casties    85:     }
                     86:     for (var i = 0; i < ma.length ; i++) {
1.6       casties    87:         var pos = ma[i].split("/");
                     88:         if (pos.length > 1) {
                     89:             marks.push(new Position(pos[0], pos[1]));
                     90:         }
1.1       casties    91:     }
                     92:     return marks;
                     93: }
                     94: 
                     95: function getAllMarks() {
                     96:     // returns a string with all marks in query format
                     97:     var marks = new Array();
                     98:     for (var i = 0; i < dlMarks.length; i++) {
1.6       casties    99:         marks.push(cropFloat(dlMarks[i].x) + "/" + cropFloat(dlMarks[i].y));
1.1       casties   100:     }
                    101:     return marks.join(",");
                    102: }
                    103: 
                    104: function addMark(pos) {
                    105:     // add a mark
                    106:     dlMarks.push(pos);
                    107:     setParameter("mk", getAllMarks());
                    108:     return true;
                    109: }
                    110: 
                    111: function deleteMark() {
                    112:     // delete the last mark
                    113:     dlMarks.pop();
                    114:     setParameter("mk", getAllMarks());
                    115:     return true;
                    116: }
                    117: 
                    118: function hasFlag(mode) {
                    119:     // returns if mode flag is set
                    120:     return (dlFlags[mode]);
                    121: }
                    122: 
                    123: function addFlag(mode) {
                    124:     // add a mode flag
                    125:     dlFlags[mode] = mode;
                    126:     setParameter("mo", getAllFlags());
                    127:     return true;
                    128: }
                    129: 
                    130: function removeFlag(mode) {
                    131:     // remove a mode flag
                    132:     if (dlFlags[mode]) {
1.6       casties   133:         delete dlFlags[mode];
1.1       casties   134:     }
                    135:     setParameter("mo", getAllFlags());
                    136:     return true;
                    137: }
                    138: 
                    139: function toggleFlag(mode) {
                    140:     // change a mode flag
                    141:     if (dlFlags[mode]) {
1.6       casties   142:         delete dlFlags[mode];
1.1       casties   143:     } else {
1.6       casties   144:         dlFlags[mode] = mode;
1.1       casties   145:     }
                    146:     setParameter("mo", getAllFlags());
                    147:     return true;
                    148: }
                    149: 
                    150: function getAllFlags() {
                    151:     // returns a string with all flags in query format
                    152:     var fa = new Array();
                    153:     for (var f in dlFlags) {
1.6       casties   154:         if ((f != "")&&(dlFlags[f] != null)) {
                    155:             fa.push(f);
                    156:         }
1.1       casties   157:     }
                    158:     return fa.join(",");
                    159: }
                    160: 
                    161: function parseFlags() {
                    162:     // sets dlFlags from the current parameters
                    163:     var flags = new Object();
                    164:     var fa = getParameter("mo").split(",");
                    165:     for (var i = 0; i < fa.length ; i++) {
1.6       casties   166:         var f = fa[i];
                    167:         if (f != "") {
                    168:             flags[f] = f;
                    169:         }
1.1       casties   170:     }
                    171:     return flags;
                    172: }    
                    173: 
                    174: 
                    175: function bestPicSize(elem, inset) {
                    176:     // returns a Size with the best image size for the given element
                    177:     if (! defined(inset)) {
1.6       casties   178:         inset = 25;
1.1       casties   179:     }
                    180:     var ws = getWinSize();
                    181:     var es = getElementPosition(elem);
                    182:     if (es) {
1.6       casties   183:         ws.width = ws.width - es.x - inset;
                    184:         ws.height = ws.height - es.y - inset;
1.1       casties   185:     }
                    186:     return ws;
                    187: }
                    188: 
1.7       casties   189: function setDLParam(e, s, relative) {
1.6       casties   190:    // sets parameter based on HTML event
                    191:    var nam;
                    192:     var val;
                    193:     if (s.type && (s.type == "select-one")) {
                    194:         nam = s.name;
                    195:         val = s.options[s.selectedIndex].value;
                    196:     } else if (s.name && s.value) {
                    197:         nam = s.name;
                    198:         val = s.value;
                    199:     }
                    200:     if (nam && val) {
1.7       casties   201:         setParameter(nam, val, relative);
1.6       casties   202:         display();
                    203:     } else {
1.7       casties   204:         alert("ERROR: unable to process event!");
1.6       casties   205:     }
                    206:     return true;
                    207: }
                    208: 
1.1       casties   209: 
                    210: /* **********************************************
                    211:  *     digilib specific routines
                    212:  * ******************************************** */
                    213: 
                    214: 
                    215: function dl_param_init() {
                    216:     // parameter initialisation before onload
1.5       casties   217:     if (!baseScriptVersion) {
1.6       casties   218:         base_init();
1.5       casties   219:     }
1.9     ! casties   220:     dlScriptVersion = "1.3a";
1.5       casties   221:     dlArea = new Rectangle(0.0, 0.0, 1.0, 1.0);
                    222:     dlMaxArea = new Rectangle(0.0, 0.0, 1.0, 1.0);
                    223:     dlTrafo = new Transform();
                    224:     dlMarks = new Array();
                    225:     dlFlags = new Object();
                    226:     elemScaler = null;
                    227:     picElem = null;
                    228:     ZOOMFACTOR = Math.sqrt(2);
1.1       casties   229: 
                    230:     // put the query parameters (sans "?") in the parameters array
1.9     ! casties   231:     // non-digilib parameters get detail level 32
        !           232:     parseParameters(location.search.slice(1),32);
1.1       casties   233:     // treat special parameters
                    234:     dlMarks = parseMarks();
                    235:     dlArea = parseArea();
                    236:     dlFlags = parseFlags();
1.9     ! casties   237:     // mask for parameters when creating new URL
        !           238:     dlUrlParamMask = 255;
1.1       casties   239: }
                    240: 
                    241: 
                    242: function dl_init() {
                    243:     // initalisation on load
1.5       casties   244:     if (!dlScriptVersion) {
1.6       casties   245:         dl_param_init();
1.5       casties   246:     }
1.1       casties   247:     elemScaler = getElement("scaler", true);
                    248:     picElem = getElement("pic", true);
                    249:     if (picElem == null && elemScaler) {
1.6       casties   250:         // in N4 pic is in the scaler layer
                    251:         picElem = elemScaler.document.images[0];
1.1       casties   252:     }
                    253:     if ((!elemScaler)||(!picElem)) {
1.6       casties   254:         alert("Sorry, digilib doesn't work here!");
                    255:         return false;
1.1       casties   256:     }
                    257:     // give a name to the window containing digilib
                    258:     if (defined(dlTarget)&&(dlTarget)) {
1.6       casties   259:         window.name = dlTarget;
1.1       casties   260:     } else {
1.6       casties   261:         window.name = "digilib";
1.1       casties   262:     }
                    263:     // put the query parameters (sans "?") in the parameters array
1.9     ! casties   264:     //parseParameters(location.search.slice(1),32);
1.1       casties   265:     // treat special parameters
                    266:     dlMarks = parseMarks();
                    267:     dlArea = parseArea();
                    268:     dlFlags = parseFlags();
                    269:     // wait for image to load and display marks
                    270:     renderMarks();
                    271:     // done
                    272:     focus();
                    273:     return;
                    274: }
                    275: 
                    276: 
                    277: function display(detail) {
                    278:     // redisplay the page
                    279:     if (! detail) {
1.7       casties   280:         detail = 255;
1.1       casties   281:     }
1.9     ! casties   282:     var queryString = getAllParameters(detail & dlUrlParamMask);
1.1       casties   283:     location.href = location.protocol + "//" + location.host + location.pathname + "?" + queryString;
                    284: }
                    285: 
                    286: 
                    287: /* **********************************************
                    288:  *     interactive digilib functions
                    289:  * ******************************************** */
                    290: 
                    291: 
                    292: function renderMarks() {
                    293:     // put the visible marks on the image
                    294:     var mark_count = dlMarks.length;
                    295:     // make shure the image is loaded so we know its size
                    296:     if (defined(picElem.complete) && picElem.complete == false && ! browserType.isN4 ) {
1.6       casties   297:         setTimeout("renderMarks()", 100);
1.1       casties   298:     } else {
1.6       casties   299:         dlTrafo = parseTrafo(picElem);
                    300:         for (var i = 0; i < 8; i++) {
                    301:             var me = getElement("dot"+i);
                    302:             if (i < mark_count) {
                    303:                 if (dlArea.containsPosition(dlMarks[i])) {
                    304:                     var mpos = dlTrafo.transform(dlMarks[i]);
                    305:                     // suboptimal to place -5 pixels and not half size of mark-image
                    306:                     mpos.x = mpos.x -5;
                    307:                     mpos.y = mpos.y -5;
                    308:                     moveElement(me, mpos);
                    309:                     showElement(me, true);
                    310:                 }
                    311:             } else {
                    312:                 // hide the other marks
                    313:                 showElement(me, false);
                    314:             }
                    315:         }
1.1       casties   316:     }
                    317: }
                    318: 
                    319: 
                    320: function setMark(reload) {
                    321:     // add a mark where clicked
                    322:     if ( dlMarks.length > 7 ) {
1.6       casties   323:         alert("Only 8 marks are possible at the moment!");
                    324:         return;
1.1       casties   325:     }
1.2       casties   326:     window.focus();
1.1       casties   327: 
                    328:     function markEvent(evt) {
1.6       casties   329:         // event handler adding a new mark
                    330:         unregisterEvent("mousedown", elemScaler, markEvent);
                    331:         var p = dlTrafo.invtransform(evtPosition(evt));
                    332:         addMark(p);
                    333:         if (defined(reload)&&(!reload)) {
                    334:             // don't redisplay
                    335:             renderMarks();
                    336:             return;
                    337:         }
                    338:         display();
1.1       casties   339:     }
                    340: 
                    341:     // starting event capture
1.2       casties   342:     registerEvent("mousedown", elemScaler, markEvent);
1.1       casties   343: }
                    344: 
                    345: 
                    346: function removeMark(reload) {
                    347:     // remove the last mark
                    348:     deleteMark();
                    349:     if (defined(reload)&&(!reload)) {
1.6       casties   350:         // don't redisplay
                    351:         renderMarks();
                    352:         return;
1.1       casties   353:     }
                    354:     display();
                    355: }
                    356: 
                    357: 
                    358: function zoomArea() {
                    359:     var click = 1;
                    360:     var pt1, pt2;
                    361:     var eck1pos, eck2pos, eck3pos, eck4pos;
                    362:     window.focus();
                    363:     var eck1 = getElement("eck1");
                    364:     var eck2 = getElement("eck2");
                    365:     var eck3 = getElement("eck3");
                    366:     var eck4 = getElement("eck4");
                    367: 
                    368:     function zoomClick(evt) {
1.6       casties   369:         // mouse click handler
                    370:         if (click == 1) {
                    371:             // first click -- start moving
                    372:             click = 2;
                    373:             pt1 = evtPosition(evt);
                    374:             pt2 = pt1;
                    375:             eck1pos = pt1;
                    376:             eck2pos = new Position(pt1.x - 12, pt1.y);
                    377:             eck3pos = new Position(pt1.x, pt1.y - 12);
                    378:             eck4pos = new Position(pt1.y - 12, pt1.y - 12);
                    379:             moveElement(eck1, eck1pos);
                    380:             moveElement(eck2, eck2pos);
                    381:             moveElement(eck3, eck3pos);
                    382:             moveElement(eck4, eck4pos);
                    383:             showElement(eck1, true);
                    384:             showElement(eck2, true);
                    385:             showElement(eck3, true);
                    386:             showElement(eck4, true);
                    387:             // show moving
                    388:             registerEvent("mousemove", elemScaler, zoomMove);
                    389:             registerEvent("mousemove", eck4, zoomMove);
                    390:             // enable drag-to-zoom
                    391:             registerEvent("mouseup", elemScaler, zoomClick);
                    392:             registerEvent("mouseup", eck4, zoomClick);
                    393:         } else {
                    394:             // second click -- end moving
                    395:             pt2 = evtPosition(evt);
                    396:             showElement(eck1, false);
                    397:             showElement(eck2, false);
                    398:             showElement(eck3, false);
                    399:             showElement(eck4, false);
                    400:             unregisterEvent("mousemove", elemScaler, zoomMove);
                    401:             unregisterEvent("mousemove", eck4, zoomMove);
                    402:             unregisterEvent("mousedown", elemScaler, zoomClick);
                    403:             unregisterEvent("mousedown", eck4, zoomClick);
                    404:             var p1 = dlTrafo.invtransform(pt1);
                    405:             var p2 = dlTrafo.invtransform(pt2);
                    406:             var ww = p2.x-p1.x;
                    407:             var wh = p2.y-p1.y;
                    408:             if ((ww > 0)&&(wh > 0)) {
                    409:                 setParameter("wx", cropFloat(p1.x));
                    410:                 setParameter("wy", cropFloat(p1.y));
                    411:                 setParameter("ww", cropFloat(ww));
                    412:                 setParameter("wh", cropFloat(wh));
                    413:                 parseArea();
                    414:                 // zoomed is always fit
                    415:                 setParameter("ws", 1);
                    416:                 display();
                    417:             }
                    418:         }
1.1       casties   419:     }
                    420: 
                    421:     function zoomMove(evt) {
1.6       casties   422:         // mouse move handler
                    423:         pt2 = evtPosition(evt);
                    424:         // restrict marks to move right and down
                    425:         eck1pos = pt1;
                    426:         eck2pos = new Position(Math.max(pt1.x, pt2.x)-12, pt1.y);
                    427:         eck3pos = new Position(pt1.x, Math.max(pt1.y, pt2.y)-12);
                    428:         eck4pos = new Position(Math.max(pt1.x, pt2.x)-12, Math.max(pt1.y, pt2.y)-12);
                    429:         moveElement(eck1, eck1pos);
                    430:         moveElement(eck2, eck2pos);
                    431:         moveElement(eck3, eck3pos);
                    432:         moveElement(eck4, eck4pos);
1.1       casties   433:     }
                    434: 
                    435:     // starting event capture
1.2       casties   436:     registerEvent("mousedown", elemScaler, zoomClick);
                    437:     registerEvent("mousedown", eck4, zoomClick);
1.1       casties   438: }
                    439: 
                    440: function zoomBy(factor) {
                    441:     // zooms by the given factor
                    442:     var newarea = dlArea.copy();
                    443:     newarea.width /= factor;
                    444:     newarea.height /= factor;
                    445:     newarea.x -= 0.5 * (newarea.width - dlArea.width);
                    446:     newarea.y -= 0.5 * (newarea.height - dlArea.height);
                    447:     newarea = dlMaxArea.fit(newarea);
                    448:     setParamFromArea(newarea);
                    449:     display();
                    450: }
                    451: 
                    452: 
                    453: function zoomFullpage() {
                    454:     // zooms out to show the whole image
                    455:     setParameter("wx", 0.0);
                    456:     setParameter("wy", 0.0);
                    457:     setParameter("ww", 1.0);
                    458:     setParameter("wh", 1.0);
                    459:     display();
                    460: }
                    461: 
                    462: 
                    463: function moveCenter() {
                    464:     // move visible area so that it's centered around the clicked point
                    465:     if ( (dlArea.width == 1.0) && (dlArea.height == 1.0) ) {
1.7       casties   466:         // nothing to do
1.6       casties   467:         return;
1.1       casties   468:     }
                    469:     window.focus();
                    470: 
                    471:     function moveCenterEvent(evt) {
1.6       casties   472:         // move to handler
                    473:         unregisterEvent("mousedown", elemScaler, moveCenterEvent);
                    474:         var pt = dlTrafo.invtransform(evtPosition(evt));
                    475:         var newarea = new Rectangle(pt.x-0.5*dlArea.width, pt.y-0.5*dlArea.height, dlArea.width, dlArea.height);
                    476:         newarea = dlMaxArea.fit(newarea);
                    477:         // set parameters
                    478:         setParamFromArea(newarea);
                    479:         parseArea();
                    480:         display();
1.1       casties   481:     }
                    482: 
                    483:     // starting event capture
1.2       casties   484:     registerEvent("mousedown", elemScaler, moveCenterEvent);
1.1       casties   485: }
                    486: 
1.5       casties   487: function moveBy(movx, movy) {
1.6       casties   488:     // move visible area by movx and movy (in units of ww, wh)
1.5       casties   489:     if ((dlArea.width == 1.0)&&(dlArea.height == 1.0)) {
1.6       casties   490:         // nothing to do
                    491:         return;
1.5       casties   492:     }
                    493:     var newarea = dlArea.copy();
                    494:     newarea.x += parseFloat(movx)*dlArea.width;
                    495:     newarea.y += parseFloat(movy)*dlArea.height;
                    496:     newarea = dlMaxArea.fit(newarea);
                    497:     // set parameters
                    498:     setParamFromArea(newarea);
                    499:     parseArea();
                    500:     display();
                    501: }
                    502: 
1.1       casties   503: function getRef() {
                    504:     // returns a reference to the current digilib set
                    505:     if (! baseUrl) {
1.6       casties   506:         var baseUrl = location.protocol + "//" + location.host + location.pathname;
1.1       casties   507:     }
                    508:     var hyperlinkRef = baseUrl;
1.9     ! casties   509:     var par = getAllParameters((7+32+64) & dlUrlParamMask); // all without ddpi, pt
1.1       casties   510:     if (par.length > 0) {
1.6       casties   511:         hyperlinkRef += "?" + par;
1.1       casties   512:     }
                    513:     return hyperlinkRef;
                    514: }
1.3       casties   515: 
                    516: function getRefWin(type, msg) {
                    517:     // shows an alert with a reference to the current digilib set
                    518:     if (! msg) {
1.6       casties   519:         msg = "Link for HTML documents";
1.4       casties   520:     }
1.3       casties   521:     prompt(msg, getRef());
1.5       casties   522: }
1.6       casties   523: 
                    524: function getQuality() {
                    525:    // returns the current q setting
                    526:     for (var i = 0; i < 3; i++) {
                    527:         if (hasFlag("q"+i)) {
                    528:            return i;
                    529:         }
                    530:     }
                    531:     return 1
                    532: }
                    533: 
                    534: function setQuality(qual) {
                    535:     // set the image quality
                    536:     for (var i = 0; i < 3; i++) {
                    537:         removeFlag("q"+i);
                    538:         if (i == qual) {
                    539:             addFlag("q"+i);
                    540:         }
                    541:     }
                    542:     setParameter("mo", getAllFlags());
                    543:     display();
                    544: }    
                    545: 
                    546: function setQualityWin(msg) {
                    547:    // dialog for setting quality
                    548:    if (! msg) {
                    549:        msg = "Quality (0..2)";
                    550:    }
                    551:    var q = getQuality();
                    552:    var newq = window.prompt(msg, q);
                    553:    if (newq) {
                    554:        setQuality(newq);
                    555:    }
                    556: }
                    557: 
                    558: function mirror(dir) {
                    559:     // mirror the image horizontally or vertically
                    560:     if (dir == "h") {
                    561:         toggleFlag("hmir");
                    562:     } else {
                    563:         toggleFlag("vmir");
                    564:     }
                    565:     setParameter("mo", getAllFlags());
                    566:     display();
                    567: }
                    568: 
1.7       casties   569: function gotoPage(gopage, keep) {
                    570:    // goto given page nr (+/-: relative)
                    571:    var oldpn = parseInt(getParameter("pn"));
                    572:    setParameter("pn", gopage, true);
1.6       casties   573:    var pn = parseInt(getParameter("pn"));
                    574:    if (pn < 1) {
1.7       casties   575:        alert("No such page! (Page number too low)");
                    576:        setParameter("pn", oldpn);
                    577:        return;
                    578:    }
                    579:    if (hasParameter("pt")) {
                    580:        pt = parseInt(getParameter("pt"))
                    581:        if (pn > pt) {
                    582:            alert("No such page! (Page number too high)");
                    583:            setParameter("pn", oldpn);
                    584:            return;
                    585:        }
                    586:    }
                    587:    if (keep) {
1.9     ! casties   588:        display(63+128); // all, no mark
1.7       casties   589:    } else {    
1.9     ! casties   590:        display(3+32+128); // fn, pn, ws, mo + pt
1.6       casties   591:    }
                    592: }
                    593: 
                    594: function gotoPageWin() {
                    595:    // dialog to ask for new page nr
1.7       casties   596:    var pn = getParameter("pn");
1.6       casties   597:    var gopage = window.prompt("Go to page", pn);
                    598:    if (gopage) {
                    599:        gotoPage(gopage);
                    600:    }
                    601: }
                    602: 
1.7       casties   603: function setParamWin(param, text, relative) {
1.6       casties   604:    // dialog to ask for new parameter value
                    605:    var val = getParameter(param);
                    606:    var newval = window.prompt(text, val);
                    607:    if (newval) {
1.7       casties   608:        setParameter(param, newval, relative);
1.6       casties   609:        display();
                    610:    }
                    611: }
                    612: 
                    613: function showOptions(show) {
                    614:    // show or hide option div
                    615:    var elem = getElement("dloptions");
                    616:    showElement(elem, show);
1.8       casties   617: }
                    618: 
                    619: function toggleOptions() {
                    620:     // toggle option div
                    621:     var elem = getElement("dloptions");
                    622:     showOptions(! isElementVisible(elem));
                    623: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>