wysihtml5x-rails 0.4.7 → 0.4.8

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.
@@ -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.7
28
+ * @license wysihtml5x v0.4.8
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.7",
39
+ version: "0.4.8",
40
40
 
41
41
  // namespaces
42
42
  commands: {},
@@ -4939,7 +4939,6 @@ wysihtml5.browser = (function() {
4939
4939
  }
4940
4940
 
4941
4941
  if (element.nodeType === wysihtml5.TEXT_NODE && element.data.match(URL_REG_EXP)) {
4942
- console.log(element);
4943
4942
  _wrapMatchesInNode(element);
4944
4943
  return;
4945
4944
  }
@@ -5249,7 +5248,60 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
5249
5248
  };
5250
5249
 
5251
5250
  })(wysihtml5);
5252
- ;/**
5251
+ ;// TODO: Refactor dom tree traversing here
5252
+ (function(wysihtml5) {
5253
+ wysihtml5.dom.domNode = function(node) {
5254
+ var defaultNodeTypes = [wysihtml5.ELEMENT_NODE, wysihtml5.TEXT_NODE];
5255
+
5256
+ var _isBlankText = function(node) {
5257
+ return node.nodeType === wysihtml5.TEXT_NODE && (/^\s*$/g).test(node.data);
5258
+ };
5259
+
5260
+ return {
5261
+
5262
+ // var node = wysihtml5.dom.domNode(element).prev({nodeTypes: [1,3], ignoreBlankTexts: true});
5263
+ prev: function(options) {
5264
+ var prevNode = node.previousSibling,
5265
+ types = (options && options.nodeTypes) ? options.nodeTypes : defaultNodeTypes;
5266
+
5267
+ if (!prevNode) {
5268
+ return null;
5269
+ }
5270
+
5271
+ if (
5272
+ (!wysihtml5.lang.array(types).contains(prevNode.nodeType)) || // nodeTypes check.
5273
+ (options && options.ignoreBlankTexts && _isBlankText(prevNode)) // Blank text nodes bypassed if set
5274
+ ) {
5275
+ return wysihtml5.dom.domNode(prevNode).prev(options);
5276
+ }
5277
+
5278
+ return prevNode;
5279
+ },
5280
+
5281
+ // var node = wysihtml5.dom.domNode(element).next({nodeTypes: [1,3], ignoreBlankTexts: true});
5282
+ next: function(options) {
5283
+ var nextNode = node.nextSibling,
5284
+ types = (options && options.nodeTypes) ? options.nodeTypes : defaultNodeTypes;
5285
+
5286
+ if (!nextNode) {
5287
+ return null;
5288
+ }
5289
+
5290
+ if (
5291
+ (!wysihtml5.lang.array(types).contains(nextNode.nodeType)) || // nodeTypes check.
5292
+ (options && options.ignoreBlankTexts && _isBlankText(nextNode)) // blank text nodes bypassed if set
5293
+ ) {
5294
+ return wysihtml5.dom.domNode(nextNode).next(options);
5295
+ }
5296
+
5297
+ return nextNode;
5298
+ }
5299
+
5300
+
5301
+
5302
+ };
5303
+ };
5304
+ })(wysihtml5);;/**
5253
5305
  * Returns the given html wrapped in a div element
5254
5306
  *
5255
5307
  * Fixing IE's inability to treat unknown elements (HTML5 section, article, ...) correctly
@@ -5380,19 +5432,7 @@ wysihtml5.dom.getParentElement = (function() {
5380
5432
  return null;
5381
5433
  };
5382
5434
  })();
5383
- ;wysihtml5.dom.getNextElement = function(node){
5384
- var nextSibling = node.nextSibling;
5385
- while(nextSibling && nextSibling.nodeType != 1) {
5386
- nextSibling = nextSibling.nextSibling;
5387
- }
5388
- return nextSibling;
5389
- };;wysihtml5.dom.getPreviousElement = function(node){
5390
- var nextSibling = node.previousSibling;
5391
- while(nextSibling && nextSibling.nodeType != 1) {
5392
- nextSibling = nextSibling.previousSibling;
5393
- }
5394
- return nextSibling;
5395
- };;/**
5435
+ ;/**
5396
5436
  * Get element's style for a specific css property
5397
5437
  *
5398
5438
  * @param {Element} element The element on which to retrieve the style
@@ -5579,7 +5619,68 @@ wysihtml5.dom.hasElementWithTagName = (function() {
5579
5619
  }
5580
5620
  };
5581
5621
  };
5582
- ;/**
5622
+ ;// TODO: Refactor dom tree traversing here
5623
+ (function(wysihtml5) {
5624
+ wysihtml5.dom.lineBreaks = function(node) {
5625
+
5626
+ function _isLineBreak(n) {
5627
+ return n.nodeName === "BR";
5628
+ }
5629
+
5630
+ /**
5631
+ * Checks whether the elment causes a visual line break
5632
+ * (<br> or block elements)
5633
+ */
5634
+ function _isLineBreakOrBlockElement(element) {
5635
+ if (_isLineBreak(element)) {
5636
+ return true;
5637
+ }
5638
+
5639
+ if (wysihtml5.dom.getStyle("display").from(element) === "block") {
5640
+ return true;
5641
+ }
5642
+
5643
+ return false;
5644
+ }
5645
+
5646
+ return {
5647
+
5648
+ /* wysihtml5.dom.lineBreaks(element).add();
5649
+ *
5650
+ * Adds line breaks before and after the given node if the previous and next siblings
5651
+ * aren't already causing a visual line break (block element or <br>)
5652
+ */
5653
+ add: function(options) {
5654
+ var doc = node.ownerDocument,
5655
+ nextSibling = wysihtml5.dom.domNode(node).next({ignoreBlankTexts: true}),
5656
+ previousSibling = wysihtml5.dom.domNode(node).prev({ignoreBlankTexts: true});
5657
+
5658
+ if (nextSibling && !_isLineBreakOrBlockElement(nextSibling)) {
5659
+ wysihtml5.dom.insert(doc.createElement("br")).after(node);
5660
+ }
5661
+ if (previousSibling && !_isLineBreakOrBlockElement(previousSibling)) {
5662
+ wysihtml5.dom.insert(doc.createElement("br")).before(node);
5663
+ }
5664
+ },
5665
+
5666
+ /* wysihtml5.dom.lineBreaks(element).remove();
5667
+ *
5668
+ * Removes line breaks before and after the given node
5669
+ */
5670
+ remove: function(options) {
5671
+ var nextSibling = wysihtml5.dom.domNode(node).next({ignoreBlankTexts: true}),
5672
+ previousSibling = wysihtml5.dom.domNode(node).prev({ignoreBlankTexts: true});
5673
+
5674
+ if (nextSibling && _isLineBreak(nextSibling)) {
5675
+ nextSibling.parentNode.removeChild(nextSibling);
5676
+ }
5677
+ if (previousSibling && _isLineBreak(previousSibling)) {
5678
+ previousSibling.parentNode.removeChild(previousSibling);
5679
+ }
5680
+ }
5681
+ };
5682
+ };
5683
+ })(wysihtml5);;/**
5583
5684
  * Method to set dom events
5584
5685
  *
5585
5686
  * @example
@@ -6486,7 +6587,7 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
6486
6587
 
6487
6588
  var doc = list.ownerDocument,
6488
6589
  fragment = doc.createDocumentFragment(),
6489
- previousSibling = list.previousElementSibling || list.previousSibling,
6590
+ previousSibling = wysihtml5.dom.domNode(list).prev({ignoreBlankTexts: true}),
6490
6591
  firstChild,
6491
6592
  lastChild,
6492
6593
  isLastChild,
@@ -7952,7 +8053,14 @@ wysihtml5.dom.query = function(elements, query) {
7952
8053
  };
7953
8054
  }
7954
8055
  })();
7955
- ;/**
8056
+ ;wysihtml5.dom.unwrap = function(node) {
8057
+ if (node.parentNode) {
8058
+ while (node.lastChild) {
8059
+ wysihtml5.dom.insert(node.lastChild).after(node);
8060
+ }
8061
+ node.parentNode.removeChild(node);
8062
+ }
8063
+ };;/**
7956
8064
  * Fix most common html formatting misbehaviors of browsers implementation when inserting
7957
8065
  * content via copy & paste contentEditable
7958
8066
  *
@@ -9059,6 +9167,48 @@ wysihtml5.quirks.ensureProperClearing = (function() {
9059
9167
  return this.getSelection().isCollapsed;
9060
9168
  },
9061
9169
 
9170
+ isEndToEndInNode: function(nodeNames) {
9171
+ var range = this.getRange(),
9172
+ parentElement = range.commonAncestorContainer,
9173
+ startNode = range.startContainer,
9174
+ endNode = range.endContainer;
9175
+
9176
+
9177
+ if (parentElement.nodeType === wysihtml5.TEXT_NODE) {
9178
+ parentElement = parentElement.parentNode;
9179
+ }
9180
+
9181
+ if (startNode.nodeType === wysihtml5.TEXT_NODE && !(/^\s*$/).test(startNode.data.substr(range.startOffset))) {
9182
+ return false;
9183
+ }
9184
+
9185
+ if (endNode.nodeType === wysihtml5.TEXT_NODE && !(/^\s*$/).test(endNode.data.substr(range.endOffset))) {
9186
+ return false;
9187
+ }
9188
+
9189
+ while (startNode && startNode !== parentElement) {
9190
+ if (startNode.nodeType !== wysihtml5.TEXT_NODE && !wysihtml5.dom.contains(parentElement, startNode)) {
9191
+ return false;
9192
+ }
9193
+ if (wysihtml5.dom.domNode(startNode).prev({ignoreBlankTexts: true})) {
9194
+ return false;
9195
+ }
9196
+ startNode = startNode.parentNode;
9197
+ }
9198
+
9199
+ while (endNode && endNode !== parentElement) {
9200
+ if (endNode.nodeType !== wysihtml5.TEXT_NODE && !wysihtml5.dom.contains(parentElement, endNode)) {
9201
+ return false;
9202
+ }
9203
+ if (wysihtml5.dom.domNode(endNode).next({ignoreBlankTexts: true})) {
9204
+ return false;
9205
+ }
9206
+ endNode = endNode.parentNode;
9207
+ }
9208
+
9209
+ return (wysihtml5.lang.array(nodeNames).contains(parentElement.nodeName)) ? parentElement : false;
9210
+ },
9211
+
9062
9212
  deselect: function() {
9063
9213
  var sel = this.getSelection();
9064
9214
  sel && sel.removeAllRanges();
@@ -10076,7 +10226,7 @@ wysihtml5.Commands = Base.extend(
10076
10226
  // Following elements are grouped
10077
10227
  // when the caret is within a H1 and the H4 is invoked, the H1 should turn into H4
10078
10228
  // instead of creating a H4 within a H1 which would result in semantically invalid html
10079
- BLOCK_ELEMENTS_GROUP = ["H1", "H2", "H3", "H4", "H5", "H6", "P", "PRE", "BLOCKQUOTE", "DIV"];
10229
+ BLOCK_ELEMENTS_GROUP = ["H1", "H2", "H3", "H4", "H5", "H6", "P", "PRE", "DIV"];
10080
10230
 
10081
10231
  /**
10082
10232
  * Remove similiar classes (based on classRegExp)
@@ -10118,67 +10268,6 @@ wysihtml5.Commands = Base.extend(
10118
10268
  return ret;
10119
10269
  }
10120
10270
 
10121
- /**
10122
- * Check whether given node is a text node and whether it's empty
10123
- */
10124
- function _isBlankTextNode(node) {
10125
- return node.nodeType === wysihtml5.TEXT_NODE && !wysihtml5.lang.string(node.data).trim();
10126
- }
10127
-
10128
- /**
10129
- * Returns previous sibling node that is not a blank text node
10130
- */
10131
- function _getPreviousSiblingThatIsNotBlank(node) {
10132
- var previousSibling = node.previousSibling;
10133
- while (previousSibling && _isBlankTextNode(previousSibling)) {
10134
- previousSibling = previousSibling.previousSibling;
10135
- }
10136
- return previousSibling;
10137
- }
10138
-
10139
- /**
10140
- * Returns next sibling node that is not a blank text node
10141
- */
10142
- function _getNextSiblingThatIsNotBlank(node) {
10143
- var nextSibling = node.nextSibling;
10144
- while (nextSibling && _isBlankTextNode(nextSibling)) {
10145
- nextSibling = nextSibling.nextSibling;
10146
- }
10147
- return nextSibling;
10148
- }
10149
-
10150
- /**
10151
- * Adds line breaks before and after the given node if the previous and next siblings
10152
- * aren't already causing a visual line break (block element or <br>)
10153
- */
10154
- function _addLineBreakBeforeAndAfter(node) {
10155
- var doc = node.ownerDocument,
10156
- nextSibling = _getNextSiblingThatIsNotBlank(node),
10157
- previousSibling = _getPreviousSiblingThatIsNotBlank(node);
10158
-
10159
- if (nextSibling && !_isLineBreakOrBlockElement(nextSibling)) {
10160
- node.parentNode.insertBefore(doc.createElement("br"), nextSibling);
10161
- }
10162
- if (previousSibling && !_isLineBreakOrBlockElement(previousSibling)) {
10163
- node.parentNode.insertBefore(doc.createElement("br"), node);
10164
- }
10165
- }
10166
-
10167
- /**
10168
- * Removes line breaks before and after the given node
10169
- */
10170
- function _removeLineBreakBeforeAndAfter(node) {
10171
- var nextSibling = _getNextSiblingThatIsNotBlank(node),
10172
- previousSibling = _getPreviousSiblingThatIsNotBlank(node);
10173
-
10174
- if (nextSibling && _isLineBreak(nextSibling)) {
10175
- nextSibling.parentNode.removeChild(nextSibling);
10176
- }
10177
- if (previousSibling && _isLineBreak(previousSibling)) {
10178
- previousSibling.parentNode.removeChild(previousSibling);
10179
- }
10180
- }
10181
-
10182
10271
  function _removeLastChildIfLineBreak(node) {
10183
10272
  var lastChild = node.lastChild;
10184
10273
  if (lastChild && _isLineBreak(lastChild)) {
@@ -10190,22 +10279,6 @@ wysihtml5.Commands = Base.extend(
10190
10279
  return node.nodeName === "BR";
10191
10280
  }
10192
10281
 
10193
- /**
10194
- * Checks whether the elment causes a visual line break
10195
- * (<br> or block elements)
10196
- */
10197
- function _isLineBreakOrBlockElement(element) {
10198
- if (_isLineBreak(element)) {
10199
- return true;
10200
- }
10201
-
10202
- if (dom.getStyle("display").from(element) === "block") {
10203
- return true;
10204
- }
10205
-
10206
- return false;
10207
- }
10208
-
10209
10282
  /**
10210
10283
  * Execute native query command
10211
10284
  * and if necessary modify the inserted node's className
@@ -10244,7 +10317,7 @@ wysihtml5.Commands = Base.extend(
10244
10317
 
10245
10318
  var surroundedNodes = composer.selection.surround(options);
10246
10319
  for (var i = 0, imax = surroundedNodes.length; i < imax; i++) {
10247
- _removeLineBreakBeforeAndAfter(surroundedNodes[i]);
10320
+ wysihtml5.dom.lineBreaks(surroundedNodes[i]).remove();
10248
10321
  _removeLastChildIfLineBreak(surroundedNodes[i]);
10249
10322
  }
10250
10323
 
@@ -10290,7 +10363,7 @@ wysihtml5.Commands = Base.extend(
10290
10363
  if (!hasClasses && !hasStyles && (useLineBreaks || nodeName === "P")) {
10291
10364
  // Insert a line break afterwards and beforewards when there are siblings
10292
10365
  // that are not of type line break or block element
10293
- _addLineBreakBeforeAndAfter(blockElements[b]);
10366
+ wysihtml5.dom.lineBreaks(blockElements[b]).add();
10294
10367
  dom.replaceWithChildNodes(blockElements[b]);
10295
10368
  } else {
10296
10369
  // Make sure that styling is kept by renaming the element to a <div> or <p> and copying over the class name
@@ -10568,7 +10641,44 @@ wysihtml5.commands.formatCode = {
10568
10641
  }
10569
10642
  };
10570
10643
  })(wysihtml5);
10571
- ;wysihtml5.commands.insertHTML = {
10644
+ ;(function(wysihtml5) {
10645
+
10646
+ wysihtml5.commands.insertBlockQuote = {
10647
+ exec: function(composer, command) {
10648
+ var state = this.state(composer, command),
10649
+ endToEndParent = composer.selection.isEndToEndInNode(['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'P']),
10650
+ prevNode, nextNode;
10651
+
10652
+ composer.selection.executeAndRestore(function() {
10653
+ if (state) {
10654
+ if (composer.config.useLineBreaks) {
10655
+ wysihtml5.dom.lineBreaks(state).add();
10656
+ }
10657
+ wysihtml5.dom.unwrap(state);
10658
+ } else {
10659
+ if (composer.selection.isCollapsed()) {
10660
+ composer.selection.selectLine();
10661
+ }
10662
+
10663
+ if (endToEndParent) {
10664
+ var qouteEl = endToEndParent.ownerDocument.createElement('blockquote');
10665
+ wysihtml5.dom.insert(qouteEl).after(endToEndParent);
10666
+ qouteEl.appendChild(endToEndParent);
10667
+ } else {
10668
+ composer.selection.surround({nodeName: "blockquote"});
10669
+ }
10670
+ }
10671
+ });
10672
+ },
10673
+ state: function(composer, command) {
10674
+ var selectedNode = composer.selection.getSelectedNode(),
10675
+ node = wysihtml5.dom.getParentElement(selectedNode, { nodeName: "BLOCKQUOTE" }, false, composer.element);
10676
+
10677
+ return (node) ? node : false;
10678
+ }
10679
+ };
10680
+
10681
+ })(wysihtml5);;wysihtml5.commands.insertHTML = {
10572
10682
  exec: function(composer, command, html) {
10573
10683
  if (composer.commands.support(command)) {
10574
10684
  composer.doc.execCommand(command, false, html);
@@ -10701,143 +10811,181 @@ wysihtml5.commands.formatCode = {
10701
10811
  })(wysihtml5);
10702
10812
  ;wysihtml5.commands.insertOrderedList = {
10703
10813
  exec: function(composer, command) {
10704
- var doc = composer.doc,
10705
- selectedNode = composer.selection.getSelectedNode(),
10706
- list = wysihtml5.dom.getParentElement(selectedNode, { nodeName: "OL" }),
10707
- otherList = wysihtml5.dom.getParentElement(selectedNode, { nodeName: "UL" }),
10708
- tempClassName = "_wysihtml5-temp-" + new Date().getTime(),
10709
- isEmpty,
10710
- tempElement;
10711
-
10712
- // do not count list elements outside of composer
10713
- if (list && !composer.element.contains(list)) {
10714
- list = null;
10715
- }
10716
- if (otherList && !composer.element.contains(otherList)) {
10717
- otherList = null;
10718
- }
10719
-
10720
- if (!list && !otherList && composer.commands.support(command)) {
10721
- doc.execCommand(command, false, null);
10722
- return;
10723
- }
10724
-
10725
- if (list) {
10726
- // Unwrap list
10727
- // <ol><li>foo</li><li>bar</li></ol>
10728
- // becomes:
10729
- // foo<br>bar<br>
10730
- composer.selection.executeAndRestore(function() {
10731
- wysihtml5.dom.resolveList(list, composer.config.useLineBreaks);
10732
- });
10733
- } else if (otherList) {
10734
- // Turn an unordered list into an ordered list
10735
- // <ul><li>foo</li><li>bar</li></ul>
10736
- // becomes:
10737
- // <ol><li>foo</li><li>bar</li></ol>
10738
- composer.selection.executeAndRestore(function() {
10739
- wysihtml5.dom.renameElement(otherList, "ol");
10740
- });
10741
- } else {
10742
- // Create list
10743
- composer.selection.executeAndRestoreRangy(function() {
10744
- tempElement = composer.selection.deblockAndSurround({
10745
- "nodeName": "div",
10746
- "className": tempClassName
10747
- });
10748
-
10749
- // This space causes new lists to never break on enter
10750
- var INVISIBLE_SPACE_REG_EXP = /\uFEFF/g;
10751
- tempElement.innerHTML = tempElement.innerHTML.replace(INVISIBLE_SPACE_REG_EXP, "");
10752
-
10753
- if (tempElement) {
10754
- isEmpty = tempElement.innerHTML === "" || tempElement.innerHTML === wysihtml5.INVISIBLE_SPACE || tempElement.innerHTML === "<br>";
10755
- list = wysihtml5.dom.convertToList(tempElement, "ol", composer.parent.config.uneditableContainerClassname);
10756
- if (isEmpty) {
10757
- composer.selection.selectNode(list.querySelector("li"), true);
10758
- }
10759
- }
10760
- });
10761
- }
10814
+ wysihtml5.commands.insertList.exec(composer, command, "OL");
10762
10815
  },
10763
10816
 
10764
- state: function(composer) {
10765
- var selectedNode = composer.selection.getSelectedNode(),
10766
- node = wysihtml5.dom.getParentElement(selectedNode, { nodeName: "OL" });
10767
-
10768
- return (composer.element.contains(node) ? node : false);
10817
+ state: function(composer, command) {
10818
+ return wysihtml5.commands.insertList.state(composer, command, "OL");
10769
10819
  }
10770
10820
  };
10771
10821
  ;wysihtml5.commands.insertUnorderedList = {
10772
10822
  exec: function(composer, command) {
10773
- var doc = composer.doc,
10774
- selectedNode = composer.selection.getSelectedNode(),
10775
- list = wysihtml5.dom.getParentElement(selectedNode, { nodeName: "UL" }),
10776
- otherList = wysihtml5.dom.getParentElement(selectedNode, { nodeName: "OL" }),
10777
- tempClassName = "_wysihtml5-temp-" + new Date().getTime(),
10778
- isEmpty,
10779
- tempElement;
10823
+ wysihtml5.commands.insertList.exec(composer, command, "UL");
10824
+ },
10780
10825
 
10781
- // do not count list elements outside of composer
10782
- if (list && !composer.element.contains(list)) {
10783
- list = null;
10826
+ state: function(composer, command) {
10827
+ return wysihtml5.commands.insertList.state(composer, command, "UL");
10828
+ }
10829
+ };
10830
+ ;wysihtml5.commands.insertList = (function() {
10831
+
10832
+ var isNode = function(node, name) {
10833
+ if (node && node.nodeName) {
10834
+ if (typeof name === 'string') {
10835
+ name = [name];
10836
+ }
10837
+ for (var n = name.length; n--;) {
10838
+ if (node.nodeName === name[n]) {
10839
+ return true;
10840
+ }
10841
+ }
10784
10842
  }
10785
- if (otherList && !composer.element.contains(otherList)) {
10786
- otherList = null;
10843
+ return false;
10844
+ };
10845
+
10846
+ var findListEl = function(node, nodeName, composer) {
10847
+ var ret = {
10848
+ el: null,
10849
+ other: false
10850
+ };
10851
+
10852
+ if (node) {
10853
+ var parentLi = wysihtml5.dom.getParentElement(node, { nodeName: "LI" });
10854
+ otherNodeName = (nodeName === "UL") ? "OL" : "UL";
10855
+
10856
+ if (isNode(node, nodeName)) {
10857
+ ret.el = node;
10858
+ } else if (isNode(node, otherNodeName)) {
10859
+ ret = {
10860
+ el: node,
10861
+ other: true
10862
+ };
10863
+ } else if (parentLi) {
10864
+ if (isNode(parentLi.parentNode, nodeName)) {
10865
+ ret.el = parentLi.parentNode;
10866
+ } else if (isNode(parentLi.parentNode, otherNodeName)) {
10867
+ ret = {
10868
+ el : parentLi.parentNode,
10869
+ other: true
10870
+ };
10871
+ }
10872
+ }
10787
10873
  }
10788
10874
 
10789
- if (!list && !otherList && composer.commands.support(command)) {
10790
- doc.execCommand(command, false, null);
10791
- return;
10875
+ // do not count list elements outside of composer
10876
+ if (ret.el && !composer.element.contains(ret.el)) {
10877
+ ret.el = null;
10792
10878
  }
10793
10879
 
10794
- if (list) {
10795
- // Unwrap list
10796
- // <ul><li>foo</li><li>bar</li></ul>
10797
- // becomes:
10798
- // foo<br>bar<br>
10799
- composer.selection.executeAndRestore(function() {
10800
- wysihtml5.dom.resolveList(list, composer.config.useLineBreaks);
10801
- });
10802
- } else if (otherList) {
10803
- // Turn an ordered list into an unordered list
10804
- // <ol><li>foo</li><li>bar</li></ol>
10805
- // becomes:
10806
- // <ul><li>foo</li><li>bar</li></ul>
10807
- composer.selection.executeAndRestore(function() {
10808
- wysihtml5.dom.renameElement(otherList, "ul");
10809
- });
10810
- } else {
10811
- // Create list
10812
- composer.selection.executeAndRestoreRangy(function() {
10813
- tempElement = composer.selection.deblockAndSurround({
10814
- "nodeName": "div",
10815
- "className": tempClassName
10816
- });
10880
+ return ret;
10881
+ };
10817
10882
 
10818
- // This space causes new lists to never break on enter
10819
- var INVISIBLE_SPACE_REG_EXP = /\uFEFF/g;
10820
- tempElement.innerHTML = tempElement.innerHTML.replace(INVISIBLE_SPACE_REG_EXP, "");
10821
-
10822
- if (tempElement) {
10823
- isEmpty = tempElement.innerHTML === "" || tempElement.innerHTML === wysihtml5.INVISIBLE_SPACE || tempElement.innerHTML === "<br>";
10824
- list = wysihtml5.dom.convertToList(tempElement, "ul", composer.parent.config.uneditableContainerClassname);
10825
- if (isEmpty) {
10826
- composer.selection.selectNode(list.querySelector("li"), true);
10827
- }
10883
+ var handleSameTypeList = function(el, nodeName, composer) {
10884
+ var otherNodeName = (nodeName === "UL") ? "OL" : "UL",
10885
+ otherLists, innerLists;
10886
+ // Unwrap list
10887
+ // <ul><li>foo</li><li>bar</li></ul>
10888
+ // becomes:
10889
+ // foo<br>bar<br>
10890
+ composer.selection.executeAndRestore(function() {
10891
+ var otherLists = getListsInSelection(otherNodeName, composer);
10892
+ if (otherLists.length) {
10893
+ for (var l = otherLists.length; l--;) {
10894
+ wysihtml5.dom.renameElement(otherLists[l], nodeName.toLowerCase());
10828
10895
  }
10829
- });
10830
- }
10831
- },
10896
+ } else {
10897
+ innerLists = getListsInSelection(['OL', 'UL'], composer);
10898
+ for (var i = innerLists.length; i--;) {
10899
+ wysihtml5.dom.resolveList(innerLists[i], composer.config.useLineBreaks);
10900
+ }
10901
+ wysihtml5.dom.resolveList(el, composer.config.useLineBreaks);
10902
+ }
10903
+ });
10904
+ };
10832
10905
 
10833
- state: function(composer) {
10834
- var selectedNode = composer.selection.getSelectedNode(),
10835
- node = wysihtml5.dom.getParentElement(selectedNode, { nodeName: "UL" });
10906
+ var handleOtherTypeList = function(el, nodeName, composer) {
10907
+ var otherNodeName = (nodeName === "UL") ? "OL" : "UL";
10908
+ // Turn an ordered list into an unordered list
10909
+ // <ol><li>foo</li><li>bar</li></ol>
10910
+ // becomes:
10911
+ // <ul><li>foo</li><li>bar</li></ul>
10912
+ // Also rename other lists in selection
10913
+ composer.selection.executeAndRestore(function() {
10914
+ var renameLists = [el].concat(getListsInSelection(otherNodeName, composer));
10836
10915
 
10837
- return (composer.element.contains(node) ? node : false);
10838
- }
10839
- };
10840
- ;wysihtml5.commands.italic = {
10916
+ // All selection inner lists get renamed too
10917
+ for (var l = renameLists.length; l--;) {
10918
+ wysihtml5.dom.renameElement(renameLists[l], nodeName.toLowerCase());
10919
+ }
10920
+ });
10921
+ };
10922
+
10923
+ var getListsInSelection = function(nodeName, composer) {
10924
+ var ranges = composer.selection.getOwnRanges(),
10925
+ renameLists = [];
10926
+
10927
+ for (var r = ranges.length; r--;) {
10928
+ renameLists = renameLists.concat(ranges[r].getNodes([1], function(node) {
10929
+ return isNode(node, nodeName);
10930
+ }));
10931
+ }
10932
+
10933
+ return renameLists;
10934
+ };
10935
+
10936
+ var createListFallback = function(nodeName, composer) {
10937
+ // Fallback for Create list
10938
+ composer.selection.executeAndRestoreRangy(function() {
10939
+ var tempClassName = "_wysihtml5-temp-" + new Date().getTime(),
10940
+ tempElement = composer.selection.deblockAndSurround({
10941
+ "nodeName": "div",
10942
+ "className": tempClassName
10943
+ }),
10944
+ isEmpty, list;
10945
+
10946
+ // This space causes new lists to never break on enter
10947
+ var INVISIBLE_SPACE_REG_EXP = /\uFEFF/g;
10948
+ tempElement.innerHTML = tempElement.innerHTML.replace(INVISIBLE_SPACE_REG_EXP, "");
10949
+
10950
+ if (tempElement) {
10951
+ isEmpty = wysihtml5.lang.array(["", "<br>", wysihtml5.INVISIBLE_SPACE]).contains(tempElement.innerHTML);
10952
+ list = wysihtml5.dom.convertToList(tempElement, nodeName.toLowerCase(), composer.parent.config.uneditableContainerClassname);
10953
+ if (isEmpty) {
10954
+ composer.selection.selectNode(list.querySelector("li"), true);
10955
+ }
10956
+ }
10957
+ });
10958
+ };
10959
+
10960
+ return {
10961
+ exec: function(composer, command, nodeName) {
10962
+ var doc = composer.doc,
10963
+ cmd = (nodeName === "OL") ? "insertorderedlist" : "insertunorderedlist",
10964
+ selectedNode = composer.selection.getSelectedNode(),
10965
+ list = findListEl(selectedNode, nodeName, composer);
10966
+
10967
+ if (!list.el) {
10968
+ if (composer.commands.support(cmd)) {
10969
+ doc.execCommand(cmd, false, null);
10970
+ } else {
10971
+ createListFallback(nodeName, composer);
10972
+ }
10973
+ } else if (list.other) {
10974
+ handleOtherTypeList(list.el, nodeName, composer);
10975
+ } else {
10976
+ handleSameTypeList(list.el, nodeName, composer);
10977
+ }
10978
+ },
10979
+
10980
+ state: function(composer, command, nodeName) {
10981
+ var selectedNode = composer.selection.getSelectedNode(),
10982
+ list = findListEl(selectedNode, nodeName, composer);
10983
+
10984
+ return (list.el && !list.other) ? list.el : false;
10985
+ }
10986
+ };
10987
+
10988
+ })();;wysihtml5.commands.italic = {
10841
10989
  exec: function(composer, command) {
10842
10990
  wysihtml5.commands.formatInline.execWithToggle(composer, command, "i");
10843
10991
  },
@@ -11119,7 +11267,7 @@ wysihtml5.commands.formatCode = {
11119
11267
  liNode = liNodes[i];
11120
11268
  listTag = (liNode.parentNode.nodeName === 'OL') ? 'OL' : 'UL';
11121
11269
  list = liNode.ownerDocument.createElement(listTag);
11122
- prevLi = wysihtml5.dom.getPreviousElement(liNode);
11270
+ prevLi = wysihtml5.dom.domNode(liNode).prev({nodeTypes: [wysihtml5.ELEMENT_NODE]});
11123
11271
  prevLiList = (prevLi) ? prevLi.querySelector('ul, ol') : null;
11124
11272
 
11125
11273
  if (prevLi) {