customMetaTagsFunctions = new Object() customMetaTagsFunctions.getInputOrSelect = function(node) { /* Get the (first) input or select form element under the given node */ var inputs = node.getElementsByTagName("input"); if(inputs.length > 0) { return inputs[0]; } var selects = node.getElementsByTagName("select"); if(selects.length > 0) { return selects[0]; } return null; } customMetaTagsFunctions.getWidgetRows = function(currnode) { /* Return primary s of current node's parent DGW */ tbody = this.getParentElementById(currnode, "datagridwidget-tbody"); return this.getRows(tbody); } customMetaTagsFunctions.getRows = function(tbody) { /* Return rows of element */ var rows = new Array() child = tbody.firstChild; while(child != null) { if(child.tagName != null) { if(child.tagName.toLowerCase() == "tr") { rows = rows.concat(child); } } child = child.nextSibling; } return rows; } customMetaTagsFunctions.autoInsertRow = function(e) { /* Add a new row when changing the last row (i.e. the infamous auto insert feature) Check that if this onchange event handler was called from the last row. In this case, add a new row for DGF. */ var currnode = window.event ? window.event.srcElement : e.currentTarget; // fetch required data structure var tbody = this.getParentElement(currnode, "TBODY"); var rows = this.getRows(tbody); var lastRow = rows[rows.length-1]; var thisRow = this.getParentElementById(currnode, "datagridwidget-row"); /* Skip the very last row which is a hidden template row */ if(rows.length-1 ==(thisRow.rowIndex)) { // Create a new row var newtr = this.createNewRow(lastRow); // Put new row to DOM tree before template row lastRow.parentNode.insertBefore(newtr, lastRow); // update orderindex hidden fields this.updateOrderIndex(tbody); } } customMetaTagsFunctions.addRowAfter = function(currnode) { /* Creates a new row before the clicked row */ // fetch required data structure var tbody = this.getParentElementById(currnode, "datagridwidget-tbody"); var thisRow = this.getParentElementById(currnode, "datagridwidget-row"); var newtr = this.createNewRow(thisRow); thisRow.parentNode.insertBefore(newtr, thisRow); // update orderindex hidden fields this.updateOrderIndex(tbody); } customMetaTagsFunctions.addRow = function(id) { /* Explitcly add row for given DataGridField @param id Archetypes field id for the widget */ // fetch required data structure var tbody = document.getElementById("datagridwidget-tbody-" + id); var rows = this.getRows(tbody); var lastRow = rows[rows.length-1]; var oldRows = rows.length; // Create a new row var newtr = this.createNewRow(lastRow); // Put new row to DOM tree before template row newNode = lastRow.parentNode.insertBefore(newtr, lastRow); // update orderindex hidden fields this.updateOrderIndex(tbody); } customMetaTagsFunctions.createNewRow = function(tr) { /* Creates a new row @param tr A row in a table where we'll be adding the new row */ var tbody = this.getParentElementById(tr, "datagridwidget-tbody"); var rows = this.getRows(tbody); // hidden template row var lastRow = rows[rows.length-1]; var newtr = document.createElement("tr"); newtr.setAttribute("id", "datagridwidget-row"); newtr.setAttribute("class", "datagridwidget-row"); // clone template contents from the last row to the newly created row // HOX HOX HOX // If f****ng IE clones lastRow directly it doesn't work. // lastRow is in hidden state and no matter what you do it remains hidden. // i.e. overriding class doesn't bring it visible. // In Firefox everything worked like a charm. // So the code below is really a hack to satisfy Microsoft codeborgs. // keywords: IE javascript clone clonenode hidden element render visibility visual child = lastRow.firstChild; while(child != null) { newchild = child.cloneNode(true); newtr.appendChild(newchild); child = child.nextSibling; } return newtr; } customMetaTagsFunctions.removeFieldRow = function(node) { /* Remove the row in which the given node is found */ var row = this.getParentElementById(node, 'datagridwidget-row'); var tbody = this.getParentElementById(node, 'datagridwidget-tbody'); tbody.removeChild(row); } customMetaTagsFunctions.moveRowDown = function(currnode){ /* Move the given row down one */ var tbody = this.getParentElementById(currnode, "datagridwidget-tbody"); var rows = this.getWidgetRows(currnode); var row = this.getParentElementById(currnode, "datagridwidget-row"); if(row == null) { alert("Couldn't find DataGridWidget row"); return; } var idx = null // We can't use nextSibling because of blank text nodes in some browsers // Need to find the index of the row for(var t = 0; t < rows.length; t++) { if(rows[t] == row) { idx = t; break; } } // Abort if the current row wasn't found if(idx == null) return; // If this was the last row (before the blank row at the end used to create // new rows), move to the top, else move down one. if(idx + 2 == rows.length) { var nextRow = rows.item[0] this.shiftRow(row, nextRow) } else { var nextRow = rows[idx+1] this.shiftRow(nextRow, row) } this.updateOrderIndex(tbody) } customMetaTagsFunctions.moveRowUp = function(currnode){ /* Move the given row up one */ var tbody = this.getParentElementById(currnode, "datagridwidget-tbody"); var rows = this.getWidgetRows(currnode); var row = this.getParentElementById(currnode, "datagridwidget-row"); if(row == null) { alert("Couldn't find DataGridWidget row"); return; } var idx = null // We can't use nextSibling because of blank text nodes in some browsers // Need to find the index of the row for(var t = 0; t < rows.length; t++) { if(rows[t] == row) { idx = t; break; } } // Abort if the current row wasn't found if(idx == null) return; // If this was the first row, move to the end (i.e. before the blank row // at the end used to create new rows), else move up one if(idx == 0) { var previousRow = rows[rows.length - 1] this.shiftRow(row, previousRow); } else { var previousRow = rows[idx-1]; this.shiftRow(row, previousRow); } this.updateOrderIndex(tbody); } customMetaTagsFunctions.shiftRow = function(bottom, top){ /* Put node top before node bottom */ bottom.parentNode.insertBefore(bottom, top) } customMetaTagsFunctions.updateOrderIndex = function (tbody) { /* Update the hidden orderindex fields to be in the right order */ var xre = new RegExp(/^orderindex__/) var idx = 0; var cell; var rows = this.getRows(tbody); /* Make sure that updateOrderIndex doesn't touch the template (last) row */ for(var i=0; i updateOrderIndex -> updaterRadioButtonGroupName is triggered on Firefox, the value of checked radio button is put to the newly generated row instead of clicked row. */ var cell; var xre = new RegExp(/^radio/) var xre2 = new RegExp(/^checkbox/) for (var c = 0; (cell = row.getElementsByTagName('INPUT').item(c)); c++) { if(cell.getAttribute('type')) { var type = cell.getAttribute('type'); if (xre.exec(type) || xre2.exec(type)) { var name = cell.getAttribute("NAME") if(name == null) continue; // save fieldId + columnId part var baseLabel = name.substring(0, name.lastIndexOf(".")); // update per row running id cell.setAttribute("NAME", baseLabel + "." + newIndex); } } } } customMetaTagsFunctions.getParentElement = function(currnode, tagname) { /* Find the first parent node with the given tag name */ tagname = tagname.toUpperCase(); var parent = currnode.parentNode; while(parent.tagName.toUpperCase() != tagname) { parent = parent.parentNode; // Next line is a safety belt if(parent.tagName.toUpperCase() == "BODY") return null; } return parent; } customMetaTagsFunctions.getParentElementById = function(currnode, id) { /* Find the first parent node with the given id Id is partially matched: the beginning of an element id matches parameter id string. Currnode: Node where ascending in DOM tree beings Id: Id string to look for. */ id = id.toLowerCase(); var parent = currnode.parentNode; while(true) { var parentId = parent.getAttribute("id"); if(parentId != null) { if(parentId.toLowerCase().substring(0, id.length) == id) break; } parent = parent.parentNode; // Next line is a safety belt if(parent.tagName.toUpperCase() == "BODY") return null; } return parent; }