Passed
Branchmaster (9e6d59)
by Plamen
01:23
created

add/table.js   F

Complexity

Total Complexity 121
Complexity/F 3.56

Size

Lines of Code 369
Function Count 34

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 1 Features 1
Metric Value
cc 0
eloc 252
c 6
b 1
f 1
nc 1
dl 0
loc 369
rs 2
wmc 121
mnd 4
bc 100
fnc 34
bpm 2.9411
cpm 3.5588
noi 12

4 Functions

Rating   Name   Duplication   Size   Complexity  
B table.js ➔ tablesLoadData 0 16 6
B table.js ➔ ??? 0 318 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
        tSection =  document.getElementById(tableContainer).
145
                        getElementsByTagName(section)[0];
146
        this.clearSection(tSection);
147
        for(var i=0; i < dt.length; i++) {
148
            var row = dt[i];
149
            var tRow = document.createElement("tr");
150
151
            this.DrawRow(row, tRow);
152
153
            tSection.appendChild(tRow);
154
            if(section === "tfoot"){
155
                this.footerProcessPaginationLinks(tSection);
156
            }
157
            this.AppendRowCalback(tableContainer);
158
        }
159
    };
160
161
    this.DrawRow = function(row, tRow){
162
        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...
163
            var tCell = document.createElement("td");
164
            if(typeof row[cell] === "string" || typeof row[cell] === "number"){
165
                tCell.innerHTML = row[cell];
166
            } else if(typeof row[cell] === "object"){
167
                this.DrawCellFromObject(row, cell, tCell);
168
            }
169
            tRow.appendChild(tCell);
170
        }
171
    };
172
173
    this.DrawCellFromObject = function(row, cell, tCell){
174
        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...
175
            if(typeof row[cell][attr] === "string"){
176
                tCell.innerHTML = row[cell][attr];
177
            } else if(typeof row[cell][attr] === "object"){
178
                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...
179
                    tCell.setAttribute(v,row[cell][attr][v]);
180
                }
181
            }
182
        }
183
    };
184
185
    this.footerProcessPaginationLinks = function(tSection){
186
        var pLinks = tSection.querySelectorAll(".paging a");
187
        if(pLinks.length>0){
188
            for(var j=0; j < pLinks.length; j++){
189
                pLinks[j].setAttribute("href","javascript:void(0);");
190
                pLinks[j].setAttribute("onclick","return table.GoPage(this);");
191
            }
192
        }
193
    };
194
195
    this.clearSection = function(tSection){
196
        if(this.iePrior(9)){
197
            if(tSection.firstChild){
198
                while (tSection.firstChild) {
199
                    tSection.removeChild(tSection.firstChild);
200
                }
201
            }
202
        } else {
203
            tSection.innerHTML="";
204
        }
205
    };
206
207
    this.SetTheTableColumnsHoverEffect = function (tableContainer){
208
        if(this.iePrior(9)) {return;}
209
        var tContainer = document.getElementById(tableContainer);
210
        var tHcells = tContainer.rows[0].cells;
211
        for(var i=0; i < tHcells.length; i++){
212
            if(tHcells[i].firstChild.tagName === "A"){
213
                tHcells[i].firstChild.setAttribute("onmouseover","table.ColumnHover('"+tableContainer+"',"+i+");");
214
                tHcells[i].firstChild.setAttribute("onmouseout","table.ColumnHover('"+tableContainer+"');");
215
            }
216
        }
217
        var pLinks = tContainer.querySelectorAll("tfoot .paging a");
218
        if(pLinks.length>0){
219
            for(var j=0; j < pLinks.length; j++){
220
                pLinks[j].setAttribute("href","javascript:void(0);");
221
                pLinks[j].setAttribute("onclick","return table.GoPage(this);");
222
            }
223
        }
224
    };
225
226
    this.ColumnHover = function(tableContainer,index){
227
        if(this.iePrior(9)) {return;}
228
        var tRow = document.getElementById(tableContainer).rows;
229
        index = Math.round(index);
230
        for(var i=0; i < (tRow.length-1); i++){
231
            if(index >= 0){
232
                tRow[i].cells[index].setAttribute("lang","col-hover");
233
            } else {
234
                for(var j=0; j < tRow[i].cells.length; j++){
235
                    if(tRow[i].cells[j].lang){
236
                        tRow[i].cells[j].removeAttribute("lang");
237
                    }
238
                }
239
            }
240
        }
241
    };
242
243
    this.getFilterFieldsByTbaleID = function(tableID){
244
        var fields = {filterBy:null, filter:null};
245
        var filterDiv = this.getFilterDivByTableIDOrNull(tableID);
246
        if(filterDiv!==null) {
247
            var selectObj = filterDiv.getElementsByTagName("select")[0];
248
            var textObj = filterDiv.getElementsByTagName("input")[0];
249
            fields.filterBy = (selectObj===null || selectObj.options[selectObj.selectedIndex].value==="all") ? null : selectObj.options[selectObj.selectedIndex].value;
250
            fields.filter = (textObj===null || textObj.value.length === 0) ? null : encodeURIComponent(textObj.value.trim());
251
        }
252
        return fields;
253
    };
254
255
    this.getFilterDivByTableIDOrNull = function(tableID){
256
        var res = null;
257
        if(document.getElementById(tableID).parentNode.getElementsByTagName("div").length > 0){
258
            for (var i = 0; i < document.getElementById(tableID).parentNode.getElementsByTagName("div").length; i++) {
259
                if(document.getElementById(tableID).parentNode.getElementsByTagName("div")[i].getAttribute("class")==="filter"){
260
                    return document.getElementById(tableID).parentNode.getElementsByTagName("div")[i];
261
                }
262
            }
263
264
        }
265
        return res;
266
    };
267
268
    this.LoadData = function(tableContainer,rq){
269
        this.setVisability(tableContainer, false);
270
        if (window.XMLHttpRequest) { xmlhttp=new XMLHttpRequest(); /* code for IE7+, Firefox, Chrome, Opera, Safari */
271
        } 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...
272
        for (var i = 0; i < this.tail.length; i++) {
273
            var ex_xmlhttp = this.tail.shift();
274
            ex_xmlhttp.abort();
275
        }
276
        xmlhttp.onreadystatechange = function() {
277
            if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
278
                d = JSON.parse(xmlhttp.responseText);
279
                table.DrawSection(tableContainer,d.body);
280
                table.DrawSection(tableContainer,d.footer,"tfoot");
281
                table.LoadEndCalback(tableContainer);
282
                table.setVisability(tableContainer, true);
283
                if(typeof rq === "object"){
284
                    table.ColumnHover(tableContainer,rq.colNo);
285
                }
286
            }
287
        };
288
        xmlhttp.open("GET", this.RequestToUrl(rq), true);
289
        xmlhttp.send();
290
        this.tail.push(xmlhttp); //put in tail to may later abort any previous
291
    };
292
293
    this.setVisability = function(tableContainer,rq){
294
        var tbl = document.getElementById(tableContainer);
295
        if(rq===true){
296
            tbl.style.filter = "none";
297
            tbl.style.opacity = "1";
298
            tbl.style.cursor = "auto";
299
        } else if(rq===false){
300
            tbl.style.filter = "blur(1px)";
301
            tbl.style.opacity = "0.8";
302
            tbl.style.cursor = "wait";
303
        } 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...
304
    };
305
306
    this.getParent = function (obj,objType){
307
        while( obj && obj.tagName !== objType.toUpperCase() ){
308
            obj = obj.parentNode;
309
        } return obj;
310
    };
311
312
    this.init = function(tableId){
313
        this.SetTheTableColumnsHoverEffect(tableId);
314
    };
315
316
    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
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...
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...
317
    this.loadJS = function(src){ var s = document.createElement('script'); s.src = src; document.getElementsByTagName('head')[0].appendChild(s);};
318
    this.loadCSS = function(src){ var s = document.createElement('link'); s.href = src; s.rel="stylesheet"; document.getElementsByTagName('head')[0].appendChild(s);};
319
320
    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...
321
    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...
322
};
323
324
/** Moves custom created filter to the Table's filter
325
 * @param {string} filterId
326
 * @param {string} tableId
327
 * @param {boolean} delay - needed in case the table is istill not executed */
328
function moveSelectorToTheTableFilter(filterId, tableId, delay){
329
    if(delay===true){
330
        setTimeout(function(){
331
            var filterDiv = document.getElementById(tableId).getElementsByTagName("div")[0];
332
            filterDiv.appendChild(document.getElementById(filterId));
333
        },500);
334
    } else {
335
        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...
336
        filterDiv.appendChild(document.getElementById(filterId));
337
    }
338
}
339
function changeListCustomFilter(selectObj){
340
    var fId = selectObj.options[selectObj.selectedIndex].value;
341
    var varName = selectObj.getAttribute("name");
342
    var varPos = document.URL.indexOf(varName);
343
    if(varPos>0){
344
        var url = fId!=="{!--Empty--!}" ? document.URL.substring(0,varPos) : document.URL.substring(0,(varPos-1));
345
    } else {
346
        var separator = document.URL.indexOf("?")>0 ? "&" : "?";
347
        url = document.URL + (fId!=="{!--Empty--!}" ? separator : "");
348
    }
349
    var newUrl = url + (fId!=="{!--Empty--!}" ? (varName + "=" + fId) : "");
350
    location.assign(newUrl);
351
}
352
353
354
function tablesLoadData(){
355
    var tables = document.getElementsByTagName("table");
356
    for (var i = 0; i < tables.length; i++) {
357
        if((table.iePrior(9) ? (typeof tables[i]["data-table"]!== 'undefined') : tables[i].hasAttribute("data-table")) && tables[i].getAttribute("data-table") === "js"){
358
            table.LoadData(tables[i].id);
359
            table.SetTheTableColumnsHoverEffect(tables[i].id);
360
        }
361
    }
362
    if(table.iePrior(10)){
363
        table.loadJS("/add/helpers/table/add/json2.js");
364
    }
365
366
    /*if(table.iePrior(8)){ //can be used to add apropriate tables links modifications
367
        // loadCSS("/add/helpers/table/add/ie7-and-down.css");
368
    }*/
369
}
370
371
/*if(window.addEventListener){window.addEventListener('load',tablesLoadData,false);} else if(window.attachEvent){window.attachEvent('onload',tablesLoadData);}*/