Passed
Branchmaster (0d6aa4)
by Plamen
01:30
created

add/table.js   F

Complexity

Total Complexity 110
Complexity/F 3.06

Size

Lines of Code 370
Function Count 36

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

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

17 Functions

Rating   Name   Duplication   Size   Complexity  
A table.js ➔ TableHelperGetParent 0 6 3
B TableSingleton.constructor 0 168 1
A table.js ➔ TableHelperProcessPaginationLinks 0 9 3
A table.js ➔ TableHelperFilterGetTableId 0 7 3
B table.js ➔ initInstance 0 155 1
A table.js ➔ TableHelperColumnHoverRelease 0 9 4
A table.js ➔ TableHelperRequestToUrl 0 17 5
A table.js ➔ TableHelperSetVisability 0 14 3
A table.js ➔ TableHelperBuildRequest_Filter 0 43 3
A table.js ➔ TableHelperIfPrior 0 12 4
A table.js ➔ TableHelperBuildRequest 0 5 1
A table.js ➔ TableHelperDrawSectionClear 0 11 4
A table.js ➔ TableHelperColumnHover 0 11 3
A table.js ➔ TableHelperDrawSectionRow_CellFromObject 0 11 5
A table.js ➔ TableHelperDrawSectionRow 0 11 5
A TableSingleton.getInstance 0 6 2
A table.js ➔ TableHelperBuildRequest_Sort 0 24 5

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 TableHelperIfPrior = function(v){
126
    var rv = false;
127
    if(window.navigator.appName === 'Microsoft Internet Explorer'){
128
        var ua = window.navigator.userAgent;
129
        var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
130
        if(re.exec(ua) !== null){
131
            rv = parseFloat(RegExp.$1);
132
        }
133
        rv = rv < v ? true : false;
134
    }
135
    return rv;
136
};
137
var TableHelperRequestToUrl = function(rq){
138
    var url = location.pathname + ".json" + location.search;
139
    if(typeof rq === "object"){
140
        var getUrlVarName = {
141
            colNo: "col", colOrd: "ord", filter: "filter",
142
            filterBy: "filter-by", pageNo: "pg", exportType: "export",
143
            tableId: "table-id"
144
        };
145
        var flagFirst = location.search.length < 1 ? true : false;
146
        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...
147
            var clue = flagFirst === true ? "?" : "&";
148
            url += clue + getUrlVarName[r] + "=" + rq[r];
149
            flagFirst = false;
150
        }
151
    }
152
    return url;
153
};
154
var TableHelperGetParent = function(obj, objType){
155
    while(obj && obj.tagName !== objType.toUpperCase()){
156
        obj = obj.parentNode;
157
    }
158
    return obj;
159
};
160
var TableHelperFilterGetTableId = function(field){
161
    if(field.tagName.toLowerCase() !== "select"){
162
        return field.getAttribute("data-table-id");
163
    }
164
    var f = field.parentNode.parentNode.getElementsByTagName("input")[0];
165
    return '' === f.value ? null : f.getAttribute("data-table-id");
166
};
167
var TableHelperDrawSectionClear = function(tSection, iePrior9){
168
    if(iePrior9){
169
        if(tSection.firstChild){
170
            while(tSection.firstChild){
171
                tSection.removeChild(tSection.firstChild);
172
            }
173
        }
174
    }else{
175
        tSection.innerHTML = "";
176
    }
177
};
178
var TableHelperDrawSectionRow = function(row, tRow){
179
    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...
180
        var tCell = document.createElement("td");
181
        if(typeof row[cell] === "string" || typeof row[cell] === "number"){
182
            tCell.innerHTML = row[cell];
183
        }else if(typeof row[cell] === "object"){
184
            TableHelperDrawSectionRow_CellFromObject(row, cell, tCell);
185
        }
186
        tRow.appendChild(tCell);
187
    }
188
};
189
var TableHelperDrawSectionRow_CellFromObject = function(row, cell, tCell){
190
    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...
191
        if(typeof row[cell][attr] === "string"){
192
            tCell.innerHTML = row[cell][attr];
193
        }else if(typeof row[cell][attr] === "object"){
194
            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...
195
                tCell.setAttribute(v, row[cell][attr][v]);
196
            }
197
        }
198
    }
199
};
200
201
//https://addyosmani.com/resources/essentialjsdesignpatterns/book/#singletonpatternjavascript
202
var TableSingleton = (function(){
203
    // Instance stores a reference to the Singleton
204
    var instance;
205
    function initInstance(){
206
        // Singleton
207
        // Private methods and variables
208
        var tail = [];
209
        function LoadData(tableContainer, rq){
210
            SetVisability(tableContainer, false);
211
            if(window.XMLHttpRequest){
212
                var xmlhttp = new XMLHttpRequest();/* code for IE7+, Firefox, Chrome, Opera, Safari */
213
            }else{ 
214
                xmlhttp = new window.ActiveXObject("Microsoft.XMLHTTP");/*code for IE6, IE5 */
215
            }
216
            for(var i = 0; i < tail.length; i++){
217
                var ex_xmlhttp = tail.shift();
218
                ex_xmlhttp.abort();
219
            }
220
            xmlhttp.onreadystatechange = function(){
221
                if(xmlhttp.readyState === 4 && xmlhttp.status === 200){
222
                    var d = JSON.parse(xmlhttp.responseText);
223
                    instance.rq = rq;
224
                    instance.Draw(tableContainer, d);
225
                }
226
            };
227
            xmlhttp.open("GET", RequestToUrl(rq), true);
228
            xmlhttp.send();
229
            tail.push(xmlhttp); //put at tail to can abort later any previous
230
        }
231
        function Init(tableId){
232
            var tContainer = document.getElementById(tableId);
233
            if(iePrior(9)){
234
                TableInitSetColumnsHoverEffect(tContainer, tableId);
235
            }
236
            var tfoot = tContainer.getElementsByTagName("tfoot")[0];
237
            TableHelperProcessPaginationLinks(tfoot);
238
        }
239
        function Draw(tableContainer, d){
240
            DrawSection(tableContainer, d.body);
241
            DrawSection(tableContainer, d.footer, "tfoot");
242
            instance.LoadEndCalback(tableContainer);
243
            SetVisability(tableContainer, true);
244
            if(this.rq !== null){
245
                var hover = document.getElementById(this.rq.tableId)
246
                            .getElementsByTagName("th")[this.rq.colNo].lang;
247
                if(hover){
248
                    instance.ColumnHover(tableContainer, this.rq.colNo);
249
                }
250
            }
251
        }
252
        function DrawSection(tableContainer, dt, tSection){
253
            var section = tSection === "tfoot" ? "tfoot" : "tbody";
254
            var tSec = document.getElementById(tableContainer)
255
                        .getElementsByTagName(section)[0];
256
            TableHelperDrawSectionClear(tSec, iePrior(9));
257
            for(var i = 0; i < dt.length; i++){
258
                var row = dt[i];
259
                var tRow = document.createElement("tr");
260
                TableHelperDrawSectionRow(row, tRow);
261
                tSec.appendChild(tRow);
262
                if(section === "tfoot"){
263
                    TableHelperProcessPaginationLinks(tSec);
264
                }
265
                instance.AppendRowCalback(tableContainer);
266
            }
267
        }
268
269
        var BuildRequest = TableHelperBuildRequest;
270
        var FilterGetTableId = TableHelperFilterGetTableId;
271
        var getParent = TableHelperGetParent;
272
        var iePrior = TableHelperIfPrior;
273
        var RequestToUrl = TableHelperRequestToUrl;
274
        var SetVisability = TableHelperSetVisability;
275
276
        return {
277
            rq: null,
278
            strAsc: String.fromCharCode(9650), //&#9650;
279
            strDesc: String.fromCharCode(9660),//&#9660; 
280
            ReloadData: function(tableId){
281
                var request = {};
282
                BuildRequest(request, tableId, this.strDesc);
283
                LoadData(tableId, request);
284
            },
285
            Filter: function(field){
286
                var crntTableId = FilterGetTableId(field);
287
                if(crntTableId !== null){
288
                    var request = {};
289
                    var exRq = this.rq;
290
                    BuildRequest(request, crntTableId, this.strDesc);
291
                    if(exRq === null ||
292
                        request.filter !== exRq.filter ||
293
                        request.filterBy !== exRq.filterBy
294
                    ){
295
                        LoadData(crntTableId, request);
296
                    }
297
                }
298
            },
299
            GoPage: function(lnk){
300
                var request = {};
301
                var table = getParent(lnk, "table");
302
                var crntTableId = table.getAttribute("id");
303
                BuildRequest(request, crntTableId, this.strDesc);
304
                //check & serve pagination jump links
305
                var jumpDir = lnk.innerHTML.trim().substr(0, 1);
306
                if(jumpDir === "+" || jumpDir === "-"){
307
                    var current = table.querySelector("tfoot .paging .a").innerHTML;
308
                    var jump = lnk.innerHTML.replace("K", "000").replace("M", "000000000");
309
                    var jumpPage = (parseInt(current) + parseInt(jump));
310
                    lnk.parentNode.setAttribute("data-page", jumpPage);
311
                    lnk.style.transform = "none";
312
                }
313
                request.pageNo = lnk.parentNode.hasAttribute("data-page") ?
314
                                    lnk.parentNode.getAttribute("data-page") :
315
                                    lnk.innerHTML;
316
                LoadData(crntTableId, request, this.strDesc);
0 ignored issues
show
Bug introduced by
The call to LoadData seems to have too many arguments starting with this.strDesc.
Loading history...
317
                return false;
318
            },
319
            Export: function(lnk, eType){
320
                var request = {};
321
                var crntTableId = getParent(lnk, "table").getAttribute("id");
322
                BuildRequest(request, crntTableId, this.strDesc);
323
                request.exportType = ["CSV", "Excel"].indexOf(eType) >= 0 ?
324
                                        eType : 
325
                                        "csv";
326
                window.open(RequestToUrl(request));
327
                return false;
328
            },
329
            Sort: function(colNo, lnk){
330
                var request = {};
331
                var crntTableId = getParent(lnk, "table").getAttribute("id");
332
                BuildRequest(request, crntTableId, this.strDesc);
333
                if(Math.round(colNo) === request.colNo){
334
                    request.colOrd = (request.colOrd === "asc" ? "desc" : "asc");
335
                }else{
336
                    request.colNo = Math.round(colNo);
337
                    request.colOrd = "asc";
338
                }
339
                LoadData(crntTableId, request);
340
                /* Clear and add new sort arrow */
341
                var headSpans = getParent(lnk, "thead").getElementsByTagName("span");
342
                var length = headSpans.length;
343
                for(var i = 0; i < length; i++){
344
                    headSpans[i].innerHTML = "";
345
                }
346
                lnk.getElementsByTagName("span")[0].innerHTML = (request.colOrd === "desc" ? this.strDesc : this.strAsc);
347
            },
348
349
            ColumnHover: function(tableContainer, index){
350
                if(!iePrior(9)){
351
                    TableHelperColumnHover.call(this, tableContainer, index);
352
                }
353
            },
354
            Draw: Draw,
355
            LoadEndCalback: function(){},/*Allows override: function(tableId){if(tableId){...}}*/
356
            AppendRowCalback:  function(){},/*Allows override: function(tableId){if(tableId){...}}*/
357
            init: Init
358
        };
359
    }
360
    return {
361
        //Get the Singleton instance if one exists, or create one if it doesn't
362
        getInstance: function(){
363
            if(!instance){
364
                instance = initInstance();
365
            }
366
            return instance;
367
        }
368
    };
369
})();
370
var table = TableSingleton.getInstance();
371