Passed
Push — master ( 7ee2bd...f943d5 )
by Alexey
05:02
created

system/static/js/Inji.js   D

Complexity

Total Complexity 64
Complexity/F 3.76

Size

Lines of Code 240
Function Count 17

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 0
nc 32
dl 0
loc 240
rs 4.5964
c 2
b 1
f 0
wmc 64
mnd 4
bc 67
fnc 17
bpm 3.9411
cpm 3.7647
noi 11

11 Functions

Rating   Name   Duplication   Size   Complexity  
A Inji.onLoad 0 13 4
A Inji.randomString 0 12 3
B Inji.get 0 26 2
A Inji.on 0 6 2
C Inji.numberFormat 0 36 7
B Inji.loadScripts 0 28 1
A Inji.event 0 7 3
B Inji.addScript 0 23 5
B Inji.start 0 25 4
B Inji.startCallbacks 0 18 5
C Inji.parseQueryString 0 38 11

How to fix   Complexity   

Complexity

Complex classes like system/static/js/Inji.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
/**
2
 * Inji js core
3
 *
4
 * @author Alexey Krupskiy <[email protected]>
5
 * @link http://inji.ru/
6
 * @copyright 2015 Alexey Krupskiy
7
 * @license https://github.com/injitools/cms-Inji/blob/master/LICENSE
8
 */
9
10
function Inji() {
11
  this.options = {};
12
  this.onLoadCallbacks = [];
13
  this.loaded = false;
14
  this.listeners = {};
15
  this.loadedScripts = {};
16
}
17
Inji.prototype.onLoad = function (callback, start) {
18
  if (typeof callback == 'function') {
19
    if (this.loaded) {
20
      callback();
21
    } else {
22
      if (start) {
23
        this.onLoadCallbacks.unshift(callback);
24
      } else {
25
        this.onLoadCallbacks.push(callback);
26
      }
27
    }
28
  }
29
}
30
Inji.prototype.startCallbacks = function () {
31
  console.log('inji start onload');
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...
32
  var callback;
33
  while (callback = this.onLoadCallbacks.shift()) {
34
    if (typeof callback == 'function') {
35
      callback();
36
    }
37
  }
38
  if (this.onLoadCallbacks.length != 0) {
39
    this.startCallbacks();
40
  }
41
  var indicator = document.getElementById('loading-indicator');
42
  if (indicator) {
43
    indicator.style.display = 'none';
44
  }
45
  inji.loaded = true;
46
  console.log('inji start complete');
47
}
48
Inji.prototype.start = function (options) {
49
  console.log('Inji start');
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...
50
  for (var key in options.compresedScripts) {
0 ignored issues
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...
51
    inji.loadedScripts[options.compresedScripts[key]] = true;
52
  }
53
  this.options = options;
54
  if (options.onLoadModules) {
55
    this.onLoad(function () {
56
      for (var key in options.onLoadModules) {
0 ignored issues
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...
57
        if (typeof inji[key] == 'undefined') {
58
          inji[key] = new window[key]();
59
          if (typeof (inji[key].init) == 'function') {
60
            console.log(key + ' init');
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...
61
            inji[key].init();
62
          }
63
        }
64
      }
65
    }, true)
66
  }
67
  if (options.scripts.length > 0) {
68
    this.loadScripts(options.scripts, 0);
69
  } else {
70
    inji.startCallbacks();
71
  }
72
}
73
Inji.prototype.loadScripts = function (scripts, key) {
74
  this.addScript(scripts[key], function () {
75
    if (typeof (scripts[key].name) != 'undefined') {
76
      inji.loadedScripts[scripts[key].file] = true;
77
      if (typeof inji[scripts[key].name] == 'undefined') {
78
        console.log('js ' + scripts[key].name + '(' + scripts[key].file + ') loaded');
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...
79
        inji[scripts[key].name] = new window[scripts[key].name]();
80
        if (typeof (inji[scripts[key].name].init) == 'function') {
81
          inji[scripts[key].name].init();
82
        }
83
      }
84
    } else if (typeof (scripts[key].file) != 'undefined') {
85
      inji.loadedScripts[scripts[key].file] = true;
86
      console.log('js ' + scripts[key].file + ' loaded');
87
88
    } else {
89
      inji.loadedScripts[scripts[key]] = true;
90
      console.log('js ' + scripts[key] + ' loaded');
91
      inji.event('loadScript', scripts[key]);
92
    }
93
    if (typeof (scripts[key + 1]) != 'undefined') {
94
      inji.loadScripts(scripts, key + 1);
95
    } else {
96
      console.log('All scripts loaded');
97
      inji.startCallbacks();
98
    }
99
  });
100
}
101
Inji.prototype.addScript = function (script, callback) {
102
  var element = document.createElement('script');
103
  var src = '';
104
  if (typeof (script.file) != 'undefined') {
105
    src = script.file;
106
  } else {
107
    src = script;
108
  }
109
  if (inji.loadedScripts[src]) {
110
    if (typeof (callback) == 'function') {
111
      callback();
112
    }
113
    return true;
114
  }
115
  element.src = src;
116
  element.type = 'text/javascript';
117
  if (typeof (callback) == 'function') {
118
    element.onload = callback;
119
  }
120
  document.head.appendChild(element);
121
122
123
}
124
Inji.prototype.on = function (eventType, callback) {
125
  if (typeof this.listeners[eventType] == 'undefined') {
126
    this.listeners[eventType] = [];
127
  }
128
  this.listeners[eventType].push(callback);
129
}
130
Inji.prototype.event = function (eventType, object) {
131
  if (typeof this.listeners[eventType] != 'undefined') {
132
    for (var key in this.listeners[eventType]) {
0 ignored issues
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...
133
      this.listeners[eventType][key](eventType, object);
134
    }
135
  }
136
}
137
Inji.prototype.randomString = function (length) {
138
  if (!length) {
139
    length = 20;
140
  }
141
  var text = "";
142
  var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
143
144
  for (var i = 0; i < length; i++)
145
    text += chars.charAt(Math.floor(Math.random() * chars.length));
146
147
  return text;
148
}
149
Inji.prototype.numberFormat = function (number, decimals, dec_point, thousands_sep) {
150
  //// Format a number with grouped thousands
151
  // 
152
  // +   original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
153
  // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
154
  // +	 bugfix by: Michael White (http://crestidg.com)
155
156
  var i, j, kw, kd, km;
157
158
  // input sanitation & defaults
159
  if (isNaN(decimals = Math.abs(decimals))) {
160
    decimals = 2;
161
  }
162
  if (dec_point == undefined) {
163
    dec_point = ",";
164
  }
165
  if (thousands_sep == undefined) {
166
    thousands_sep = ".";
167
  }
168
169
  i = parseInt(number = (+number || 0).toFixed(decimals)) + "";
170
171
  if ((j = i.length) > 3) {
172
    j = j % 3;
173
  } else {
174
    j = 0;
175
  }
176
177
  km = (j ? i.substr(0, j) + thousands_sep : "");
178
  kw = i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousands_sep);
179
  //kd = (decimals ? dec_point + Math.abs(number - i).toFixed(decimals).slice(2) : "");
180
  kd = (decimals ? dec_point + Math.abs(number - i).toFixed(decimals).replace(/-/, 0).slice(2) : "");
181
182
183
  return km + kw + kd;
184
}
185
Inji.prototype.get = function (query) {
186
  var element = document.querySelector(query);
187
  if (element) {
188
    return new function () {
189
      this.element = element;
190
      this.attr = function (name) {
191
        for (var key in this.element.attributes) {
0 ignored issues
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...
192
          var attr = element.attributes[key];
193
          if (attr.name == name) {
194
            return attr.value;
195
          }
196
        }
197
        return null;
198
      }
199
      this.data = function (name) {
200
        var data = this.attr('data-' + name);
201
        try {
202
          return JSON.parse(data);
203
        } catch (e) {
204
          return data;
205
        }
206
207
      }
208
    }
209
  }
210
}
211
Inji.prototype.parseQueryString = function (string) {
212
  var result = {};
0 ignored issues
show
Unused Code introduced by
The assignment to variable result seems to be never used. Consider removing it.
Loading history...
213
214
  string = string.indexOf('?') === 0 ? string.substr(1) : string;
215
  if (!string.length) {
216
    return [];
217
  }
218
  string = decodeURIComponent(string.replace(/\[[\"\']/g, '[').replace(/[\"\']\]/g, ']'));
219
  var result = {};
220
  var params = string.split('&');
221
  for (var key in params) {
0 ignored issues
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...
222
    var item = params[key];
223
    var itemPaths = item.match(/\[([^\]]*)\]/g);
224
    if (itemPaths === null) {
225
      result[item.split('=')[0]] = item.split('=')[1];
226
      continue;
227
    }
228
    var rootParam = item.substr(0, item.indexOf('['));
229
    if (typeof result[rootParam] == 'undefined') {
230
      result[rootParam] = {};
231
    }
232
    var resultCurPath = result[rootParam];
233
    for (var itemPathKey in itemPaths) {
0 ignored issues
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...
234
      var itemPath = itemPaths[itemPathKey].replace('[', '').replace(']', '');
235
      if (itemPath == '') {
236
        itemPath = Object.keys(resultCurPath).length;
237
      }
238
      if (typeof resultCurPath[itemPath] == 'undefined') {
239
        resultCurPath[itemPath] = parseInt(itemPathKey) + 1 < itemPaths.length ? {} : item.split('=')[1];
240
      }
241
      if (parseInt(itemPathKey) + 1 < itemPaths.length) {
242
        resultCurPath = resultCurPath[itemPath];
243
      }
244
    }
245
246
  }
247
  return result;
248
}
249
var inji = new Inji();