@atlaskit/editor-jira-transformer 8.2.3 → 8.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,70 +9,64 @@ export class JIRATransformer {
9
9
  this.customEncoders = customEncoders || {};
10
10
  this.mediaContextInfo = mediaContextInfo;
11
11
  }
12
-
13
12
  encode(node) {
14
13
  this.doc = this.makeDocument();
15
14
  this.doc.body.appendChild(this.encodeFragment(node.content));
16
- const html = this.doc.body.innerHTML; // JIRA encodes empty documents as an empty string
15
+ const html = this.doc.body.innerHTML;
17
16
 
17
+ // JIRA encodes empty documents as an empty string
18
18
  if (html === '<p></p>') {
19
19
  return '';
20
- } // Normalise to XHTML style self closing tags.
21
-
20
+ }
22
21
 
22
+ // Normalise to XHTML style self closing tags.
23
23
  return html.replace(/<br><\/br>/g, '<br />').replace(/<br>/g, '<br />').replace(/<hr><\/hr>/g, '<hr />').replace(/<hr>/g, '<hr />').replace(/&amp;/g, '&');
24
24
  }
25
-
26
25
  parse(html) {
27
26
  const convertedNodes = new WeakMap();
28
27
  const dom = fixDoc(parseHtml(html)).querySelector('body');
29
- const nodes = bfsOrder(dom); // JIRA encodes empty content as a single nbsp
28
+ const nodes = bfsOrder(dom);
30
29
 
30
+ // JIRA encodes empty content as a single nbsp
31
31
  if (nodes.length === 1 && nodes[0].textContent === '\xa0') {
32
32
  const schemaNodes = this.schema.nodes;
33
33
  return schemaNodes.doc.createChecked({}, schemaNodes.paragraph.createChecked());
34
- } // Process through nodes in reverse (so deepest child elements are first).
35
-
34
+ }
36
35
 
36
+ // Process through nodes in reverse (so deepest child elements are first).
37
37
  for (let i = nodes.length - 1; i >= 0; i--) {
38
- const node = nodes[i]; // for tables we take tbody content, because tbody is not in schema so the whole bfs thing wouldn't work
39
-
38
+ const node = nodes[i];
39
+ // for tables we take tbody content, because tbody is not in schema so the whole bfs thing wouldn't work
40
40
  const targetNode = node.tagName && node.tagName.toUpperCase() === 'TABLE' ? node.firstChild : node;
41
41
  const content = this.getContent(targetNode, convertedNodes);
42
42
  const candidate = convert(content, node, this.schema);
43
-
44
43
  if (typeof candidate !== 'undefined') {
45
44
  convertedNodes.set(node, candidate);
46
45
  }
47
46
  }
47
+ const content = this.getContent(dom, convertedNodes);
48
48
 
49
- const content = this.getContent(dom, convertedNodes); // Dangling inline nodes can't be directly inserted into a document, so
49
+ // Dangling inline nodes can't be directly inserted into a document, so
50
50
  // we attempt to wrap in a paragraph.
51
-
52
51
  const compatibleContent = this.schema.nodes.doc.validContent(content) ? content : ensureBlocks(content, this.schema);
53
52
  return this.schema.nodes.doc.createChecked({}, compatibleContent);
54
53
  }
54
+
55
55
  /*
56
56
  * Contructs a struct string of replacement blocks and marks for a given node
57
57
  */
58
-
59
-
60
58
  getContent(node, convertedNodes) {
61
59
  let fragment = Fragment.fromArray([]);
62
60
  let childIndex;
63
-
64
61
  for (childIndex = 0; childIndex < node.childNodes.length; childIndex++) {
65
62
  const child = node.childNodes[childIndex];
66
63
  const thing = convertedNodes.get(child);
67
-
68
64
  if (thing instanceof Fragment || thing instanceof PMNode) {
69
65
  fragment = fragment.append(Fragment.from(thing));
70
66
  }
71
67
  }
72
-
73
68
  return fragment;
74
69
  }
75
-
76
70
  encodeNode(node) {
77
71
  const {
78
72
  blockquote,
@@ -91,19 +85,23 @@ export class JIRATransformer {
91
85
  mediaSingle,
92
86
  media,
93
87
  table
94
- } = this.schema.nodes; // We compare node type names in this method rather than
88
+ } = this.schema.nodes;
89
+
90
+ // We compare node type names in this method rather than
95
91
  // node types directly as the node comparision fails.
92
+
96
93
  // This suggests the schema which is coming from
97
94
  // the doc has been recreated after being passed
98
95
  // to this transformer on setup which is somewhat
99
96
  // unexpected.
97
+
100
98
  // This package is internally (within editor) considered
101
99
  // "obsolete", and we are aiming to either hand over
102
100
  // or deprecate.
101
+
103
102
  // This "fix" is being done to unblock an existing
104
103
  // consumer so they can apply an unrelated security
105
104
  // upgrade.
106
-
107
105
  if (node.isText) {
108
106
  return this.encodeText(node);
109
107
  } else if (node.type.name === heading.name) {
@@ -115,7 +113,6 @@ export class JIRATransformer {
115
113
  } else if (node.type.name === hardBreak.name) {
116
114
  return this.encodeHardBreak();
117
115
  }
118
-
119
116
  if (isSchemaWithLists(this.schema)) {
120
117
  if (node.type.name === bulletList.name) {
121
118
  return this.encodeBulletList(node);
@@ -125,23 +122,18 @@ export class JIRATransformer {
125
122
  return this.encodeListItem(node);
126
123
  }
127
124
  }
128
-
129
125
  if (isSchemaWithMentions(this.schema) && node.type.name === mention.name) {
130
126
  return this.encodeMention(node, this.customEncoders.mention);
131
127
  }
132
-
133
128
  if (isSchemaWithEmojis(this.schema) && node.type.name === emoji.name) {
134
129
  return this.encodeEmoji(node);
135
130
  }
136
-
137
131
  if (isSchemaWithCodeBlock(this.schema) && node.type.name === codeBlock.name) {
138
132
  return this.encodeCodeBlock(node);
139
133
  }
140
-
141
134
  if (isSchemaWithBlockQuotes(this.schema) && node.type.name === blockquote.name) {
142
135
  return this.encodeBlockQuote(node);
143
136
  }
144
-
145
137
  if (isSchemaWithMedia(this.schema)) {
146
138
  if (node.type.name === mediaGroup.name) {
147
139
  return this.encodeMediaGroup(node);
@@ -151,27 +143,22 @@ export class JIRATransformer {
151
143
  return this.encodeMedia(node);
152
144
  }
153
145
  }
154
-
155
146
  if (isSchemaWithTables(this.schema) && node.type.name === table.name) {
156
147
  return this.encodeTable(node);
157
148
  }
158
-
159
149
  throw new Error(`Unexpected node '${node.type.name}' for HTML encoding`);
160
150
  }
161
-
162
151
  makeDocument() {
163
152
  const doc = document.implementation.createHTMLDocument('');
164
153
  doc.body = doc.createElement('body');
165
154
  doc.documentElement.appendChild(doc.body);
166
155
  return doc;
167
156
  }
168
-
169
157
  encodeFragment(fragment) {
170
158
  const documentFragment = this.doc.createDocumentFragment();
171
159
  fragment.forEach(node => documentFragment.appendChild(this.encodeNode(node)));
172
160
  return documentFragment;
173
161
  }
174
-
175
162
  encodeHeading(node) {
176
163
  function anchorNameEncode(name) {
177
164
  const noSpaces = name.replace(/ /g, '');
@@ -179,11 +166,10 @@ export class JIRATransformer {
179
166
  const specialsEncoded = uriEncoded.replace(/[!'()*]/g, c => '%' + c.charCodeAt(0).toString(16));
180
167
  return specialsEncoded;
181
168
  }
182
-
183
169
  const {
184
170
  level
185
- } = node.attrs; // @see ED-4708
186
-
171
+ } = node.attrs;
172
+ // @see ED-4708
187
173
  const elem = this.doc.createElement(`h${level === 6 ? 5 : level}`);
188
174
  const anchor = this.doc.createElement('a');
189
175
  anchor.setAttribute('name', anchorNameEncode(node.textContent));
@@ -191,13 +177,11 @@ export class JIRATransformer {
191
177
  elem.appendChild(this.encodeFragment(node.content));
192
178
  return elem;
193
179
  }
194
-
195
180
  encodeParagraph(node) {
196
181
  const elem = this.doc.createElement('p');
197
182
  elem.appendChild(this.encodeFragment(node.content));
198
183
  return elem;
199
184
  }
200
-
201
185
  encodeText(node) {
202
186
  if (node.text) {
203
187
  const root = this.doc.createDocumentFragment();
@@ -213,127 +197,102 @@ export class JIRATransformer {
213
197
  underline,
214
198
  textColor
215
199
  } = this.schema.marks;
216
-
217
200
  for (const mark of node.marks) {
218
201
  switch (mark.type) {
219
202
  case strong:
220
203
  elem = elem.appendChild(this.doc.createElement('b'));
221
204
  break;
222
-
223
205
  case em:
224
206
  elem = elem.appendChild(this.doc.createElement('em'));
225
207
  break;
226
-
227
208
  case code:
228
209
  elem = elem.appendChild(this.doc.createElement('tt'));
229
210
  break;
230
-
231
211
  case strike:
232
212
  elem = elem.appendChild(this.doc.createElement('del'));
233
213
  break;
234
-
235
214
  case underline:
236
215
  elem = elem.appendChild(this.doc.createElement('ins'));
237
216
  break;
238
-
239
217
  case subsup:
240
218
  elem = elem.appendChild(this.doc.createElement(mark.attrs['type']));
241
219
  break;
242
-
243
220
  case link:
244
221
  const linkElem = this.doc.createElement('a');
245
222
  const href = mark.attrs['href'];
246
- /** JIRA always expects external-link attribute set on links created via editor unless its #fragment */
247
223
 
224
+ /** JIRA always expects external-link attribute set on links created via editor unless its #fragment */
248
225
  if (!href.match(/^#/)) {
249
226
  linkElem.setAttribute('class', 'external-link');
250
227
  linkElem.setAttribute('rel', 'nofollow');
251
228
  }
252
-
253
229
  linkElem.setAttribute('href', href);
254
-
255
230
  if (mark.attrs['title']) {
256
231
  linkElem.setAttribute('title', mark.attrs['title']);
257
232
  }
258
-
259
233
  elem = elem.appendChild(linkElem);
260
234
  break;
261
-
262
235
  case textColor:
263
236
  const fontElem = this.doc.createElement('font');
264
237
  fontElem.setAttribute('color', mark.attrs['color']);
265
238
  elem = elem.appendChild(fontElem);
266
239
  break;
267
-
268
240
  case typeAheadQuery:
269
241
  break;
270
-
271
242
  default:
272
243
  throw new Error(`Unable to encode mark '${mark.type.name}'`);
273
244
  }
274
245
  }
275
-
276
246
  elem.textContent = node.text;
277
247
  return root;
278
248
  } else {
279
249
  return this.doc.createTextNode('');
280
250
  }
281
251
  }
282
-
283
252
  encodeHardBreak() {
284
253
  return this.doc.createElement('br');
285
254
  }
286
-
287
255
  encodeHorizontalRule() {
288
256
  return this.doc.createElement('hr');
289
257
  }
290
-
291
258
  encodeBulletList(node) {
292
259
  const elem = this.doc.createElement('ul');
293
260
  elem.setAttribute('class', 'alternate');
294
261
  elem.setAttribute('type', 'disc');
295
262
  elem.appendChild(this.encodeFragment(node.content));
296
-
297
263
  for (let index = 0; index < elem.childElementCount; index++) {
298
264
  elem.children[index].setAttribute('data-parent', 'ul');
299
265
  }
300
-
301
266
  return elem;
302
267
  }
303
-
304
268
  encodeOrderedList(node) {
305
269
  const elem = this.doc.createElement('ol');
306
270
  elem.appendChild(this.encodeFragment(node.content));
307
-
308
271
  for (let index = 0; index < elem.childElementCount; index++) {
309
272
  elem.children[index].setAttribute('data-parent', 'ol');
310
273
  }
311
-
312
274
  return elem;
313
275
  }
314
-
315
276
  encodeListItem(node) {
316
277
  const elem = this.doc.createElement('li');
317
-
318
278
  if (node.content.childCount) {
319
279
  let hasBlocks = false;
320
280
  node.content.forEach(childNode => {
321
281
  if (childNode.type === this.schema.nodes.bulletList || childNode.type === this.schema.nodes.orderedList) {
322
282
  const list = this.encodeNode(childNode);
283
+
323
284
  /**
324
285
  * Changing type for nested list:
325
286
  *
326
287
  * Second level -> circle
327
288
  * Third and deeper -> square
328
289
  */
329
-
330
290
  if (list instanceof HTMLElement && list.tagName === 'UL') {
331
291
  list.setAttribute('type', 'circle');
332
292
  [].forEach.call(list.querySelectorAll('ul'), ul => {
333
293
  ul.setAttribute('type', 'square');
334
294
  });
335
295
  }
336
-
337
296
  elem.appendChild(list);
338
297
  } else if (childNode.type.name === 'paragraph' && !hasBlocks) {
339
298
  // Strip the paragraph node from the list item.
@@ -342,15 +301,12 @@ export class JIRATransformer {
342
301
  if (childNode.isBlock) {
343
302
  hasBlocks = true;
344
303
  }
345
-
346
304
  elem.appendChild(this.encodeNode(childNode));
347
305
  }
348
306
  });
349
307
  }
350
-
351
308
  return elem;
352
309
  }
353
-
354
310
  encodeMention(node, encoder) {
355
311
  const elem = this.doc.createElement('a');
356
312
  elem.setAttribute('class', 'user-hover');
@@ -359,45 +315,39 @@ export class JIRATransformer {
359
315
  elem.appendChild(this.doc.createTextNode(node.attrs.text));
360
316
  return elem;
361
317
  }
362
-
363
318
  encodeEmoji(node) {
364
319
  return this.doc.createTextNode(node.attrs && node.attrs.text);
365
320
  }
366
-
367
321
  encodeCodeBlock(node) {
368
322
  const elem = this.doc.createElement('div');
369
323
  elem.setAttribute('class', 'code panel');
370
324
  const content = this.doc.createElement('div');
371
325
  content.setAttribute('class', 'codeContent panelContent');
372
- const pre = this.doc.createElement('pre'); // java is default language for JIRA
373
-
326
+ const pre = this.doc.createElement('pre');
327
+ // java is default language for JIRA
374
328
  pre.setAttribute('class', `code-${(node.attrs.language || 'plain').toLocaleLowerCase()}`);
375
329
  pre.appendChild(this.encodeFragment(node.content));
376
330
  content.appendChild(pre);
377
331
  elem.appendChild(content);
378
332
  return elem;
379
333
  }
380
-
381
334
  encodeBlockQuote(node) {
382
335
  const elem = this.doc.createElement('blockquote');
383
336
  elem.appendChild(this.encodeFragment(node.content));
384
337
  return elem;
385
338
  }
386
-
387
339
  encodeMediaGroup(node) {
388
340
  const elem = this.doc.createElement('p');
389
341
  elem.setAttribute('class', 'mediaGroup');
390
342
  elem.appendChild(this.encodeFragment(node.content));
391
343
  return elem;
392
344
  }
393
-
394
345
  encodeMediaSingle(node) {
395
346
  const elem = this.doc.createElement('p');
396
347
  elem.setAttribute('class', 'mediaSingle');
397
348
  elem.appendChild(this.encodeFragment(node.content));
398
349
  return elem;
399
350
  }
400
-
401
351
  addDataToNode(domNode, mediaNode, defaultDisplayType = 'thumbnail') {
402
352
  const {
403
353
  id,
@@ -407,30 +357,24 @@ export class JIRATransformer {
407
357
  __displayType,
408
358
  width,
409
359
  height
410
- } = mediaNode.attrs; // Order of dataset matters in IE Edge, please keep the current order
411
-
360
+ } = mediaNode.attrs;
361
+ // Order of dataset matters in IE Edge, please keep the current order
412
362
  domNode.setAttribute('data-attachment-type', __displayType || defaultDisplayType);
413
-
414
363
  if (__fileName) {
415
364
  domNode.setAttribute('data-attachment-name', __fileName);
416
365
  }
417
-
418
366
  if (width) {
419
367
  domNode.setAttribute('data-width', width);
420
368
  }
421
-
422
369
  if (height) {
423
370
  domNode.setAttribute('data-height', height);
424
371
  }
425
-
426
372
  domNode.setAttribute('data-media-services-type', type);
427
373
  domNode.setAttribute('data-media-services-id', id);
428
-
429
374
  if (collection) {
430
375
  domNode.setAttribute('data-media-services-collection', collection);
431
376
  }
432
377
  }
433
-
434
378
  buildURLWithContextInfo(fileId, contextInfo) {
435
379
  const {
436
380
  clientId,
@@ -440,17 +384,14 @@ export class JIRATransformer {
440
384
  } = contextInfo;
441
385
  return `${baseUrl}/file/${fileId}/image?token=${token}&client=${clientId}&collection=${collection}&width=200&height=200&mode=fit`;
442
386
  }
443
-
444
387
  isImageMimeType(mimeType) {
445
388
  return mimeType && mimeType.indexOf('image/') > -1;
446
389
  }
447
-
448
390
  encodeMedia(node) {
449
391
  // span.image-wrap > a > jira-attachment-thumbnail > img[data-media-*] > content
450
392
  // span.no-br > a[data-media] > content
451
393
  const elem = this.doc.createElement('span');
452
394
  const a = this.doc.createElement('a');
453
-
454
395
  if (node.attrs.__displayType === 'file' || !(node.attrs.__displayType || this.isImageMimeType(node.attrs.__fileMimeType))) {
455
396
  elem.setAttribute('class', 'nobr');
456
397
  this.addDataToNode(a, node, 'file');
@@ -458,24 +399,21 @@ export class JIRATransformer {
458
399
  } else {
459
400
  elem.setAttribute('class', 'image-wrap');
460
401
  const img = this.doc.createElement('img');
461
- img.setAttribute('alt', node.attrs.__fileName); // Newly uploaded items have collection
462
-
402
+ img.setAttribute('alt', node.attrs.__fileName);
403
+ // Newly uploaded items have collection
463
404
  if (node.attrs.collection && this.mediaContextInfo && this.mediaContextInfo.uploadContext) {
464
405
  img.setAttribute('src', this.buildURLWithContextInfo(node.attrs.id, this.mediaContextInfo.uploadContext));
465
406
  } else if (this.mediaContextInfo && this.mediaContextInfo.viewContext) {
466
407
  img.setAttribute('src', this.buildURLWithContextInfo(node.attrs.id, this.mediaContextInfo.viewContext));
467
408
  }
468
-
469
409
  this.addDataToNode(img, node);
470
410
  const jiraThumb = this.doc.createElement('jira-attachment-thumbnail');
471
411
  jiraThumb.appendChild(img);
472
412
  a.appendChild(jiraThumb);
473
413
  }
474
-
475
414
  elem.appendChild(a);
476
415
  return elem;
477
416
  }
478
-
479
417
  encodeTable(node) {
480
418
  const elem = this.doc.createElement('table');
481
419
  const tbody = this.doc.createElement('tbody');
@@ -496,5 +434,4 @@ export class JIRATransformer {
496
434
  elem.setAttribute('class', 'confluenceTable');
497
435
  return elem;
498
436
  }
499
-
500
437
  }
@@ -6,7 +6,6 @@ export default function (fragment) {
6
6
  collapse(tree.documentElement, isBlock);
7
7
  return tree;
8
8
  }
9
-
10
9
  function isBlock(node) {
11
10
  // these blocks are mainly used to collapse whitespace between the blocks
12
11
  // (preventing spurious text nodes of ' ')
@@ -62,6 +61,5 @@ function isBlock(node) {
62
61
  case 'UL':
63
62
  return true;
64
63
  }
65
-
66
64
  return false;
67
65
  }