eggification
[MosaicDocument.git] / Products / MosaicDocument / default_blocks / tree_block_script.js
diff --git a/Products/MosaicDocument/default_blocks/tree_block_script.js b/Products/MosaicDocument/default_blocks/tree_block_script.js
new file mode 100644 (file)
index 0000000..d115432
--- /dev/null
@@ -0,0 +1,280 @@
+// (c) BenoĆ®t PIN 2006 
+// http://plinn.org
+// Licence GPL
+
+var TreeMaker;
+
+(function() {
+/* root -> base node (typically a tbody or a table)
+*  filter -> comma separated list of portal_types 
+*/
+TreeMaker = function (root, filter, baseImgUrl) {
+       this.root = root;
+       var tm = this;
+       this.root.onclick = function(evt) { tm.refreshTree(evt); };
+       this.filter = filter;
+       this.baseImgUrl = baseImgUrl;
+       this.depthCpt = new Array();
+       this._lastAniImg = null;
+       
+       // preload images
+       var images = ['pl.png', 'pl_ani.png', 'mi.png', 'mi_ani.png'], img;
+       for (var i=0 ; i < images.length ; i++) {
+               img = new Image();
+               img.src = this.baseImgUrl + images[i];
+       }
+}
+
+/*
+* expand / collapse handler
+* object loading trigger
+*/
+TreeMaker.prototype.refreshTree = function (evt) {
+       var target = getTargetedObject(evt);
+       if (target.blur)
+               target.blur();
+
+       if (target.tagName == 'IMG') {
+               target.parentNode.blur();
+               var srcParts = target.src.split("/");
+               var imgId = srcParts[srcParts.length-1];
+               var parentTd = target.parentNode.parentNode;
+               var parentRow = parentTd.parentNode;
+               
+
+               switch (imgId) {
+                       case "pl.png" :
+                       case "pl_ani.png" :
+                               var linkCell = parentTd.nextSibling;
+                               while (linkCell.nodeType != 1)
+                                       linkCell = linkCell.nextSibling;
+
+                               var obUrl = linkCell.getElementsByTagName("A")[0].href;
+
+                               var req = new XMLHttpRequest();
+                               var tm = this;
+                               req.onreadystatechange = function() {
+                                       switch (req.readyState) {
+                                               case 1:
+                                                       showProgressImage();
+                                                       break;
+                                               case 4:
+                                                       hideProgressImage();
+                                                       tm.importRows(req, parentRow);
+                                       };
+                               };
+                               target.src = this.baseImgUrl + "mi_ani.png";
+                               this._lastAniImg = target;
+                               window.setTimeout(function(){tm._removeLastAniImg();}, 500);
+
+                               req.open("POST", obUrl + "/xml_nav_tree", true);
+                               req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
+                               req.send("filter=" + encodeURIComponent(this.filter) +
+                                                "&root_name=" + encodeURIComponent(this.root.id) +
+                                                "&expansion=" + encodeURIComponent(this.getExpansion()));
+                               
+                               break;
+
+                       case "mi.png" :
+                       case "mi_ani.png" :
+                               this.removeChildNodes(parentRow);
+                               target.src = this.baseImgUrl + "pl_ani.png";
+                               this._lastAniImg = target;
+                               var tm = this;
+                               window.setTimeout(function(){tm._removeLastAniImg();}, 500);
+                               document.cookie = encodeURIComponent(this.root.id) + '-state=' + encodeURIComponent(this.getExpansion()) +
+                                                                 ';path=/';
+                               break;
+               } // end switch (imgId)
+               disableDefault(evt);
+               disablePropagation(evt);
+       }
+};
+
+
+TreeMaker.prototype._removeLastAniImg = function() {
+       if (this._lastAniImg) {
+               this._lastAniImg.src = this._lastAniImg.src.replace("_ani", "");
+       }
+};
+
+TreeMaker.prototype.getExpansion = function() {
+       var rows = this.root.getElementsByTagName('TR');
+       var row, cells, stateCell, button, expid, node_depth, last_depth = -1, dd, step;
+       var steps = new Array();
+       steps.push(this.root.getAttribute('name'));
+       
+       var expanded = (/.*mi\.png$|.*mi_ani\.png$/);
+       for(i=0 ; i < rows.length ; i++) {
+               row = rows[i];
+               cells = row.getElementsByTagName('TD');
+               stateCell = cells[cells.length-2]; // cell where the +/- button is
+               button = stateCell.getElementsByTagName('IMG');
+               if (! button.length)
+                       continue;
+               button = button[0];
+               if (expanded.test(button.src)) {
+                       expid = button.parentNode.getAttribute("name");
+                       node_depth = cells[0].getAttribute('colspan') || 0;
+                       dd = last_depth - node_depth + 1;
+                       last_depth = node_depth;
+                       if (dd > 0) {
+                               step = '';
+                               for (var j = 0 ;  j < dd ; j++)
+                                       step = step + '_';
+                               steps.push(step);
+                       }
+                       steps.push(expid);
+               }
+       }
+       return steps.join(':');
+};
+
+
+/*
+* expand the tree: sends request and imports rows based on xml response.
+*/
+TreeMaker.prototype.importRows = function(req, parentRow) {
+       var rows = req.responseXML.documentElement.getElementsByTagName("row");
+       var clickedCells = parentRow.getElementsByTagName("TD");
+       var row, newRow, indentCell, stateCell, linkCell, img, a, indentValue, colspan,
+               incTableDepth=false, cols, linkCellColSpan;
+       
+       for (var i = 0 ; i < rows.length ; i++ ) {
+               row = rows[i];
+               
+               
+               newRow = document.createElement("TR");
+               indentCell = document.createElement("TD");
+               stateCell = document.createElement("TD");
+               stateCell.width = "16";
+               linkCell = document.createElement("TD");
+               linkCell.width = "99%";
+
+
+               if (clickedCells.length == 3) {
+                       indentValue = parseInt(clickedCells[0].getAttribute("colspan"));
+                       colspan = parseInt(clickedCells[2].getAttribute("colspan"));
+               }
+               else {
+                       indentValue = 0;
+                       colspan = parseInt(clickedCells[1].getAttribute("colspan"));
+               }
+
+               cols = indentValue + colspan;
+
+               if (colspan == 1)
+               incTableDepth = true;
+
+       indentCell.colSpan =   indentValue + 1;
+       if (!this.depthCpt[indentValue])
+               this.depthCpt[indentValue] = 1;
+       else
+               this.depthCpt[indentValue] += 1;
+
+       // IE : it's not possible to set colSpan attr to 0 :-(((
+       linkCellColSpan = cols - indentValue - 1
+       if (linkCellColSpan == 0)
+               linkCell.nullColSpan = true;
+           else
+               linkCell.colSpan = linkCellColSpan;
+
+               img = document.createElement("IMG");
+               img.src = row.getAttribute("icon");
+               img.height = row.getAttribute("height");
+               img.width = row.getAttribute("width");
+               a = document.createElement("A");
+
+               a.setAttribute("href", row.getAttribute("url"));
+               a.setAttribute("title", row.getAttribute("description"));
+               a.innerHTML = row.childNodes[0].nodeValue;
+
+               if (row.getAttribute("state") == "-1") {
+                       var stateLink = document.createElement("A");
+                       stateLink.href = ".";
+                       stateLink.setAttribute("name", row.getAttribute("name"));
+                       var stateImg = document.createElement("IMG");
+                       stateImg.src = this.baseImgUrl + "pl.png";
+                       stateImg.border = "0";
+                       stateImg.height = "16";
+                       stateImg.width = "16";
+                       stateLink.appendChild(stateImg)
+                       stateCell.appendChild(stateLink);
+               }
+               else
+                       stateCell.innerHTML = "&nbsp;&nbsp;";
+               
+               linkCell.appendChild(img);
+               linkCell.appendChild(a);
+               newRow.appendChild(indentCell);
+               newRow.appendChild(stateCell);
+               newRow.appendChild(linkCell);
+               
+                               
+               this.root.insertBefore(newRow, parentRow.nextSibling);
+       } //end for
+       
+       if (incTableDepth) {
+               var rows = this.root.getElementsByTagName("TR");
+               var cells, lastCell, lastColspan;
+               for (var i = 0 ; i < rows.length ; i++) {
+                       cells = rows[i].getElementsByTagName("TD");
+                       lastCell = cells[cells.length - 1];
+
+                       if (lastCell.nullColSpan) {
+                               lastCell.nullColSpan = false;
+                               lastColspan = 0;
+                       }
+                       else 
+                               lastColspan = parseInt(lastCell.getAttribute("colspan"));
+
+                       lastCell.colSpan = lastColspan + 1;
+               }
+       }
+};
+
+/*
+* collapse the tree: removes deeper rows after the 'baseRow' passed.
+*/
+TreeMaker.prototype.removeChildNodes = function(baseRow) {
+       var baseCells = baseRow.getElementsByTagName("TD");
+       var baseColSpan = baseCells[baseCells.length-1].colSpan;
+       var nextRow = baseRow.nextSibling;
+       var tbody = baseRow.parentNode;
+       var depthCpt = this.depthCpt;
+       var nextCells, nextRow2;
+
+       while (nextRow) {
+               if (nextRow.nodeType == 1) {
+                       nextCells = nextRow.getElementsByTagName("TD");
+                       if (nextCells.length == 3 && nextCells[2].colSpan < baseColSpan) {
+                               nextRow2 = nextRow.nextSibling;
+                               depthCpt[nextCells[0].colSpan-1] -= 1;
+                               tbody.removeChild(nextRow);
+                               nextRow = nextRow2;
+                               continue;
+                       }
+                       break;
+               }
+               nextRow = nextRow.nextSibling; // text node
+       }
+       
+       // recalc colspans for Safari
+       var maxDepth = depthCpt.length - 1;
+       var depthReduction = 0;
+       while (depthCpt[maxDepth - depthReduction] == 0) {
+               depthCpt.pop();
+               depthReduction++;
+       }
+       
+       if (depthReduction) {
+               var rows = tbody.getElementsByTagName("TR");
+               var cells, lastCell, lastColspan;
+               for (var i = 0 ; i < rows.length ; i++) {
+                       cells = rows[i].getElementsByTagName("TD");
+                       lastCell = cells[cells.length - 1];
+                       lastCell.colSpan = parseInt(lastCell.colSpan) - depthReduction;
+               }
+       }
+};
+})();
\ No newline at end of file