Completed
Push — master ( 3d58fe...e58be0 )
by
unknown
01:39
created

src/server/controllers/editor.js   F

Complexity

Total Complexity 75
Complexity/F 4.17

Size

Lines of Code 279
Function Count 18

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 2 Features 0
Metric Value
nc 1
dl 0
loc 279
rs 3.8888
noi 8
c 2
b 2
f 0
cc 0
wmc 75
mnd 5
bc 59
fnc 18
bpm 3.2777
cpm 4.1666

10 Functions

Rating   Name   Duplication   Size   Complexity  
A editor.js ➔ orderByTabindex 0 9 3
C editor.js ➔ addToForm 0 26 8
C editor.js ➔ add 0 29 15
A editor.js ➔ insertAbeEach 0 14 4
A editor.js ➔ getDataIdWithNoSlash 0 8 2
A editor.js ➔ matchAttrAbe 0 8 2
A editor.js ➔ addSource 0 15 3
D editor.js ➔ each 0 44 10
C editor.js ➔ orderBlock 0 56 11
A editor.js ➔ editor 0 49 1

How to fix   Complexity   

Complexity

Complex classes like src/server/controllers/editor.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
import {Promise} from 'bluebird'
2
import path from 'path'
3
4
import {
5
  cmsData,
6
  cmsEditor,
7
  coreUtils,
0 ignored issues
show
Unused Code introduced by
The variable coreUtils seems to be never used. Consider removing it.
Loading history...
8
  abeEngine,
9
  cmsTemplates,
10
  abeExtend
11
} from '../../cli'
12
13
function add(obj, json, text, util) {
14
  var value = obj.value
15
  
16
  if(obj.key.indexOf('[') > -1) {
17
    var key = obj.key.split('[')[0]
18
    var index = obj.key.match(/[^\[]+?(?=\])/)[0]
19
    var prop = obj.key.replace(/[^\.]+?\./, '')
20
21
    if(typeof json[key] !== 'undefined' && json[key] !== null &&
22
       typeof json[key][index] !== 'undefined' && json[key][index] !== null &&
23
       typeof json[key][index][prop] !== 'undefined' && json[key][index][prop] !== null) {
24
      obj.value = json[getDataIdWithNoSlash(key)][index][prop]
25
    }else if(typeof value !== 'undefined' && value !== null && value !== '') {
26
      if(typeof json[key] === 'undefined' || json[key] === null){
27
        json[key] = []
28
      }
29
      if(typeof json[key][index] === 'undefined' || json[key][index] === null){
30
        json[key][index] = {}
31
      }
32
      json[key][index][prop] = value
33
    }
34
  }
35
36
  obj.key = getDataIdWithNoSlash(obj.key)
37
38
  util.add(obj)
39
40
  return value
41
}
42
43
function getDataIdWithNoSlash(key) {
44
  var trueKey = key
45
  if (trueKey.indexOf('/') > -1) {
46
    trueKey = trueKey.split('/')
47
    trueKey = trueKey[trueKey.length - 1]
48
  }
49
  return trueKey
50
}
51
52
function addToForm(match, text, json, util, arrayBlock, keyArray = null, i = 0) {
53
  var v = `{{${match}}}`,
54
    obj = cmsData.attributes.getAll(v, json)
55
56
  var realKey
57
  if(typeof keyArray !== 'undefined' && keyArray !== null) {
58
    realKey = obj.key.replace(/[^\.]+?\./, '')
59
60
    if(obj.key.indexOf(keyArray + '.') >= 0 && realKey.length > 0){
61
      obj.keyArray = keyArray
62
      obj.realKey = realKey
63
      obj.key = keyArray + '[' + i + '].' + realKey
64
      obj.desc = obj.desc + ' ' + i,
0 ignored issues
show
Comprehensibility introduced by
Usage of the sequence operator is discouraged, since it may lead to obfuscated code.

The sequence or comma operator allows the inclusion of multiple expressions where only is permitted. The result of the sequence is the value of the last expression.

This operator is most often used in for statements.

Used in another places it can make code hard to read, especially when people do not realize it even exists as a seperate operator.

This check looks for usage of the sequence operator in locations where it is not necessary and could be replaced by a series of expressions or statements.

var a,b,c;

a = 1, b = 1,  c= 3;

could just as well be written as:

var a,b,c;

a = 1;
b = 1;
c = 3;

To learn more about the sequence operator, please refer to the MDN.

Loading history...
65
      insertAbeEach(obj, text, json, util, arrayBlock)
66
67
    }else if(util.dontHaveKey(obj.key)) {
68
      obj.value = json[getDataIdWithNoSlash(obj.key)]
69
      json[getDataIdWithNoSlash(obj.key)] = add(obj, json, text, util)
70
    }
71
72
  }else if(util.dontHaveKey(obj.key) && cmsData.regex.isSingleAbe(v, text)) {
73
    realKey = obj.key.replace(/\./g, '-')
74
    obj.value = json[getDataIdWithNoSlash(realKey)]
75
    json[getDataIdWithNoSlash(obj.key)] = add(obj, json, text, util)
76
  }
77
}
78
79
function matchAttrAbe(text, json, util, arrayBlock) {
80
  var patt = /abe [^{{}}]+?(?=\}})/g,
81
    match
82
  // While regexp match HandlebarsJS template item => keepgoing
83
  while (match = patt.exec(text)) {
84
    addToForm(match[0], text, json, util, arrayBlock, null, null)
85
  }
86
}
87
88
function insertAbeEach (obj, text, json, util, arrayBlock) {
89
  if(typeof arrayBlock[obj.keyArray][obj.realKey] === 'undefined' || arrayBlock[obj.keyArray][obj.realKey] === null) {
90
    arrayBlock[obj.keyArray][obj.realKey] = []
91
  }
92
  var exist = false
93
  Array.prototype.forEach.call(arrayBlock[obj.keyArray][obj.realKey], (block) => {
94
    if(block.key === obj.key) {
95
      exist = true
96
    }
97
  })
98
  if(!exist) {
99
    arrayBlock[obj.keyArray][obj.realKey].push(obj)
100
  }
101
}
102
103
function each(text, json, util, arrayBlock) {
104
  let pattEach = /(\{\{#each (\r|\t|\n|.)*?\/each\}\})/g
105
  let patt = /abe [^{{}}]+?(?=\}})/g
106
  var textEach, match
107
108
  while (textEach = pattEach.exec(text)) {
109
    var i
110
    var keyArray = textEach[0].match(/#each (\n|.)*?\}/)
111
    keyArray = keyArray[0].slice(6, keyArray[0].length - 1)
112
113
    if(keyArray.split(' ').length > 1){
114
      keyArray = keyArray.split(' ')[0]
115
    }
116
    arrayBlock[keyArray] = []
117
    // ce while boucle sur les block de contenu {{abe}}
118
    while (match = patt.exec(textEach[0])) {
119
      var v = match[0]
120
121
      if(v.indexOf('abe') > -1){
122
        if(json[keyArray]){
123
          for (i = 0; i < json[keyArray].length; i++) {
124
            addToForm(v, text, json, util, arrayBlock, keyArray, i)
125
          }
126
        }else{
127
          addToForm(v, text, json, util, arrayBlock, keyArray, 0)
128
        }
129
      }
130
    }
131
132
    // ici on boucle a nouveau sur les champs pour les placer a la suite dans le formulaire
133
    var attrArray = [],
134
      length = 0
135
    for(var index in arrayBlock[keyArray]) {
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...
136
      attrArray.push(index)
137
      length = arrayBlock[keyArray][index].length
138
    }
139
140
    for (i = 0; i < length; i++) {
141
      for (var j = 0; j < attrArray.length; j++) {
142
        add(arrayBlock[keyArray][attrArray[j]][i], json, text, util)
143
      }
144
    }
145
  }
146
}
147
148
function addSource(text, json, util) {
149
  var listReg = /({{abe.*type=[\'|\"]data.*}})/g
150
  var match
151
152
  while (match = listReg.exec(text)) {
153
    var obj = cmsData.attributes.getAll(match[0], json)
154
155
    if(obj.editable) {
156
      obj.value = json[getDataIdWithNoSlash(obj.key)]
157
      add(obj, json, text, util)
158
    }else {
159
      json[getDataIdWithNoSlash(obj.key)] = obj.source
160
    }
161
  }
162
}
163
164
function orderByTabindex(a, b) {
165
  if(a.order < b.order) {
166
    return -1
167
  }else if(a.order > b.order) {
168
    return 1
169
  }
170
171
  return 0
172
}
173
174
function orderBlock(util) {
175
    
176
  var formBlock = {}
177
178
  for(var tab in util.form) {
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...
179
180
    var formBlockTab = {}
181
    for (var i = 0; i < util.form[tab].item.length; i++) {
182
      var blockName = (util.form[tab].item[i].block === '') ? 'default_' + i : util.form[tab].item[i].block
183
      if(util.form[tab].item[i].key.indexOf('[') > -1){
184
        blockName = util.form[tab].item[i].key.split('[')[0]
185
      }
186
      if(typeof formBlockTab[blockName] === 'undefined' || formBlockTab[blockName] === null) {
187
        formBlockTab[blockName] = []
188
      }
189
      formBlockTab[blockName].push(util.form[tab].item[i])
190
    }
191
    if(typeof blockName !== 'undefined' && blockName !== null) {
0 ignored issues
show
Bug introduced by
The variable blockName seems to not be initialized for all possible execution paths.
Loading history...
192
      formBlockTab[blockName].sort(orderByTabindex)
193
    }
194
    if(typeof formBlock[tab] === 'undefined' || formBlock[tab] === null) {
195
      formBlock[tab] = {}
196
    }
197
198
    var formBlockOrdered = {}
199
    var arKeys = Object.keys(formBlockTab).sort((a,b) => {
200
      if(parseFloat(formBlockTab[a][0].order) < parseFloat(formBlockTab[b][0].order)) {
0 ignored issues
show
Bug introduced by
The variable formBlockTab is changed as part of the for-each loop for example by {} on line 180. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
201
        return -1
202
      }else if(parseFloat(formBlockTab[a][0].order) > parseFloat(formBlockTab[b][0].order)) {
203
        return 1
204
      }
205
      return 0
206
    })
207
208
    Array.prototype.forEach.call(arKeys, (arKey) => {
209
      formBlockOrdered[arKey] = formBlockTab[arKey]
0 ignored issues
show
Bug introduced by
The variable formBlockOrdered is changed as part of the for-each loop for example by {} on line 198. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
Bug introduced by
The variable formBlockTab is changed as part of the for-each loop for example by {} on line 180. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
210
    })
211
    formBlock[tab] = formBlockOrdered
212
  }
213
214
  var formTabsOrdered = {}
215
  var arKeysTabs = Object.keys(formBlock).sort((a,b) => {
216
    if(parseFloat(formBlock[a][Object.keys(formBlock[a])[0]][0].order) < parseFloat(formBlock[b][Object.keys(formBlock[b])[0]][0].order)) {
217
      return -1
218
    }else if(parseFloat(formBlock[a][Object.keys(formBlock[a])[0]][0].order) > parseFloat(formBlock[b][Object.keys(formBlock[b])[0]][0].order)) {
219
      return 1
220
    }
221
    return 0
222
  })
223
224
  Array.prototype.forEach.call(arKeysTabs, (arKeysTab) => {
225
    formTabsOrdered[arKeysTab] = formBlock[arKeysTab]
226
  })
227
228
  return formTabsOrdered
229
}
230
231
export function editor(text, json, documentLink, precontrib = false) {
232
  let p = new Promise((resolve) => {
233
    var util = new cmsEditor.form()
234
    var arrayBlock = []
235
    
236
    cmsData.source.getDataList(path.dirname(documentLink), text, json)
237
      .then(() => {
238
        addSource(text, json, util)
239
240
        text = cmsData.source.removeDataList(text)
241
242
        if (!precontrib) {
243
          text = cmsTemplates.template.setAbeSlugDefaultValueIfDoesntExist(text)
244
          text = cmsTemplates.template.setAbePrecontribDefaultValueIfDoesntExist(text)
245
        }
246
247
        matchAttrAbe(text, json, util, arrayBlock)
248
        arrayBlock = []
249
        each(text, json, util, arrayBlock)
250
251
        if(typeof json.abe_meta !== 'undefined' && json.abe_meta !== null) {
252
          var links = json.abe_meta.link.split('/')
253
          var link = links.pop()
254
          json.abe_meta.cleanName = link.replace(/\..+$/, '')
255
          json.abe_meta.cleanFilename = links.join('/').replace(/\..+$/, '')
256
        }
257
258
        // HOOKS beforeEditorFormBlocks
259
        json = abeExtend.hooks.instance.trigger('beforeEditorFormBlocks', json, text)
260
261
        var blocks = orderBlock(util)
262
263
        // HOOKS afterEditorFormBlocks
264
        blocks = abeExtend.hooks.instance.trigger('afterEditorFormBlocks', blocks, json, text)
265
266
        abeEngine.instance.content = json
267
268
        resolve({
269
          text: text,
270
          form: blocks,
271
          json: json
272
        })
273
      }).catch(function(e) {
274
        console.error(e)
275
      })
276
  })
277
278
  return p
279
}