wysihtml-rails 0.5.3 → 0.5.4
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.
- data/lib/wysihtml/rails/version.rb +1 -1
- data/vendor/assets/javascripts/wysihtml-toolbar.js +336 -237
- data/vendor/assets/javascripts/wysihtml.js +336 -237
- metadata +4 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license wysihtml v0.5.
|
|
2
|
+
* @license wysihtml v0.5.4
|
|
3
3
|
* https://github.com/Voog/wysihtml
|
|
4
4
|
*
|
|
5
5
|
* Author: Christopher Blum (https://github.com/tiff)
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
*/
|
|
12
12
|
var wysihtml5 = {
|
|
13
|
-
version: "0.5.
|
|
13
|
+
version: "0.5.4",
|
|
14
14
|
|
|
15
15
|
// namespaces
|
|
16
16
|
commands: {},
|
|
@@ -7938,11 +7938,6 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
|
|
|
7938
7938
|
return nodes;
|
|
7939
7939
|
}
|
|
7940
7940
|
|
|
7941
|
-
// Returns if node is the rangy selection bookmark element (that must not be taken into account in most situatons and is removed on selection restoring)
|
|
7942
|
-
function isBookmark(n) {
|
|
7943
|
-
return n && n.nodeType === 1 && n.classList.contains('rangySelectionBoundary');
|
|
7944
|
-
}
|
|
7945
|
-
|
|
7946
7941
|
wysihtml5.dom.domNode = function(node) {
|
|
7947
7942
|
var defaultNodeTypes = [wysihtml5.ELEMENT_NODE, wysihtml5.TEXT_NODE];
|
|
7948
7943
|
|
|
@@ -7951,7 +7946,12 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
|
|
|
7951
7946
|
is: {
|
|
7952
7947
|
emptyTextNode: function(ignoreWhitespace) {
|
|
7953
7948
|
var regx = ignoreWhitespace ? (/^\s*$/g) : (/^[\r\n]*$/g);
|
|
7954
|
-
return node.nodeType === wysihtml5.TEXT_NODE && (regx).test(node.data);
|
|
7949
|
+
return node && node.nodeType === wysihtml5.TEXT_NODE && (regx).test(node.data);
|
|
7950
|
+
},
|
|
7951
|
+
|
|
7952
|
+
// Returns if node is the rangy selection bookmark element (that must not be taken into account in most situatons and is removed on selection restoring)
|
|
7953
|
+
rangyBookmark: function() {
|
|
7954
|
+
return node && node.nodeType === 1 && node.classList.contains('rangySelectionBoundary');
|
|
7955
7955
|
},
|
|
7956
7956
|
|
|
7957
7957
|
visible: function() {
|
|
@@ -7990,7 +7990,7 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
|
|
|
7990
7990
|
}
|
|
7991
7991
|
|
|
7992
7992
|
if (
|
|
7993
|
-
|
|
7993
|
+
wysihtml5.dom.domNode(prevNode).is.rangyBookmark() || // is Rangy temporary boomark element (bypass)
|
|
7994
7994
|
(!wysihtml5.lang.array(types).contains(prevNode.nodeType)) || // nodeTypes check.
|
|
7995
7995
|
(options && options.ignoreBlankTexts && wysihtml5.dom.domNode(prevNode).is.emptyTextNode(true)) // Blank text nodes bypassed if set
|
|
7996
7996
|
) {
|
|
@@ -8010,7 +8010,7 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
|
|
|
8010
8010
|
}
|
|
8011
8011
|
|
|
8012
8012
|
if (
|
|
8013
|
-
|
|
8013
|
+
wysihtml5.dom.domNode(nextNode).is.rangyBookmark() || // is Rangy temporary boomark element (bypass)
|
|
8014
8014
|
(!wysihtml5.lang.array(types).contains(nextNode.nodeType)) || // nodeTypes check.
|
|
8015
8015
|
(options && options.ignoreBlankTexts && wysihtml5.dom.domNode(nextNode).is.emptyTextNode(true)) // blank text nodes bypassed if set
|
|
8016
8016
|
) {
|
|
@@ -11762,7 +11762,7 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
|
11762
11762
|
}
|
|
11763
11763
|
};
|
|
11764
11764
|
|
|
11765
|
-
blankNode.appendChild(
|
|
11765
|
+
blankNode.appendChild(container.ownerDocument.createTextNode(wysihtml5.INVISIBLE_SPACE));
|
|
11766
11766
|
blankNode.className = '_wysihtml5-temp-caret-fix';
|
|
11767
11767
|
blankNode.style.display = 'block';
|
|
11768
11768
|
blankNode.style.minWidth = '1px';
|
|
@@ -12198,10 +12198,17 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
|
12198
12198
|
nextNode = caretNode.nextSibling;
|
|
12199
12199
|
}
|
|
12200
12200
|
} else {
|
|
12201
|
-
|
|
12201
|
+
if (r[0].startOffset === 0 && r[0].startContainer.previousSibling) {
|
|
12202
|
+
caretNode = r[0].startContainer.previousSibling;
|
|
12203
|
+
if (caretNode.nodeType === 3) {
|
|
12204
|
+
offset = caretNode.data.length;
|
|
12205
|
+
}
|
|
12206
|
+
} else {
|
|
12207
|
+
caretNode = r[0].startContainer;
|
|
12208
|
+
offset = r[0].startOffset;
|
|
12209
|
+
}
|
|
12202
12210
|
prevNode = caretNode.previousSibling;
|
|
12203
12211
|
nextNode = caretNode.nextSibling;
|
|
12204
|
-
offset = r[0].startOffset;
|
|
12205
12212
|
}
|
|
12206
12213
|
|
|
12207
12214
|
return {
|
|
@@ -12647,8 +12654,8 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
|
12647
12654
|
if (wysihtml5.browser.supportsSelectionModify()) {
|
|
12648
12655
|
this._selectLine_W3C();
|
|
12649
12656
|
} else if (r.nativeRange && r.nativeRange.getBoundingClientRect) {
|
|
12650
|
-
|
|
12651
|
-
|
|
12657
|
+
// For IE Edge as it ditched the old api and did not fully implement the new one (as expected)
|
|
12658
|
+
this._selectLineUniversal();
|
|
12652
12659
|
}
|
|
12653
12660
|
},
|
|
12654
12661
|
|
|
@@ -12664,7 +12671,6 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
|
12664
12671
|
} else {
|
|
12665
12672
|
return node.data && node.data.length || 0;
|
|
12666
12673
|
}
|
|
12667
|
-
// body...
|
|
12668
12674
|
},
|
|
12669
12675
|
anode = s.anchorNode.nodeType === 1 ? s.anchorNode.childNodes[s.anchorOffset] : s.anchorNode,
|
|
12670
12676
|
fnode = s.focusNode.nodeType === 1 ? s.focusNode.childNodes[s.focusOffset] : s.focusNode;
|
|
@@ -12773,7 +12779,16 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
|
12773
12779
|
r.moveEnd('character', 1);
|
|
12774
12780
|
} else if (r.startContainer.nodeType === 1 && r.startContainer.childNodes[r.startOffset] && r.startContainer.childNodes[r.startOffset].nodeType === 3 && r.startContainer.childNodes[r.startOffset].data.length > 0) {
|
|
12775
12781
|
r.moveEnd('character', 1);
|
|
12776
|
-
} else if (
|
|
12782
|
+
} else if (
|
|
12783
|
+
r.startOffset > 0 &&
|
|
12784
|
+
(
|
|
12785
|
+
r.startContainer.nodeType === 3 ||
|
|
12786
|
+
(
|
|
12787
|
+
r.startContainer.nodeType === 1 &&
|
|
12788
|
+
!isLineBreakingElement(prevNode(r.startContainer.childNodes[r.startOffset - 1]))
|
|
12789
|
+
)
|
|
12790
|
+
)
|
|
12791
|
+
) {
|
|
12777
12792
|
r.moveStart('character', -1);
|
|
12778
12793
|
}
|
|
12779
12794
|
}
|
|
@@ -12783,6 +12798,7 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
|
12783
12798
|
|
|
12784
12799
|
// Is probably just empty line as can not be expanded
|
|
12785
12800
|
rect = r.nativeRange.getBoundingClientRect();
|
|
12801
|
+
// If startnode is not line break allready move the start position of range by -1 character until clientRect top changes;
|
|
12786
12802
|
do {
|
|
12787
12803
|
amount = r.moveStart('character', -1);
|
|
12788
12804
|
testRect = r.nativeRange.getBoundingClientRect();
|
|
@@ -12793,31 +12809,31 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
|
12793
12809
|
}
|
|
12794
12810
|
count++;
|
|
12795
12811
|
} while (amount !== 0 && !found && count < 2000);
|
|
12796
|
-
|
|
12797
12812
|
count = 0;
|
|
12798
12813
|
found = false;
|
|
12799
12814
|
rect = r.nativeRange.getBoundingClientRect();
|
|
12800
|
-
|
|
12801
|
-
|
|
12802
|
-
|
|
12803
|
-
|
|
12804
|
-
r.
|
|
12805
|
-
|
|
12806
|
-
|
|
12807
|
-
|
|
12808
|
-
|
|
12809
|
-
|
|
12810
|
-
|
|
12811
|
-
|
|
12812
|
-
|
|
12815
|
+
|
|
12816
|
+
if (r.endContainer !== this.contain || (this.contain.lastChild && this.contain.childNodes[r.endOffset] !== this.contain.lastChild)) {
|
|
12817
|
+
do {
|
|
12818
|
+
amount = r.moveEnd('character', 1);
|
|
12819
|
+
testRect = r.nativeRange.getBoundingClientRect();
|
|
12820
|
+
if (!testRect || Math.floor(testRect.bottom) !== Math.floor(rect.bottom)) {
|
|
12821
|
+
r.moveEnd('character', -1);
|
|
12822
|
+
|
|
12823
|
+
// Fix a IE line end marked by linebreak element although caret is before it
|
|
12824
|
+
// If causes problems should be changed to be applied only to IE
|
|
12825
|
+
if (r.endContainer && r.endContainer.nodeType === 1 && r.endContainer.childNodes[r.endOffset] && r.endContainer.childNodes[r.endOffset].nodeType === 1 && r.endContainer.childNodes[r.endOffset].nodeName === "BR" && r.endContainer.childNodes[r.endOffset].previousSibling) {
|
|
12826
|
+
if (r.endContainer.childNodes[r.endOffset].previousSibling.nodeType === 1) {
|
|
12827
|
+
r.setEnd(r.endContainer.childNodes[r.endOffset].previousSibling, r.endContainer.childNodes[r.endOffset].previousSibling.childNodes.length);
|
|
12828
|
+
} else if (r.endContainer.childNodes[r.endOffset].previousSibling.nodeType === 3) {
|
|
12829
|
+
r.setEnd(r.endContainer.childNodes[r.endOffset].previousSibling, r.endContainer.childNodes[r.endOffset].previousSibling.data.length);
|
|
12830
|
+
}
|
|
12813
12831
|
}
|
|
12832
|
+
found = true;
|
|
12814
12833
|
}
|
|
12815
|
-
|
|
12816
|
-
|
|
12817
|
-
|
|
12818
|
-
count++;
|
|
12819
|
-
} while (amount !== 0 && !found && count < 2000);
|
|
12820
|
-
|
|
12834
|
+
count++;
|
|
12835
|
+
} while (amount !== 0 && !found && count < 2000);
|
|
12836
|
+
}
|
|
12821
12837
|
r.select();
|
|
12822
12838
|
this.includeRangyRangeHelpers();
|
|
12823
12839
|
},
|
|
@@ -14159,7 +14175,7 @@ wysihtml5.Commands = Base.extend(
|
|
|
14159
14175
|
nbIdx;
|
|
14160
14176
|
|
|
14161
14177
|
for (var i = elements.length; i--;) {
|
|
14162
|
-
if (elements[i].innerHTML.replace(/[\uFEFF]/g, '') === "") {
|
|
14178
|
+
if (elements[i].innerHTML.replace(/[\uFEFF]/g, '') === "" && (newBlockElements.length === 0 || elements[i] !== newBlockElements[newBlockElements.length - 1])) {
|
|
14163
14179
|
// If cleanup removes some new block elements. remove them from newblocks array too
|
|
14164
14180
|
nbIdx = wysihtml5.lang.array(newBlockElements).indexOf(elements[i]);
|
|
14165
14181
|
if (nbIdx > -1) {
|
|
@@ -14496,8 +14512,13 @@ wysihtml5.Commands = Base.extend(
|
|
|
14496
14512
|
}
|
|
14497
14513
|
composer.selection.splitElementAtCaret(outerInlines.parent, fragment);
|
|
14498
14514
|
} else {
|
|
14499
|
-
|
|
14515
|
+
var fc = fragment.firstChild,
|
|
14516
|
+
lc = fragment.lastChild;
|
|
14517
|
+
|
|
14500
14518
|
range.insertNode(fragment);
|
|
14519
|
+
// restore range position as it might get lost in webkit sometimes
|
|
14520
|
+
range.setStartBefore(fc);
|
|
14521
|
+
range.setEndAfter(lc);
|
|
14501
14522
|
}
|
|
14502
14523
|
}
|
|
14503
14524
|
}
|
|
@@ -14626,7 +14647,21 @@ wysihtml5.Commands = Base.extend(
|
|
|
14626
14647
|
startNode = getRangeNode(r.startContainer, r.startOffset),
|
|
14627
14648
|
endNode = getRangeNode(r.endContainer, r.endOffset),
|
|
14628
14649
|
prevNode = (r.startContainer === startNode && startNode.nodeType === 3 && !isWhitespaceBefore(startNode, r.startOffset)) ? startNode : wysihtml5.dom.domNode(startNode).prev({nodeTypes: [1,3], ignoreBlankTexts: true}),
|
|
14629
|
-
nextNode = (
|
|
14650
|
+
nextNode = (
|
|
14651
|
+
(
|
|
14652
|
+
r.endContainer.nodeType === 1 &&
|
|
14653
|
+
r.endContainer.childNodes[r.endOffset] === endNode &&
|
|
14654
|
+
(
|
|
14655
|
+
endNode.nodeType === 1 ||
|
|
14656
|
+
!isWhitespaceAfter(endNode, r.endOffset) &&
|
|
14657
|
+
!wysihtml5.dom.domNode(endNode).is.rangyBookmark()
|
|
14658
|
+
)
|
|
14659
|
+
) || (
|
|
14660
|
+
r.endContainer === endNode &&
|
|
14661
|
+
endNode.nodeType === 3 &&
|
|
14662
|
+
!isWhitespaceAfter(endNode, r.endOffset)
|
|
14663
|
+
)
|
|
14664
|
+
) ? endNode : wysihtml5.dom.domNode(endNode).next({nodeTypes: [1,3], ignoreBlankTexts: true}),
|
|
14630
14665
|
content = r.extractContents(),
|
|
14631
14666
|
fragment = composer.doc.createDocumentFragment(),
|
|
14632
14667
|
similarOuterBlock = similarOptions ? wysihtml5.dom.getParentElement(rangeStartContainer, similarOptions, null, composer.element) : null,
|
|
@@ -14635,6 +14670,11 @@ wysihtml5.Commands = Base.extend(
|
|
|
14635
14670
|
wrapper, blocks, children,
|
|
14636
14671
|
firstc, lastC;
|
|
14637
14672
|
|
|
14673
|
+
if (wysihtml5.dom.domNode(nextNode).is.rangyBookmark()) {
|
|
14674
|
+
endNode = nextNode;
|
|
14675
|
+
nextNode = endNode.nextSibling;
|
|
14676
|
+
}
|
|
14677
|
+
|
|
14638
14678
|
trimBlankTextsAndBreaks(content);
|
|
14639
14679
|
|
|
14640
14680
|
if (options && options.nodeName === "BLOCKQUOTE") {
|
|
@@ -14684,6 +14724,16 @@ wysihtml5.Commands = Base.extend(
|
|
|
14684
14724
|
}
|
|
14685
14725
|
injectFragmentToRange(fragment, r, composer, firstOuterBlock);
|
|
14686
14726
|
removeSurroundingLineBreaks(prevNode, nextNode, composer);
|
|
14727
|
+
|
|
14728
|
+
// Fix webkit madness by inserting linebreak rangy after cursor marker to blank last block
|
|
14729
|
+
// (if it contains rangy bookmark, so selection can be restored later correctly)
|
|
14730
|
+
if (blocks.length > 0 &&
|
|
14731
|
+
(
|
|
14732
|
+
typeof blocks[blocks.length - 1].lastChild === "undefined" || wysihtml5.dom.domNode(blocks[blocks.length - 1].lastChild).is.rangyBookmark()
|
|
14733
|
+
)
|
|
14734
|
+
) {
|
|
14735
|
+
blocks[blocks.length - 1].appendChild(composer.doc.createElement('br'));
|
|
14736
|
+
}
|
|
14687
14737
|
return blocks;
|
|
14688
14738
|
}
|
|
14689
14739
|
|
|
@@ -15832,7 +15882,9 @@ wysihtml5.Commands = Base.extend(
|
|
|
15832
15882
|
for (var i = innerLists.length; i--;) {
|
|
15833
15883
|
wysihtml5.dom.resolveList(innerLists[i], composer.config.useLineBreaks);
|
|
15834
15884
|
}
|
|
15835
|
-
|
|
15885
|
+
if (innerLists.length === 0) {
|
|
15886
|
+
wysihtml5.dom.resolveList(el, composer.config.useLineBreaks);
|
|
15887
|
+
}
|
|
15836
15888
|
}
|
|
15837
15889
|
});
|
|
15838
15890
|
};
|
|
@@ -15900,8 +15952,34 @@ wysihtml5.Commands = Base.extend(
|
|
|
15900
15952
|
exec: function(composer, command, nodeName) {
|
|
15901
15953
|
var doc = composer.doc,
|
|
15902
15954
|
cmd = (nodeName === "OL") ? "insertOrderedList" : "insertUnorderedList",
|
|
15903
|
-
|
|
15904
|
-
|
|
15955
|
+
s = composer.selection.getSelection(),
|
|
15956
|
+
anode = s.anchorNode.nodeType === 1 && s.anchorNode.firstChild ? s.anchorNode.childNodes[s.anchorOffset] : s.anchorNode,
|
|
15957
|
+
fnode = s.focusNode.nodeType === 1 && s.focusNode.firstChild ? s.focusNode.childNodes[s.focusOffset] || s.focusNode.lastChild : s.focusNode,
|
|
15958
|
+
selectedNode, list;
|
|
15959
|
+
|
|
15960
|
+
if (s.isBackwards()) {
|
|
15961
|
+
// swap variables
|
|
15962
|
+
anode = [fnode, fnode = anode][0];
|
|
15963
|
+
}
|
|
15964
|
+
|
|
15965
|
+
if (wysihtml5.dom.domNode(fnode).is.emptyTextNode(true) && fnode) {
|
|
15966
|
+
fnode = wysihtml5.dom.domNode(fnode).prev({nodeTypes: [1,3], ignoreBlankTexts: true});
|
|
15967
|
+
}
|
|
15968
|
+
if (wysihtml5.dom.domNode(anode).is.emptyTextNode(true) && anode) {
|
|
15969
|
+
anode = wysihtml5.dom.domNode(anode).next({nodeTypes: [1,3], ignoreBlankTexts: true});
|
|
15970
|
+
}
|
|
15971
|
+
|
|
15972
|
+
if (anode && fnode) {
|
|
15973
|
+
if (anode === fnode) {
|
|
15974
|
+
selectedNode = anode;
|
|
15975
|
+
} else {
|
|
15976
|
+
selectedNode = wysihtml5.dom.domNode(anode).commonAncestor(fnode, composer.element);
|
|
15977
|
+
}
|
|
15978
|
+
} else {
|
|
15979
|
+
selectedNode = composer.selection.getSelectedNode();
|
|
15980
|
+
}
|
|
15981
|
+
|
|
15982
|
+
list = findListEl(selectedNode, nodeName, composer);
|
|
15905
15983
|
|
|
15906
15984
|
if (!list.el) {
|
|
15907
15985
|
if (composer.commands.support(cmd)) {
|
|
@@ -17390,155 +17468,248 @@ wysihtml5.views.View = Base.extend(
|
|
|
17390
17468
|
"73": "italic", // I
|
|
17391
17469
|
"85": "underline" // U
|
|
17392
17470
|
};
|
|
17471
|
+
|
|
17472
|
+
var actions = {
|
|
17393
17473
|
|
|
17394
|
-
|
|
17395
|
-
|
|
17396
|
-
|
|
17397
|
-
|
|
17398
|
-
|
|
17399
|
-
|
|
17400
|
-
|
|
17474
|
+
// Adds multiple eventlisteners to target, bound to one callback
|
|
17475
|
+
// TODO: If needed elsewhere make it part of wysihtml5.dom or sth
|
|
17476
|
+
addListeners: function (target, events, callback) {
|
|
17477
|
+
for(var i = 0, max = events.length; i < max; i++) {
|
|
17478
|
+
target.addEventListener(events[i], callback, false);
|
|
17479
|
+
}
|
|
17480
|
+
},
|
|
17401
17481
|
|
|
17402
|
-
|
|
17403
|
-
|
|
17404
|
-
|
|
17405
|
-
|
|
17406
|
-
|
|
17407
|
-
|
|
17408
|
-
|
|
17482
|
+
// Removes multiple eventlisteners from target, bound to one callback
|
|
17483
|
+
// TODO: If needed elsewhere make it part of wysihtml5.dom or sth
|
|
17484
|
+
removeListeners: function (target, events, callback) {
|
|
17485
|
+
for(var i = 0, max = events.length; i < max; i++) {
|
|
17486
|
+
target.removeEventListener(events[i], callback, false);
|
|
17487
|
+
}
|
|
17488
|
+
},
|
|
17409
17489
|
|
|
17410
|
-
|
|
17411
|
-
|
|
17412
|
-
|
|
17413
|
-
|
|
17414
|
-
|
|
17415
|
-
|
|
17416
|
-
|
|
17417
|
-
|
|
17418
|
-
|
|
17419
|
-
|
|
17490
|
+
// Override for giving user ability to delete last line break in table cell
|
|
17491
|
+
fixLastBrDeletionInTable: function(composer, force) {
|
|
17492
|
+
if (composer.selection.caretIsLastInSelection()) {
|
|
17493
|
+
var sel = composer.selection.getSelection(),
|
|
17494
|
+
aNode = sel.anchorNode;
|
|
17495
|
+
if (aNode && aNode.nodeType === 1 && (wysihtml5.dom.getParentElement(aNode, {query: 'td, th'}, false, composer.element) || force)) {
|
|
17496
|
+
var nextNode = aNode.childNodes[sel.anchorOffset];
|
|
17497
|
+
if (nextNode && nextNode.nodeType === 1 & nextNode.nodeName === "BR") {
|
|
17498
|
+
nextNode.parentNode.removeChild(nextNode);
|
|
17499
|
+
return true;
|
|
17500
|
+
}
|
|
17420
17501
|
}
|
|
17421
17502
|
}
|
|
17422
|
-
|
|
17423
|
-
|
|
17424
|
-
};
|
|
17503
|
+
return false;
|
|
17504
|
+
},
|
|
17425
17505
|
|
|
17426
|
-
|
|
17427
|
-
|
|
17428
|
-
|
|
17429
|
-
|
|
17430
|
-
|
|
17506
|
+
// If found an uneditable before caret then notify it before deletion
|
|
17507
|
+
handleUneditableDeletion: function(composer) {
|
|
17508
|
+
var before = composer.selection.getBeforeSelection(true);
|
|
17509
|
+
if (before && (before.type === "element" || before.type === "leafnode") && before.node.nodeType === 1 && before.node.classList.contains(composer.config.classNames.uneditableContainer)) {
|
|
17510
|
+
if (actions.fixLastBrDeletionInTable(composer, true)) {
|
|
17511
|
+
return true;
|
|
17512
|
+
}
|
|
17513
|
+
try {
|
|
17514
|
+
var ev = new CustomEvent("wysihtml5:uneditable:delete", {bubbles: true, cancelable: false});
|
|
17515
|
+
before.node.dispatchEvent(ev);
|
|
17516
|
+
} catch (err) {}
|
|
17517
|
+
before.node.parentNode.removeChild(before.node);
|
|
17431
17518
|
return true;
|
|
17432
17519
|
}
|
|
17433
|
-
|
|
17434
|
-
|
|
17435
|
-
before.node.dispatchEvent(ev);
|
|
17436
|
-
} catch (err) {}
|
|
17437
|
-
before.node.parentNode.removeChild(before.node);
|
|
17438
|
-
return true;
|
|
17439
|
-
}
|
|
17440
|
-
return false;
|
|
17441
|
-
};
|
|
17520
|
+
return false;
|
|
17521
|
+
},
|
|
17442
17522
|
|
|
17443
|
-
|
|
17444
|
-
|
|
17445
|
-
|
|
17446
|
-
|
|
17447
|
-
|
|
17448
|
-
|
|
17449
|
-
|
|
17450
|
-
|
|
17451
|
-
|
|
17452
|
-
|
|
17453
|
-
|
|
17454
|
-
|
|
17455
|
-
|
|
17456
|
-
|
|
17457
|
-
|
|
17458
|
-
|
|
17459
|
-
|
|
17460
|
-
|
|
17461
|
-
|
|
17462
|
-
|
|
17463
|
-
|
|
17464
|
-
|
|
17465
|
-
|
|
17466
|
-
|
|
17467
|
-
|
|
17468
|
-
|
|
17469
|
-
|
|
17470
|
-
|
|
17471
|
-
|
|
17472
|
-
|
|
17523
|
+
// Deletion with caret in the beginning of headings and other block elvel elements needs special attention
|
|
17524
|
+
// Not allways does it concate text to previous block node correctly (browsers do unexpected miracles here especially webkit)
|
|
17525
|
+
fixDeleteInTheBeginningOfBlock: function(composer) {
|
|
17526
|
+
var selection = composer.selection,
|
|
17527
|
+
prevNode = selection.getPreviousNode();
|
|
17528
|
+
|
|
17529
|
+
if (selection.caretIsFirstInSelection() &&
|
|
17530
|
+
prevNode &&
|
|
17531
|
+
prevNode.nodeType === 1 &&
|
|
17532
|
+
(/block/).test(composer.win.getComputedStyle(prevNode).display) &&
|
|
17533
|
+
!domNode(prevNode).test({
|
|
17534
|
+
query: "ol, ul, table, tr, dl"
|
|
17535
|
+
})
|
|
17536
|
+
) {
|
|
17537
|
+
if ((/^\s*$/).test(prevNode.textContent || prevNode.innerText)) {
|
|
17538
|
+
// If heading is empty remove the heading node
|
|
17539
|
+
prevNode.parentNode.removeChild(prevNode);
|
|
17540
|
+
return true;
|
|
17541
|
+
} else {
|
|
17542
|
+
if (prevNode.lastChild) {
|
|
17543
|
+
var selNode = prevNode.lastChild,
|
|
17544
|
+
selectedNode = selection.getSelectedNode(),
|
|
17545
|
+
commonAncestorNode = domNode(prevNode).commonAncestor(selectedNode, composer.element),
|
|
17546
|
+
curNode = wysihtml5.dom.getParentElement(selectedNode, {
|
|
17547
|
+
query: "h1, h2, h3, h4, h5, h6, p, pre, div, blockquote"
|
|
17548
|
+
}, false, commonAncestorNode || composer.element);
|
|
17549
|
+
|
|
17550
|
+
if (curNode) {
|
|
17551
|
+
domNode(curNode).transferContentTo(prevNode, true);
|
|
17552
|
+
selection.setAfter(selNode);
|
|
17553
|
+
return true;
|
|
17554
|
+
}
|
|
17555
|
+
}
|
|
17556
|
+
}
|
|
17557
|
+
}
|
|
17558
|
+
return false;
|
|
17559
|
+
},
|
|
17560
|
+
|
|
17561
|
+
/* In IE when deleting with caret at the begining of LI, list gets broken into half instead of merging the LI with previous */
|
|
17562
|
+
/* This does not match other browsers an is less intuitive from UI standpoint, thus has to be fixed */
|
|
17563
|
+
fixDeleteInTheBeginningOfLi: function(composer) {
|
|
17564
|
+
if (wysihtml5.browser.hasLiDeletingProblem()) {
|
|
17565
|
+
var selection = composer.selection.getSelection(),
|
|
17566
|
+
aNode = selection.anchorNode,
|
|
17567
|
+
listNode, prevNode, firstNode,
|
|
17568
|
+
isInBeginnig = composer.selection.caretIsFirstInSelection();
|
|
17569
|
+
|
|
17570
|
+
// Fix caret at the beginnig of first textNode in LI
|
|
17571
|
+
if (aNode.nodeType === 3 && selection.anchorOffset === 0 && aNode === aNode.parentNode.firstChild) {
|
|
17572
|
+
aNode = aNode.parentNode;
|
|
17573
|
+
isInBeginnig = true;
|
|
17574
|
+
}
|
|
17575
|
+
|
|
17576
|
+
if (isInBeginnig && aNode && aNode.nodeType === 1 && aNode.nodeName === "LI") {
|
|
17577
|
+
prevNode = domNode(aNode).prev({nodeTypes: [1,3], ignoreBlankTexts: true});
|
|
17578
|
+
if (!prevNode && aNode.parentNode && (aNode.parentNode.nodeName === "UL" || aNode.parentNode.nodeName === "OL")) {
|
|
17579
|
+
prevNode = domNode(aNode.parentNode).prev({nodeTypes: [1,3], ignoreBlankTexts: true});
|
|
17580
|
+
}
|
|
17581
|
+
if (prevNode) {
|
|
17582
|
+
firstNode = aNode.firstChild;
|
|
17583
|
+
domNode(aNode).transferContentTo(prevNode, true);
|
|
17584
|
+
if (firstNode) {
|
|
17585
|
+
composer.selection.setBefore(firstNode);
|
|
17586
|
+
} else if (prevNode) {
|
|
17587
|
+
if (prevNode.nodeType === 1) {
|
|
17588
|
+
if (prevNode.lastChild) {
|
|
17589
|
+
composer.selection.setAfter(prevNode.lastChild);
|
|
17590
|
+
} else {
|
|
17591
|
+
composer.selection.selectNode(prevNode);
|
|
17592
|
+
}
|
|
17593
|
+
} else {
|
|
17594
|
+
composer.selection.setAfter(prevNode);
|
|
17595
|
+
}
|
|
17596
|
+
}
|
|
17473
17597
|
return true;
|
|
17474
17598
|
}
|
|
17475
17599
|
}
|
|
17476
17600
|
}
|
|
17477
|
-
|
|
17478
|
-
|
|
17479
|
-
|
|
17601
|
+
return false;
|
|
17602
|
+
},
|
|
17603
|
+
|
|
17604
|
+
// Table management
|
|
17605
|
+
// If present enableObjectResizing and enableInlineTableEditing command should be called with false to prevent native table handlers
|
|
17606
|
+
initTableHandling: function() {
|
|
17607
|
+
var hideHandlers = function() {
|
|
17608
|
+
window.removeEventListener('load', hideHandlers);
|
|
17609
|
+
this.doc.execCommand("enableObjectResizing", false, "false");
|
|
17610
|
+
this.doc.execCommand("enableInlineTableEditing", false, "false");
|
|
17611
|
+
}.bind(this),
|
|
17612
|
+
iframeInitiator = (function() {
|
|
17613
|
+
hideHandlers.call(this);
|
|
17614
|
+
actions.removeListeners(this.sandbox.getIframe(), ["focus", "mouseup", "mouseover"], iframeInitiator);
|
|
17615
|
+
}).bind(this);
|
|
17616
|
+
|
|
17617
|
+
if( this.doc.execCommand &&
|
|
17618
|
+
wysihtml5.browser.supportsCommand(this.doc, "enableObjectResizing") &&
|
|
17619
|
+
wysihtml5.browser.supportsCommand(this.doc, "enableInlineTableEditing"))
|
|
17620
|
+
{
|
|
17621
|
+
if (this.sandbox.getIframe) {
|
|
17622
|
+
actions.addListeners(this.sandbox.getIframe(), ["focus", "mouseup", "mouseover"], iframeInitiator);
|
|
17623
|
+
} else {
|
|
17624
|
+
window.addEventListener('load', hideHandlers);
|
|
17625
|
+
}
|
|
17626
|
+
}
|
|
17627
|
+
this.tableSelection = wysihtml5.quirks.tableCellsSelection(this.element, this.parent);
|
|
17628
|
+
},
|
|
17629
|
+
|
|
17630
|
+
// Fixes some misbehaviours of enters in linebreaks mode (natively a bit unsupported feature)
|
|
17631
|
+
// Returns true if some corrections is applied so events know when to prevent default
|
|
17632
|
+
doLineBreaksModeEnterWithCaret: function(composer) {
|
|
17633
|
+
var breakNodes = "p, pre, div, blockquote",
|
|
17634
|
+
caretInfo, parent, txtNode,
|
|
17635
|
+
ret = false;
|
|
17636
|
+
|
|
17637
|
+
caretInfo = composer.selection.getNodesNearCaret();
|
|
17638
|
+
if (caretInfo) {
|
|
17639
|
+
|
|
17640
|
+
if (caretInfo.caretNode || caretInfo.nextNode) {
|
|
17641
|
+
parent = dom.getParentElement(caretInfo.caretNode || caretInfo.nextNode, { query: breakNodes }, 2);
|
|
17642
|
+
if (parent === composer.element) {
|
|
17643
|
+
parent = undefined;
|
|
17644
|
+
}
|
|
17645
|
+
}
|
|
17646
|
+
|
|
17647
|
+
if (parent && caretInfo.caretNode) {
|
|
17648
|
+
if (domNode(caretInfo.caretNode).is.lineBreak()) {
|
|
17649
|
+
|
|
17650
|
+
if (composer.config.doubleLineBreakEscapesBlock) {
|
|
17651
|
+
// Double enter (enter on blank line) exits block element in useLineBreaks mode.
|
|
17652
|
+
ret = true;
|
|
17653
|
+
caretInfo.caretNode.parentNode.removeChild(caretInfo.caretNode);
|
|
17654
|
+
|
|
17655
|
+
// Ensure surplous line breaks are not added to preceding element
|
|
17656
|
+
if (domNode(caretInfo.nextNode).is.lineBreak()) {
|
|
17657
|
+
caretInfo.nextNode.parentNode.removeChild(caretInfo.nextNode);
|
|
17658
|
+
}
|
|
17480
17659
|
|
|
17481
|
-
|
|
17482
|
-
|
|
17483
|
-
|
|
17484
|
-
if (wysihtml5.browser.hasLiDeletingProblem()) {
|
|
17485
|
-
var selection = composer.selection.getSelection(),
|
|
17486
|
-
aNode = selection.anchorNode,
|
|
17487
|
-
listNode, prevNode, firstNode,
|
|
17488
|
-
isInBeginnig = composer.selection.caretIsFirstInSelection();
|
|
17489
|
-
|
|
17490
|
-
// Fix caret at the beginnig of first textNode in LI
|
|
17491
|
-
if (aNode.nodeType === 3 && selection.anchorOffset === 0 && aNode === aNode.parentNode.firstChild) {
|
|
17492
|
-
aNode = aNode.parentNode;
|
|
17493
|
-
isInBeginnig = true;
|
|
17494
|
-
}
|
|
17495
|
-
|
|
17496
|
-
if (isInBeginnig && aNode && aNode.nodeType === 1 && aNode.nodeName === "LI") {
|
|
17497
|
-
prevNode = domNode(aNode).prev({nodeTypes: [1,3], ignoreBlankTexts: true});
|
|
17498
|
-
if (!prevNode && aNode.parentNode && (aNode.parentNode.nodeName === "UL" || aNode.parentNode.nodeName === "OL")) {
|
|
17499
|
-
prevNode = domNode(aNode.parentNode).prev({nodeTypes: [1,3], ignoreBlankTexts: true});
|
|
17500
|
-
}
|
|
17501
|
-
if (prevNode) {
|
|
17502
|
-
firstNode = aNode.firstChild;
|
|
17503
|
-
domNode(aNode).transferContentTo(prevNode, true);
|
|
17504
|
-
if (firstNode) {
|
|
17505
|
-
composer.selection.setBefore(firstNode);
|
|
17506
|
-
} else if (prevNode) {
|
|
17507
|
-
if (prevNode.nodeType === 1) {
|
|
17508
|
-
if (prevNode.lastChild) {
|
|
17509
|
-
composer.selection.setAfter(prevNode.lastChild);
|
|
17660
|
+
var brNode = composer.doc.createElement('br');
|
|
17661
|
+
if (domNode(caretInfo.nextNode).is.lineBreak() && caretInfo.nextNode === parent.lastChild) {
|
|
17662
|
+
parent.parentNode.insertBefore(brNode, parent.nextSibling);
|
|
17510
17663
|
} else {
|
|
17511
|
-
composer.selection.
|
|
17664
|
+
composer.selection.splitElementAtCaret(parent, brNode);
|
|
17512
17665
|
}
|
|
17513
|
-
|
|
17514
|
-
|
|
17666
|
+
|
|
17667
|
+
// Ensure surplous blank lines are not added to preceding element
|
|
17668
|
+
if (caretInfo.nextNode && caretInfo.nextNode.nodeType === 3) {
|
|
17669
|
+
// Replaces blank lines at the beginning of textnode
|
|
17670
|
+
caretInfo.nextNode.data = caretInfo.nextNode.data.replace(/^ *[\r\n]+/, '');
|
|
17671
|
+
}
|
|
17672
|
+
composer.selection.setBefore(brNode);
|
|
17515
17673
|
}
|
|
17674
|
+
|
|
17675
|
+
} else if (caretInfo.caretNode.nodeType === 3 && wysihtml5.browser.hasCaretBlockElementIssue() && caretInfo.textOffset === caretInfo.caretNode.data.length && !caretInfo.nextNode) {
|
|
17676
|
+
|
|
17677
|
+
// This fixes annoying webkit issue when you press enter at the end of a block then seemingly nothing happens.
|
|
17678
|
+
// in reality one line break is generated and cursor is reported after it, but when entering something cursor jumps before the br
|
|
17679
|
+
ret = true;
|
|
17680
|
+
var br1 = composer.doc.createElement('br'),
|
|
17681
|
+
br2 = composer.doc.createElement('br'),
|
|
17682
|
+
f = composer.doc.createDocumentFragment();
|
|
17683
|
+
f.appendChild(br1);
|
|
17684
|
+
f.appendChild(br2);
|
|
17685
|
+
composer.selection.insertNode(f);
|
|
17686
|
+
composer.selection.setBefore(br2);
|
|
17687
|
+
|
|
17516
17688
|
}
|
|
17517
|
-
return true;
|
|
17518
17689
|
}
|
|
17519
17690
|
}
|
|
17691
|
+
return ret;
|
|
17520
17692
|
}
|
|
17521
|
-
|
|
17522
|
-
}
|
|
17693
|
+
};
|
|
17523
17694
|
|
|
17524
17695
|
var handleDeleteKeyPress = function(event, composer) {
|
|
17525
17696
|
var selection = composer.selection,
|
|
17526
17697
|
element = composer.element;
|
|
17527
17698
|
|
|
17528
17699
|
if (selection.isCollapsed()) {
|
|
17529
|
-
if (handleUneditableDeletion(composer)) {
|
|
17700
|
+
if (actions.handleUneditableDeletion(composer)) {
|
|
17530
17701
|
event.preventDefault();
|
|
17531
17702
|
return;
|
|
17532
17703
|
}
|
|
17533
|
-
if (fixDeleteInTheBeginningOfLi(composer)) {
|
|
17704
|
+
if (actions.fixDeleteInTheBeginningOfLi(composer)) {
|
|
17534
17705
|
event.preventDefault();
|
|
17535
17706
|
return;
|
|
17536
17707
|
}
|
|
17537
|
-
if (fixDeleteInTheBeginningOfBlock(composer)) {
|
|
17708
|
+
if (actions.fixDeleteInTheBeginningOfBlock(composer)) {
|
|
17538
17709
|
event.preventDefault();
|
|
17539
17710
|
return;
|
|
17540
17711
|
}
|
|
17541
|
-
if (fixLastBrDeletionInTable(composer)) {
|
|
17712
|
+
if (actions.fixLastBrDeletionInTable(composer)) {
|
|
17542
17713
|
event.preventDefault();
|
|
17543
17714
|
return;
|
|
17544
17715
|
}
|
|
@@ -17558,59 +17729,8 @@ wysihtml5.views.View = Base.extend(
|
|
|
17558
17729
|
caretInfo, parent, txtNode;
|
|
17559
17730
|
|
|
17560
17731
|
if (composer.selection.isCollapsed()) {
|
|
17561
|
-
|
|
17562
|
-
|
|
17563
|
-
|
|
17564
|
-
if (caretInfo.caretNode || caretInfo.nextNode) {
|
|
17565
|
-
parent = dom.getParentElement(caretInfo.caretNode || caretInfo.nextNode, { query: breakNodes }, 2);
|
|
17566
|
-
if (parent === composer.element) {
|
|
17567
|
-
parent = undefined;
|
|
17568
|
-
}
|
|
17569
|
-
}
|
|
17570
|
-
|
|
17571
|
-
if (parent && caretInfo.caretNode) {
|
|
17572
|
-
if (domNode(caretInfo.caretNode).is.lineBreak()) {
|
|
17573
|
-
|
|
17574
|
-
if (composer.config.doubleLineBreakEscapesBlock) {
|
|
17575
|
-
// Double enter (enter on blank line) exits block element in useLineBreaks mode.
|
|
17576
|
-
event.preventDefault();
|
|
17577
|
-
caretInfo.caretNode.parentNode.removeChild(caretInfo.caretNode);
|
|
17578
|
-
|
|
17579
|
-
// Ensure surplous line breaks are not added to preceding element
|
|
17580
|
-
if (domNode(caretInfo.nextNode).is.lineBreak()) {
|
|
17581
|
-
caretInfo.nextNode.parentNode.removeChild(caretInfo.nextNode);
|
|
17582
|
-
}
|
|
17583
|
-
|
|
17584
|
-
var brNode = composer.doc.createElement('br');
|
|
17585
|
-
if (domNode(caretInfo.nextNode).is.lineBreak() && caretInfo.nextNode === parent.lastChild) {
|
|
17586
|
-
parent.parentNode.insertBefore(brNode, parent.nextSibling);
|
|
17587
|
-
} else {
|
|
17588
|
-
composer.selection.splitElementAtCaret(parent, brNode);
|
|
17589
|
-
}
|
|
17590
|
-
|
|
17591
|
-
// Ensure surplous blank lines are not added to preceding element
|
|
17592
|
-
if (caretInfo.nextNode && caretInfo.nextNode.nodeType === 3) {
|
|
17593
|
-
// Replaces blank lines at the beginning of textnode
|
|
17594
|
-
caretInfo.nextNode.data = caretInfo.nextNode.data.replace(/^ *[\r\n]+/, '');
|
|
17595
|
-
}
|
|
17596
|
-
composer.selection.setBefore(brNode);
|
|
17597
|
-
}
|
|
17598
|
-
|
|
17599
|
-
} else if (caretInfo.caretNode.nodeType === 3 && wysihtml5.browser.hasCaretBlockElementIssue() && caretInfo.textOffset === caretInfo.caretNode.data.length && !caretInfo.nextNode) {
|
|
17600
|
-
|
|
17601
|
-
// This fixes annoying webkit issue when you press enter at the end of a block then seemingly nothing happens.
|
|
17602
|
-
// in reality one line break is generated and cursor is reported after it, but when entering something cursor jumps before the br
|
|
17603
|
-
event.preventDefault();
|
|
17604
|
-
var br1 = composer.doc.createElement('br'),
|
|
17605
|
-
br2 = composer.doc.createElement('br'),
|
|
17606
|
-
f = composer.doc.createDocumentFragment();
|
|
17607
|
-
f.appendChild(br1);
|
|
17608
|
-
f.appendChild(br2);
|
|
17609
|
-
composer.selection.insertNode(f);
|
|
17610
|
-
composer.selection.setBefore(br2);
|
|
17611
|
-
|
|
17612
|
-
}
|
|
17613
|
-
}
|
|
17732
|
+
if (actions.doLineBreaksModeEnterWithCaret(composer)) {
|
|
17733
|
+
event.preventDefault();
|
|
17614
17734
|
}
|
|
17615
17735
|
}
|
|
17616
17736
|
}
|
|
@@ -17797,31 +17917,10 @@ wysihtml5.views.View = Base.extend(
|
|
|
17797
17917
|
}).bind(this), 0);
|
|
17798
17918
|
};
|
|
17799
17919
|
|
|
17800
|
-
|
|
17801
|
-
|
|
17802
|
-
|
|
17803
|
-
|
|
17804
|
-
window.removeEventListener('load', hideHandlers);
|
|
17805
|
-
this.doc.execCommand("enableObjectResizing", false, "false");
|
|
17806
|
-
this.doc.execCommand("enableInlineTableEditing", false, "false");
|
|
17807
|
-
}.bind(this),
|
|
17808
|
-
iframeInitiator = (function() {
|
|
17809
|
-
hideHandlers.call(this);
|
|
17810
|
-
removeListeners(this.sandbox.getIframe(), ["focus", "mouseup", "mouseover"], iframeInitiator);
|
|
17811
|
-
}).bind(this);
|
|
17812
|
-
|
|
17813
|
-
if( this.doc.execCommand &&
|
|
17814
|
-
wysihtml5.browser.supportsCommand(this.doc, "enableObjectResizing") &&
|
|
17815
|
-
wysihtml5.browser.supportsCommand(this.doc, "enableInlineTableEditing"))
|
|
17816
|
-
{
|
|
17817
|
-
if (this.sandbox.getIframe) {
|
|
17818
|
-
addListeners(this.sandbox.getIframe(), ["focus", "mouseup", "mouseover"], iframeInitiator);
|
|
17819
|
-
} else {
|
|
17820
|
-
window.addEventListener('load', hideHandlers);
|
|
17821
|
-
}
|
|
17822
|
-
}
|
|
17823
|
-
this.tableSelection = wysihtml5.quirks.tableCellsSelection(this.element, this.parent);
|
|
17824
|
-
};
|
|
17920
|
+
|
|
17921
|
+
|
|
17922
|
+
// Testing requires actions to be accessible from out of scope
|
|
17923
|
+
wysihtml5.views.Composer.prototype.observeActions = actions;
|
|
17825
17924
|
|
|
17826
17925
|
wysihtml5.views.Composer.prototype.observe = function() {
|
|
17827
17926
|
var that = this,
|
|
@@ -17847,14 +17946,14 @@ wysihtml5.views.View = Base.extend(
|
|
|
17847
17946
|
// --------- User interactions --
|
|
17848
17947
|
if (this.config.handleTables) {
|
|
17849
17948
|
// If handleTables option is true, table handling functions are bound
|
|
17850
|
-
initTableHandling.call(this);
|
|
17949
|
+
actions.initTableHandling.call(this);
|
|
17851
17950
|
}
|
|
17852
17951
|
|
|
17853
|
-
addListeners(focusBlurElement, ["drop", "paste", "mouseup", "focus", "keyup"], handleUserInteraction.bind(this));
|
|
17952
|
+
actions.addListeners(focusBlurElement, ["drop", "paste", "mouseup", "focus", "keyup"], handleUserInteraction.bind(this));
|
|
17854
17953
|
focusBlurElement.addEventListener("focus", handleFocus.bind(this), false);
|
|
17855
17954
|
focusBlurElement.addEventListener("blur", handleBlur.bind(this), false);
|
|
17856
17955
|
|
|
17857
|
-
addListeners(this.element, ["drop", "paste", "beforepaste"], handlePaste.bind(this), false);
|
|
17956
|
+
actions.addListeners(this.element, ["drop", "paste", "beforepaste"], handlePaste.bind(this), false);
|
|
17858
17957
|
this.element.addEventListener("copy", handleCopy.bind(this), false);
|
|
17859
17958
|
this.element.addEventListener("mousedown", handleMouseDown.bind(this), false);
|
|
17860
17959
|
this.element.addEventListener("click", handleClick.bind(this), false);
|