wysihtml5x-rails 0.4.7 → 0.4.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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) {