Passed
Branchmaster (b421ee)
by Plamen
01:32
created

add/table.js   F

Complexity

Total Complexity 128
Complexity/F 3.28

Size

Lines of Code 458
Function Count 39

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 37
Bugs 3 Features 1
Metric Value
cc 0
eloc 306
c 37
b 3
f 1
nc 1
dl 0
loc 458
rs 2
wmc 128
mnd 4
bc 110
fnc 39
bpm 2.8205
cpm 3.282
noi 8

4 Functions

Rating   Name   Duplication   Size   Complexity  
A table.js ➔ tablesLoadData 0 20 5
A table.js ➔ changeListCustomFilter 0 16 4
A table.js ➔ moveSelectorToTheTableFilter 0 13 2
B table.js ➔ ??? 0 396 1

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 strAsc = String.fromCharCode(9650); //▲
2
var strDesc = String.fromCharCode(9660);//▼
3
var xmlhttp;
4
var d;
5
6
var table = new function(){
7
    this.rq = null;
8
    this.tail = [];
9
10
    this.ReloadData = function(tableId){
11
        var request = {};
12
        this.BuildRequest(request, tableId);
13
        this.LoadData(tableId, request);
14
    };
15
16
    this.BuildRequest = function(request, crntTableId, skipPropertyArray){
17
        this.rq = request;
18
        this.checkSkip = function(skipProperty){
19
            var result = false;
20
            if(skipPropertyArray && Object.prototype.toString
21
                    .call(skipPropertyArray) === '[object Array]'
22
                    ){
23
                if(skipPropertyArray.indexOf(skipProperty) >= 0){
24
                    result = true;
25
                }
26
            }
27
            return result;
28
        };
29
        this.getSort = function(){
30
            var thTags = document.getElementById(crntTableId)
31
                    .getElementsByTagName("thead")[0]
32
                    .getElementsByTagName("th");
33
            var length = thTags.length;
34
            for(var i = 0; i < length; i++){
35
                var link = thTags[i].getElementsByTagName("a")[0];
36
                if(link){
37
                    var span = link.getElementsByTagName("span")[0];
38
                    if(span && this.setSortByFirstLinkFirstSpan(span, i)){
39
                        break;
40
                    }
41
                }
42
            }
43
        };
44
        this.setSortByFirstLinkFirstSpan = function(span, i){
45
            var order = span.innerHTML;
46
            if(order.length === 1){
47
                this.rq.colNo = i;
48
                this.rq.colOrd = (order === window.strDesc) ?
49
                        "desc" : "asc";
50
            }
51
            return this.rq.colNo === i;
52
        };
53
        this.getFilter = function(){
54
            var r = this.getFilterFieldsByTableID(crntTableId);
55
            if(r.filter !== null){
56
                this.rq.filter = r.filter;
57
            }
58
            if(r.filterBy !== null){
59
                this.rq.filterBy = r.filterBy;
60
            }
61
        };
62
63
        /* Build request object */
64
        if(!this.checkSkip("sort")){
65
            this.getSort();
66
        }
67
        if(!this.checkSkip("filter")){
68
            this.getFilter();
69
        }
70
71
        this.rq.tableId = crntTableId;
72
        return this.rq;
73
    };
74
75
    this.RequestToUrl = function(rq){
76
        var url = location.pathname + ".json" + location.search;
77
        if(typeof rq === "object"){
78
            var getUrlVarName = {
79
                colNo: "col", colOrd: "ord", filter: "filter",
80
                filterBy: "filter-by", pageNo: "pg", exportType: "export",
81
                tableId: "table-id"
82
            };
83
            var flagFirst = location.search.length < 1 ? true : false;
84
            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...
85
                var clue = flagFirst === true ? "?" : "&";
86
                url += clue + getUrlVarName[r] + "=" + rq[r];
87
                flagFirst = false;
88
            }
89
        }
90
        return url;
91
    };
92
93
    this.Filter = function(field){
94
        var crntTableId = this.FilterGetTableId(field);
95
        if(crntTableId !== null){
96
            var request = {};
97
            var exRq = this.rq;
98
            this.BuildRequest(request, crntTableId);
99
            if(exRq === null ||
100
                    request.filter !== exRq.filter ||
101
                    request.filterBy !== exRq.filterBy
102
                    ){
103
                this.LoadData(crntTableId, request);
104
            }
105
        }
106
    };
107
108
    this.FilterGetTableId = function(field){
109
        if(field.tagName.toLowerCase() !== "select"){
110
            return field.getAttribute("data-table-id");
111
        }
112
        var f = field.parentNode.parentNode.getElementsByTagName("input")[0];
113
        return '' === f.value ? null : f.getAttribute("data-table-id");
114
    };
115
116
    this.GoPage = function(lnk){
117
        var request = {};
118
        var table = this.getParent(lnk, "table");
119
        var crntTableId = table.getAttribute("id");
120
        this.BuildRequest(request, crntTableId);
121
        //check & serve pagination jump links
122
        var jumpDir = lnk.innerHTML.trim().substr(0, 1);
123
        if(jumpDir === "+" || jumpDir === "-"){
124
            var current = table.querySelector("tfoot .paging .a").innerHTML;
125
            var jump = lnk.innerHTML.replace("K", "000").replace("M", "000000000");
126
            var jumpPage = (parseInt(current) + parseInt(jump));
127
            lnk.parentNode.setAttribute("data-page", jumpPage);
128
            lnk.style.transform = "none";
129
        }
130
        request.pageNo = lnk.parentNode.hasAttribute("data-page") ?
131
                lnk.parentNode.getAttribute("data-page") :
132
                lnk.innerHTML;
133
        this.LoadData(crntTableId, request);
134
        return false;
135
    };
136
137
    this.Export = function(lnk, eType){
138
        var request = {};
139
        var crntTableId = this.getParent(lnk, "table").getAttribute("id");
140
        this.BuildRequest(request, crntTableId);
141
        request.exportType = ["CSV", "Excel"].indexOf(eType) >= 0 ? eType : "csv";
142
        window.open(this.RequestToUrl(request));
143
        return false;
144
    };
145
146
    this.Sort = function(colNo, lnk){
147
        var request = {};
148
        var crntTableId = this.getParent(lnk, "table").getAttribute("id");
149
        this.BuildRequest(request, crntTableId);
150
        if(Math.round(colNo) === request.colNo){
151
            request.colOrd = request.colOrd === "asc" ? "desc" : "asc";
152
        }else{
153
            request.colNo = Math.round(colNo);
154
            request.colOrd = "asc";
155
        }
156
        this.LoadData(crntTableId, request);
157
        /* Clear and add new sort arrow */
158
        var headSpans = this.getParent(lnk, "thead").getElementsByTagName("span");
159
        var length = headSpans.length;
160
        for(var i = 0; i < length; i++){
161
            headSpans[i].innerHTML = "";
162
        }
163
        lnk.getElementsByTagName("span")[0].innerHTML = (request.colOrd === "desc" ? window.strDesc : window.strAsc);
164
    };
165
166
    this.DrawSection = function(tableContainer, dt, tSection){
167
        var section = tSection === "tfoot" ? "tfoot" : "tbody";
168
        tSection = document.getElementById(tableContainer).
169
                getElementsByTagName(section)[0];
170
        this.clearSection(tSection);
171
        for(var i = 0; i < dt.length; i++){
172
            var row = dt[i];
173
            var tRow = document.createElement("tr");
174
175
            this.DrawRow(row, tRow);
176
177
            tSection.appendChild(tRow);
178
            if(section === "tfoot"){
179
                this.footerProcessPaginationLinks(tSection);
180
            }
181
            this.AppendRowCalback(tableContainer);
182
        }
183
    };
184
185
    this.DrawRow = function(row, tRow){
186
        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...
187
            var tCell = document.createElement("td");
188
            if(typeof row[cell] === "string" || typeof row[cell] === "number"){
189
                tCell.innerHTML = row[cell];
190
            }else if(typeof row[cell] === "object"){
191
                this.DrawCellFromObject(row, cell, tCell);
192
            }
193
            tRow.appendChild(tCell);
194
        }
195
    };
196
197
    this.DrawCellFromObject = function(row, cell, tCell){
198
        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...
199
            if(typeof row[cell][attr] === "string"){
200
                tCell.innerHTML = row[cell][attr];
201
            }else if(typeof row[cell][attr] === "object"){
202
                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...
203
                    tCell.setAttribute(v, row[cell][attr][v]);
204
                }
205
            }
206
        }
207
    };
208
209
    this.footerProcessPaginationLinks = function(tSection){
210
        var pLinks = tSection.querySelectorAll(".paging a");
211
        if(pLinks.length > 0){
212
            for(var j = 0; j < pLinks.length; j++){
213
                pLinks[j].setAttribute("href", "javascript:void(0);");
214
                pLinks[j].setAttribute("onclick", "return table.GoPage(this);");
215
            }
216
        }
217
    };
218
219
    this.clearSection = function(tSection){
220
        if(this.iePrior(9)){
221
            if(tSection.firstChild){
222
                while(tSection.firstChild){
223
                    tSection.removeChild(tSection.firstChild);
224
                }
225
            }
226
        }else{
227
            tSection.innerHTML = "";
228
        }
229
    };
230
231
    this.SetTheTableColumnsHoverEffect = function(tableContainer){
232
        if(this.iePrior(9)){
233
            return;
234
        }
235
        var tContainer = document.getElementById(tableContainer);
236
        var tHcells = tContainer.rows[0].cells;
237
        for(var i = 0; i < tHcells.length; i++){
238
            if(tHcells[i].firstChild.tagName === "A"){
239
                tHcells[i].firstChild.setAttribute("onmouseover", "table.ColumnHover('" + tableContainer + "'," + i + ");");
240
                tHcells[i].firstChild.setAttribute("onmouseout", "table.ColumnHover('" + tableContainer + "');");
241
            }
242
        }
243
        this.setPagingLinksSetActions(tContainer);
244
    };
245
246
    this.setPagingLinksSetActions = function(tContainer){
247
        var pLinks = tContainer.querySelectorAll("tfoot .paging a");
248
        if(pLinks.length > 0){
249
            for(var j = 0; j < pLinks.length; j++){
250
                pLinks[j].setAttribute("href", "javascript:void(0);");
251
                pLinks[j].setAttribute("onclick", "return table.GoPage(this);");
252
            }
253
        }
254
    };
255
256
    this.ColumnHover = function(tableContainer, index=null){
257
        if(!this.iePrior(9)){
258
            var rows = document.getElementById(tableContainer).rows;
259
            var upto = rows.length - 1;
260
            if(index === null){
261
                this.columnHoverRelease(rows, upto);
262
            } else {
263
                for(var i = 0; i < upto; i++){
264
                    rows[i].cells[index].setAttribute("lang", "col-hover");
265
                }
266
            }
267
        }
268
    };
269
    this.columnHoverRelease = function(rows, upto){
270
        for(var i = 0; i < upto; i++){
271
            for(var j = 0; j < rows[i].cells.length; j++){
272
                if(rows[i].cells[j].lang){
273
                    rows[i].cells[j].removeAttribute("lang");
274
                }
275
            }
276
        }
277
    };
278
279
    this.getFilterFieldsByTableID = function(tableID){
280
        var fields = {filterBy: null, filter: null};
281
        var filterDiv = this.getFilterDivByTableIDOrNull(tableID);
282
        if(filterDiv !== null){
283
            this.setFilterFields(fields, filterDiv);
284
        }
285
        return fields;
286
    };
287
    this.setFilterFields = function(fields, filterDiv){
288
        var slctObj = filterDiv.getElementsByTagName("select")[0];
289
        if(slctObj && slctObj.options[slctObj.selectedIndex].value !== "all"){
290
            fields.filterBy = slctObj.options[slctObj.selectedIndex].value;
291
        }
292
        var textObj = filterDiv.getElementsByTagName("input")[0];
293
        if(textObj && textObj.value.length !== 0){
294
            fields.filter = encodeURIComponent(textObj.value.trim());
295
        }
296
    };
297
298
    this.getFilterDivByTableIDOrNull = function(tableID){
299
        var res = null;
300
        if(document.getElementById(tableID).parentNode.getElementsByTagName("div").length > 0){
301
            for(var i = 0; i < document.getElementById(tableID).parentNode.getElementsByTagName("div").length; i++){
302
                if(document.getElementById(tableID).parentNode.getElementsByTagName("div")[i].getAttribute("class") === "filter"){
303
                    return document.getElementById(tableID).parentNode.getElementsByTagName("div")[i];
304
                }
305
            }
306
307
        }
308
        return res;
309
    };
310
311
    this.LoadData = function(tableContainer, rq){
312
        this.setVisability(tableContainer, false);
313
        if(window.XMLHttpRequest){
314
            xmlhttp = new XMLHttpRequest();/* code for IE7+, Firefox, Chrome, Opera, Safari */
315
        }else{ 
316
            xmlhttp = new window.ActiveXObject("Microsoft.XMLHTTP");/*code for IE6, IE5 */
317
        }
318
        for(var i = 0; i < this.tail.length; i++){
319
            var ex_xmlhttp = this.tail.shift();
320
            ex_xmlhttp.abort();
321
        }
322
        xmlhttp.onreadystatechange = function(){
323
            if(xmlhttp.readyState === 4 && xmlhttp.status === 200){
324
                d = JSON.parse(xmlhttp.responseText);
325
                table.DrawSection(tableContainer, d.body);
326
                table.DrawSection(tableContainer, d.footer, "tfoot");
327
                table.LoadEndCalback(tableContainer);
328
                table.setVisability(tableContainer, true);
329
                if(typeof rq === "object"){
330
                    var hover = document.getElementById(rq.tableId)
331
                                .getElementsByTagName("th")[rq.colNo].lang;
332
                    if(hover){
333
                        table.ColumnHover(tableContainer, rq.colNo);
334
                    }
335
                }
336
            }
337
        };
338
        xmlhttp.open("GET", this.RequestToUrl(rq), true);
339
        xmlhttp.send();
340
        this.tail.push(xmlhttp); //put in tail to may later abort any previous
341
    };
342
343
    this.setVisability = function(tableContainer, rq){
344
        var tbl = document.getElementById(tableContainer);
345
        if(rq === true){
346
            tbl.style.filter = "none";
347
            tbl.style.opacity = "1";
348
            tbl.style.cursor = "auto";
349
        }else if(rq === false){
350
            tbl.style.filter = "blur(1px)";
351
            tbl.style.opacity = "0.8";
352
            tbl.style.cursor = "wait";
353
        }else{
354
            console.log("table error in the rq value"); /*Shows error*/
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
355
        }
356
    };
357
358
    this.getParent = function(obj, objType){
359
        while(obj && obj.tagName !== objType.toUpperCase()){
360
            obj = obj.parentNode;
361
        }
362
        return obj;
363
    };
364
365
    this.init = function(tableId){
366
        this.SetTheTableColumnsHoverEffect(tableId);
367
    };
368
369
    this.iePrior = function(v){
370
        var rv = false;
371
        if(window.navigator.appName === 'Microsoft Internet Explorer'){
372
            var ua = navigator.userAgent;
0 ignored issues
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
373
            var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
374
            if(re.exec(ua) !== null){
375
                rv = parseFloat(RegExp.$1);
376
            }
377
            rv = rv < v ? true : false;
378
        }
379
        return rv;
380
    };
381
    this.loadJS = function(src){
382
        var s = document.createElement('script');
383
        s.src = src;
384
        document.getElementsByTagName('head')[0].appendChild(s);
385
    };
386
    this.loadCSS = function(src){
387
        var s = document.createElement('link');
388
        s.href = src;
389
        s.rel = "stylesheet";
390
        document.getElementsByTagName('head')[0].appendChild(s);
391
    };
392
393
    this.LoadEndCalback = function(tableId){
394
        if(tableId){/*Allows override*/
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
395
        }
396
    };
397
    this.AppendRowCalback = function(tableId){
398
        if(tableId){/*Allows override*/
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
399
        }
400
    };
401
};
402
403
/** Moves custom created filter to the Table's filter
404
 * @param {string} filterId
405
 * @param {string} tableId
406
 * @param {boolean} delay - needed in case the table is istill not executed */
407
function moveSelectorToTheTableFilter(filterId, tableId, delay){
408
    if(delay === true){
409
        setTimeout(function(){
410
            var filterDiv = document.getElementById(tableId)
411
                    .getElementsByTagName("div")[0];
412
            filterDiv.appendChild(document.getElementById(filterId));
413
        }, 500);
414
    }else{
415
        var filterDiv = document.getElementById(tableId)
416
                .getElementsByTagName("div")[0];
417
        filterDiv.appendChild(document.getElementById(filterId));
418
    }
419
}
420
421
function changeListCustomFilter(selectObj){
422
    var name = selectObj.getAttribute("name");
423
424
    var inUrlPos = document.URL.indexOf(name);
425
    var url = inUrlPos !== -1 ?
426
            document.URL.substring(0, (inUrlPos - 1)) :
427
            document.URL;
428
429
    var value = selectObj.options[selectObj.selectedIndex].value;
430
    if(value !== "{!--Empty--!}"){
431
        var clue = document.URL.indexOf("?") > 0 ? "&" : "?";
432
        url += (clue + name + "=" + value);
433
    }
434
435
    location.assign(url);
436
}
437
438
439
function tablesLoadData(){
440
    var tables = document.getElementsByTagName("table");
441
    var envPrior9 = table.iePrior(9);
442
    for(var i = 0; i < tables.length; i++){
443
        var isProcessable = envPrior9 ?
444
                typeof tables[i]["data-table"] !== 'undefined' :
445
                tables[i].hasAttribute("data-table");
446
        if(isProcessable && tables[i].getAttribute("data-table") === "js"){
447
            table.LoadData(tables[i].id);
448
            table.SetTheTableColumnsHoverEffect(tables[i].id);
449
        }
450
    }
451
    /*if(table.iePrior(10)){
452
     table.loadJS("/add/helpers/table/add/json2.js");
453
     }
454
     
455
     if(table.iePrior(8)){ //can be used to add apropriate tables links modifications
456
     // loadCSS("/add/helpers/table/add/ie7-and-down.css");
457
     }*/
458
}
459
460
/*if(window.addEventListener){window.addEventListener('load',tablesLoadData,false);} else if(window.attachEvent){window.attachEvent('onload',tablesLoadData);}*/