wysihtml-rails 0.5.3 → 0.5.4
Sign up to get free protection for your applications and to get access to all the features.
- 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);
|