Passed
Branch master (c2f34b)
by greg
02:22
created

EditorBlock.js ➔ ???   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 7
Bugs 7 Features 0
Metric Value
c 7
b 7
f 0
nc 4
nop 0
dl 0
loc 22
cc 3
rs 9.2
1
/*global document, abe, $, jQuery */
2
3
import {IframeNode, IframeCommentNode} from '../utils/iframe'
4
import {nextSibling} from '../utils/dom'
5
import Color from '../utils/color-picker'
6
import Link from '../utils/link-picker'
7
import RichText from '../utils/rich-texarea'
8
import Json from './EditorJson'
9
import EditorUtils from './EditorUtils'
10
import on from 'on'
11
12
export default class EditorBlock {
13
  constructor() {
14
    this._json = Json.instance
15
    var colorWysiwyg = document.querySelector('.wysiwyg-popup.color')
16
    if (colorWysiwyg != null) {
17
      this.color = new Color(colorWysiwyg)
18
    }
19
    var linkWysiwyg = document.querySelector('.wysiwyg-popup.link')
20
    if (linkWysiwyg != null) {
21
      this.link = new Link(linkWysiwyg)
22
    }
23
24
    this._removeblock = [].slice.call(document.querySelectorAll('.list-group[data-block]'))
25
    this._handleClickRemoveBlock = this._clickRemoveBlock.bind(this)
26
    
27
    this._addblock = [].slice.call(document.querySelectorAll('.add-block'))
28
    this._handleClickAddBlock = this._clickAddBlock.bind(this)
29
30
    this.onNewBlock = on(this)
31
    this.onRemoveBlock = on(this)
32
33
    this._bindEvents()
34
  }
35
36
  /**
37
   * bind events
38
   * @return {[type]} [description]
39
   */
40
  _bindEvents() {
41
    this._removeblock.forEach((block) => {
42
      block.addEventListener('click', this._handleClickRemoveBlock)
43
    })
44
    this._addblock.forEach((block) => {
45
      block.addEventListener('click', this._handleClickAddBlock)
46
    })
47
  }
48
49
  /**
50
   * event remove block
51
   * @param  {[type]} e [description]
52
   * @return {[type]}   [description]
53
   */
54
  _clickRemoveBlock(e) {
55
    var target = e.target
56
      , elem = target
57
      , parent = null
58
      , listGroup = null
59
      , blockAttr = ''
60
      , wasFound = false
61
      , startNumber = 0
62
      , endNumber = 0
63
    
64
    if(elem.classList.contains('glyphicon-trash') || elem.classList.contains('remove-block')){
65
      for(; elem && elem !== document; elem = elem.parentNode){
66
        if (elem.hasAttribute('data-block')) {
67
          parent = elem
68
          listGroup = parent.parentNode
69
          blockAttr = listGroup.getAttribute('data-block')
70
          break
71
        }
72
      }
73
    }
74
75
    if(parent && listGroup){
76
      if(listGroup.querySelectorAll('[data-block]').length === 1){
77
        var items = IframeNode('#page-template', `[data-abe-block="${blockAttr}0"]`)
78
        Array.prototype.forEach.call(items, (item) => {
79
          item.parentNode.removeChild(item)
80
        })
81
        var child = document.querySelector(`[data-block=${blockAttr}0]`)
82
        child.style.display = 'none'
83
        Array.prototype.forEach.call(child.querySelectorAll('.form-abe'), (item) => {
84
          item.value = ''
85
        })
86
        delete abe.json._data[blockAttr][0]
87
      }
88
      else{
89
        var toRemove = null
90
        Array.prototype.forEach.call(listGroup.querySelectorAll('[data-block]'), (block) => {
91
          var currentBlockAttr = block.getAttribute('data-block')
92
          var nb = parseInt(currentBlockAttr.replace(blockAttr, ''))
93
          if(wasFound){
94
            Array.prototype.forEach.call(listGroup.querySelectorAll('.form-abe'), (el) => {
95
              el.setAttribute('value', el.value)
96
            })
97
            var blockId = blockAttr + (nb-1)
98
            var html = block.innerHTML
99
100
            html = html.replace(/data-block=(\'|\")(.*)(\'|\")/g, `data-block="${blockId}"`)
101
            html = html.replace(/data-target=(\'|\")(.*)(\'|\")/g, `data-target="#${blockId}"`)
102
            html = html.replace(new RegExp('id=(' + '\\\'' + '|\\"' + ')' + blockAttr + '(\\d+)(' + '\\\'' + '|\\"' + ')', 'g'), `id="${blockId}"`)
103
            html = html.replace(/\[(\d+)\]/g, `[${nb-1}]`)
104
            block.innerHTML = html
105
            block.setAttribute('data-block', blockAttr + (nb - 1))
106
            var labelCount = block.querySelector('.label-count')
107
            labelCount.textContent = parseInt(labelCount.textContent) - 1
108
            Array.prototype.forEach.call(block.querySelectorAll('label'), (label) => {
109
              label.textContent = label.textContent.replace(new RegExp(nb, 'g'), nb - 1)
110
            })
111
112
            Array.prototype.forEach.call(IframeNode('#page-template', `[data-abe-block="${blockAttr + nb}"]`), (el) => {
113
              el.parentNode.removeChild(el)
114
            })
115
            
116
            endNumber = nb
117
          }
118
          else if(currentBlockAttr === parent.getAttribute('data-block')){
119
            Array.prototype.forEach.call(IframeNode('#page-template', `[data-abe-block="${blockAttr + nb}"]`), (el) => {
120
              el.parentNode.removeChild(el)
121
            })
122
123
            toRemove = block
124
            wasFound = true
125
            startNumber = nb
126
          }
127
        })
128
129
        toRemove.remove()
130
131
        var json = this._json.data
132
        for(var i = startNumber; i < endNumber; i++){
133
          this._insertNewBlock(blockAttr, i)
134
          Array.prototype.forEach.call(document.querySelectorAll('[data-block="' + blockAttr + i + '"] .form-abe'), (el) => {
135
            var key = el.getAttribute('data-id').split('-')
136
            if(key){
137
              key = key[1]
138
              json[blockAttr][i][key] = el.value
0 ignored issues
show
Bug introduced by
The variable i is changed as part of the for loop for example by i++ on line 132. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
139
              var nodes = EditorUtils.getNode(EditorUtils.getAttr(el))
140
              Array.prototype.forEach.call(nodes, (node) => {
141
                EditorUtils.formToHtml(node, el)
142
              })
143
            }
144
          })
145
        }
146
        json[blockAttr].pop()
147
        this._json.data = json
148
      }
149
    }
150
151
    this.onRemoveBlock._fire()
152
  }
153
154
  /**
155
   * event add new block
156
   * @param  {[type]} e [description]
157
   * @return {[type]}   [description]
158
   */
159
  _clickAddBlock(e) {
160
    let target = e.currentTarget
161
    var dataLink = target.getAttribute('data-id-link')
162
    var prevListItem = target.parentNode.parentNode.querySelectorAll('.list-block')
163
    var listGroupItem = prevListItem.length
164
    prevListItem = prevListItem[prevListItem.length - 1]
165
166
    var attrId = (typeof dataLink !== 'undefined' && dataLink !== null) ? 'data-id-link' : 'data-id'
167
      , itemNumber = 0
168
      , newNumber = 0
169
      , rex = new RegExp(itemNumber, 'g')
170
171
    if(listGroupItem > 1 || (listGroupItem === 1 && prevListItem.style.display !== 'none')) {
172
      newNumber = this._createNewBlock(prevListItem, itemNumber, newNumber)
173
      rex = new RegExp(newNumber - 1, 'g')
174
    }else {
175
      prevListItem.style.display = 'block'
176
    }
177
178
    prevListItem = target.parentNode.parentNode.querySelectorAll('.list-block')
179
    prevListItem = prevListItem[prevListItem.length - 1]
180
    var prevButton = prevListItem.querySelector('button')
181
    var dataTarget = prevButton.getAttribute('data-target')
182
    var newTarget = dataTarget.replace(rex, newNumber)
183
184
    var contentListItem = prevListItem.querySelector(dataTarget)
185
    contentListItem.setAttribute('id', newTarget.slice(1))
186
    contentListItem.setAttribute(attrId, newTarget.slice(1))
187
188
    prevButton.setAttribute('data-target', newTarget)
189
    this._insertNewBlock(prevListItem.parentNode.getAttribute('data-block'), newNumber)
190
    var labels = prevListItem.querySelectorAll('label')
191
    Array.prototype.forEach.call(labels, (label) => {
192
      label.innerHTML = label.innerHTML.replace(rex, newNumber)
193
    })
194
195
    if($(target).parents('.list-group').find('.list-block').size() > 1){
196
      prevListItem.querySelector('.label-count').textContent = parseInt(prevListItem.querySelector('.label-count').textContent) + 1
197
    }
198
199
    this.onNewBlock._fire()
200
201
    if(typeof jQuery !== 'undefined' && jQuery !== null){ // Bootstrap collapse
202
      var blocks = $(target).parents('.list-group').find('.list-block > [data-id]')
203
      $(target).parents('.list-group').find('.list-block .collapse').collapse('hide')
204
      setTimeout(function () {
205
        $('#' + blocks[blocks.length - 1].id).collapse('show')
206
      }, 200)
207
    }
208
209
  }
210
211
  /**
212
   * insert node page side
213
   * @param  {[type]} dataBlock [description]
214
   * @param  {[type]} newNumber [description]
215
   * @return {[type]}           [description]
216
   */
217
  _insertNewBlock(dataBlock, newNumber) {
218
    var blockContent = IframeCommentNode('#page-template', dataBlock)
219
    if(typeof blockContent !== 'undefined' && blockContent !== null && blockContent.length > 0) {
220
      blockContent = blockContent[0]
221
      var blockHtml = unescape(blockContent.textContent.replace(/\[\[([\S\s]*?)\]\]/, ''))
222
                        .replace(new RegExp(`-${dataBlock}0`, 'g'), `-${dataBlock}${newNumber}`)
223
                        .replace(/\[0\]-/g, '' + newNumber + '-')
224
      var newBlock = document.createElement('abe')
225
      newBlock.innerHTML = blockHtml
226
227
      var childs = [].slice.call(newBlock.childNodes)
228
      Array.prototype.forEach.call(childs, (child) => {
229
        if(typeof child.setAttribute !== 'undefined' && child.setAttribute !== null) {
230
          child.setAttribute('data-abe-block', dataBlock + newNumber)
231
        }
232
        blockContent.parentNode.insertBefore(child, blockContent)
233
      })
234
      
235
    }
236
  }
237
238
  /**
239
   * remove default value into a form
240
   * @param  {[type]} block [description]
241
   * @return {[type]}       [description]
242
   */
243
  _unValueForm(block) {
244
245
    var inputs = [].slice.call(block.querySelectorAll('input'))
246
    Array.prototype.forEach.call(inputs, (input) => {
247
      input.value = ''
248
    })
249
250
    var textareas = [].slice.call(block.querySelectorAll('textarea'))
251
    Array.prototype.forEach.call(textareas, (textarea) => {
252
      textarea.value = ''
253
    })
254
255
    // var contenteditables = [].slice.call(block.querySelectorAll('[contenteditable]'))
256
    // Array.prototype.forEach.call(contenteditables, (contenteditable) => {
257
    //   contenteditable.innerHTML = ''
258
    // })
259
260
    var selects = [].slice.call(block.querySelectorAll('select'))
261
    Array.prototype.forEach.call(selects, (select) => {
262
      select.value = ''
263
264
      var options = [].slice.call(select.querySelectorAll('option'))
265
      Array.prototype.forEach.call(options, (option) => {
266
        option.removeAttribute('selected')
267
      })
268
    })
269
  }
270
271
  /**
272
   * Create admin side block
273
   * @param  {[type]} prevListItem [description]
274
   * @param  {[type]} itemNumber   [description]
275
   * @param  {[type]} newNumber    [description]
276
   * @return {[type]}              [description]
277
   */
278
  _createNewBlock(prevListItem, itemNumber, newNumber) {
279
    var htmlBlockItem = prevListItem.innerHTML
280
281
    htmlBlockItem = htmlBlockItem.replace(/\[(.*?)\]/g, function(val, $_1) {
282
      itemNumber = parseInt($_1)
283
      newNumber = itemNumber + 1
284
      return '[' + newNumber + ']'
285
    })
286
    var rex = new RegExp(itemNumber, 'g')
287
    
288
    var dataBlock = prevListItem.getAttribute('data-block').replace(rex, newNumber)
289
290
    var newBlock = document.createElement('div')
291
    newBlock.classList.add('list-block')
292
    newBlock.setAttribute('data-block', dataBlock)
293
    newBlock.innerHTML = htmlBlockItem
294
    var next = nextSibling(prevListItem.parentNode, prevListItem)
295
    prevListItem.parentNode.insertBefore(newBlock, next)
296
    this._unValueForm(newBlock)
297
298
    var richs = [].slice.call(newBlock.querySelectorAll('[contenteditable]'))
299
    if(typeof richs !== 'undefined' && richs !== null && richs.length > 0) {
300
      Array.prototype.forEach.call(richs, (rich) => {
301
        rich.remove()
302
      })
303
      var newRichs = [].slice.call(newBlock.querySelectorAll('.rich'))
304
      Array.prototype.forEach.call(newRichs, (newRich) => {
305
        new RichText(newRich, this.color, this.link)
0 ignored issues
show
Unused Code Best Practice introduced by
The object created with new RichText(newRich, this.color, this.link) is not used but discarded. Consider invoking another function instead of a constructor if you are doing this purely for side effects.
Loading history...
306
      })
307
    }
308
309
    return newNumber
310
  }
311
}