source: main/trunk/greenstone3/web/interfaces/oran/js/documentmaker_scripts_util.js@ 25065

Last change on this file since 25065 was 25065, checked in by sjm84, 12 years ago

Ampersands in the transaction text are now turned into %26 and turned back again on the server

  • Property svn:executable set to *
File size: 20.8 KB
Line 
1//Some "constants" to match the server constants
2var SUCCESS = 1;
3var ACCEPTED = 2;
4var ERROR = 3;
5var CONTINUING = 10;
6var COMPLETED = 11;
7var HALTED = 12;
8
9function getElementsByClassName(cl, parent)
10{
11 var elemArray = [];
12 var classRegEx = new RegExp("\\b" + cl + "\\b");
13 var elems;
14 if(parent)
15 {
16 elems = parent.getElementsByTagName("*");
17 }
18 else
19 {
20 elems = document.getElementsByTagName("*");
21 }
22
23 for (var i = 0; i < elems.length; i++)
24 {
25 var classeName = elems[i].className;
26 if (classRegEx.test(classeName)) elemArray.push(elems[i]);
27 }
28
29 return elemArray;
30};
31
32function getNextSiblingOfType(elem, type)
33{
34 if(elem == null)
35 {
36 return null;
37 }
38
39 var current = elem.nextSibling;
40 while(current != null)
41 {
42 if(current.nodeName.toLowerCase() == type)
43 {
44 return current;
45 }
46
47 current = current.nextSibling;
48 }
49 return null;
50}
51
52function getPrevSiblingOfType(elem, type)
53{
54 if(elem == null)
55 {
56 return null;
57 }
58
59 var current = elem.previousSibling;
60 while(current != null)
61 {
62 if(current.nodeName.toLowerCase() == type)
63 {
64 return current;
65 }
66
67 current = current.previousSibling;
68 }
69 return null;
70}
71
72function saveTransaction(transaction)
73{
74 console.log(transaction);
75 _transactions.push(transaction);
76}
77
78function undo()
79{
80 if(_undoOperations.length == 0)
81 {
82 return;
83 }
84
85 var undoOp = _undoOperations.pop();
86
87 //Create/Duplicate undo
88 if(undoOp.op == "del")
89 {
90 if(undoOp.srcElem.childList)
91 {
92 removeFromParent(undoOp.srcElem.childList);
93 }
94 if(undoOp.srcElem.parentItem)
95 {
96 undoOp.srcElem.parentItem.menu.newSectionLink.style.display = "inline";
97 undoOp.srcElem.parentItem.childList = null;
98 }
99 removeFromParent(undoOp.srcElem);
100 }
101
102 if(undoOp.op == "delMeta")
103 {
104 if(undoOp.srcElem.childList)
105 {
106 removeFromParent(undoOp.srcElem.childList);
107 }
108 if(undoOp.srcElem.parentItem)
109 {
110 undoOp.srcElem.parentItem.menu.newSectionLink.style.display = "inline";
111 undoOp.srcElem.parentItem.childList = null;
112 }
113 de.doc.unregisterEditSection(undoOp.srcElem);
114 removeFromParent(undoOp.srcElem);
115 }
116
117 //Move undo (mva is move after, mvb is move before, mvi is move into)
118 else if(undoOp.op == "mva" || undoOp.op == "mvb" || undoOp.op == "mvi")
119 {
120 if(undoOp.op == "mvb")
121 {
122 undoOp.refElem.parentNode.insertBefore(undoOp.srcElem, undoOp.refElem);
123 }
124 else if(undoOp.op == "mva")
125 {
126 insertAfter(undoOp.srcElem, undoOp.refElem);
127 }
128 else
129 {
130 undoOp.refElem.removeChild(undoOp.refElem.firstChild);
131 undoOp.refElem.appendChild(undoOp.srcElem);
132 }
133
134 if(undoOp.srcElem.textDiv)
135 {
136 insertAfter(undoOp.srcElem.textDiv, undoOp.srcElem);
137 }
138 if(undoOp.srcElem.childList)
139 {
140 insertAfter(undoOp.srcElem.childList, undoOp.srcElem.textDiv);
141 }
142
143 if(undoOp.srcElem.onmouseout)
144 {
145 //Uncolour the section if it coloured
146 undoOp.srcElem.onmouseout();
147 }
148 updateFromTop();
149 }
150
151 if(undoOp.removeTransaction)
152 {
153 _transactions.pop();
154 }
155}
156
157function addCollectionToBuild(collection)
158{
159 for(var i = 0; i < _collectionsToBuild.length; i++)
160 {
161 if(collection == _collectionsToBuild[i])
162 {
163 return;
164 }
165 }
166 _collectionsToBuild.push(collection);
167}
168
169function save()
170{
171 var changes = de.Changes.getChangedEditableSections();
172
173 for(var i = 0; i < changes.length; i++)
174 {
175 var changedElem = changes[i];
176 if(hasClass(changedElem, "metadataTableCellValue"))
177 {
178 //Save metadata
179 }
180 else if(hasClass(changedElem, "renderedText"))
181 {
182 //Save content
183 var section = changedElem.parentDiv.parentItem;
184 saveTransaction('{"operation":"setText", "text":"' + changedElem.innerHTML.replace(/"/g, "\\\"").replace(/&/g, "%26") + '", "collection":"' + section.collection + '", "oid":"' + section.nodeID + '"}');
185 addCollectionToBuild(section.collection);
186 }
187 }
188
189 var request = "[";
190 for(var i = 0; i < _transactions.length; i++)
191 {
192 request += _transactions[i];
193 if(i != _transactions.length - 1)
194 {
195 request +=",";
196 }
197 }
198 request += "]";
199
200 var statusID;
201 var ajax = new gs.functions.ajaxRequest();
202 ajax.open("POST", _baseURL, true);
203 ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
204 ajax.onreadystatechange = function()
205 {
206 if(ajax.readyState == 4 && ajax.status == 200)
207 {
208 var text = ajax.responseText;
209 var xml = validateXML(text);
210
211 var errorElems;
212 if(!xml || checkForErrors(xml))
213 {
214 alert("There was an error saving, aborting");
215
216 var saveButton = document.getElementById("saveButton");
217 saveButton.innerHTML = "Save changes";
218 saveButton.disabled = false;
219
220 _statusBar.removeStatus(statusID);
221 return;
222 }
223
224 _statusBar.removeStatus(statusID);
225 buildCollections(_collectionsToBuild);
226 }
227 }
228
229 var saveButton = document.getElementById("saveButton");
230 saveButton.innerHTML = "Saving...";
231 saveButton.disabled = true;
232
233 statusID = _statusBar.addStatus("Modifying archive files...");
234 ajax.send("a=g&rt=r&s=DocumentExecuteTransaction&s1.transactions=" + request);
235}
236
237function buildCollections(collections)
238{
239 var saveButton = document.getElementById("saveButton");
240 if(!collections || collections.length == 0)
241 {
242 console.log("List of collections to build is empty");
243 saveButton.innerHTML = "Save changes";
244 saveButton.disabled = false;
245 return;
246 }
247
248 var counter = 0;
249 var statusID = 0;
250 var buildFunction = function()
251 {
252 var ajax = new gs.functions.ajaxRequest();
253 ajax.open("GET", _baseURL + "?a=g&rt=r&ro=1&s=BuildCollection&s1.collection=" + collections[counter]);
254 ajax.onreadystatechange = function()
255 {
256 if(ajax.readyState == 4 && ajax.status == 200)
257 {
258 var text = ajax.responseText;
259 var xml = validateXML(text);
260
261 if(!xml || checkForErrors(xml))
262 {
263 alert("Could not build collection -> " + collections[counter] + ", aborting");
264
265 _statusBar.removeStatus(statusID);
266 saveButton.innerHTML = "Save changes";
267 saveButton.disabled = false;
268
269 return;
270 }
271
272 var status = xml.getElementsByTagName("status")[0];
273 var pid = status.getAttribute("pid");
274
275 startCheckLoop(pid, "BuildCollection", statusID, function()
276 {
277 var localAjax = new gs.functions.ajaxRequest();
278 localAjax.open("GET", _baseURL + "?a=g&rt=r&ro=1&s=ActivateCollection&s1.collection=" + collections[counter], true);
279 localAjax.onreadystatechange = function()
280 {
281 if(localAjax.readyState == 4 && localAjax.status == 200)
282 {
283 var localText = localAjax.responseText;
284 var localXML = validateXML(localText);
285
286 if(!xml || checkForErrors(xml))
287 {
288 alert("Could not activate collection -> " + collections[counter] + ", aborting");
289
290 _statusBar.removeStatus(statusID);
291 saveButton.innerHTML = "Save changes";
292 saveButton.disabled = false;
293
294 return;
295 }
296
297 var localStatus = localXML.getElementsByTagName("status")[0];
298 if(localStatus)
299 {
300 var localPID = localStatus.getAttribute("pid");
301 startCheckLoop(localPID, "ActivateCollection", statusID, function()
302 {
303 if(counter == collections.length - 1)
304 {
305 removeCollectionsFromBuildList(collections);
306 }
307 else
308 {
309 counter++;
310 buildFunction();
311 }
312
313 _transactions = new Array();
314
315 _statusBar.removeStatus(statusID);
316 saveButton.innerHTML = "Save changes";
317 saveButton.disabled = false;
318 });
319 }
320 }
321 }
322 _statusBar.changeStatus(statusID, "Activating collection " + collections[counter] + "...");
323 localAjax.send();
324 });
325 }
326 }
327 statusID = _statusBar.addStatus("Building collection " + collections[counter] + "...");
328 ajax.send();
329 }
330 buildFunction();
331}
332
333function startCheckLoop(pid, serverFunction, statusID, callbackFunction)
334{
335 var ajaxFunction = function()
336 {
337 var saveButton = document.getElementById("saveButton");
338
339 var ajax = new gs.functions.ajaxRequest();
340 ajax.open("GET", _baseURL + "?a=g&rt=s&ro=1&s=" + serverFunction + "&s1.pid=" + pid, true);
341 ajax.onreadystatechange = function()
342 {
343 if(ajax.readyState == 4 && ajax.status == 200)
344 {
345 var text = ajax.responseText;
346 var xml = validateXML(text);
347
348 if(!xml || checkForErrors(xml))
349 {
350 alert("Could not check status of " + serverFunction + ", there was an error in the XML, aborting");
351
352 _statusBar.removeStatus(statusID);
353 saveButton.innerHTML = "Save changes";
354 saveButton.disabled = false;
355
356 return;
357 }
358
359 var status = xml.getElementsByTagName("status")[0];
360 var code = status.getAttribute("code");
361
362 if (code == COMPLETED || code == SUCCESS)
363 {
364 callbackFunction();
365 }
366 else if (code == HALTED || code == ERROR)
367 {
368 alert("Could not check status of " + serverFunction + ", there was an error on the server, aborting");
369
370 _statusBar.removeStatus(statusID);
371 saveButton.innerHTML = "Save changes";
372 saveButton.disabled = false;
373 }
374 else
375 {
376 setTimeout(ajaxFunction, 1000);
377 }
378 }
379 }
380 ajax.send();
381 }
382 ajaxFunction();
383}
384
385function removeCollectionsFromBuildList(collections)
386{
387 var tempArray = new Array();
388 for(var i = 0; i < _collectionsToBuild.length; i++)
389 {
390 var found = false;
391 for(var j = 0; j < collections.length; j++)
392 {
393 if(collections[j] == _collectionsToBuild[i])
394 {
395 found = true;
396 break;
397 }
398 }
399
400 if(!found)
401 {
402 tempArray.push(_collectionsToBuild[i]);
403 }
404 }
405 _collectionsToBuild = tempArray;
406}
407
408function checkForErrors(xml)
409{
410 var errorElems = xml.getElementsByTagName("error");
411
412 if(errorElems && errorElems.length > 0)
413 {
414 var errorString = "There was an error saving your changes: ";
415 for(var i = 0; i < errorElems.length; i++)
416 {
417 errorString += " " + errorElems.item(i).firstChild.nodeValue;
418 }
419 alert(errorString);
420 return true;
421 }
422 return false; //No errors
423}
424
425function validateXML(txt)
426{
427 // code for IE
428 if (window.ActiveXObject)
429 {
430 var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
431 xmlDoc.async = "false";
432 xmlDoc.loadXML(document.all(txt).value);
433
434 if(xmlDoc.parseError.errorCode!=0)
435 {
436 txt = "Error Code: " + xmlDoc.parseError.errorCode + "\n";
437 txt = txt + "Error Reason: " + xmlDoc.parseError.reason;
438 txt = txt + "Error Line: " + xmlDoc.parseError.line;
439 console.log(txt);
440 return null;
441 }
442
443 return xmlDoc;
444 }
445 // code for Mozilla, Firefox, Opera, etc.
446 else if (document.implementation.createDocument)
447 {
448 var parser = new DOMParser();
449 var xmlDoc = parser.parseFromString(txt,"text/xml");
450
451 if (xmlDoc.getElementsByTagName("parsererror").length > 0)
452 {
453 console.log("There was an error parsing the XML");
454 return null;
455 }
456
457 return xmlDoc;
458 }
459 else
460 {
461 console.log('Your browser cannot handle XML validation');
462 }
463 return null;
464}
465
466function addFunctionalityToTable(table)
467{
468 var rows = table.getElementsByTagName("TR");
469 for(var i = 0; i < rows.length; i++)
470 {
471 var cells = rows[i].getElementsByTagName("TD");
472
473 //This registering can cause a sizeable delay so we'll thread it (effectively) so the browser is not paused
474 setTimeout(function(){de.doc.registerEditSection(cells[1])}, 0);
475
476 addRemoveLinkToRow(rows[i]);
477 }
478
479 var metaNameField = document.createElement("INPUT");
480 metaNameField.setAttribute("type", "text");
481 insertAfter(metaNameField, table);
482
483 var addRowButton = document.createElement("BUTTON");
484 addRowButton.innerHTML = "Add new metadata";
485 addRowButton.onclick = function()
486 {
487 var name = metaNameField.value;
488 if(!name || name == "")
489 {
490 console.log("No value given for new metadata name");
491 return;
492 }
493
494 var newRow = document.createElement("TR");
495 var nameCell = document.createElement("TD");
496 var valueCell = document.createElement("TD");
497 nameCell.setAttribute("class", "metaTableCellName");
498 nameCell.innerHTML = name;
499 valueCell.setAttribute("class", "metaTableCell editable");
500
501 newRow.appendChild(nameCell);
502 newRow.appendChild(valueCell);
503 addRemoveLinkToRow(newRow);
504 table.appendChild(newRow);
505
506 var undo = new Array();
507 undo.op = "delMeta";
508 undo.srcElem = newRow;
509 undo.removeTransaction = false;
510 _undoOperations.push(undo);
511
512 //Threading this function here probably isn't necessary like the other times it is called
513 de.doc.registerEditSection(valueCell);
514 };
515 insertAfter(addRowButton, metaNameField);
516}
517
518function addRemoveLinkToRow(row)
519{
520 var newCell = document.createElement("TD");
521 var removeLink = document.createElement("A");
522 removeLink.innerHTML = "remove";
523 removeLink.setAttribute("href", "javascript:;");
524 removeLink.onclick = function()
525 {
526 var undo = new Array();
527 var prev = getPrevSiblingOfType(row, "tr");
528 var next = getNextSiblingOfType(row, "tr");
529 var parent = row.parentNode;
530 if(prev)
531 {
532 undo.op = "mva";
533 undo.refElem = prev;
534 }
535 else if(next)
536 {
537 undo.op = "mvb";
538 undo.refElem = next;
539 }
540 else
541 {
542 undo.op = "mvi";
543 undo.refElem = parent;
544 }
545 undo.srcElem = row;
546 undo.removeTransaction = true;
547 _undoOperations.push(undo);
548
549 /*
550 saveTransaction('{"operation":"deleteMetadata", "collection":"' + section.collection + '", "oid":"' + section.nodeID + '"}');
551 addCollectionToBuild(section.collection);
552 */
553
554 _deletedSections.push(row);
555 removeFromParent(row);
556 }
557 newCell.appendChild(removeLink);
558 newCell.setAttribute("class", "metaTableCell");
559 newCell.setAttribute("style", "font-size:0.6em; padding-left: 3px; padding-right: 3px;");
560 row.appendChild(newCell);
561}
562
563function createTopMenuBar()
564{
565 //Create the top menu bar
566 var headerTable = document.createElement("TABLE");
567 var tableBody = document.createElement("TBODY");
568 var row = document.createElement("TR");
569 var newDocCell = document.createElement("TD");
570 var newSecCell = document.createElement("TD");
571 var saveCell = document.createElement("TD");
572 var undoCell = document.createElement("TD");
573 newDocCell.setAttribute("class", "headerTableTD");
574 newSecCell.setAttribute("class", "headerTableTD");
575 undoCell.setAttribute("class", "headerTableTD");
576 saveCell.setAttribute("class", "headerTableTD");
577
578 headerTable.appendChild(tableBody);
579 tableBody.appendChild(row);
580 row.appendChild(saveCell);
581 row.appendChild(undoCell);
582 row.appendChild(newDocCell);
583 row.appendChild(newSecCell);
584
585 //The "Save changes" button
586 var saveButton = document.createElement("BUTTON");
587 saveButton.innerHTML = "Save changes";
588 saveButton.setAttribute("onclick", "save();");
589 saveButton.setAttribute("id", "saveButton");
590 saveCell.appendChild(saveButton);
591
592 //The "Undo" button
593 var undoButton = document.createElement("BUTTON");
594 undoButton.innerHTML = "Undo";
595 undoButton.setAttribute("onclick", "undo();");
596 undoCell.appendChild(undoButton);
597
598 //The "Create new document" button
599 var newDocButton = document.createElement("BUTTON");
600 newDocButton.innerHTML = "Create new document";
601 newDocButton.setAttribute("onclick", "createNewDocumentArea();");
602 newDocCell.appendChild(newDocButton);
603
604 //The "Insert new section" LI
605 var newSecLI = createDraggableNewSection(newSecCell);
606
607 return headerTable;
608}
609
610function getMetadataFromNode(node, name)
611{
612 var currentNode = node.firstChild;
613 while(currentNode != null)
614 {
615 if(currentNode.nodeName == "metadataList")
616 {
617 currentNode = currentNode.firstChild;
618 break;
619 }
620
621 currentNode = currentNode.nextSibling;
622 }
623
624 while(currentNode != null)
625 {
626 if(currentNode.nodeName == "metadata" && currentNode.getAttribute("name") == name)
627 {
628 return currentNode.firstChild.nodeValue;
629 }
630
631 currentNode = currentNode.nextSibling;
632 }
633 return "{UNTITLED}";
634}
635
636function storeMetadata(node, listItem)
637{
638 listItem.metadata = new Array();
639
640 var currentNode = node.firstChild;
641 while(currentNode != null)
642 {
643 if(currentNode.nodeName == "metadataList")
644 {
645 currentNode = currentNode.firstChild;
646 break;
647 }
648
649 currentNode = currentNode.nextSibling;
650 }
651
652 while(currentNode != null)
653 {
654 if(currentNode.nodeName == "metadata")
655 {
656 listItem.metadata[currentNode.getAttribute("name")] = currentNode.firstChild.nodeValue;
657 }
658
659 currentNode = currentNode.nextSibling;
660 }
661}
662
663function hasClass(elem, classVal)
664{
665 if(!elem || !elem.getAttribute("class"))
666 {
667 return false;
668 }
669
670 return (elem.getAttribute("class").search(classVal) != -1)
671}
672
673function getNodeContent(node)
674{
675 var currentNode = node.firstChild;
676 while(currentNode != null)
677 {
678 if(currentNode.nodeName == "nodeContent")
679 {
680 return currentNode.firstChild;
681 }
682
683 currentNode = currentNode.nextSibling;
684 }
685 return null;
686}
687
688function containsDocumentNode(node)
689{
690 var currentNode = node.firstChild;
691 while(currentNode != null)
692 {
693 if(currentNode.nodeName == "documentNode")
694 {
695 return true;
696 }
697
698 currentNode = currentNode.nextSibling;
699 }
700 return false;
701}
702
703function isExpanded(textDiv)
704{
705 if(!textDiv.style.display || textDiv.style.display == "block")
706 {
707 return true;
708 }
709 return false;
710}
711
712function toggleTextDiv(section)
713{
714 var textDiv = section.textDiv;
715 if(textDiv)
716 {
717 if(isExpanded(textDiv))
718 {
719 textDiv.style.display = "none";
720 section.menu.editTextLink.innerHTML = "edit";
721 }
722 else
723 {
724 textDiv.style.display = "block";
725 section.menu.editTextLink.innerHTML = "hide";
726 }
727 }
728}
729
730function updateFromTop()
731{
732 updateRecursive(document.getElementById("dbDiv"), null, null, 0);
733}
734
735function insertAfter(elem, refElem)
736{
737 if(refElem.nextSibling)
738 {
739 refElem.parentNode.insertBefore(elem, refElem.nextSibling);
740 }
741 else
742 {
743 refElem.parentNode.appendChild(elem);
744 }
745}
746
747function removeFromParent(elem)
748{
749 elem.parentNode.removeChild(elem);
750}
751
752function createSectionTitle(text)
753{
754 var textSpan = document.createElement("SPAN");
755 if(text)
756 {
757 textSpan.appendChild(document.createTextNode(" " + text + " "));
758 }
759 else
760 {
761 textSpan.appendChild(document.createTextNode(" [UNTITLED SECTION] "));
762 }
763 return textSpan;
764}
765
766function setMouseOverAndOutFunctions(section)
767{
768 //Colour the list item and display the menu on mouse over
769 section.onmouseover = function(e)
770 {
771 if(this.menu){this.menu.style.display = "inline";}
772 this.style.background = "rgb(255, 200, 0)";
773 };
774 //Uncolour the list item and hide the menu on mouse out
775 section.onmouseout = function(e)
776 {
777 if(this.menu){this.menu.style.display = "none";}
778 this.style.background = "none";
779 };
780}
781
782function createDraggableNewSection(parent)
783{
784 var newSecLI = document.createElement("LI");
785 var newSpan = document.createElement("SPAN");
786 newSpan.innerHTML = "Insert new section ";
787
788 newSecLI.sectionTitle = newSpan;
789 newSecLI.appendChild(newSpan);
790 newSecLI.setAttribute("class", "dragItem newSection");
791 newSecLI.newSection = true;
792 newSecLI.parent = parent;
793 newSecLI.index = -1;
794 new YAHOO.example.DDList(newSecLI);
795 parent.appendChild(newSecLI);
796}
797
798function closeAllOpenContents()
799{
800 for(var i = 0; i < _allContents.length; i++)
801 {
802 if(isExpanded(_allContents[i].textDiv))
803 {
804 toggleTextDiv(_allContents[i]);
805 }
806 }
807 DDM.refreshCache();
808}
809
810//Status Bar class (initialised with new StatusBar(elem);)
811function StatusBar(mainElem)
812{
813 var _statusMap = new Array();
814 var _statusIDCounter = 0;
815 var _mainElem = mainElem;
816 var _activeMessages = 0;
817
818 _mainElem.style.display = "none";
819
820 this.addStatus = function(newStatus)
821 {
822 _mainElem.style.display = "block";
823 var newStatusDiv = document.createElement("DIV");
824 var newStatusSpan = document.createElement("SPAN");
825
826 var workingImage = document.createElement("IMG");
827 workingImage.setAttribute("src", gs.imageURLs.loading);
828 workingImage.setAttribute("height", "16px");
829 workingImage.setAttribute("width", "16px");
830 newStatusDiv.appendChild(workingImage);
831
832 newStatusDiv.appendChild(newStatusSpan);
833 newStatusSpan.innerHTML = " " + newStatus;
834 newStatusDiv.setAttribute("class", "statusMessage");
835 newStatusDiv.span = newStatusSpan;
836
837 _mainElem.appendChild(newStatusDiv);
838 _statusMap["status" + _statusIDCounter] = newStatusDiv;
839 _activeMessages++;
840 return _statusIDCounter++;
841 }
842
843 this.changeStatus = function(id, newStatus)
844 {
845 if(_statusMap["status" + id])
846 {
847 _statusMap["status" + id].span.innerHTML = " " + newStatus;
848 }
849 }
850
851 this.removeStatus = function(id)
852 {
853 if(_statusMap["status" + id])
854 {
855 removeFromParent(_statusMap["status" + id]);
856
857 if(--_activeMessages == 0)
858 {
859 _mainElem.style.display = "none";
860 }
861 }
862 }
863}
864
865/*
866function toggleEdit(e)
867{
868 var mousePos = de.events.getXYInWindowFromEvent(e);
869 var cDesc = de.cursor.getCursorDescAtXY(mousePos.x, mousePos.y, de.events.getEventTarget(e));
870 de.cursor.setCursor(cDesc);
871}
872*/
Note: See TracBrowser for help on using the repository browser.