| Total Complexity | 108 | 
| Complexity/F | 3.09 | 
| Lines of Code | 369 | 
| Function Count | 35 | 
| Duplicated Lines | 0 | 
| Ratio | 0 % | 
| Changes | 62 | ||
| Bugs | 4 | Features | 1 | 
Complex classes like add/table.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | var TableHelper = { | 
            ||
| 2 |     BuildRequest: { | 
            ||
| 3 |         Sort: function (rq, strDesc){ | 
            ||
| 4 |             function sortBySpan(span, i){ | 
            ||
| 5 | var order = span.innerHTML;  | 
            ||
| 6 |                 if(order.length === 1){ | 
            ||
| 7 | rq.colNo = i;  | 
            ||
| 8 | rq.colOrd = order === strDesc ? "desc" : "asc";  | 
            ||
| 9 | }  | 
            ||
| 10 | return rq.colNo === i;  | 
            ||
| 11 | }  | 
            ||
| 12 | |||
| 13 | var thTags = document.getElementById(rq.tableId)  | 
            ||
| 14 |                     .getElementsByTagName("thead")[0] | 
            ||
| 15 |                     .getElementsByTagName("th"); | 
            ||
| 16 | var length = thTags.length;  | 
            ||
| 17 |             for(var i = 0; i < length; i++){ | 
            ||
| 18 |                 var link = thTags[i].getElementsByTagName("a")[0]; | 
            ||
| 19 |                 if(link){ | 
            ||
| 20 |                     var span = link.getElementsByTagName("span")[0]; | 
            ||
| 21 |                     if(span && sortBySpan(span, i)){ | 
            ||
| 22 | break;  | 
            ||
| 23 | }  | 
            ||
| 24 | }  | 
            ||
| 25 | }  | 
            ||
| 26 | },  | 
            ||
| 27 |     Filter: function (rq){ | 
            ||
| 28 |             function getFilterFieldsByTableID(tableID){ | 
            ||
| 29 |                 var fields = {filterBy: null, filter: null}; | 
            ||
| 30 | var filterDiv = getFilterDivByTableIDOrNull(tableID);  | 
            ||
| 31 |                 if(filterDiv !== null){ | 
            ||
| 32 | setFilterBy(fields, filterDiv);  | 
            ||
| 33 | setFilterValue(fields, filterDiv);  | 
            ||
| 34 | }  | 
            ||
| 35 | return fields;  | 
            ||
| 36 | }  | 
            ||
| 37 |             function getFilterDivByTableIDOrNull(tableID){ | 
            ||
| 38 | var res = null;  | 
            ||
| 39 |                 if(document.getElementById(tableID).parentNode.getElementsByTagName("div").length > 0){ | 
            ||
| 40 |                     for(var i = 0; i < document.getElementById(tableID).parentNode.getElementsByTagName("div").length; i++){ | 
            ||
| 41 |                         if(document.getElementById(tableID).parentNode.getElementsByTagName("div")[i].getAttribute("class") === "filter"){ | 
            ||
| 42 |                             return document.getElementById(tableID).parentNode.getElementsByTagName("div")[i]; | 
            ||
| 43 | }  | 
            ||
| 44 | }  | 
            ||
| 45 | |||
| 46 | }  | 
            ||
| 47 | return res;  | 
            ||
| 48 | }  | 
            ||
| 49 |             function setFilterBy(fields, filterDiv){ | 
            ||
| 50 |                 var slctObj = filterDiv.getElementsByTagName("select")[0]; | 
            ||
| 51 |                 if(slctObj && slctObj.options[slctObj.selectedIndex].value !== "all"){ | 
            ||
| 52 | fields.filterBy = slctObj.options[slctObj.selectedIndex].value;  | 
            ||
| 53 | }  | 
            ||
| 54 | }  | 
            ||
| 55 |             function setFilterValue(fields, filterDiv){ | 
            ||
| 56 |                 var textObj = filterDiv.getElementsByTagName("input")[0]; | 
            ||
| 57 |                 if(textObj && textObj.value && textObj.value.length !== 0){ | 
            ||
| 58 | fields.filter = encodeURIComponent(textObj.value.trim());  | 
            ||
| 59 | }  | 
            ||
| 60 | }  | 
            ||
| 61 | |||
| 62 | var r = getFilterFieldsByTableID(rq.tableId);  | 
            ||
| 63 |             if(r.filter !== null){ | 
            ||
| 64 | rq.filter = r.filter;  | 
            ||
| 65 | }  | 
            ||
| 66 |             if(r.filterBy !== null){ | 
            ||
| 67 | rq.filterBy = r.filterBy;  | 
            ||
| 68 | }  | 
            ||
| 69 | }  | 
            ||
| 70 | },  | 
            ||
| 71 |     ColumnHover: function(tableContainer, index){ | 
            ||
| 72 | var rows = document.getElementById(tableContainer).rows;  | 
            ||
| 73 | var upto = rows.length - 1;  | 
            ||
| 74 |         if(typeof index === "undefined"){ | 
            ||
| 75 | ColumnHoverRelease(rows, upto);  | 
            ||
| 76 |         } else { | 
            ||
| 77 |             for(var i = 0; i < upto; i++){ | 
            ||
| 78 |                 rows[i].cells[index].setAttribute("lang", "col-hover"); | 
            ||
| 79 | }  | 
            ||
| 80 | }  | 
            ||
| 81 |         function ColumnHoverRelease(rows, upto){ | 
            ||
| 82 |             for(var i = 0; i < upto; i++){ | 
            ||
| 83 |                 for(var j = 0; j < rows[i].cells.length; j++){ | 
            ||
| 84 |                     if(rows[i].cells[j].lang){ | 
            ||
| 85 |                         rows[i].cells[j].removeAttribute("lang"); | 
            ||
| 86 | }  | 
            ||
| 87 | }  | 
            ||
| 88 | }  | 
            ||
| 89 | };  | 
            ||
| 90 | },  | 
            ||
| 91 |     Draw: function(tableContainer, d, instance){ | 
            ||
| 92 | DrawSection(tableContainer, d.body);  | 
            ||
| 93 | DrawSection(tableContainer, d.footer, "tfoot");  | 
            ||
| 94 |         if(instance.rq !== null){ | 
            ||
| 95 | var hover = document.getElementById(instance.rq.tableId)  | 
            ||
| 96 |                         .getElementsByTagName("th")[instance.rq.colNo].lang; | 
            ||
| 97 |             if(hover){ | 
            ||
| 98 | instance.ColumnHover(tableContainer, instance.rq.colNo);  | 
            ||
| 99 | }  | 
            ||
| 100 | }  | 
            ||
| 101 | },  | 
            ||
| 102 |     DrawSection: function(tableContainer, dt, tSection){ | 
            ||
| 103 | var section = tSection === "tfoot" ? "tfoot" : "tbody";  | 
            ||
| 104 | var tSec = document.getElementById(tableContainer)  | 
            ||
| 105 | .getElementsByTagName(section)[0];  | 
            ||
| 106 | Clear(tSec, TableHelper.IePrior(9));  | 
            ||
| 107 |         for(var i = 0; i < dt.length; i++){ | 
            ||
| 108 | var row = dt[i];  | 
            ||
| 109 |             var tRow = document.createElement("tr"); | 
            ||
| 110 | Row(row, tRow);  | 
            ||
| 111 | tSec.appendChild(tRow);  | 
            ||
| 112 |             if(section === "tfoot"){ | 
            ||
| 113 | TableHelper.ProcessPaginationLinks(tSec);  | 
            ||
| 114 | }  | 
            ||
| 115 | }  | 
            ||
| 116 |         function Clear(tSection, iePrior9){ | 
            ||
| 117 |             if(iePrior9){ | 
            ||
| 118 |                 if(tSection.firstChild){ | 
            ||
| 119 |                     while(tSection.firstChild){ | 
            ||
| 120 | tSection.removeChild(tSection.firstChild);  | 
            ||
| 121 | }  | 
            ||
| 122 | }  | 
            ||
| 123 |             }else{ | 
            ||
| 124 | tSection.innerHTML = "";  | 
            ||
| 125 | }  | 
            ||
| 126 | }  | 
            ||
| 127 |         function Row(row, tRow){ | 
            ||
| 128 |             for(var cell in row){ | 
            ||
| 
                                                                                                    
                         1 ignored issue 
                            –
                            show
                         | 
                |||
| 129 |                 var tCell = document.createElement("td"); | 
            ||
| 130 |                 if(typeof row[cell] === "string" || typeof row[cell] === "number"){ | 
            ||
| 131 | tCell.innerHTML = row[cell];  | 
            ||
| 132 |                 }else if(typeof row[cell] === "object"){ | 
            ||
| 133 | RowCellFromObject(row, cell, tCell);  | 
            ||
| 134 | }  | 
            ||
| 135 | tRow.appendChild(tCell);  | 
            ||
| 136 | }  | 
            ||
| 137 | }  | 
            ||
| 138 |         function RowCellFromObject(row, cell, tCell){ | 
            ||
| 139 |             for(var attr in row[cell]){ | 
            ||
| 
                                                                                                    
                         1 ignored issue 
                            –
                            show
                         | 
                |||
| 140 |                 if(typeof row[cell][attr] === "string"){ | 
            ||
| 141 | tCell.innerHTML = row[cell][attr];  | 
            ||
| 142 |                 }else if(typeof row[cell][attr] === "object"){ | 
            ||
| 143 |                     for(var v in row[cell][attr]){ | 
            ||
| 
                                                                                                    
                         1 ignored issue 
                            –
                            show
                         | 
                |||
| 144 | tCell.setAttribute(v, row[cell][attr][v]);  | 
            ||
| 145 | }  | 
            ||
| 146 | }  | 
            ||
| 147 | }  | 
            ||
| 148 | }  | 
            ||
| 149 | },  | 
            ||
| 150 |     Filter: { | 
            ||
| 151 |         GetTableId: function(field){ | 
            ||
| 152 |             if(field.tagName.toLowerCase() !== "select"){ | 
            ||
| 153 |                 return field.getAttribute("data-table-id"); | 
            ||
| 154 | }  | 
            ||
| 155 |             var f = field.parentNode.parentNode.getElementsByTagName("input")[0]; | 
            ||
| 156 |             return '' === f.value ? null : f.getAttribute("data-table-id"); | 
            ||
| 157 | }  | 
            ||
| 158 | },  | 
            ||
| 159 |     Init: { | 
            ||
| 160 |         SetColumnsHoverEffect: function (tContainer, tableId){ | 
            ||
| 161 | var tHcells = tContainer.rows[0].cells;  | 
            ||
| 162 |             for(var i = 0; i < tHcells.length; i++){ | 
            ||
| 163 |                 if(tHcells[i].firstChild.tagName === "A"){ | 
            ||
| 164 |                     tHcells[i].firstChild.setAttribute("onmouseover", "table.ColumnHover('" + tableId + "'," + i + ");"); | 
            ||
| 165 |                     tHcells[i].firstChild.setAttribute("onmouseout", "table.ColumnHover('" + tableId + "');"); | 
            ||
| 166 | }  | 
            ||
| 167 | }  | 
            ||
| 168 | }  | 
            ||
| 169 | },  | 
            ||
| 170 |     GoPage: { | 
            ||
| 171 |         GetNo: function(lnk, tableId){ | 
            ||
| 172 | //check & serve pagination jump links  | 
            ||
| 173 | var jumpDir = lnk.innerHTML.trim().substr(0, 1);  | 
            ||
| 174 |             if(jumpDir === "+" || jumpDir === "-"){ | 
            ||
| 175 | var current = document.getElementById(tableId)  | 
            ||
| 176 |                                 .querySelector("tfoot .paging .a").innerHTML; | 
            ||
| 177 |                 var jump = lnk.innerHTML.replace("K", "000").replace("M", "000000000"); | 
            ||
| 178 | var jumpPage = (parseInt(current) + parseInt(jump));  | 
            ||
| 179 |                 lnk.parentNode.setAttribute("data-page", jumpPage); | 
            ||
| 180 | lnk.style.transform = "none";  | 
            ||
| 181 | }  | 
            ||
| 182 |             return lnk.parentNode.hasAttribute("data-page") ? | 
            ||
| 183 |                     lnk.parentNode.getAttribute("data-page") : | 
            ||
| 184 | lnk.innerHTML;  | 
            ||
| 185 | }  | 
            ||
| 186 | },  | 
            ||
| 187 |     LoadData: { | 
            ||
| 188 |         SetVisability: function(tableContainer, flag){ | 
            ||
| 189 | var tbl = document.getElementById(tableContainer);  | 
            ||
| 190 |             if(flag === true){ | 
            ||
| 191 | tbl.style.filter = "none";  | 
            ||
| 192 | tbl.style.opacity = "1";  | 
            ||
| 193 | tbl.style.cursor = "auto";  | 
            ||
| 194 |             }else if(flag === false){ | 
            ||
| 195 | tbl.style.filter = "blur(1px)";  | 
            ||
| 196 | tbl.style.opacity = "0.8";  | 
            ||
| 197 | tbl.style.cursor = "wait";  | 
            ||
| 198 |             }else{ | 
            ||
| 199 |                 console.error("table error in the flag value"); | 
            ||
| 200 | }  | 
            ||
| 201 | }  | 
            ||
| 202 | },  | 
            ||
| 203 | |||
| 204 |     IePrior: function(v){ | 
            ||
| 205 | var rv = false;  | 
            ||
| 206 |         if(window.navigator.appName === 'Microsoft Internet Explorer'){ | 
            ||
| 207 | var ua = window.navigator.userAgent;  | 
            ||
| 208 |             var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})"); | 
            ||
| 209 |             if(re.exec(ua) !== null){ | 
            ||
| 210 | rv = parseFloat(RegExp.$1);  | 
            ||
| 211 | }  | 
            ||
| 212 | rv = rv < v ? true : false;  | 
            ||
| 213 | }  | 
            ||
| 214 | return rv;  | 
            ||
| 215 | },  | 
            ||
| 216 |     GetParent: function(obj, objType){ | 
            ||
| 217 |         while(obj && obj.tagName !== objType.toUpperCase()){ | 
            ||
| 218 | obj = obj.parentNode;  | 
            ||
| 219 | }  | 
            ||
| 220 | return obj;  | 
            ||
| 221 | },  | 
            ||
| 222 |     ProcessPaginationLinks: function(tfoot){ | 
            ||
| 223 |         var pLinks = tfoot.querySelectorAll(".paging a"); | 
            ||
| 224 |         if(pLinks.length > 0){ | 
            ||
| 225 |             for(var j = 0; j < pLinks.length; j++){ | 
            ||
| 226 |                 pLinks[j].setAttribute("href", "javascript:void(0);"); | 
            ||
| 227 |                 pLinks[j].setAttribute("onclick", "return table.GoPage(this);"); | 
            ||
| 228 | }  | 
            ||
| 229 | }  | 
            ||
| 230 | },  | 
            ||
| 231 |     RequestToUrl: function(rq){ | 
            ||
| 232 | var url = location.pathname + ".json" + location.search;  | 
            ||
| 233 |         if(typeof rq === "object"){ | 
            ||
| 234 |             var getUrlVarName = { | 
            ||
| 235 | colNo: "col", colOrd: "ord", filter: "filter",  | 
            ||
| 236 | filterBy: "filter-by", pageNo: "pg", exportType: "export",  | 
            ||
| 237 | tableId: "table-id"  | 
            ||
| 238 | };  | 
            ||
| 239 | var flagFirst = location.search.length < 1 ? true : false;  | 
            ||
| 240 |             for(var r in rq){ | 
            ||
| 
                                                                                                    
                         1 ignored issue 
                            –
                            show
                         | 
                |||
| 241 | var clue = flagFirst === true ? "?" : "&";  | 
            ||
| 242 | url += clue + getUrlVarName[r] + "=" + rq[r];  | 
            ||
| 243 | flagFirst = false;  | 
            ||
| 244 | }  | 
            ||
| 245 | }  | 
            ||
| 246 | return url;  | 
            ||
| 247 | }  | 
            ||
| 248 | };  | 
            ||
| 249 | |||
| 250 | //https://addyosmani.com/resources/essentialjsdesignpatterns/book/#singletonpatternjavascript  | 
            ||
| 251 | var TableSingleton = (function(){ | 
            ||
| 252 | // Instance stores a reference to the Singleton  | 
            ||
| 253 | var instance;  | 
            ||
| 254 |     function initInstance(){ | 
            ||
| 255 | // Singleton  | 
            ||
| 256 | // Private methods and variables  | 
            ||
| 257 |         function BuildRequest(rq, crntTableId, strDesc){ | 
            ||
| 258 | rq.tableId = crntTableId;  | 
            ||
| 259 | TableHelper.BuildRequest.Sort(rq, strDesc);  | 
            ||
| 260 | TableHelper.BuildRequest.Filter(rq);  | 
            ||
| 261 | };  | 
            ||
| 262 | var tail = null;  | 
            ||
| 263 |         function LoadData(tableContainer, rq){ | 
            ||
| 264 |             if(tail!==null){ tail.abort();} | 
            ||
| 265 | TableHelper.LoadData.SetVisability(tableContainer, false);  | 
            ||
| 266 | var xmlhttp = window.XMLHttpRequest ?  | 
            ||
| 267 | new XMLHttpRequest() : /* code for IE7+, Firefox, Chrome, Opera, Safari */  | 
            ||
| 268 |                             new window.ActiveXObject("Microsoft.XMLHTTP");/*code for IE6, IE5 */ | 
            ||
| 269 |             xmlhttp.onreadystatechange = function(){ | 
            ||
| 270 |                 if(xmlhttp.readyState === 4 && xmlhttp.status === 200){ | 
            ||
| 271 | var d = JSON.parse(xmlhttp.responseText);  | 
            ||
| 272 | TableHelper.Draw(tableContainer, d, instance);  | 
            ||
| 273 | TableHelper.LoadData.SetVisability(tableContainer, true);  | 
            ||
| 274 | instance.LoadEndCalback(tableContainer);  | 
            ||
| 275 | }  | 
            ||
| 276 | };  | 
            ||
| 277 |             xmlhttp.open("GET", RequestToUrl(rq), true); | 
            ||
| 278 | xmlhttp.send();  | 
            ||
| 279 | tail = xmlhttp; //put at tail to can abort later any previous  | 
            ||
| 280 | }  | 
            ||
| 281 |         function ReloadData(tableId){ | 
            ||
| 282 |             var request = {}; | 
            ||
| 283 | BuildRequest(request, tableId, this.strDesc);  | 
            ||
| 284 | LoadData(tableId, request);  | 
            ||
| 285 | }  | 
            ||
| 286 | |||
| 287 | var GoPageGetNo = TableHelper.GoPage.GetNo;  | 
            ||
| 288 | var getParent = TableHelper.GetParent;  | 
            ||
| 289 | var RequestToUrl = TableHelper.RequestToUrl;  | 
            ||
| 290 | |||
| 291 |         return { | 
            ||
| 292 | rq: null,  | 
            ||
| 293 | strAsc: String.fromCharCode(9650), //▲  | 
            ||
| 294 | strDesc: String.fromCharCode(9660),//▼  | 
            ||
| 295 | ColumnHover: TableHelper.ColumnHover, //function(tableContainer, index)  | 
            ||
| 296 |             Export: function(lnk, eType){ | 
            ||
| 297 |                 var request = {}; | 
            ||
| 298 |                 var crntTableId = getParent(lnk, "table").getAttribute("id"); | 
            ||
| 299 | BuildRequest(request, crntTableId, this.strDesc);  | 
            ||
| 300 | request.exportType = ["CSV", "Excel"].indexOf(eType) >= 0 ?  | 
            ||
| 301 | eType :  | 
            ||
| 302 | "csv";  | 
            ||
| 303 | window.open(RequestToUrl(request));  | 
            ||
| 304 | return false;  | 
            ||
| 305 | },  | 
            ||
| 306 |             Filter: function(field){ | 
            ||
| 307 | var crntTableId = TableHelper.Filter.GetTableId(field);  | 
            ||
| 308 |                 if(crntTableId !== null){ | 
            ||
| 309 |                     var request = {}; | 
            ||
| 310 | var exRq = this.rq;  | 
            ||
| 311 | BuildRequest(request, crntTableId, this.strDesc);  | 
            ||
| 312 | if(exRq === null ||  | 
            ||
| 313 | request.filter !== exRq.filter ||  | 
            ||
| 314 | request.filterBy !== exRq.filterBy  | 
            ||
| 315 |                     ){ | 
            ||
| 316 | LoadData(crntTableId, request);  | 
            ||
| 317 | }  | 
            ||
| 318 | }  | 
            ||
| 319 | },  | 
            ||
| 320 |             GoPage: function(lnk){ | 
            ||
| 321 |                 var request = {}; | 
            ||
| 322 |                 var crntTableId = getParent(lnk, "table").getAttribute("id"); | 
            ||
| 323 | BuildRequest(request, crntTableId, this.strDesc);  | 
            ||
| 324 | request.pageNo = GoPageGetNo(lnk, crntTableId);  | 
            ||
| 325 | LoadData(crntTableId, request);  | 
            ||
| 326 | return false;  | 
            ||
| 327 | },  | 
            ||
| 328 |             init: function (tableId){ | 
            ||
| 329 | var tContainer = document.getElementById(tableId);  | 
            ||
| 330 |                 if(!TableHelper.IePrior(9)){ | 
            ||
| 331 | TableHelper.Init.SetColumnsHoverEffect(tContainer, tableId);  | 
            ||
| 332 | }  | 
            ||
| 333 |                 var tfoot = tContainer.getElementsByTagName("tfoot")[0]; | 
            ||
| 334 | TableHelper.ProcessPaginationLinks(tfoot);  | 
            ||
| 335 | },  | 
            ||
| 336 |             LoadEndCalback: function(){},/*Allows override: function(tableId){if(tableId){...}}*/ | 
            ||
| 337 | ReloadData: ReloadData,  | 
            ||
| 338 |             Sort: function(colNo, lnk){ | 
            ||
| 339 |                 var request = {}; | 
            ||
| 340 |                 var crntTableId = getParent(lnk, "table").getAttribute("id"); | 
            ||
| 341 | BuildRequest(request, crntTableId, this.strDesc);  | 
            ||
| 342 |                 if(Math.round(colNo) === request.colNo){ | 
            ||
| 343 | request.colOrd = (request.colOrd === "asc" ? "desc" : "asc");  | 
            ||
| 344 |                 }else{ | 
            ||
| 345 | request.colNo = Math.round(colNo);  | 
            ||
| 346 | request.colOrd = "asc";  | 
            ||
| 347 | }  | 
            ||
| 348 | LoadData(crntTableId, request);  | 
            ||
| 349 | /* Clear and add new sort arrow */  | 
            ||
| 350 |                 var headSpans = getParent(lnk, "thead").getElementsByTagName("span"); | 
            ||
| 351 | var length = headSpans.length;  | 
            ||
| 352 |                 for(var i = 0; i < length; i++){ | 
            ||
| 353 | headSpans[i].innerHTML = "";  | 
            ||
| 354 | }  | 
            ||
| 355 |                 lnk.getElementsByTagName("span")[0].innerHTML = (request.colOrd === "desc" ? this.strDesc : this.strAsc); | 
            ||
| 356 | }  | 
            ||
| 357 | };  | 
            ||
| 358 | }  | 
            ||
| 359 |     return { | 
            ||
| 360 | //Get the Singleton instance if one exists, or create one if it doesn't  | 
            ||
| 361 |         getInstance: function(){ | 
            ||
| 362 |             if(!instance){ | 
            ||
| 363 | instance = initInstance();  | 
            ||
| 364 | }  | 
            ||
| 365 | return instance;  | 
            ||
| 366 | }  | 
            ||
| 367 | };  | 
            ||
| 368 | })();  | 
            ||
| 369 | var table = TableSingleton.getInstance();  | 
            ||
| 370 | 
When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically: