Passed
Branchmaster (129ea8)
by Plamen
01:24
created

add/table.js   F

Complexity

Total Complexity 117
Complexity/F 3.9

Size

Lines of Code 351
Function Count 30

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
cc 0
eloc 244
c 3
b 1
f 0
nc 1
dl 0
loc 351
rs 2
wmc 117
mnd 8
bc 96
fnc 30
bpm 3.2
cpm 3.9
noi 12

4 Functions

Rating   Name   Duplication   Size   Complexity  
B table.js ➔ tablesLoadData 0 16 6
B table.js ➔ ??? 0 300 1
B table.js ➔ changeListCustomFilter 0 13 6
A table.js ➔ moveSelectorToTheTableFilter 0 11 2

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

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
299
    this.loadJS = function(src){ var s = document.createElement('script'); s.src = src; document.getElementsByTagName('head')[0].appendChild(s);};
300
    this.loadCSS = function(src){ var s = document.createElement('link'); s.href = src; s.rel="stylesheet"; document.getElementsByTagName('head')[0].appendChild(s);};
301
    
302
    this.LoadEndCalback = function(tableId){};
0 ignored issues
show
Unused Code introduced by
The parameter tableId is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
303
    this.AppendRowCalback = function(tableId){};
0 ignored issues
show
Unused Code introduced by
The parameter tableId is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
304
};
305
306
/** Moves custom created filter to the Table's filter
307
 * @param {string} filterId
308
 * @param {string} tableId
309
 * @param {boolean} delay - needed in case the table is istill not executed */
310
function moveSelectorToTheTableFilter(filterId, tableId, delay){
311
    if(delay===true){
312
        setTimeout(function(){
313
            var filterDiv = document.getElementById(tableId).getElementsByTagName("div")[0];
314
            filterDiv.appendChild(document.getElementById(filterId));
315
        },500);
316
    } else {
317
        filterDiv = document.getElementById(tableId).getElementsByTagName("div")[0];
0 ignored issues
show
Bug introduced by
The variable filterDiv seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.filterDiv.
Loading history...
318
        filterDiv.appendChild(document.getElementById(filterId));
319
    }
320
}
321
function changeListCustomFilter(selectObj){
322
    var fId = selectObj.options[selectObj.selectedIndex].value;
323
    var varName = selectObj.getAttribute("name");
324
    var varPos = document.URL.indexOf(varName);
325
    if(varPos>0){
326
        var url = fId!=="{!--Empty--!}" ? document.URL.substring(0,varPos) : document.URL.substring(0,(varPos-1));
327
    } else {
328
        var separator = document.URL.indexOf("?")>0 ? "&" : "?";
329
        url = document.URL + (fId!=="{!--Empty--!}" ? separator : "");
330
    }
331
    var newUrl = url + (fId!=="{!--Empty--!}" ? (varName + "=" + fId) : "");
332
    location.assign(newUrl);
333
}
334
335
336
function tablesLoadData(){
337
    var tables = document.getElementsByTagName("table");
338
    for (var i = 0; i < tables.length; i++) { 
339
        if((table.iePrior(9) ? (typeof tables[i]["data-table"]!== 'undefined') : tables[i].hasAttribute("data-table")) && tables[i].getAttribute("data-table") === "js"){
340
            table.LoadData(tables[i].id);
341
            table.SetTheTableColumnsHoverEffect(tables[i].id);
342
        }
343
    }
344
    if(table.iePrior(10)){
345
        table.loadJS("/add/helpers/table/add/json2.js");
346
    }
347
    
348
    /*if(table.iePrior(8)){ //can be used to add apropriate tables links modifications
349
        // loadCSS("/add/helpers/table/add/ie7-and-down.css");
350
    }*/
351
}
352
353
/*if(window.addEventListener){window.addEventListener('load',tablesLoadData,false);} else if(window.attachEvent){window.attachEvent('onload',tablesLoadData);}*/