|
| 1 | +var MRVSUtils = Class.create(); |
| 2 | + |
| 3 | +// Default configuration for the MutationObserver |
| 4 | +MRVSUtils.OBSERVER_CONFIG = { |
| 5 | + subtree: true, |
| 6 | + childList: true |
| 7 | +}; |
| 8 | + |
| 9 | +MRVSUtils.prototype = { |
| 10 | + /* |
| 11 | + * initialise the MRVSUtils instance |
| 12 | + * @param {String} Name of multi-row variable set to watch |
| 13 | + */ |
| 14 | + initialize: function (mrvsName) { |
| 15 | + this.mrvsID = g_form.getControl(mrvsName).id; |
| 16 | + this.mrvsID = this.mrvsID.replace(/(.*:)/, ''); |
| 17 | + this.table = document.getElementById(this.mrvsID + "_table"); |
| 18 | + this.columnNames = this._getColumnNames(); |
| 19 | + this.rowIds_Old = []; |
| 20 | + this.rowIds = []; |
| 21 | + this.isUpdate = false; |
| 22 | + }, |
| 23 | + |
| 24 | + /* |
| 25 | + * Process all mutations from the observer |
| 26 | + * @param {MutationList} Array of all mutations observed |
| 27 | + * @returns {JSON} Array of updates |
| 28 | + */ |
| 29 | + processMutations: function (mutations) { |
| 30 | + this._updateRowIds(); |
| 31 | + var mutationList = this._filterEvents(mutations); |
| 32 | + return this._processMutation(mutationList[0]); |
| 33 | + }, |
| 34 | + |
| 35 | + /* |
| 36 | + * Get the table ID for the multi-row variable set |
| 37 | + * @return {string} (sys_id)_table |
| 38 | + */ |
| 39 | + getTableID: function () { |
| 40 | + return [this.mrvsID, "table"].join('_'); |
| 41 | + }, |
| 42 | + |
| 43 | + /* |
| 44 | + * get list of column names |
| 45 | + * used when building the modified data JSON |
| 46 | + */ |
| 47 | + _getColumnNames: function () { |
| 48 | + var columnNames = []; |
| 49 | + var headers = this.table.getElementsByTagName('th'); |
| 50 | + for (var _col = 0; _col < headers.length; _col++) { |
| 51 | + columnNames.push(headers[_col].innerText); |
| 52 | + } |
| 53 | + |
| 54 | + return columnNames; |
| 55 | + }, |
| 56 | + |
| 57 | + /* |
| 58 | + * re-scan the MRVS table to get an up to date list of rows |
| 59 | + */ |
| 60 | + _updateRowIds: function () { |
| 61 | + this.rowIds = []; |
| 62 | + var body = this.table.getElementsByTagName('tbody'); |
| 63 | + var rows = body[0].getElementsByTagName('tr'); |
| 64 | + for (var _row = 0; _row < rows.length; _row++) { |
| 65 | + this.rowIds.push(rows[_row].id); |
| 66 | + } |
| 67 | + }, |
| 68 | + |
| 69 | + /* |
| 70 | + * check if this is an mutation we care about |
| 71 | + * basically, if it's a update to TBODY and has either added or removed nodes, |
| 72 | + * or it's a updated row which should give us both added and removed for a single TD (however this is |
| 73 | + * not guaranteed if the original cell value was empty) |
| 74 | + */ |
| 75 | + _isUpdateEvent: function (mutation) { |
| 76 | + var isAddDelete = ((mutation.target.nodeName == 'TBODY' && mutation.target.id == 'empty_table_row') && |
| 77 | + ((mutation.removedNodes.length > 0 && mutation.removedNodes[0].className != 'list2_no_records') || |
| 78 | + (mutation.addedNodes.length > 0 && mutation.addedNodes[0].className != 'list2_no_records'))); |
| 79 | + var isUpdate = (mutation.target.nodeName == 'TD' && (mutation.removedNodes.length > 0 || mutation.addedNodes.length > 0)); |
| 80 | + return isAddDelete || isUpdate; |
| 81 | + }, |
| 82 | + |
| 83 | + /* |
| 84 | + * for the given node, get the cells contents |
| 85 | + */ |
| 86 | + _getCellData: function (node, rowIds) { |
| 87 | + var cellData = {}; |
| 88 | + var cells = node.cells; |
| 89 | + for (var i = 0; i < cells.length; i++) { |
| 90 | + if (cells[i].className == 'vt') cellData[this.columnNames[i]] = cells[i].innerText; |
| 91 | + } |
| 92 | + |
| 93 | + cellData.row_number = rowIds.indexOf(node.id) > -1 ? rowIds.indexOf(node.id) + 1 : undefined; |
| 94 | + cellData.row_id = node.id; |
| 95 | + return cellData; |
| 96 | + }, |
| 97 | + |
| 98 | + /* |
| 99 | + * process the given nodes (either added or deleted) and build the response using the cell data |
| 100 | + */ |
| 101 | + _getNodeData: function (nodes, rowIds) { |
| 102 | + var modifiedRows = []; |
| 103 | + nodes.forEach(function (_node, _index, _list) { |
| 104 | + modifiedRows.push(this._getCellData(_node, rowIds)); |
| 105 | + }, this); |
| 106 | + return modifiedRows; |
| 107 | + }, |
| 108 | + |
| 109 | + /* |
| 110 | + * given a mutation, build the JSON response depending on the mutation type |
| 111 | + */ |
| 112 | + _processMutation: function (mutation) { |
| 113 | + var modifiedData = {}; |
| 114 | + if (this.isUpdate) { // special handling as some updates only have a single event |
| 115 | + // this is a row update |
| 116 | + modifiedData.updated = this._getCellData(mutation.target.parentElement, this.rowIds); |
| 117 | + } else if (mutation.addedNodes.length && mutation.removedNodes.length == 0) { |
| 118 | + modifiedData.added = this._getNodeData(mutation.addedNodes, this.rowIds); |
| 119 | + } else { |
| 120 | + // pass in the old row_id list otherwise we won't know what row was release. |
| 121 | + modifiedData.removed = this._getNodeData(mutation.removedNodes, this.rowIds_Old); |
| 122 | + } |
| 123 | + |
| 124 | + this.rowIds_Old = this.rowIds; |
| 125 | + return modifiedData; |
| 126 | + }, |
| 127 | + |
| 128 | + /* |
| 129 | + * filter the mutation list for mutations we care about |
| 130 | + * If only one mutation is provided then it's assumed it's a row update (based on extensive testing!!) |
| 131 | + */ |
| 132 | + _filterEvents: function (mutationList) { |
| 133 | + this.isUpdate = false; |
| 134 | + if (mutationList.length > 1) { |
| 135 | + mutationList = mutationList.filter(function (_mutation) { |
| 136 | + return this._isUpdateEvent(_mutation); |
| 137 | + }, this); |
| 138 | + } else { |
| 139 | + this.isUpdate = (mutationList[0].addedNodes.length > 0 && mutationList[0].removedNodes.length > 0); |
| 140 | + } |
| 141 | + return mutationList; |
| 142 | + } |
| 143 | +}; |
0 commit comments