wysihtml5x-rails 0.4.5 → 0.4.6

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0e9b69b5c919068f7b13f31518e2d94ad243e2c6
4
+ data.tar.gz: daa18493aca70d98cce1908d21b3a5f423e5aceb
5
+ SHA512:
6
+ metadata.gz: 785854013b0d44cbce92021376b6f0e87dd6b09bce62b63d39338eec816b2695ec55f397f319953dc08c935adb26e637e3b7a0e22780d241330d52cdd0fb726b
7
+ data.tar.gz: f7dee483d6aa30c6802aebbf25a448964be6979e0886cb5d1a7b7f9437e4cb1697aec655a320abec4ec106e9ffbd5b517d4fd21e2373f022128ea120dc895bea
@@ -1,5 +1,5 @@
1
1
  module Wysihtml5x
2
2
  module Rails
3
- VERSION = "0.4.5"
3
+ VERSION = "0.4.6"
4
4
  end
5
5
  end
@@ -77,6 +77,12 @@ var wysihtml5ParserRules = {
77
77
 
78
78
 
79
79
  "type_definitions": {
80
+
81
+ "visible_content_object": {
82
+ "methods": {
83
+ "has_visible_contet": 1
84
+ }
85
+ },
80
86
 
81
87
  "alignment_object": {
82
88
  "classes": {
@@ -344,7 +350,7 @@ var wysihtml5ParserRules = {
344
350
 
345
351
  "div": {
346
352
  "one_of_type": {
347
- "alignment_object": 1,
353
+ "visible_content_object": 1,
348
354
  },
349
355
  "remove_action": "unwrap",
350
356
  "keep_styles": {
@@ -25,7 +25,7 @@ if(!Array.isArray) {
25
25
  return Object.prototype.toString.call(arg) === '[object Array]';
26
26
  };
27
27
  };/**
28
- * @license wysihtml5x v0.4.5
28
+ * @license wysihtml5x v0.4.6
29
29
  * https://github.com/Edicy/wysihtml5
30
30
  *
31
31
  * Author: Christopher Blum (https://github.com/tiff)
@@ -36,7 +36,7 @@ if(!Array.isArray) {
36
36
  *
37
37
  */
38
38
  var wysihtml5 = {
39
- version: "0.4.5",
39
+ version: "0.4.6",
40
40
 
41
41
  // namespaces
42
42
  commands: {},
@@ -5362,74 +5362,22 @@ wysihtml5.dom.getParentElement = (function() {
5362
5362
  return styles[styles.length - 1] === cssStyle;
5363
5363
  }
5364
5364
 
5365
- function _getParentElementWithNodeName(node, nodeName, levels) {
5366
- while (levels-- && node && node.nodeName !== "BODY") {
5367
- if (_isSameNodeName(node.nodeName, nodeName)) {
5368
- return node;
5369
- }
5370
- node = node.parentNode;
5371
- }
5372
- return null;
5373
- }
5365
+ return function(node, matchingSet, levels, container) {
5366
+ var findByStyle = (matchingSet.cssStyle || matchingSet.styleRegExp),
5367
+ findByClass = (matchingSet.className || matchingSet.classRegExp);
5374
5368
 
5375
- function _getParentElementWithNodeNameAndClassName(node, nodeName, className, classRegExp, levels) {
5376
- while (levels-- && node && node.nodeName !== "BODY") {
5377
- if (_isElement(node) &&
5378
- _isSameNodeName(node.nodeName, nodeName) &&
5379
- _hasClassName(node, className, classRegExp)) {
5380
- return node;
5381
- }
5382
- node = node.parentNode;
5383
- }
5384
- return null;
5385
- }
5386
-
5387
- function _getParentElementWithNodeNameAndStyle(node, nodeName, cssStyle, styleRegExp, levels) {
5388
- while (levels-- && node && node.nodeName !== "BODY") {
5389
- if (_isElement(node) &&
5390
- _isSameNodeName(node.nodeName, nodeName) &&
5391
- _hasStyle(node, cssStyle, styleRegExp)
5392
- ) {
5393
- return node;
5394
- }
5395
- node = node.parentNode;
5396
- }
5397
- return null;
5398
- }
5369
+ levels = levels || 50; // Go max 50 nodes upwards from current node
5399
5370
 
5400
- function _getParentElementWithNodeNameAndClassNameAndStyle(node, nodeName, className, classRegExp, cssStyle, styleRegExp, levels) {
5401
- while (levels-- && node && node.nodeName !== "BODY") {
5402
- if (_isElement(node) &&
5403
- _isSameNodeName(node.nodeName, nodeName) &&
5404
- _hasStyle(node, cssStyle, styleRegExp) &&
5405
- _hasClassName(node, className, classRegExp)
5371
+ while (levels-- && node && node.nodeName !== "BODY" && (!container || node !== container)) {
5372
+ if (_isElement(node) && _isSameNodeName(node.nodeName, matchingSet.nodeName) &&
5373
+ (!findByStyle || _hasStyle(node, matchingSet.cssStyle, matchingSet.styleRegExp)) &&
5374
+ (!findByClass || _hasClassName(node, matchingSet.className, matchingSet.classRegExp))
5406
5375
  ) {
5407
5376
  return node;
5408
5377
  }
5409
5378
  node = node.parentNode;
5410
5379
  }
5411
5380
  return null;
5412
- }
5413
-
5414
- return function(node, matchingSet, levels) {
5415
- levels = levels || 50; // Go max 50 nodes upwards from current node
5416
- if ((matchingSet.className || matchingSet.classRegExp) && (matchingSet.cssStyle || matchingSet.styleRegExp)) {
5417
- return _getParentElementWithNodeNameAndClassNameAndStyle(
5418
- node, matchingSet.nodeName, matchingSet.className, matchingSet.classRegExp, matchingSet.cssStyle, matchingSet.styleRegExp, levels
5419
- );
5420
- } else if (matchingSet.className || matchingSet.classRegExp) {
5421
- return _getParentElementWithNodeNameAndClassName(
5422
- node, matchingSet.nodeName, matchingSet.className, matchingSet.classRegExp, levels
5423
- );
5424
- } else if (matchingSet.cssStyle || matchingSet.styleRegExp) {
5425
- return _getParentElementWithNodeNameAndStyle(
5426
- node, matchingSet.nodeName, matchingSet.cssStyle, matchingSet.styleRegExp, levels
5427
- );
5428
- } else {
5429
- return _getParentElementWithNodeName(
5430
- node, matchingSet.nodeName, levels
5431
- );
5432
- }
5433
5381
  };
5434
5382
  })();
5435
5383
  ;wysihtml5.dom.getNextElement = function(node){
@@ -5885,7 +5833,6 @@ wysihtml5.dom.parse = (function() {
5885
5833
  nodeName = oldNode.nodeName.toLowerCase(),
5886
5834
  scopeName = oldNode.scopeName;
5887
5835
 
5888
-
5889
5836
  /**
5890
5837
  * We already parsed that element
5891
5838
  * ignore it! (yes, this sometimes happens in IE8 when the html is invalid)
@@ -5940,7 +5887,7 @@ wysihtml5.dom.parse = (function() {
5940
5887
  _handleAttributes(oldNode, newNode, rule);
5941
5888
  _handleStyles(oldNode, newNode, rule);
5942
5889
  // tests if type condition is met or node should be removed/unwrapped
5943
- if (rule.one_of_type && !_testTypes(newNode, currentRules, rule.one_of_type)) {
5890
+ if (rule.one_of_type && !_testTypes(oldNode, currentRules, rule.one_of_type)) {
5944
5891
  return (rule.remove_action && rule.remove_action == "unwrap") ? false : null;
5945
5892
  }
5946
5893
 
@@ -5985,6 +5932,18 @@ wysihtml5.dom.parse = (function() {
5985
5932
  nodeStyles = oldNode.getAttribute("style"),
5986
5933
  classesLength, s, s_corrected, a, attr, currentClass, styleProp;
5987
5934
 
5935
+ // test for methods
5936
+ if (definition.methods) {
5937
+ for (var m in definition.methods) {
5938
+ if (definition.methods.hasOwnProperty(m) && typeCeckMethods[m]) {
5939
+
5940
+ if (typeCeckMethods[m](oldNode)) {
5941
+ return true;
5942
+ }
5943
+ }
5944
+ }
5945
+ }
5946
+
5988
5947
  // test for classes, if one found return true
5989
5948
  if (nodeClasses && definition.classes) {
5990
5949
  nodeClasses = nodeClasses.replace(/^\s+/g, '').replace(/\s+$/g, '').split(WHITE_SPACE_REG_EXP);
@@ -6364,6 +6323,40 @@ wysihtml5.dom.parse = (function() {
6364
6323
  })()
6365
6324
  };
6366
6325
 
6326
+ // checks if element is possibly visible
6327
+ var typeCeckMethods = {
6328
+ has_visible_contet: (function() {
6329
+ var txt,
6330
+ isVisible = false,
6331
+ visibleElements = ['img', 'video', 'picture', 'br', 'script', 'noscript',
6332
+ 'style', 'table', 'iframe', 'object', 'embed', 'audio',
6333
+ 'svg', 'input', 'button', 'select','textarea', 'canvas'];
6334
+
6335
+ return function(el) {
6336
+
6337
+ // has visible innertext. so is visible
6338
+ txt = (el.innerText || el.textContent).replace(/\s/g, '');
6339
+ if (txt && txt.length > 0) {
6340
+ return true;
6341
+ }
6342
+
6343
+ // matches list of visible dimensioned elements
6344
+ for (var i = visibleElements.length; i--;) {
6345
+ if (el.querySelector(visibleElements[i])) {
6346
+ return true;
6347
+ }
6348
+ }
6349
+
6350
+ // try to measure dimesions in last resort. (can find only of elements in dom)
6351
+ if (el.offsetWidth && el.offsetWidth > 0 && el.offsetHeight && el.offsetHeight > 0) {
6352
+ return true;
6353
+ }
6354
+
6355
+ return false;
6356
+ };
6357
+ })()
6358
+ };
6359
+
6367
6360
  return parse;
6368
6361
  })();
6369
6362
  ;/**
@@ -8555,6 +8548,19 @@ wysihtml5.quirks.ensureProperClearing = (function() {
8555
8548
  return (ret !== this.contain) ? ret : false;
8556
8549
  },
8557
8550
 
8551
+ getSelectionParentsByTag: function(tagName) {
8552
+ var nodes = this.getSelectedOwnNodes(),
8553
+ curEl, parents = [];
8554
+
8555
+ for (var i = 0, maxi = nodes.length; i < maxi; i++) {
8556
+ curEl = (nodes[i].nodeName && nodes[i].nodeName === 'LI') ? nodes[i] : wysihtml5.dom.getParentElement(nodes[i], { nodeName: ['LI']}, false, this.contain);
8557
+ if (curEl) {
8558
+ parents.push(curEl);
8559
+ }
8560
+ }
8561
+ return (parents.length) ? parents : null;
8562
+ },
8563
+
8558
8564
  getRangeToNodeEnd: function() {
8559
8565
  if (this.isCollapsed()) {
8560
8566
  var range = this.getRange(),
@@ -9606,6 +9612,7 @@ wysihtml5.quirks.ensureProperClearing = (function() {
9606
9612
  ancestor, styleAncestor, textNodes;
9607
9613
 
9608
9614
  for (var ri = range.length; ri--;) {
9615
+
9609
9616
  textNodes = range[ri].getNodes([wysihtml5.TEXT_NODE]);
9610
9617
  if (!textNodes.length) {
9611
9618
  ancestor = this.getAncestorWithClass(range[ri].startContainer);
@@ -9621,10 +9628,11 @@ wysihtml5.quirks.ensureProperClearing = (function() {
9621
9628
  if (!ancestor) {
9622
9629
  ancestor = this.getAncestorWithStyle(textNodes[i]);
9623
9630
  }
9624
- if (!(selectedText != "" && !ancestor)) {
9631
+ if (ancestor && selectedText != "") {
9625
9632
  ancestors.push(ancestor);
9626
9633
  }
9627
9634
  }
9635
+
9628
9636
  }
9629
9637
 
9630
9638
  return (ancestors.length) ? ancestors : false;
@@ -10461,13 +10469,19 @@ wysihtml5.commands.formatCode = {
10461
10469
  }
10462
10470
 
10463
10471
  function _getApplier(tagName, className, classRegExp, cssStyle, styleRegExp, container) {
10464
- var identifier = tagName + ":" + className;
10472
+ var identifier = tagName;
10473
+
10474
+ if (className) {
10475
+ identifier += ":" + className;
10476
+ }
10465
10477
  if (cssStyle) {
10466
10478
  identifier += ":" + cssStyle;
10467
10479
  }
10480
+
10468
10481
  if (!htmlApplier[identifier]) {
10469
10482
  htmlApplier[identifier] = new wysihtml5.selection.HTMLApplier(_getTagNames(tagName), className, classRegExp, true, cssStyle, styleRegExp, container);
10470
10483
  }
10484
+
10471
10485
  return htmlApplier[identifier];
10472
10486
  }
10473
10487
 
@@ -10546,7 +10560,7 @@ wysihtml5.commands.formatCode = {
10546
10560
 
10547
10561
  ownRanges = composer.selection.getOwnRanges();
10548
10562
 
10549
- if (ownRanges.length == 0) {
10563
+ if (!ownRanges || ownRanges.length === 0) {
10550
10564
  return false;
10551
10565
  }
10552
10566
 
@@ -11082,7 +11096,125 @@ wysihtml5.commands.formatCode = {
11082
11096
  return false;
11083
11097
  }
11084
11098
  };
11085
- ;/**
11099
+ ;wysihtml5.commands.indentList = {
11100
+ exec: function(composer, command, value) {
11101
+ var listEls = composer.selection.getSelectionParentsByTag('LI');
11102
+ if (listEls) {
11103
+ return this.tryToPushLiLevel(listEls, composer.selection);
11104
+ }
11105
+ return false;
11106
+ },
11107
+
11108
+ state: function(composer, command) {
11109
+ return false;
11110
+ },
11111
+
11112
+ tryToPushLiLevel: function(liNodes, selection) {
11113
+ var listTag, list, prevLi, liNode, prevLiList,
11114
+ found = false;
11115
+
11116
+ selection.executeAndRestoreRangy(function() {
11117
+
11118
+ for (var i = liNodes.length; i--;) {
11119
+ liNode = liNodes[i];
11120
+ listTag = (liNode.parentNode.nodeName === 'OL') ? 'OL' : 'UL';
11121
+ list = liNode.ownerDocument.createElement(listTag);
11122
+ prevLi = wysihtml5.dom.getPreviousElement(liNode);
11123
+ prevLiList = (prevLi) ? prevLi.querySelector('ul, ol') : null;
11124
+
11125
+ if (prevLi) {
11126
+ if (prevLiList) {
11127
+ prevLiList.appendChild(liNode);
11128
+ } else {
11129
+ list.appendChild(liNode);
11130
+ prevLi.appendChild(list);
11131
+ }
11132
+ found = true;
11133
+ }
11134
+ }
11135
+
11136
+ });
11137
+ return found;
11138
+ }
11139
+ };
11140
+ ;wysihtml5.commands.outdentList = {
11141
+ exec: function(composer, command, value) {
11142
+ var listEls = composer.selection.getSelectionParentsByTag('LI');
11143
+ if (listEls) {
11144
+ return this.tryToPullLiLevel(listEls, composer);
11145
+ }
11146
+ return false;
11147
+ },
11148
+
11149
+ state: function(composer, command) {
11150
+ return false;
11151
+ },
11152
+
11153
+ tryToPullLiLevel: function(liNodes, composer) {
11154
+ var listNode, outerListNode, outerLiNode, list, prevLi, liNode, afterList,
11155
+ found = false,
11156
+ that = this;
11157
+
11158
+ composer.selection.executeAndRestoreRangy(function() {
11159
+
11160
+ for (var i = liNodes.length; i--;) {
11161
+ liNode = liNodes[i];
11162
+ if (liNode.parentNode) {
11163
+ listNode = liNode.parentNode;
11164
+
11165
+ if (listNode.tagName === 'OL' || listNode.tagName === 'UL') {
11166
+ found = true;
11167
+
11168
+ outerListNode = wysihtml5.dom.getParentElement(listNode.parentNode, { nodeName: ['OL', 'UL']}, false, composer.element);
11169
+ outerLiNode = wysihtml5.dom.getParentElement(listNode.parentNode, { nodeName: ['LI']}, false, composer.element);
11170
+
11171
+ if (outerListNode && outerLiNode) {
11172
+
11173
+ if (liNode.nextSibling) {
11174
+ afterList = that.getAfterList(listNode, liNode);
11175
+ liNode.appendChild(afterList);
11176
+ }
11177
+ outerListNode.insertBefore(liNode, outerLiNode.nextSibling);
11178
+
11179
+ } else {
11180
+
11181
+ if (liNode.nextSibling) {
11182
+ afterList = that.getAfterList(listNode, liNode);
11183
+ liNode.appendChild(afterList);
11184
+ }
11185
+
11186
+ for (var j = liNode.childNodes.length; j--;) {
11187
+ listNode.parentNode.insertBefore(liNode.childNodes[j], listNode.nextSibling);
11188
+ }
11189
+
11190
+ listNode.parentNode.insertBefore(document.createElement('br'), listNode.nextSibling);
11191
+ liNode.parentNode.removeChild(liNode);
11192
+
11193
+ }
11194
+
11195
+ // cleanup
11196
+ if (listNode.childNodes.length === 0) {
11197
+ listNode.parentNode.removeChild(listNode);
11198
+ }
11199
+ }
11200
+ }
11201
+ }
11202
+
11203
+ });
11204
+ return found;
11205
+ },
11206
+
11207
+ getAfterList: function(listNode, liNode) {
11208
+ var nodeName = listNode.nodeName,
11209
+ newList = document.createElement(nodeName);
11210
+
11211
+ while (liNode.nextSibling) {
11212
+ newList.appendChild(liNode.nextSibling);
11213
+ }
11214
+ return newList;
11215
+ }
11216
+
11217
+ };;/**
11086
11218
  * Undo Manager for wysihtml5
11087
11219
  * slightly inspired by http://rniwa.com/editing/undomanager.html#the-undomanager-interface
11088
11220
  */
@@ -12059,9 +12191,12 @@ wysihtml5.views.View = Base.extend(
12059
12191
  }
12060
12192
  };
12061
12193
 
12062
- var handleDeleteKeyPress = function(event, selection, element) {
12194
+ var handleDeleteKeyPress = function(event, selection, element, composer) {
12063
12195
  if (selection.isCollapsed()) {
12064
- if (selection.caretIsInTheBeginnig()) {
12196
+ if (selection.caretIsInTheBeginnig('LI')) {
12197
+ event.preventDefault();
12198
+ composer.commands.exec('outdentList');
12199
+ } else if (selection.caretIsInTheBeginnig()) {
12065
12200
  event.preventDefault();
12066
12201
  } else {
12067
12202
  var beforeUneditable = selection.caretIsBeforeUneditable();
@@ -12078,38 +12213,11 @@ wysihtml5.views.View = Base.extend(
12078
12213
  }
12079
12214
  };
12080
12215
 
12081
- var tryToPushLiLevel = function(selection) {
12082
- var prevLi;
12083
- selection.executeAndRestoreRangy(function() {
12084
- var selNode = selection.getSelectedNode(),
12085
- liNode = (selNode.nodeName && selNode.nodeName === 'LI') ? selNode : selNode.parentNode,
12086
- listTag, list;
12087
-
12088
- if (liNode.getAttribute('class') === "rangySelectionBoundary") {
12089
- liNode = liNode.parentNode;
12090
- }
12091
-
12092
- if (liNode.nodeName === 'LI') {
12093
- listTag = (liNode.parentNode.nodeName === 'OL') ? 'OL' : 'UL';
12094
- list = selNode.ownerDocument.createElement(listTag);
12095
- prevLi = wysihtml5.dom.getPreviousElement(liNode);
12096
-
12097
- if (prevLi) {
12098
- list.appendChild(liNode);
12099
- prevLi.appendChild(list);
12100
- }
12101
- }
12102
-
12103
- });
12104
- return (prevLi) ? true : false;
12105
- };
12106
-
12107
-
12108
12216
  var handleTabKeyDown = function(composer, element) {
12109
12217
  if (!composer.selection.isCollapsed()) {
12110
12218
  composer.selection.deleteContents();
12111
12219
  } else if (composer.selection.caretIsInTheBeginnig('LI')) {
12112
- if (tryToPushLiLevel(composer.selection)) return;
12220
+ if (composer.commands.exec('indentList')) return;
12113
12221
  }
12114
12222
 
12115
12223
  // Is &emsp; close enough to tab. Could not find enough counter arguments for now.
@@ -12260,8 +12368,8 @@ wysihtml5.views.View = Base.extend(
12260
12368
  }
12261
12369
  if (keyCode === 8) {
12262
12370
  // delete key
12263
- handleDeleteKeyPress(event, that.selection, element);
12264
- } else if (keyCode === 9) {
12371
+ handleDeleteKeyPress(event, that.selection, element, that);
12372
+ } else if (that.config.handleTabKey && keyCode === 9) {
12265
12373
  event.preventDefault();
12266
12374
  handleTabKeyDown(that, element);
12267
12375
  }
@@ -12540,6 +12648,8 @@ wysihtml5.views.View = Base.extend(
12540
12648
  autoLink: true,
12541
12649
  // Includes table editing events and cell selection tracking
12542
12650
  handleTables: true,
12651
+ // Tab key inserts tab into text as default behaviour. It can be disabled to regain keyboard navigation
12652
+ handleTabKey: true,
12543
12653
  // Object which includes parser rules to apply when html gets inserted via copy & paste
12544
12654
  // See parser_rules/*.js for examples
12545
12655
  parserRules: { tags: { br: {}, span: {}, div: {}, p: {} }, classes: {} },
@@ -12561,7 +12671,6 @@ wysihtml5.views.View = Base.extend(
12561
12671
  cleanUp: true,
12562
12672
  // Whether to use div instead of secure iframe
12563
12673
  contentEditableMode: false,
12564
- xingAlert: false,
12565
12674
  // Classname of container that editor should not touch and pass through
12566
12675
  // Pass false to disable
12567
12676
  uneditableContainerClassname: "wysihtml5-uneditable-container"
@@ -12601,11 +12710,6 @@ wysihtml5.views.View = Base.extend(
12601
12710
  }
12602
12711
 
12603
12712
  this.on("beforeload", this.handleBeforeLoad);
12604
-
12605
-
12606
- if (this.config.xingAlert) {
12607
- try { console.log("Heya! This page is using wysihtml5 for rich text editing. Check out https://github.com/xing/wysihtml5");} catch(e) {}
12608
- }
12609
12713
  },
12610
12714
 
12611
12715
  handleBeforeLoad: function() {
@@ -25,7 +25,7 @@ if(!Array.isArray) {
25
25
  return Object.prototype.toString.call(arg) === '[object Array]';
26
26
  };
27
27
  };/**
28
- * @license wysihtml5x v0.4.5
28
+ * @license wysihtml5x v0.4.6
29
29
  * https://github.com/Edicy/wysihtml5
30
30
  *
31
31
  * Author: Christopher Blum (https://github.com/tiff)
@@ -36,7 +36,7 @@ if(!Array.isArray) {
36
36
  *
37
37
  */
38
38
  var wysihtml5 = {
39
- version: "0.4.5",
39
+ version: "0.4.6",
40
40
 
41
41
  // namespaces
42
42
  commands: {},
@@ -5362,74 +5362,22 @@ wysihtml5.dom.getParentElement = (function() {
5362
5362
  return styles[styles.length - 1] === cssStyle;
5363
5363
  }
5364
5364
 
5365
- function _getParentElementWithNodeName(node, nodeName, levels) {
5366
- while (levels-- && node && node.nodeName !== "BODY") {
5367
- if (_isSameNodeName(node.nodeName, nodeName)) {
5368
- return node;
5369
- }
5370
- node = node.parentNode;
5371
- }
5372
- return null;
5373
- }
5365
+ return function(node, matchingSet, levels, container) {
5366
+ var findByStyle = (matchingSet.cssStyle || matchingSet.styleRegExp),
5367
+ findByClass = (matchingSet.className || matchingSet.classRegExp);
5374
5368
 
5375
- function _getParentElementWithNodeNameAndClassName(node, nodeName, className, classRegExp, levels) {
5376
- while (levels-- && node && node.nodeName !== "BODY") {
5377
- if (_isElement(node) &&
5378
- _isSameNodeName(node.nodeName, nodeName) &&
5379
- _hasClassName(node, className, classRegExp)) {
5380
- return node;
5381
- }
5382
- node = node.parentNode;
5383
- }
5384
- return null;
5385
- }
5386
-
5387
- function _getParentElementWithNodeNameAndStyle(node, nodeName, cssStyle, styleRegExp, levels) {
5388
- while (levels-- && node && node.nodeName !== "BODY") {
5389
- if (_isElement(node) &&
5390
- _isSameNodeName(node.nodeName, nodeName) &&
5391
- _hasStyle(node, cssStyle, styleRegExp)
5392
- ) {
5393
- return node;
5394
- }
5395
- node = node.parentNode;
5396
- }
5397
- return null;
5398
- }
5369
+ levels = levels || 50; // Go max 50 nodes upwards from current node
5399
5370
 
5400
- function _getParentElementWithNodeNameAndClassNameAndStyle(node, nodeName, className, classRegExp, cssStyle, styleRegExp, levels) {
5401
- while (levels-- && node && node.nodeName !== "BODY") {
5402
- if (_isElement(node) &&
5403
- _isSameNodeName(node.nodeName, nodeName) &&
5404
- _hasStyle(node, cssStyle, styleRegExp) &&
5405
- _hasClassName(node, className, classRegExp)
5371
+ while (levels-- && node && node.nodeName !== "BODY" && (!container || node !== container)) {
5372
+ if (_isElement(node) && _isSameNodeName(node.nodeName, matchingSet.nodeName) &&
5373
+ (!findByStyle || _hasStyle(node, matchingSet.cssStyle, matchingSet.styleRegExp)) &&
5374
+ (!findByClass || _hasClassName(node, matchingSet.className, matchingSet.classRegExp))
5406
5375
  ) {
5407
5376
  return node;
5408
5377
  }
5409
5378
  node = node.parentNode;
5410
5379
  }
5411
5380
  return null;
5412
- }
5413
-
5414
- return function(node, matchingSet, levels) {
5415
- levels = levels || 50; // Go max 50 nodes upwards from current node
5416
- if ((matchingSet.className || matchingSet.classRegExp) && (matchingSet.cssStyle || matchingSet.styleRegExp)) {
5417
- return _getParentElementWithNodeNameAndClassNameAndStyle(
5418
- node, matchingSet.nodeName, matchingSet.className, matchingSet.classRegExp, matchingSet.cssStyle, matchingSet.styleRegExp, levels
5419
- );
5420
- } else if (matchingSet.className || matchingSet.classRegExp) {
5421
- return _getParentElementWithNodeNameAndClassName(
5422
- node, matchingSet.nodeName, matchingSet.className, matchingSet.classRegExp, levels
5423
- );
5424
- } else if (matchingSet.cssStyle || matchingSet.styleRegExp) {
5425
- return _getParentElementWithNodeNameAndStyle(
5426
- node, matchingSet.nodeName, matchingSet.cssStyle, matchingSet.styleRegExp, levels
5427
- );
5428
- } else {
5429
- return _getParentElementWithNodeName(
5430
- node, matchingSet.nodeName, levels
5431
- );
5432
- }
5433
5381
  };
5434
5382
  })();
5435
5383
  ;wysihtml5.dom.getNextElement = function(node){
@@ -5885,7 +5833,6 @@ wysihtml5.dom.parse = (function() {
5885
5833
  nodeName = oldNode.nodeName.toLowerCase(),
5886
5834
  scopeName = oldNode.scopeName;
5887
5835
 
5888
-
5889
5836
  /**
5890
5837
  * We already parsed that element
5891
5838
  * ignore it! (yes, this sometimes happens in IE8 when the html is invalid)
@@ -5940,7 +5887,7 @@ wysihtml5.dom.parse = (function() {
5940
5887
  _handleAttributes(oldNode, newNode, rule);
5941
5888
  _handleStyles(oldNode, newNode, rule);
5942
5889
  // tests if type condition is met or node should be removed/unwrapped
5943
- if (rule.one_of_type && !_testTypes(newNode, currentRules, rule.one_of_type)) {
5890
+ if (rule.one_of_type && !_testTypes(oldNode, currentRules, rule.one_of_type)) {
5944
5891
  return (rule.remove_action && rule.remove_action == "unwrap") ? false : null;
5945
5892
  }
5946
5893
 
@@ -5985,6 +5932,18 @@ wysihtml5.dom.parse = (function() {
5985
5932
  nodeStyles = oldNode.getAttribute("style"),
5986
5933
  classesLength, s, s_corrected, a, attr, currentClass, styleProp;
5987
5934
 
5935
+ // test for methods
5936
+ if (definition.methods) {
5937
+ for (var m in definition.methods) {
5938
+ if (definition.methods.hasOwnProperty(m) && typeCeckMethods[m]) {
5939
+
5940
+ if (typeCeckMethods[m](oldNode)) {
5941
+ return true;
5942
+ }
5943
+ }
5944
+ }
5945
+ }
5946
+
5988
5947
  // test for classes, if one found return true
5989
5948
  if (nodeClasses && definition.classes) {
5990
5949
  nodeClasses = nodeClasses.replace(/^\s+/g, '').replace(/\s+$/g, '').split(WHITE_SPACE_REG_EXP);
@@ -6364,6 +6323,40 @@ wysihtml5.dom.parse = (function() {
6364
6323
  })()
6365
6324
  };
6366
6325
 
6326
+ // checks if element is possibly visible
6327
+ var typeCeckMethods = {
6328
+ has_visible_contet: (function() {
6329
+ var txt,
6330
+ isVisible = false,
6331
+ visibleElements = ['img', 'video', 'picture', 'br', 'script', 'noscript',
6332
+ 'style', 'table', 'iframe', 'object', 'embed', 'audio',
6333
+ 'svg', 'input', 'button', 'select','textarea', 'canvas'];
6334
+
6335
+ return function(el) {
6336
+
6337
+ // has visible innertext. so is visible
6338
+ txt = (el.innerText || el.textContent).replace(/\s/g, '');
6339
+ if (txt && txt.length > 0) {
6340
+ return true;
6341
+ }
6342
+
6343
+ // matches list of visible dimensioned elements
6344
+ for (var i = visibleElements.length; i--;) {
6345
+ if (el.querySelector(visibleElements[i])) {
6346
+ return true;
6347
+ }
6348
+ }
6349
+
6350
+ // try to measure dimesions in last resort. (can find only of elements in dom)
6351
+ if (el.offsetWidth && el.offsetWidth > 0 && el.offsetHeight && el.offsetHeight > 0) {
6352
+ return true;
6353
+ }
6354
+
6355
+ return false;
6356
+ };
6357
+ })()
6358
+ };
6359
+
6367
6360
  return parse;
6368
6361
  })();
6369
6362
  ;/**
@@ -8555,6 +8548,19 @@ wysihtml5.quirks.ensureProperClearing = (function() {
8555
8548
  return (ret !== this.contain) ? ret : false;
8556
8549
  },
8557
8550
 
8551
+ getSelectionParentsByTag: function(tagName) {
8552
+ var nodes = this.getSelectedOwnNodes(),
8553
+ curEl, parents = [];
8554
+
8555
+ for (var i = 0, maxi = nodes.length; i < maxi; i++) {
8556
+ curEl = (nodes[i].nodeName && nodes[i].nodeName === 'LI') ? nodes[i] : wysihtml5.dom.getParentElement(nodes[i], { nodeName: ['LI']}, false, this.contain);
8557
+ if (curEl) {
8558
+ parents.push(curEl);
8559
+ }
8560
+ }
8561
+ return (parents.length) ? parents : null;
8562
+ },
8563
+
8558
8564
  getRangeToNodeEnd: function() {
8559
8565
  if (this.isCollapsed()) {
8560
8566
  var range = this.getRange(),
@@ -9606,6 +9612,7 @@ wysihtml5.quirks.ensureProperClearing = (function() {
9606
9612
  ancestor, styleAncestor, textNodes;
9607
9613
 
9608
9614
  for (var ri = range.length; ri--;) {
9615
+
9609
9616
  textNodes = range[ri].getNodes([wysihtml5.TEXT_NODE]);
9610
9617
  if (!textNodes.length) {
9611
9618
  ancestor = this.getAncestorWithClass(range[ri].startContainer);
@@ -9621,10 +9628,11 @@ wysihtml5.quirks.ensureProperClearing = (function() {
9621
9628
  if (!ancestor) {
9622
9629
  ancestor = this.getAncestorWithStyle(textNodes[i]);
9623
9630
  }
9624
- if (!(selectedText != "" && !ancestor)) {
9631
+ if (ancestor && selectedText != "") {
9625
9632
  ancestors.push(ancestor);
9626
9633
  }
9627
9634
  }
9635
+
9628
9636
  }
9629
9637
 
9630
9638
  return (ancestors.length) ? ancestors : false;
@@ -10461,13 +10469,19 @@ wysihtml5.commands.formatCode = {
10461
10469
  }
10462
10470
 
10463
10471
  function _getApplier(tagName, className, classRegExp, cssStyle, styleRegExp, container) {
10464
- var identifier = tagName + ":" + className;
10472
+ var identifier = tagName;
10473
+
10474
+ if (className) {
10475
+ identifier += ":" + className;
10476
+ }
10465
10477
  if (cssStyle) {
10466
10478
  identifier += ":" + cssStyle;
10467
10479
  }
10480
+
10468
10481
  if (!htmlApplier[identifier]) {
10469
10482
  htmlApplier[identifier] = new wysihtml5.selection.HTMLApplier(_getTagNames(tagName), className, classRegExp, true, cssStyle, styleRegExp, container);
10470
10483
  }
10484
+
10471
10485
  return htmlApplier[identifier];
10472
10486
  }
10473
10487
 
@@ -10546,7 +10560,7 @@ wysihtml5.commands.formatCode = {
10546
10560
 
10547
10561
  ownRanges = composer.selection.getOwnRanges();
10548
10562
 
10549
- if (ownRanges.length == 0) {
10563
+ if (!ownRanges || ownRanges.length === 0) {
10550
10564
  return false;
10551
10565
  }
10552
10566
 
@@ -11082,7 +11096,125 @@ wysihtml5.commands.formatCode = {
11082
11096
  return false;
11083
11097
  }
11084
11098
  };
11085
- ;/**
11099
+ ;wysihtml5.commands.indentList = {
11100
+ exec: function(composer, command, value) {
11101
+ var listEls = composer.selection.getSelectionParentsByTag('LI');
11102
+ if (listEls) {
11103
+ return this.tryToPushLiLevel(listEls, composer.selection);
11104
+ }
11105
+ return false;
11106
+ },
11107
+
11108
+ state: function(composer, command) {
11109
+ return false;
11110
+ },
11111
+
11112
+ tryToPushLiLevel: function(liNodes, selection) {
11113
+ var listTag, list, prevLi, liNode, prevLiList,
11114
+ found = false;
11115
+
11116
+ selection.executeAndRestoreRangy(function() {
11117
+
11118
+ for (var i = liNodes.length; i--;) {
11119
+ liNode = liNodes[i];
11120
+ listTag = (liNode.parentNode.nodeName === 'OL') ? 'OL' : 'UL';
11121
+ list = liNode.ownerDocument.createElement(listTag);
11122
+ prevLi = wysihtml5.dom.getPreviousElement(liNode);
11123
+ prevLiList = (prevLi) ? prevLi.querySelector('ul, ol') : null;
11124
+
11125
+ if (prevLi) {
11126
+ if (prevLiList) {
11127
+ prevLiList.appendChild(liNode);
11128
+ } else {
11129
+ list.appendChild(liNode);
11130
+ prevLi.appendChild(list);
11131
+ }
11132
+ found = true;
11133
+ }
11134
+ }
11135
+
11136
+ });
11137
+ return found;
11138
+ }
11139
+ };
11140
+ ;wysihtml5.commands.outdentList = {
11141
+ exec: function(composer, command, value) {
11142
+ var listEls = composer.selection.getSelectionParentsByTag('LI');
11143
+ if (listEls) {
11144
+ return this.tryToPullLiLevel(listEls, composer);
11145
+ }
11146
+ return false;
11147
+ },
11148
+
11149
+ state: function(composer, command) {
11150
+ return false;
11151
+ },
11152
+
11153
+ tryToPullLiLevel: function(liNodes, composer) {
11154
+ var listNode, outerListNode, outerLiNode, list, prevLi, liNode, afterList,
11155
+ found = false,
11156
+ that = this;
11157
+
11158
+ composer.selection.executeAndRestoreRangy(function() {
11159
+
11160
+ for (var i = liNodes.length; i--;) {
11161
+ liNode = liNodes[i];
11162
+ if (liNode.parentNode) {
11163
+ listNode = liNode.parentNode;
11164
+
11165
+ if (listNode.tagName === 'OL' || listNode.tagName === 'UL') {
11166
+ found = true;
11167
+
11168
+ outerListNode = wysihtml5.dom.getParentElement(listNode.parentNode, { nodeName: ['OL', 'UL']}, false, composer.element);
11169
+ outerLiNode = wysihtml5.dom.getParentElement(listNode.parentNode, { nodeName: ['LI']}, false, composer.element);
11170
+
11171
+ if (outerListNode && outerLiNode) {
11172
+
11173
+ if (liNode.nextSibling) {
11174
+ afterList = that.getAfterList(listNode, liNode);
11175
+ liNode.appendChild(afterList);
11176
+ }
11177
+ outerListNode.insertBefore(liNode, outerLiNode.nextSibling);
11178
+
11179
+ } else {
11180
+
11181
+ if (liNode.nextSibling) {
11182
+ afterList = that.getAfterList(listNode, liNode);
11183
+ liNode.appendChild(afterList);
11184
+ }
11185
+
11186
+ for (var j = liNode.childNodes.length; j--;) {
11187
+ listNode.parentNode.insertBefore(liNode.childNodes[j], listNode.nextSibling);
11188
+ }
11189
+
11190
+ listNode.parentNode.insertBefore(document.createElement('br'), listNode.nextSibling);
11191
+ liNode.parentNode.removeChild(liNode);
11192
+
11193
+ }
11194
+
11195
+ // cleanup
11196
+ if (listNode.childNodes.length === 0) {
11197
+ listNode.parentNode.removeChild(listNode);
11198
+ }
11199
+ }
11200
+ }
11201
+ }
11202
+
11203
+ });
11204
+ return found;
11205
+ },
11206
+
11207
+ getAfterList: function(listNode, liNode) {
11208
+ var nodeName = listNode.nodeName,
11209
+ newList = document.createElement(nodeName);
11210
+
11211
+ while (liNode.nextSibling) {
11212
+ newList.appendChild(liNode.nextSibling);
11213
+ }
11214
+ return newList;
11215
+ }
11216
+
11217
+ };;/**
11086
11218
  * Undo Manager for wysihtml5
11087
11219
  * slightly inspired by http://rniwa.com/editing/undomanager.html#the-undomanager-interface
11088
11220
  */
@@ -12059,9 +12191,12 @@ wysihtml5.views.View = Base.extend(
12059
12191
  }
12060
12192
  };
12061
12193
 
12062
- var handleDeleteKeyPress = function(event, selection, element) {
12194
+ var handleDeleteKeyPress = function(event, selection, element, composer) {
12063
12195
  if (selection.isCollapsed()) {
12064
- if (selection.caretIsInTheBeginnig()) {
12196
+ if (selection.caretIsInTheBeginnig('LI')) {
12197
+ event.preventDefault();
12198
+ composer.commands.exec('outdentList');
12199
+ } else if (selection.caretIsInTheBeginnig()) {
12065
12200
  event.preventDefault();
12066
12201
  } else {
12067
12202
  var beforeUneditable = selection.caretIsBeforeUneditable();
@@ -12078,38 +12213,11 @@ wysihtml5.views.View = Base.extend(
12078
12213
  }
12079
12214
  };
12080
12215
 
12081
- var tryToPushLiLevel = function(selection) {
12082
- var prevLi;
12083
- selection.executeAndRestoreRangy(function() {
12084
- var selNode = selection.getSelectedNode(),
12085
- liNode = (selNode.nodeName && selNode.nodeName === 'LI') ? selNode : selNode.parentNode,
12086
- listTag, list;
12087
-
12088
- if (liNode.getAttribute('class') === "rangySelectionBoundary") {
12089
- liNode = liNode.parentNode;
12090
- }
12091
-
12092
- if (liNode.nodeName === 'LI') {
12093
- listTag = (liNode.parentNode.nodeName === 'OL') ? 'OL' : 'UL';
12094
- list = selNode.ownerDocument.createElement(listTag);
12095
- prevLi = wysihtml5.dom.getPreviousElement(liNode);
12096
-
12097
- if (prevLi) {
12098
- list.appendChild(liNode);
12099
- prevLi.appendChild(list);
12100
- }
12101
- }
12102
-
12103
- });
12104
- return (prevLi) ? true : false;
12105
- };
12106
-
12107
-
12108
12216
  var handleTabKeyDown = function(composer, element) {
12109
12217
  if (!composer.selection.isCollapsed()) {
12110
12218
  composer.selection.deleteContents();
12111
12219
  } else if (composer.selection.caretIsInTheBeginnig('LI')) {
12112
- if (tryToPushLiLevel(composer.selection)) return;
12220
+ if (composer.commands.exec('indentList')) return;
12113
12221
  }
12114
12222
 
12115
12223
  // Is &emsp; close enough to tab. Could not find enough counter arguments for now.
@@ -12260,8 +12368,8 @@ wysihtml5.views.View = Base.extend(
12260
12368
  }
12261
12369
  if (keyCode === 8) {
12262
12370
  // delete key
12263
- handleDeleteKeyPress(event, that.selection, element);
12264
- } else if (keyCode === 9) {
12371
+ handleDeleteKeyPress(event, that.selection, element, that);
12372
+ } else if (that.config.handleTabKey && keyCode === 9) {
12265
12373
  event.preventDefault();
12266
12374
  handleTabKeyDown(that, element);
12267
12375
  }
@@ -12540,6 +12648,8 @@ wysihtml5.views.View = Base.extend(
12540
12648
  autoLink: true,
12541
12649
  // Includes table editing events and cell selection tracking
12542
12650
  handleTables: true,
12651
+ // Tab key inserts tab into text as default behaviour. It can be disabled to regain keyboard navigation
12652
+ handleTabKey: true,
12543
12653
  // Object which includes parser rules to apply when html gets inserted via copy & paste
12544
12654
  // See parser_rules/*.js for examples
12545
12655
  parserRules: { tags: { br: {}, span: {}, div: {}, p: {} }, classes: {} },
@@ -12561,7 +12671,6 @@ wysihtml5.views.View = Base.extend(
12561
12671
  cleanUp: true,
12562
12672
  // Whether to use div instead of secure iframe
12563
12673
  contentEditableMode: false,
12564
- xingAlert: false,
12565
12674
  // Classname of container that editor should not touch and pass through
12566
12675
  // Pass false to disable
12567
12676
  uneditableContainerClassname: "wysihtml5-uneditable-container"
@@ -12601,11 +12710,6 @@ wysihtml5.views.View = Base.extend(
12601
12710
  }
12602
12711
 
12603
12712
  this.on("beforeload", this.handleBeforeLoad);
12604
-
12605
-
12606
- if (this.config.xingAlert) {
12607
- try { console.log("Heya! This page is using wysihtml5 for rich text editing. Check out https://github.com/xing/wysihtml5");} catch(e) {}
12608
- }
12609
12713
  },
12610
12714
 
12611
12715
  handleBeforeLoad: function() {
metadata CHANGED
@@ -1,72 +1,65 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: wysihtml5x-rails
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 4
8
- - 5
9
- version: 0.4.5
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.6
10
5
  platform: ruby
11
- authors:
6
+ authors:
12
7
  - Tanel Jakobsoo
13
8
  autorequire:
14
9
  bindir: bin
15
10
  cert_chain: []
16
-
17
- date: 2014-05-06 00:00:00 +03:00
18
- default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
11
+ date: 2014-06-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
21
14
  name: railties
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
- requirements:
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
25
17
  - - ">="
26
- - !ruby/object:Gem::Version
27
- segments:
28
- - 3
29
- - 1
30
- - 0
18
+ - !ruby/object:Gem::Version
31
19
  version: 3.1.0
32
20
  type: :runtime
33
- version_requirements: *id001
34
- - !ruby/object:Gem::Dependency
35
- name: bundler
36
21
  prerelease: false
37
- requirement: &id002 !ruby/object:Gem::Requirement
38
- requirements:
39
- - - ~>
40
- - !ruby/object:Gem::Version
41
- segments:
42
- - 1
43
- - 3
44
- version: "1.3"
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 3.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
45
34
  type: :development
46
- version_requirements: *id002
47
- - !ruby/object:Gem::Dependency
48
- name: rake
49
35
  prerelease: false
50
- requirement: &id003 !ruby/object:Gem::Requirement
51
- requirements:
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
52
45
  - - ">="
53
- - !ruby/object:Gem::Version
54
- segments:
55
- - 0
56
- version: "0"
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
57
48
  type: :development
58
- version_requirements: *id003
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
59
55
  description: A wysiwyg5x text editor for Rails assets pipeline
60
- email:
56
+ email:
61
57
  - tanel@fraktal.ee
62
58
  executables: []
63
-
64
59
  extensions: []
65
-
66
60
  extra_rdoc_files: []
67
-
68
- files:
69
- - .gitignore
61
+ files:
62
+ - ".gitignore"
70
63
  - Gemfile
71
64
  - LICENSE.txt
72
65
  - README.md
@@ -80,35 +73,29 @@ files:
80
73
  - vendor/assets/javascripts/wysihtml5x.js
81
74
  - vendor/assets/stylesheets/wysihtml5x.css
82
75
  - wysihtml5x-rails.gemspec
83
- has_rdoc: true
84
76
  homepage: https://github.com/Edicy/wysihtml5x-rails
85
- licenses:
77
+ licenses:
86
78
  - MIT
79
+ metadata: {}
87
80
  post_install_message:
88
81
  rdoc_options: []
89
-
90
- require_paths:
82
+ require_paths:
91
83
  - lib
92
- required_ruby_version: !ruby/object:Gem::Requirement
93
- requirements:
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
94
86
  - - ">="
95
- - !ruby/object:Gem::Version
96
- segments:
97
- - 0
98
- version: "0"
99
- required_rubygems_version: !ruby/object:Gem::Requirement
100
- requirements:
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
101
91
  - - ">="
102
- - !ruby/object:Gem::Version
103
- segments:
104
- - 0
105
- version: "0"
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
106
94
  requirements: []
107
-
108
95
  rubyforge_project:
109
- rubygems_version: 1.3.6
96
+ rubygems_version: 2.2.2
110
97
  signing_key:
111
- specification_version: 3
112
- summary: Wysihtml5x (http://edicy.github.io/wysihtml5) text editor for Rails assets pipeline.
98
+ specification_version: 4
99
+ summary: Wysihtml5x (http://edicy.github.io/wysihtml5) text editor for Rails assets
100
+ pipeline.
113
101
  test_files: []
114
-