Passed
Branchmaster (a353d4)
by Plamen
01:26
created

add/table.js   F

Complexity

Total Complexity 110
Complexity/F 3.06

Size

Lines of Code 366
Function Count 36

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 50
Bugs 4 Features 1
Metric Value
cc 0
eloc 264
c 50
b 4
f 1
nc 1
dl 0
loc 366
rs 2
wmc 110
mnd 4
bc 95
fnc 36
bpm 2.6387
cpm 3.0555
noi 4

19 Functions

Rating   Name   Duplication   Size   Complexity  
A TableSingleton.getInstance 0 6 2
A table.js ➔ TableHelperProcessPaginationLinks 0 9 3
A table.js ➔ TableHelperColumnHoverRelease 0 9 4
A table.js ➔ TableHelperSetVisability 0 14 3
A table.js ➔ TableHelperBuildRequest_Filter 0 43 3
A table.js ➔ TableHelperBuildRequest 0 5 1
A table.js ➔ TableHelperColumnHover 0 11 3
A table.js ➔ TableHelperBuildRequest_Sort 0 24 5
A table.js ➔ TableHelperGetParent 0 6 3
B TableSingleton.constructor 0 134 1
A table.js ➔ TableHelperGoPageGetNo 0 15 4
A table.js ➔ TableHelperFilterGetTableId 0 7 3
B table.js ➔ initInstance 0 121 1
A table.js ➔ TableHelperIePrior 0 12 4
A table.js ➔ TableHelperRequestToUrl 0 17 5
A table.js ➔ TableHelperDraw_Section 0 15 4
A table.js ➔ TableHelperDraw_SectionRowCellFromObject 0 11 5
A table.js ➔ TableHelperDraw_SectionRow 0 11 5
A table.js ➔ TableHelperDraw_SectionClear 0 11 4

How to fix   Complexity   

Complexity

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 TableInitSetColumnsHoverEffect = function(tContainer, tableId){
2
    var tHcells = tContainer.rows[0].cells;
3
    for(var i = 0; i < tHcells.length; i++){
4
        if(tHcells[i].firstChild.tagName === "A"){
5
            tHcells[i].firstChild.setAttribute("onmouseover", "table.ColumnHover('" + tableId + "'," + i + ");");
6
            tHcells[i].firstChild.setAttribute("onmouseout", "table.ColumnHover('" + tableId + "');");
7
        }
8
    }
9
};
10
var TableHelperBuildRequest = function(rq, crntTableId, strDesc){
11
    rq.tableId = crntTableId;
12
    TableHelperBuildRequest_Sort(rq, strDesc);
13
    TableHelperBuildRequest_Filter(rq);
14
};
15
var TableHelperBuildRequest_Sort = function(rq, strDesc){
16
    function sortBySpan(span, i){
17
        var order = span.innerHTML;
18
        if(order.length === 1){
19
            rq.colNo = i;
20
            rq.colOrd = order === strDesc ? "desc" : "asc";
21
        }
22
        return rq.colNo === i;
23
    }
24
    
25
    var thTags = document.getElementById(rq.tableId)
26
            .getElementsByTagName("thead")[0]
27
            .getElementsByTagName("th");
28
    var length = thTags.length;
29
    for(var i = 0; i < length; i++){
30
        var link = thTags[i].getElementsByTagName("a")[0];
31
        if(link){
32
            var span = link.getElementsByTagName("span")[0];
33
            if(span && sortBySpan(span, i)){
34
                break;
35
            }
36
        }
37
    }
38
};
39
var TableHelperBuildRequest_Filter = function(rq){
40
    function getFilterFieldsByTableID(tableID){
41
        var fields = {filterBy: null, filter: null};
42
        var filterDiv = getFilterDivByTableIDOrNull(tableID);
43
        if(filterDiv !== null){
44
            setFilterBy(fields, filterDiv);
45
            setFilterValue(fields, filterDiv);
46
        }
47
        return fields;
48
    }
49
    function getFilterDivByTableIDOrNull(tableID){
50
        var res = null;
51
        if(document.getElementById(tableID).parentNode.getElementsByTagName("div").length > 0){
52
            for(var i = 0; i < document.getElementById(tableID).parentNode.getElementsByTagName("div").length; i++){
53
                if(document.getElementById(tableID).parentNode.getElementsByTagName("div")[i].getAttribute("class") === "filter"){
54
                    return document.getElementById(tableID).parentNode.getElementsByTagName("div")[i];
55
                }
56
            }
57
58
        }
59
        return res;
60
    }
61
    function setFilterBy(fields, filterDiv){
62
        var slctObj = filterDiv.getElementsByTagName("select")[0];
63
        if(slctObj && slctObj.options[slctObj.selectedIndex].value !== "all"){
64
            fields.filterBy = slctObj.options[slctObj.selectedIndex].value;
65
        }
66
    }
67
    function setFilterValue(fields, filterDiv){
68
        var textObj = filterDiv.getElementsByTagName("input")[0];
69
        if(textObj && textObj.value && textObj.value.length !== 0){
70
            fields.filter = encodeURIComponent(textObj.value.trim());
71
        }
72
    }
73
74
    var r = getFilterFieldsByTableID(rq.tableId);
75
    if(r.filter !== null){
76
        rq.filter = r.filter;
77
    }
78
    if(r.filterBy !== null){
79
        rq.filterBy = r.filterBy;
80
    }
81
};
82
var TableHelperColumnHover = function(tableContainer, index){
83
    var rows = document.getElementById(tableContainer).rows;
84
    var upto = rows.length - 1;
85
    if(typeof index === "undefined"){
86
        TableHelperColumnHoverRelease(rows, upto);
87
    } else {
88
        for(var i = 0; i < upto; i++){
89
            rows[i].cells[index].setAttribute("lang", "col-hover");
90
        }
91
    }
92
};
93
var TableHelperColumnHoverRelease = function(rows, upto){
94
    for(var i = 0; i < upto; i++){
95
        for(var j = 0; j < rows[i].cells.length; j++){
96
            if(rows[i].cells[j].lang){
97
                rows[i].cells[j].removeAttribute("lang");
98
            }
99
        }
100
    }
101
};
102
var TableHelperSetVisability = function(tableContainer, flag){
103
    var tbl = document.getElementById(tableContainer);
104
    if(flag === true){
105
        tbl.style.filter = "none";
106
        tbl.style.opacity = "1";
107
        tbl.style.cursor = "auto";
108
    }else if(flag === false){
109
        tbl.style.filter = "blur(1px)";
110
        tbl.style.opacity = "0.8";
111
        tbl.style.cursor = "wait";
112
    }else{
113
        console.error("table error in the flag value");
114
    }
115
};
116
var TableHelperProcessPaginationLinks = function(tfoot){
117
    var pLinks = tfoot.querySelectorAll(".paging a");
118
    if(pLinks.length > 0){
119
        for(var j = 0; j < pLinks.length; j++){
120
            pLinks[j].setAttribute("href", "javascript:void(0);");
121
            pLinks[j].setAttribute("onclick", "return table.GoPage(this);");
122
        }
123
    }
124
};
125
var TableHelperGoPageGetNo = function(lnk, tableId){
126
    //check & serve pagination jump links
127
    var jumpDir = lnk.innerHTML.trim().substr(0, 1);
128
    if(jumpDir === "+" || jumpDir === "-"){
129
        var current = document.getElementById(tableId)
130
                        .querySelector("tfoot .paging .a").innerHTML;
131
        var jump = lnk.innerHTML.replace("K", "000").replace("M", "000000000");
132
        var jumpPage = (parseInt(current) + parseInt(jump));
133
        lnk.parentNode.setAttribute("data-page", jumpPage);
134
        lnk.style.transform = "none";
135
    }
136
    return lnk.parentNode.hasAttribute("data-page") ?
137
            lnk.parentNode.getAttribute("data-page") :
138
            lnk.innerHTML;
139
};
140
var TableHelperIePrior = function(v){
141
    var rv = false;
142
    if(window.navigator.appName === 'Microsoft Internet Explorer'){
143
        var ua = window.navigator.userAgent;
144
        var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
145
        if(re.exec(ua) !== null){
146
            rv = parseFloat(RegExp.$1);
147
        }
148
        rv = rv < v ? true : false;
149
    }
150
    return rv;
151
};
152
var TableHelperRequestToUrl = function(rq){
153
    var url = location.pathname + ".json" + location.search;
154
    if(typeof rq === "object"){
155
        var getUrlVarName = {
156
            colNo: "col", colOrd: "ord", filter: "filter",
157
            filterBy: "filter-by", pageNo: "pg", exportType: "export",
158
            tableId: "table-id"
159
        };
160
        var flagFirst = location.search.length < 1 ? true : false;
161
        for(var r in rq){
1 ignored issue
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

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:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
162
            var clue = flagFirst === true ? "?" : "&";
163
            url += clue + getUrlVarName[r] + "=" + rq[r];
164
            flagFirst = false;
165
        }
166
    }
167
    return url;
168
};
169
var TableHelperGetParent = function(obj, objType){
170
    while(obj && obj.tagName !== objType.toUpperCase()){
171
        obj = obj.parentNode;
172
    }
173
    return obj;
174
};
175
var TableHelperFilterGetTableId = function(field){
176
    if(field.tagName.toLowerCase() !== "select"){
177
        return field.getAttribute("data-table-id");
178
    }
179
    var f = field.parentNode.parentNode.getElementsByTagName("input")[0];
180
    return '' === f.value ? null : f.getAttribute("data-table-id");
181
};
182
var TableHelperDraw_Section = function(tableContainer, dt, tSection){
183
    var section = tSection === "tfoot" ? "tfoot" : "tbody";
184
    var tSec = document.getElementById(tableContainer)
185
                .getElementsByTagName(section)[0];
186
    TableHelperDraw_SectionClear(tSec, TableHelperIePrior(9));
187
    for(var i = 0; i < dt.length; i++){
188
        var row = dt[i];
189
        var tRow = document.createElement("tr");
190
        TableHelperDraw_SectionRow(row, tRow);
191
        tSec.appendChild(tRow);
192
        if(section === "tfoot"){
193
            TableHelperProcessPaginationLinks(tSec);
194
        }
195
    }
196
};
197
var TableHelperDraw_SectionClear = function(tSection, iePrior9){
198
    if(iePrior9){
199
        if(tSection.firstChild){
200
            while(tSection.firstChild){
201
                tSection.removeChild(tSection.firstChild);
202
            }
203
        }
204
    }else{
205
        tSection.innerHTML = "";
206
    }
207
};
208
var TableHelperDraw_SectionRow = function(row, tRow){
209
    for(var cell in row){
1 ignored issue
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

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:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
210
        var tCell = document.createElement("td");
211
        if(typeof row[cell] === "string" || typeof row[cell] === "number"){
212
            tCell.innerHTML = row[cell];
213
        }else if(typeof row[cell] === "object"){
214
            TableHelperDraw_SectionRowCellFromObject(row, cell, tCell);
215
        }
216
        tRow.appendChild(tCell);
217
    }
218
};
219
var TableHelperDraw_SectionRowCellFromObject = function(row, cell, tCell){
220
    for(var attr in row[cell]){
1 ignored issue
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

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:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
221
        if(typeof row[cell][attr] === "string"){
222
            tCell.innerHTML = row[cell][attr];
223
        }else if(typeof row[cell][attr] === "object"){
224
            for(var v in row[cell][attr]){
1 ignored issue
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

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:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
225
                tCell.setAttribute(v, row[cell][attr][v]);
226
            }
227
        }
228
    }
229
};
230
231
//https://addyosmani.com/resources/essentialjsdesignpatterns/book/#singletonpatternjavascript
232
var TableSingleton = (function(){
233
    // Instance stores a reference to the Singleton
234
    var instance;
235
    function initInstance(){
236
        // Singleton
237
        // Private methods and variables
238
        var tail = null;
239
        function LoadData(tableContainer, rq){
240
            TableHelperSetVisability(tableContainer, false);
241
            if(window.XMLHttpRequest){
242
                var xmlhttp = new XMLHttpRequest();/* code for IE7+, Firefox, Chrome, Opera, Safari */
243
            }else{ 
244
                xmlhttp = new window.ActiveXObject("Microsoft.XMLHTTP");/*code for IE6, IE5 */
245
            }
246
            if(tail!==null){
247
                tail.abort();
248
            }
249
            xmlhttp.onreadystatechange = function(){
250
                if(xmlhttp.readyState === 4 && xmlhttp.status === 200){
251
                    Draw(tableContainer, JSON.parse(xmlhttp.responseText));
252
                    TableHelperSetVisability(tableContainer, true);
253
                    instance.LoadEndCalback(tableContainer);
254
                }
255
            };
256
            xmlhttp.open("GET", RequestToUrl(rq), true);
257
            xmlhttp.send();
258
            tail = xmlhttp; //put at tail to can abort later any previous
259
        }
260
        function Init(tableId){
261
            var tContainer = document.getElementById(tableId);
262
            if(iePrior(9)){
263
                TableInitSetColumnsHoverEffect(tContainer, tableId);
264
            }
265
            var tfoot = tContainer.getElementsByTagName("tfoot")[0];
266
            TableHelperProcessPaginationLinks(tfoot);
267
        }
268
        function Draw(tableContainer, d){
269
            TableHelperDraw_Section(tableContainer, d.body);
270
            TableHelperDraw_Section(tableContainer, d.footer, "tfoot");
271
            if(instance.rq !== null){
272
                var hover = document.getElementById(instance.rq.tableId)
273
                            .getElementsByTagName("th")[instance.rq.colNo].lang;
274
                if(hover){
275
                    instance.ColumnHover(tableContainer, instance.rq.colNo);
276
                }
277
            }
278
        }
279
280
        var BuildRequest = TableHelperBuildRequest;
281
        var FilterGetTableId = TableHelperFilterGetTableId;
282
        var GoPageGetNo = TableHelperGoPageGetNo;
283
        var getParent = TableHelperGetParent;
284
        var iePrior = TableHelperIePrior;
285
        var RequestToUrl = TableHelperRequestToUrl;
286
287
        return {
288
            rq: null,
289
            strAsc: String.fromCharCode(9650), //&#9650;
290
            strDesc: String.fromCharCode(9660),//&#9660; 
291
            ReloadData: function(tableId){
292
                var request = {};
293
                BuildRequest(request, tableId, this.strDesc);
294
                LoadData(tableId, request);
295
            },
296
            Filter: function(field){
297
                var crntTableId = FilterGetTableId(field);
298
                if(crntTableId !== null){
299
                    var request = {};
300
                    var exRq = this.rq;
301
                    BuildRequest(request, crntTableId, this.strDesc);
302
                    if(exRq === null ||
303
                        request.filter !== exRq.filter ||
304
                        request.filterBy !== exRq.filterBy
305
                    ){
306
                        LoadData(crntTableId, request);
307
                    }
308
                }
309
            },
310
            GoPage: function(lnk){
311
                var request = {};
312
                var crntTableId = getParent(lnk, "table").getAttribute("id");
313
                BuildRequest(request, crntTableId, this.strDesc);
314
                request.pageNo = GoPageGetNo(lnk, crntTableId);
315
                LoadData(crntTableId, request);
316
                return false;
317
            },
318
            Export: function(lnk, eType){
319
                var request = {};
320
                var crntTableId = getParent(lnk, "table").getAttribute("id");
321
                BuildRequest(request, crntTableId, this.strDesc);
322
                request.exportType = ["CSV", "Excel"].indexOf(eType) >= 0 ?
323
                                        eType : 
324
                                        "csv";
325
                window.open(RequestToUrl(request));
326
                return false;
327
            },
328
            Sort: function(colNo, lnk){
329
                var request = {};
330
                var crntTableId = getParent(lnk, "table").getAttribute("id");
331
                BuildRequest(request, crntTableId, this.strDesc);
332
                if(Math.round(colNo) === request.colNo){
333
                    request.colOrd = (request.colOrd === "asc" ? "desc" : "asc");
334
                }else{
335
                    request.colNo = Math.round(colNo);
336
                    request.colOrd = "asc";
337
                }
338
                LoadData(crntTableId, request);
339
                /* Clear and add new sort arrow */
340
                var headSpans = getParent(lnk, "thead").getElementsByTagName("span");
341
                var length = headSpans.length;
342
                for(var i = 0; i < length; i++){
343
                    headSpans[i].innerHTML = "";
344
                }
345
                lnk.getElementsByTagName("span")[0].innerHTML = (request.colOrd === "desc" ? this.strDesc : this.strAsc);
346
            },
347
            ColumnHover: function(tableContainer, index){
348
                if(!iePrior(9)){
349
                    TableHelperColumnHover.call(this, tableContainer, index);
350
                }
351
            },
352
            LoadEndCalback: function(){},/*Allows override: function(tableId){if(tableId){...}}*/
353
            init: Init
354
        };
355
    }
356
    return {
357
        //Get the Singleton instance if one exists, or create one if it doesn't
358
        getInstance: function(){
359
            if(!instance){
360
                instance = initInstance();
361
            }
362
            return instance;
363
        }
364
    };
365
})();
366
var table = TableSingleton.getInstance();
367