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