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 |
|
|
|
|
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) |
|
|
|
|
306
|
|
|
}) |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
return newNumber |
310
|
|
|
} |
311
|
|
|
} |