wysihtml-rails 0.5.0.beta8 → 0.5.0.beta9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/wysihtml/rails/version.rb +1 -1
- data/vendor/assets/javascripts/wysihtml-toolbar.js +1235 -423
- data/vendor/assets/javascripts/wysihtml.js +1235 -423
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 390f760e7e1ad7366a3b8463d5fd6ad12dce0920
|
4
|
+
data.tar.gz: 88c4a8460bffbb8e885402ba05484859354d0894
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80e460e6841fbe1d87bb34836850187b7c767c5fc69510d7ad7302855f88605eaa27f706bda27c2529607484a1fdc65aaa072724637d898d0b3a350cae0e13af
|
7
|
+
data.tar.gz: 3d7420f8b77dd86084a877aec874565ee36f9360ff3fc58c796563b80c844da2c0a3c2d9592b259c8f01bcfb08972fcfbbef6d5b758ea406bb020b3ed99922d2
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license wysihtml v0.5.0-
|
2
|
+
* @license wysihtml v0.5.0-beta9
|
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.0-
|
13
|
+
version: "0.5.0-beta9",
|
14
14
|
|
15
15
|
// namespaces
|
16
16
|
commands: {},
|
@@ -360,6 +360,101 @@ var wysihtml5 = {
|
|
360
360
|
}
|
361
361
|
|
362
362
|
}
|
363
|
+
|
364
|
+
// Safary has a bug of not restoring selection after node.normalize correctly.
|
365
|
+
// Detects the misbegaviour and patches it
|
366
|
+
var normalizeHasCaretError = function() {
|
367
|
+
if ("createRange" in document && "getSelection" in window) {
|
368
|
+
var e = document.createElement('div'),
|
369
|
+
t1 = document.createTextNode('a'),
|
370
|
+
t2 = document.createTextNode('a'),
|
371
|
+
t3 = document.createTextNode('a'),
|
372
|
+
r = document.createRange(),
|
373
|
+
s, ret;
|
374
|
+
|
375
|
+
e.setAttribute('contenteditable', 'true');
|
376
|
+
e.appendChild(t1);
|
377
|
+
e.appendChild(t2);
|
378
|
+
e.appendChild(t3);
|
379
|
+
document.body.appendChild(e);
|
380
|
+
r.setStart(t2, 1);
|
381
|
+
r.setEnd(t2, 1);
|
382
|
+
|
383
|
+
s = window.getSelection();
|
384
|
+
s.removeAllRanges();
|
385
|
+
s.addRange(r);
|
386
|
+
e.normalize();
|
387
|
+
s = window.getSelection();
|
388
|
+
|
389
|
+
ret = (e.childNodes.length !== 1 || s.anchorNode !== e.firstChild || s.anchorOffset !== 2);
|
390
|
+
e.parentNode.removeChild(e);
|
391
|
+
return ret;
|
392
|
+
}
|
393
|
+
};
|
394
|
+
|
395
|
+
var getTextNodes = function(node){
|
396
|
+
var all = [];
|
397
|
+
for (node=node.firstChild;node;node=node.nextSibling){
|
398
|
+
if (node.nodeType == 3) {
|
399
|
+
all.push(node);
|
400
|
+
} else {
|
401
|
+
all = all.concat(getTextNodes(node));
|
402
|
+
}
|
403
|
+
}
|
404
|
+
return all;
|
405
|
+
};
|
406
|
+
|
407
|
+
var normalizeFix = function() {
|
408
|
+
var f = Node.prototype.normalize;
|
409
|
+
var nf = function() {
|
410
|
+
var texts = getTextNodes(this),
|
411
|
+
s = this.ownerDocument.defaultView.getSelection(),
|
412
|
+
anode = s.anchorNode,
|
413
|
+
aoffset = s.anchorOffset,
|
414
|
+
fnode = s.focusNode,
|
415
|
+
foffset = s.focusOffset,
|
416
|
+
r = this.ownerDocument.createRange(),
|
417
|
+
prevTxt = texts.shift(),
|
418
|
+
curText = prevTxt ? texts.shift() : null;
|
419
|
+
|
420
|
+
if ((anode === fnode && foffset < aoffset) || (anode !== fnode && (anode.compareDocumentPosition(fnode) & Node.DOCUMENT_POSITION_PRECEDING))) {
|
421
|
+
fnode = [anode, anode = fnode][0];
|
422
|
+
foffset = [aoffset, aoffset = foffset][0];
|
423
|
+
}
|
424
|
+
|
425
|
+
while(prevTxt && curText) {
|
426
|
+
if (curText.previousSibling && curText.previousSibling === prevTxt) {
|
427
|
+
if (anode === curText) {
|
428
|
+
anode = prevTxt;
|
429
|
+
aoffset = prevTxt.nodeValue.length + aoffset;
|
430
|
+
}
|
431
|
+
if (fnode === curText) {
|
432
|
+
fnode = prevTxt;
|
433
|
+
foffset = prevTxt.nodeValue.length + foffset;
|
434
|
+
}
|
435
|
+
prevTxt.nodeValue = prevTxt.nodeValue + curText.nodeValue;
|
436
|
+
curText.parentNode.removeChild(curText);
|
437
|
+
curText = texts.shift();
|
438
|
+
} else {
|
439
|
+
prevTxt = curText;
|
440
|
+
curText = texts.shift();
|
441
|
+
}
|
442
|
+
}
|
443
|
+
|
444
|
+
if (anode && anode.parentNode && fnode && fnode.parentNode) {
|
445
|
+
r.setStart(anode, aoffset);
|
446
|
+
r.setEnd(fnode, foffset);
|
447
|
+
s.removeAllRanges();
|
448
|
+
s.addRange(r);
|
449
|
+
}
|
450
|
+
|
451
|
+
};
|
452
|
+
Node.prototype.normalize = nf;
|
453
|
+
};
|
454
|
+
|
455
|
+
if ("Node" in window && "normalize" in Node.prototype && normalizeHasCaretError()) {
|
456
|
+
normalizeFix();
|
457
|
+
}
|
363
458
|
};
|
364
459
|
|
365
460
|
wysihtml5.polyfills(window, document);
|
@@ -367,10 +462,10 @@ wysihtml5.polyfills(window, document);
|
|
367
462
|
* Rangy, a cross-browser JavaScript range and selection library
|
368
463
|
* https://github.com/timdown/rangy
|
369
464
|
*
|
370
|
-
* Copyright
|
465
|
+
* Copyright 2015, Tim Down
|
371
466
|
* Licensed under the MIT license.
|
372
|
-
* Version: 1.3.0
|
373
|
-
* Build date:
|
467
|
+
* Version: 1.3.0
|
468
|
+
* Build date: 10 May 2015
|
374
469
|
*/
|
375
470
|
|
376
471
|
(function(factory, root) {
|
@@ -447,6 +542,16 @@ wysihtml5.polyfills(window, document);
|
|
447
542
|
return isHostObject(doc, "body") ? doc.body : doc.getElementsByTagName("body")[0];
|
448
543
|
}
|
449
544
|
|
545
|
+
var forEach = [].forEach ?
|
546
|
+
function(arr, func) {
|
547
|
+
arr.forEach(func);
|
548
|
+
} :
|
549
|
+
function(arr, func) {
|
550
|
+
for (var i = 0, len = arr.length; i < len; ++i) {
|
551
|
+
func(arr[i], i);
|
552
|
+
}
|
553
|
+
};
|
554
|
+
|
450
555
|
var modules = {};
|
451
556
|
|
452
557
|
var isBrowser = (typeof window != UNDEFINED && typeof document != UNDEFINED);
|
@@ -459,11 +564,12 @@ wysihtml5.polyfills(window, document);
|
|
459
564
|
areHostObjects: areHostObjects,
|
460
565
|
areHostProperties: areHostProperties,
|
461
566
|
isTextRange: isTextRange,
|
462
|
-
getBody: getBody
|
567
|
+
getBody: getBody,
|
568
|
+
forEach: forEach
|
463
569
|
};
|
464
570
|
|
465
571
|
var api = {
|
466
|
-
version: "1.3.0
|
572
|
+
version: "1.3.0",
|
467
573
|
initialized: false,
|
468
574
|
isBrowser: isBrowser,
|
469
575
|
supported: true,
|
@@ -471,7 +577,7 @@ wysihtml5.polyfills(window, document);
|
|
471
577
|
features: {},
|
472
578
|
modules: modules,
|
473
579
|
config: {
|
474
|
-
alertOnFail:
|
580
|
+
alertOnFail: false,
|
475
581
|
alertOnWarn: false,
|
476
582
|
preferTextRange: false,
|
477
583
|
autoInitialize: (typeof rangyAutoInitialize == UNDEFINED) ? true : rangyAutoInitialize
|
@@ -539,7 +645,7 @@ wysihtml5.polyfills(window, document);
|
|
539
645
|
} else {
|
540
646
|
fail("hasOwnProperty not supported");
|
541
647
|
}
|
542
|
-
|
648
|
+
|
543
649
|
// Test whether we're in a browser and bail out if not
|
544
650
|
if (!isBrowser) {
|
545
651
|
fail("Rangy can only run in a browser");
|
@@ -660,6 +766,24 @@ wysihtml5.polyfills(window, document);
|
|
660
766
|
}
|
661
767
|
}
|
662
768
|
|
769
|
+
function deprecationNotice(deprecated, replacement, module) {
|
770
|
+
if (module) {
|
771
|
+
deprecated += " in module " + module.name;
|
772
|
+
}
|
773
|
+
api.warn("DEPRECATED: " + deprecated + " is deprecated. Please use " +
|
774
|
+
replacement + " instead.");
|
775
|
+
}
|
776
|
+
|
777
|
+
function createAliasForDeprecatedMethod(owner, deprecated, replacement, module) {
|
778
|
+
owner[deprecated] = function() {
|
779
|
+
deprecationNotice(deprecated, replacement, module);
|
780
|
+
return owner[replacement].apply(owner, util.toArray(arguments));
|
781
|
+
};
|
782
|
+
}
|
783
|
+
|
784
|
+
util.deprecationNotice = deprecationNotice;
|
785
|
+
util.createAliasForDeprecatedMethod = createAliasForDeprecatedMethod;
|
786
|
+
|
663
787
|
// Allow external scripts to initialize this library in case it's loaded after the document has loaded
|
664
788
|
api.init = init;
|
665
789
|
|
@@ -690,6 +814,7 @@ wysihtml5.polyfills(window, document);
|
|
690
814
|
|
691
815
|
if (isBrowser) {
|
692
816
|
api.shim = api.createMissingNativeApi = shim;
|
817
|
+
createAliasForDeprecatedMethod(api, "createMissingNativeApi", "shim");
|
693
818
|
}
|
694
819
|
|
695
820
|
function Module(name, dependencies, initializer) {
|
@@ -717,15 +842,15 @@ wysihtml5.polyfills(window, document);
|
|
717
842
|
throw new Error("required module '" + moduleName + "' not supported");
|
718
843
|
}
|
719
844
|
}
|
720
|
-
|
845
|
+
|
721
846
|
// Now run initializer
|
722
847
|
this.initializer(this);
|
723
848
|
},
|
724
|
-
|
849
|
+
|
725
850
|
fail: function(reason) {
|
726
851
|
this.initialized = true;
|
727
852
|
this.supported = false;
|
728
|
-
throw new Error(
|
853
|
+
throw new Error(reason);
|
729
854
|
},
|
730
855
|
|
731
856
|
warn: function(msg) {
|
@@ -733,7 +858,7 @@ wysihtml5.polyfills(window, document);
|
|
733
858
|
},
|
734
859
|
|
735
860
|
deprecationNotice: function(deprecated, replacement) {
|
736
|
-
api.warn("DEPRECATED: " + deprecated + " in module " + this.name + "is deprecated. Please use " +
|
861
|
+
api.warn("DEPRECATED: " + deprecated + " in module " + this.name + " is deprecated. Please use " +
|
737
862
|
replacement + " instead");
|
738
863
|
},
|
739
864
|
|
@@ -741,7 +866,7 @@ wysihtml5.polyfills(window, document);
|
|
741
866
|
return new Error("Error in Rangy " + this.name + " module: " + msg);
|
742
867
|
}
|
743
868
|
};
|
744
|
-
|
869
|
+
|
745
870
|
function createModule(name, dependencies, initFunc) {
|
746
871
|
var newModule = new Module(name, dependencies, function(module) {
|
747
872
|
if (!module.initialized) {
|
@@ -802,6 +927,7 @@ wysihtml5.polyfills(window, document);
|
|
802
927
|
api.createCoreModule("DomUtil", [], function(api, module) {
|
803
928
|
var UNDEF = "undefined";
|
804
929
|
var util = api.util;
|
930
|
+
var getBody = util.getBody;
|
805
931
|
|
806
932
|
// Perform feature tests
|
807
933
|
if (!util.areHostMethods(document, ["createDocumentFragment", "createElement", "createTextNode"])) {
|
@@ -1113,7 +1239,7 @@ wysihtml5.polyfills(window, document);
|
|
1113
1239
|
var el = document.createElement("b");
|
1114
1240
|
el.innerHTML = "1";
|
1115
1241
|
var textNode = el.firstChild;
|
1116
|
-
el.innerHTML = "<br
|
1242
|
+
el.innerHTML = "<br />";
|
1117
1243
|
crashyTextNodes = isBrokenNode(textNode);
|
1118
1244
|
|
1119
1245
|
api.features.crashyTextNodes = crashyTextNodes;
|
@@ -1153,12 +1279,35 @@ wysihtml5.polyfills(window, document);
|
|
1153
1279
|
};
|
1154
1280
|
} else if (typeof document.documentElement.currentStyle != UNDEF) {
|
1155
1281
|
getComputedStyleProperty = function(el, propName) {
|
1156
|
-
return el.currentStyle[propName];
|
1282
|
+
return el.currentStyle ? el.currentStyle[propName] : "";
|
1157
1283
|
};
|
1158
1284
|
} else {
|
1159
1285
|
module.fail("No means of obtaining computed style properties found");
|
1160
1286
|
}
|
1161
1287
|
|
1288
|
+
function createTestElement(doc, html, contentEditable) {
|
1289
|
+
var body = getBody(doc);
|
1290
|
+
var el = doc.createElement("div");
|
1291
|
+
el.contentEditable = "" + !!contentEditable;
|
1292
|
+
if (html) {
|
1293
|
+
el.innerHTML = html;
|
1294
|
+
}
|
1295
|
+
|
1296
|
+
// Insert the test element at the start of the body to prevent scrolling to the bottom in iOS (issue #292)
|
1297
|
+
var bodyFirstChild = body.firstChild;
|
1298
|
+
if (bodyFirstChild) {
|
1299
|
+
body.insertBefore(el, bodyFirstChild);
|
1300
|
+
} else {
|
1301
|
+
body.appendChild(el);
|
1302
|
+
}
|
1303
|
+
|
1304
|
+
return el;
|
1305
|
+
}
|
1306
|
+
|
1307
|
+
function removeNode(node) {
|
1308
|
+
return node.parentNode.removeChild(node);
|
1309
|
+
}
|
1310
|
+
|
1162
1311
|
function NodeIterator(root) {
|
1163
1312
|
this.root = root;
|
1164
1313
|
this._next = root;
|
@@ -1256,7 +1405,7 @@ wysihtml5.polyfills(window, document);
|
|
1256
1405
|
getWindow: getWindow,
|
1257
1406
|
getIframeWindow: getIframeWindow,
|
1258
1407
|
getIframeDocument: getIframeDocument,
|
1259
|
-
getBody:
|
1408
|
+
getBody: getBody,
|
1260
1409
|
isWindow: isWindow,
|
1261
1410
|
getContentDocument: getContentDocument,
|
1262
1411
|
getRootContainer: getRootContainer,
|
@@ -1264,6 +1413,8 @@ wysihtml5.polyfills(window, document);
|
|
1264
1413
|
isBrokenNode: isBrokenNode,
|
1265
1414
|
inspectNode: inspectNode,
|
1266
1415
|
getComputedStyleProperty: getComputedStyleProperty,
|
1416
|
+
createTestElement: createTestElement,
|
1417
|
+
removeNode: removeNode,
|
1267
1418
|
fragmentFromNodeChildren: fragmentFromNodeChildren,
|
1268
1419
|
createIterator: createIterator,
|
1269
1420
|
DomPosition: DomPosition
|
@@ -1293,6 +1444,8 @@ wysihtml5.polyfills(window, document);
|
|
1293
1444
|
var getRootContainer = dom.getRootContainer;
|
1294
1445
|
var crashyTextNodes = api.features.crashyTextNodes;
|
1295
1446
|
|
1447
|
+
var removeNode = dom.removeNode;
|
1448
|
+
|
1296
1449
|
/*----------------------------------------------------------------------------------------------------------------*/
|
1297
1450
|
|
1298
1451
|
// Utility functions
|
@@ -1306,6 +1459,10 @@ wysihtml5.polyfills(window, document);
|
|
1306
1459
|
return range.document || getDocument(range.startContainer);
|
1307
1460
|
}
|
1308
1461
|
|
1462
|
+
function getRangeRoot(range) {
|
1463
|
+
return getRootContainer(range.startContainer);
|
1464
|
+
}
|
1465
|
+
|
1309
1466
|
function getBoundaryBeforeNode(node) {
|
1310
1467
|
return new DomPosition(node.parentNode, getNodeIndex(node));
|
1311
1468
|
}
|
@@ -1540,7 +1697,7 @@ wysihtml5.polyfills(window, document);
|
|
1540
1697
|
}
|
1541
1698
|
} else {
|
1542
1699
|
if (current.parentNode) {
|
1543
|
-
|
1700
|
+
removeNode(current);
|
1544
1701
|
} else {
|
1545
1702
|
}
|
1546
1703
|
}
|
@@ -1643,26 +1800,21 @@ wysihtml5.polyfills(window, document);
|
|
1643
1800
|
}
|
1644
1801
|
}
|
1645
1802
|
|
1646
|
-
function isOrphan(node) {
|
1647
|
-
return (crashyTextNodes && dom.isBrokenNode(node)) ||
|
1648
|
-
!arrayContains(rootContainerNodeTypes, node.nodeType) && !getDocumentOrFragmentContainer(node, true);
|
1649
|
-
}
|
1650
|
-
|
1651
1803
|
function isValidOffset(node, offset) {
|
1652
1804
|
return offset <= (isCharacterDataNode(node) ? node.length : node.childNodes.length);
|
1653
1805
|
}
|
1654
1806
|
|
1655
1807
|
function isRangeValid(range) {
|
1656
1808
|
return (!!range.startContainer && !!range.endContainer &&
|
1657
|
-
!
|
1658
|
-
|
1809
|
+
!(crashyTextNodes && (dom.isBrokenNode(range.startContainer) || dom.isBrokenNode(range.endContainer))) &&
|
1810
|
+
getRootContainer(range.startContainer) == getRootContainer(range.endContainer) &&
|
1659
1811
|
isValidOffset(range.startContainer, range.startOffset) &&
|
1660
1812
|
isValidOffset(range.endContainer, range.endOffset));
|
1661
1813
|
}
|
1662
1814
|
|
1663
1815
|
function assertRangeValid(range) {
|
1664
1816
|
if (!isRangeValid(range)) {
|
1665
|
-
throw new Error("Range error: Range is
|
1817
|
+
throw new Error("Range error: Range is not valid. This usually happens after DOM mutation. Range: (" + range.inspect() + ")");
|
1666
1818
|
}
|
1667
1819
|
}
|
1668
1820
|
|
@@ -1773,7 +1925,7 @@ wysihtml5.polyfills(window, document);
|
|
1773
1925
|
}
|
1774
1926
|
range.setStartAndEnd(sc, so, ec, eo);
|
1775
1927
|
}
|
1776
|
-
|
1928
|
+
|
1777
1929
|
function rangeToHtml(range) {
|
1778
1930
|
assertRangeValid(range);
|
1779
1931
|
var container = range.commonAncestorContainer.parentNode.cloneNode(false);
|
@@ -1956,13 +2108,14 @@ wysihtml5.polyfills(window, document);
|
|
1956
2108
|
// with it (as in WebKit) or not (as in Gecko pre-1.9, and the default)
|
1957
2109
|
intersectsNode: function(node, touchingIsIntersecting) {
|
1958
2110
|
assertRangeValid(this);
|
1959
|
-
|
1960
|
-
if (getDocument(node) !== getRangeDocument(this)) {
|
2111
|
+
if (getRootContainer(node) != getRangeRoot(this)) {
|
1961
2112
|
return false;
|
1962
2113
|
}
|
1963
2114
|
|
1964
2115
|
var parent = node.parentNode, offset = getNodeIndex(node);
|
1965
|
-
|
2116
|
+
if (!parent) {
|
2117
|
+
return true;
|
2118
|
+
}
|
1966
2119
|
|
1967
2120
|
var startComparison = comparePoints(parent, offset, this.endContainer, this.endOffset),
|
1968
2121
|
endComparison = comparePoints(parent, offset + 1, this.startContainer, this.startOffset);
|
@@ -2072,7 +2225,7 @@ wysihtml5.polyfills(window, document);
|
|
2072
2225
|
this.setStartAfter(node);
|
2073
2226
|
this.collapse(true);
|
2074
2227
|
},
|
2075
|
-
|
2228
|
+
|
2076
2229
|
getBookmark: function(containerNode) {
|
2077
2230
|
var doc = getRangeDocument(this);
|
2078
2231
|
var preSelectionRange = api.createRange(doc);
|
@@ -2092,7 +2245,7 @@ wysihtml5.polyfills(window, document);
|
|
2092
2245
|
containerNode: containerNode
|
2093
2246
|
};
|
2094
2247
|
},
|
2095
|
-
|
2248
|
+
|
2096
2249
|
moveToBookmark: function(bookmark) {
|
2097
2250
|
var containerNode = bookmark.containerNode;
|
2098
2251
|
var charIndex = 0;
|
@@ -2134,11 +2287,11 @@ wysihtml5.polyfills(window, document);
|
|
2134
2287
|
isValid: function() {
|
2135
2288
|
return isRangeValid(this);
|
2136
2289
|
},
|
2137
|
-
|
2290
|
+
|
2138
2291
|
inspect: function() {
|
2139
2292
|
return inspect(this);
|
2140
2293
|
},
|
2141
|
-
|
2294
|
+
|
2142
2295
|
detach: function() {
|
2143
2296
|
// In DOM4, detach() is now a no-op.
|
2144
2297
|
}
|
@@ -2275,7 +2428,7 @@ wysihtml5.polyfills(window, document);
|
|
2275
2428
|
|
2276
2429
|
boundaryUpdater(this, sc, so, ec, eo);
|
2277
2430
|
},
|
2278
|
-
|
2431
|
+
|
2279
2432
|
setBoundary: function(node, offset, isStart) {
|
2280
2433
|
this["set" + (isStart ? "Start" : "End")](node, offset);
|
2281
2434
|
},
|
@@ -2345,7 +2498,7 @@ wysihtml5.polyfills(window, document);
|
|
2345
2498
|
ec = node;
|
2346
2499
|
eo = node.length;
|
2347
2500
|
node.appendData(sibling.data);
|
2348
|
-
|
2501
|
+
removeNode(sibling);
|
2349
2502
|
}
|
2350
2503
|
};
|
2351
2504
|
|
@@ -2356,7 +2509,7 @@ wysihtml5.polyfills(window, document);
|
|
2356
2509
|
var nodeLength = node.length;
|
2357
2510
|
so = sibling.length;
|
2358
2511
|
node.insertData(0, sibling.data);
|
2359
|
-
|
2512
|
+
removeNode(sibling);
|
2360
2513
|
if (sc == ec) {
|
2361
2514
|
eo += so;
|
2362
2515
|
ec = sc;
|
@@ -2373,10 +2526,22 @@ wysihtml5.polyfills(window, document);
|
|
2373
2526
|
};
|
2374
2527
|
|
2375
2528
|
var normalizeStart = true;
|
2529
|
+
var sibling;
|
2376
2530
|
|
2377
2531
|
if (isCharacterDataNode(ec)) {
|
2378
|
-
if (ec.length
|
2532
|
+
if (eo == ec.length) {
|
2379
2533
|
mergeForward(ec);
|
2534
|
+
} else if (eo == 0) {
|
2535
|
+
sibling = ec.previousSibling;
|
2536
|
+
if (sibling && sibling.nodeType == ec.nodeType) {
|
2537
|
+
eo = sibling.length;
|
2538
|
+
if (sc == ec) {
|
2539
|
+
normalizeStart = false;
|
2540
|
+
}
|
2541
|
+
sibling.appendData(ec.data);
|
2542
|
+
removeNode(ec);
|
2543
|
+
ec = sibling;
|
2544
|
+
}
|
2380
2545
|
}
|
2381
2546
|
} else {
|
2382
2547
|
if (eo > 0) {
|
@@ -2392,6 +2557,16 @@ wysihtml5.polyfills(window, document);
|
|
2392
2557
|
if (isCharacterDataNode(sc)) {
|
2393
2558
|
if (so == 0) {
|
2394
2559
|
mergeBackward(sc);
|
2560
|
+
} else if (so == sc.length) {
|
2561
|
+
sibling = sc.nextSibling;
|
2562
|
+
if (sibling && sibling.nodeType == sc.nodeType) {
|
2563
|
+
if (ec == sibling) {
|
2564
|
+
ec = sc;
|
2565
|
+
eo += sc.length;
|
2566
|
+
}
|
2567
|
+
sc.appendData(sibling.data);
|
2568
|
+
removeNode(sibling);
|
2569
|
+
}
|
2395
2570
|
}
|
2396
2571
|
} else {
|
2397
2572
|
if (so < sc.childNodes.length) {
|
@@ -2470,7 +2645,7 @@ wysihtml5.polyfills(window, document);
|
|
2470
2645
|
|
2471
2646
|
/*----------------------------------------------------------------------------------------------------------------*/
|
2472
2647
|
|
2473
|
-
// Wrappers for the browser's native DOM Range and/or TextRange implementation
|
2648
|
+
// Wrappers for the browser's native DOM Range and/or TextRange implementation
|
2474
2649
|
api.createCoreModule("WrappedRange", ["DomRange"], function(api, module) {
|
2475
2650
|
var WrappedRange, WrappedTextRange;
|
2476
2651
|
var dom = api.dom;
|
@@ -2736,7 +2911,7 @@ wysihtml5.polyfills(window, document);
|
|
2736
2911
|
};
|
2737
2912
|
})();
|
2738
2913
|
}
|
2739
|
-
|
2914
|
+
|
2740
2915
|
if (api.features.implementsTextRange) {
|
2741
2916
|
/*
|
2742
2917
|
This is a workaround for a bug where IE returns the wrong container element from the TextRange's parentElement()
|
@@ -2803,7 +2978,7 @@ wysihtml5.polyfills(window, document);
|
|
2803
2978
|
// Workaround for HTML5 Shiv's insane violation of document.createElement(). See Rangy issue 104 and HTML5
|
2804
2979
|
// Shiv issue 64: https://github.com/aFarkas/html5shiv/issues/64
|
2805
2980
|
if (workingNode.parentNode) {
|
2806
|
-
|
2981
|
+
dom.removeNode(workingNode);
|
2807
2982
|
}
|
2808
2983
|
|
2809
2984
|
var comparison, workingComparisonType = isStart ? "StartToStart" : "StartToEnd";
|
@@ -2858,11 +3033,11 @@ wysihtml5.polyfills(window, document);
|
|
2858
3033
|
For the particular case of a boundary within a text node containing rendered line breaks (within a
|
2859
3034
|
<pre> element, for example), we need a slightly complicated approach to get the boundary's offset in
|
2860
3035
|
IE. The facts:
|
2861
|
-
|
3036
|
+
|
2862
3037
|
- Each line break is represented as \r in the text node's data/nodeValue properties
|
2863
3038
|
- Each line break is represented as \r\n in the TextRange's 'text' property
|
2864
3039
|
- The 'text' property of the TextRange does not contain trailing line breaks
|
2865
|
-
|
3040
|
+
|
2866
3041
|
To get round the problem presented by the final fact above, we can use the fact that TextRange's
|
2867
3042
|
moveStart() and moveEnd() methods return the actual number of characters moved, which is not
|
2868
3043
|
necessarily the same as the number of characters it was instructed to move. The simplest approach is
|
@@ -2871,13 +3046,13 @@ wysihtml5.polyfills(window, document);
|
|
2871
3046
|
"move-negative-gazillion" method). However, this is extremely slow when the document is large and
|
2872
3047
|
the range is near the end of it. Clearly doing the mirror image (i.e. moving the range boundaries to
|
2873
3048
|
the end of the document) has the same problem.
|
2874
|
-
|
3049
|
+
|
2875
3050
|
Another approach that works is to use moveStart() to move the start boundary of the range up to the
|
2876
3051
|
end boundary one character at a time and incrementing a counter with the value returned by the
|
2877
3052
|
moveStart() call. However, the check for whether the start boundary has reached the end boundary is
|
2878
3053
|
expensive, so this method is slow (although unlike "move-negative-gazillion" is largely unaffected
|
2879
3054
|
by the location of the range within the document).
|
2880
|
-
|
3055
|
+
|
2881
3056
|
The approach used below is a hybrid of the two methods above. It uses the fact that a string
|
2882
3057
|
containing the TextRange's 'text' property with each \r\n converted to a single \r character cannot
|
2883
3058
|
be longer than the text of the TextRange, so the start of the range is moved that length initially
|
@@ -2912,7 +3087,7 @@ wysihtml5.polyfills(window, document);
|
|
2912
3087
|
}
|
2913
3088
|
|
2914
3089
|
// Clean up
|
2915
|
-
|
3090
|
+
dom.removeNode(workingNode);
|
2916
3091
|
|
2917
3092
|
return {
|
2918
3093
|
boundaryPosition: boundaryPosition,
|
@@ -3061,15 +3236,8 @@ wysihtml5.polyfills(window, document);
|
|
3061
3236
|
return new DomRange(doc);
|
3062
3237
|
};
|
3063
3238
|
|
3064
|
-
api
|
3065
|
-
|
3066
|
-
return api.createRange(iframeEl);
|
3067
|
-
};
|
3068
|
-
|
3069
|
-
api.createIframeRangyRange = function(iframeEl) {
|
3070
|
-
module.deprecationNotice("createIframeRangyRange()", "createRangyRange(iframeEl)");
|
3071
|
-
return api.createRangyRange(iframeEl);
|
3072
|
-
};
|
3239
|
+
util.createAliasForDeprecatedMethod(api, "createIframeRange", "createRange");
|
3240
|
+
util.createAliasForDeprecatedMethod(api, "createIframeRangyRange", "createRangyRange");
|
3073
3241
|
|
3074
3242
|
api.addShimListener(function(win) {
|
3075
3243
|
var doc = win.document;
|
@@ -3107,8 +3275,8 @@ wysihtml5.polyfills(window, document);
|
|
3107
3275
|
var rangesEqual = DomRange.rangesEqual;
|
3108
3276
|
|
3109
3277
|
|
3110
|
-
// Utility function to support direction parameters in the API that may be a string ("backward"
|
3111
|
-
// Boolean (true for backwards).
|
3278
|
+
// Utility function to support direction parameters in the API that may be a string ("backward", "backwards",
|
3279
|
+
// "forward" or "forwards") or a Boolean (true for backwards).
|
3112
3280
|
function isDirectionBackward(dir) {
|
3113
3281
|
return (typeof dir == "string") ? /^backward(s)?$/i.test(dir) : !!dir;
|
3114
3282
|
}
|
@@ -3133,7 +3301,7 @@ wysihtml5.polyfills(window, document);
|
|
3133
3301
|
function getDocSelection(winParam) {
|
3134
3302
|
return getWindow(winParam, "getDocSelection").document.selection;
|
3135
3303
|
}
|
3136
|
-
|
3304
|
+
|
3137
3305
|
function winSelectionIsBackward(sel) {
|
3138
3306
|
var backward = false;
|
3139
3307
|
if (sel.anchorNode) {
|
@@ -3167,11 +3335,19 @@ wysihtml5.polyfills(window, document);
|
|
3167
3335
|
};
|
3168
3336
|
} else {
|
3169
3337
|
module.fail("Neither document.selection or window.getSelection() detected.");
|
3338
|
+
return false;
|
3170
3339
|
}
|
3171
3340
|
|
3172
3341
|
api.getNativeSelection = getNativeSelection;
|
3173
3342
|
|
3174
3343
|
var testSelection = getNativeSelection();
|
3344
|
+
|
3345
|
+
// In Firefox, the selection is null in an iframe with display: none. See issue #138.
|
3346
|
+
if (!testSelection) {
|
3347
|
+
module.fail("Native selection was null (possibly issue 138?)");
|
3348
|
+
return false;
|
3349
|
+
}
|
3350
|
+
|
3175
3351
|
var testRange = api.createNativeRange(document);
|
3176
3352
|
var body = getBody(document);
|
3177
3353
|
|
@@ -3184,7 +3360,7 @@ wysihtml5.polyfills(window, document);
|
|
3184
3360
|
// Test for existence of native selection extend() method
|
3185
3361
|
var selectionHasExtend = isHostMethod(testSelection, "extend");
|
3186
3362
|
features.selectionHasExtend = selectionHasExtend;
|
3187
|
-
|
3363
|
+
|
3188
3364
|
// Test if rangeCount exists
|
3189
3365
|
var selectionHasRangeCount = (typeof testSelection.rangeCount == NUMBER);
|
3190
3366
|
features.selectionHasRangeCount = selectionHasRangeCount;
|
@@ -3208,25 +3384,22 @@ wysihtml5.polyfills(window, document);
|
|
3208
3384
|
// Previously an iframe was used but this caused problems in some circumstances in IE, so tests are
|
3209
3385
|
// performed on the current document's selection. See issue 109.
|
3210
3386
|
|
3211
|
-
// Note also that if a selection previously existed, it is wiped by these tests. This
|
3212
|
-
//
|
3213
|
-
//
|
3214
|
-
// selection.
|
3387
|
+
// Note also that if a selection previously existed, it is wiped and later restored by these tests. This
|
3388
|
+
// will result in the selection direction begin reversed if the original selection was backwards and the
|
3389
|
+
// browser does not support setting backwards selections (Internet Explorer, I'm looking at you).
|
3215
3390
|
var sel = window.getSelection();
|
3216
3391
|
if (sel) {
|
3217
3392
|
// Store the current selection
|
3218
3393
|
var originalSelectionRangeCount = sel.rangeCount;
|
3219
3394
|
var selectionHasMultipleRanges = (originalSelectionRangeCount > 1);
|
3220
3395
|
var originalSelectionRanges = [];
|
3221
|
-
var originalSelectionBackward = winSelectionIsBackward(sel);
|
3396
|
+
var originalSelectionBackward = winSelectionIsBackward(sel);
|
3222
3397
|
for (var i = 0; i < originalSelectionRangeCount; ++i) {
|
3223
3398
|
originalSelectionRanges[i] = sel.getRangeAt(i);
|
3224
3399
|
}
|
3225
|
-
|
3400
|
+
|
3226
3401
|
// Create some test elements
|
3227
|
-
var
|
3228
|
-
var testEl = body.appendChild( document.createElement("div") );
|
3229
|
-
testEl.contentEditable = "false";
|
3402
|
+
var testEl = dom.createTestElement(document, "", false);
|
3230
3403
|
var textNode = testEl.appendChild( document.createTextNode("\u00a0\u00a0\u00a0") );
|
3231
3404
|
|
3232
3405
|
// Test whether the native selection will allow a collapsed selection within a non-editable element
|
@@ -3234,6 +3407,7 @@ wysihtml5.polyfills(window, document);
|
|
3234
3407
|
|
3235
3408
|
r1.setStart(textNode, 1);
|
3236
3409
|
r1.collapse(true);
|
3410
|
+
sel.removeAllRanges();
|
3237
3411
|
sel.addRange(r1);
|
3238
3412
|
collapsedNonEditableSelectionsSupported = (sel.rangeCount == 1);
|
3239
3413
|
sel.removeAllRanges();
|
@@ -3260,7 +3434,7 @@ wysihtml5.polyfills(window, document);
|
|
3260
3434
|
}
|
3261
3435
|
|
3262
3436
|
// Clean up
|
3263
|
-
|
3437
|
+
dom.removeNode(testEl);
|
3264
3438
|
sel.removeAllRanges();
|
3265
3439
|
|
3266
3440
|
for (i = 0; i < originalSelectionRangeCount; ++i) {
|
@@ -3518,10 +3692,7 @@ wysihtml5.polyfills(window, document);
|
|
3518
3692
|
|
3519
3693
|
api.getSelection = getSelection;
|
3520
3694
|
|
3521
|
-
api
|
3522
|
-
module.deprecationNotice("getIframeSelection()", "getSelection(iframeEl)");
|
3523
|
-
return api.getSelection(dom.getIframeWindow(iframeEl));
|
3524
|
-
};
|
3695
|
+
util.createAliasForDeprecatedMethod(api, "getIframeSelection", "getSelection");
|
3525
3696
|
|
3526
3697
|
var selProto = WrappedSelection.prototype;
|
3527
3698
|
|
@@ -3882,8 +4053,8 @@ wysihtml5.polyfills(window, document);
|
|
3882
4053
|
}
|
3883
4054
|
};
|
3884
4055
|
|
3885
|
-
// The spec is very specific on how selectAllChildren should be implemented
|
3886
|
-
// never used by Rangy.
|
4056
|
+
// The spec is very specific on how selectAllChildren should be implemented and not all browsers implement it as
|
4057
|
+
// specified so the native implementation is never used by Rangy.
|
3887
4058
|
selProto.selectAllChildren = function(node) {
|
3888
4059
|
assertNodeInSameDocument(this, node);
|
3889
4060
|
var range = api.createRange(node);
|
@@ -3899,7 +4070,7 @@ wysihtml5.polyfills(window, document);
|
|
3899
4070
|
while (controlRange.length) {
|
3900
4071
|
element = controlRange.item(0);
|
3901
4072
|
controlRange.remove(element);
|
3902
|
-
|
4073
|
+
dom.removeNode(element);
|
3903
4074
|
}
|
3904
4075
|
this.refresh();
|
3905
4076
|
} else if (this.rangeCount) {
|
@@ -3941,11 +4112,11 @@ wysihtml5.polyfills(window, document);
|
|
3941
4112
|
selProto.callMethodOnEachRange = function(methodName, params) {
|
3942
4113
|
var results = [];
|
3943
4114
|
this.eachRange( function(range) {
|
3944
|
-
results.push( range[methodName].apply(range, params) );
|
4115
|
+
results.push( range[methodName].apply(range, params || []) );
|
3945
4116
|
} );
|
3946
4117
|
return results;
|
3947
4118
|
};
|
3948
|
-
|
4119
|
+
|
3949
4120
|
function createStartOrEndSetter(isStart) {
|
3950
4121
|
return function(node, offset) {
|
3951
4122
|
var range;
|
@@ -3962,7 +4133,7 @@ wysihtml5.polyfills(window, document);
|
|
3962
4133
|
|
3963
4134
|
selProto.setStart = createStartOrEndSetter(true);
|
3964
4135
|
selProto.setEnd = createStartOrEndSetter(false);
|
3965
|
-
|
4136
|
+
|
3966
4137
|
// Add select() method to Range prototype. Any existing selection will be removed.
|
3967
4138
|
api.rangePrototype.select = function(direction) {
|
3968
4139
|
getSelection( this.getDocument() ).setSingleRange(this, direction);
|
@@ -4012,6 +4183,20 @@ wysihtml5.polyfills(window, document);
|
|
4012
4183
|
}
|
4013
4184
|
};
|
4014
4185
|
|
4186
|
+
selProto.saveRanges = function() {
|
4187
|
+
return {
|
4188
|
+
backward: this.isBackward(),
|
4189
|
+
ranges: this.callMethodOnEachRange("cloneRange")
|
4190
|
+
};
|
4191
|
+
};
|
4192
|
+
|
4193
|
+
selProto.restoreRanges = function(selRanges) {
|
4194
|
+
this.removeAllRanges();
|
4195
|
+
for (var i = 0, range; range = selRanges.ranges[i]; ++i) {
|
4196
|
+
this.addRange(range, (selRanges.backward && i == 0));
|
4197
|
+
}
|
4198
|
+
};
|
4199
|
+
|
4015
4200
|
selProto.toHtml = function() {
|
4016
4201
|
var rangeHtmls = [];
|
4017
4202
|
this.eachRange(function(range) {
|
@@ -4028,7 +4213,7 @@ wysihtml5.polyfills(window, document);
|
|
4028
4213
|
if (isTextRange(range)) {
|
4029
4214
|
return range;
|
4030
4215
|
} else {
|
4031
|
-
throw module.createError("getNativeTextRange: selection is a control selection");
|
4216
|
+
throw module.createError("getNativeTextRange: selection is a control selection");
|
4032
4217
|
}
|
4033
4218
|
} else if (this.rangeCount > 0) {
|
4034
4219
|
return api.WrappedTextRange.rangeToTextRange( this.getRangeAt(0) );
|
@@ -4126,10 +4311,10 @@ wysihtml5.polyfills(window, document);
|
|
4126
4311
|
*
|
4127
4312
|
* Depends on Rangy core.
|
4128
4313
|
*
|
4129
|
-
* Copyright
|
4314
|
+
* Copyright 2015, Tim Down
|
4130
4315
|
* Licensed under the MIT license.
|
4131
|
-
* Version: 1.3.0
|
4132
|
-
* Build date:
|
4316
|
+
* Version: 1.3.0
|
4317
|
+
* Build date: 10 May 2015
|
4133
4318
|
*/
|
4134
4319
|
(function(factory, root) {
|
4135
4320
|
if (typeof define == "function" && define.amd) {
|
@@ -4145,7 +4330,8 @@ wysihtml5.polyfills(window, document);
|
|
4145
4330
|
})(function(rangy) {
|
4146
4331
|
rangy.createModule("SaveRestore", ["WrappedRange"], function(api, module) {
|
4147
4332
|
var dom = api.dom;
|
4148
|
-
|
4333
|
+
var removeNode = dom.removeNode;
|
4334
|
+
var isDirectionBackward = api.Selection.isDirectionBackward;
|
4149
4335
|
var markerTextChar = "\ufeff";
|
4150
4336
|
|
4151
4337
|
function gEBI(id, doc) {
|
@@ -4177,7 +4363,7 @@ wysihtml5.polyfills(window, document);
|
|
4177
4363
|
var markerEl = gEBI(markerId, doc);
|
4178
4364
|
if (markerEl) {
|
4179
4365
|
range[atStart ? "setStartBefore" : "setEndBefore"](markerEl);
|
4180
|
-
|
4366
|
+
removeNode(markerEl);
|
4181
4367
|
} else {
|
4182
4368
|
module.warn("Marker element has been removed. Cannot restore selection.");
|
4183
4369
|
}
|
@@ -4187,8 +4373,9 @@ wysihtml5.polyfills(window, document);
|
|
4187
4373
|
return r2.compareBoundaryPoints(r1.START_TO_START, r1);
|
4188
4374
|
}
|
4189
4375
|
|
4190
|
-
function saveRange(range,
|
4376
|
+
function saveRange(range, direction) {
|
4191
4377
|
var startEl, endEl, doc = api.DomRange.getRangeDocument(range), text = range.toString();
|
4378
|
+
var backward = isDirectionBackward(direction);
|
4192
4379
|
|
4193
4380
|
if (range.collapsed) {
|
4194
4381
|
endEl = insertRangeBoundaryMarker(range, false);
|
@@ -4228,11 +4415,11 @@ wysihtml5.polyfills(window, document);
|
|
4228
4415
|
|
4229
4416
|
// Workaround for issue 17
|
4230
4417
|
if (previousNode && previousNode.nodeType == 3) {
|
4231
|
-
|
4418
|
+
removeNode(markerEl);
|
4232
4419
|
range.collapseToPoint(previousNode, previousNode.length);
|
4233
4420
|
} else {
|
4234
4421
|
range.collapseBefore(markerEl);
|
4235
|
-
|
4422
|
+
removeNode(markerEl);
|
4236
4423
|
}
|
4237
4424
|
} else {
|
4238
4425
|
module.warn("Marker element has been removed. Cannot restore selection.");
|
@@ -4249,8 +4436,9 @@ wysihtml5.polyfills(window, document);
|
|
4249
4436
|
return range;
|
4250
4437
|
}
|
4251
4438
|
|
4252
|
-
function saveRanges(ranges,
|
4439
|
+
function saveRanges(ranges, direction) {
|
4253
4440
|
var rangeInfos = [], range, doc;
|
4441
|
+
var backward = isDirectionBackward(direction);
|
4254
4442
|
|
4255
4443
|
// Order the ranges by position within the DOM, latest first, cloning the array to leave the original untouched
|
4256
4444
|
ranges = ranges.slice(0);
|
@@ -4289,7 +4477,7 @@ wysihtml5.polyfills(window, document);
|
|
4289
4477
|
|
4290
4478
|
// Ensure current selection is unaffected
|
4291
4479
|
if (backward) {
|
4292
|
-
sel.setSingleRange(ranges[0],
|
4480
|
+
sel.setSingleRange(ranges[0], backward);
|
4293
4481
|
} else {
|
4294
4482
|
sel.setRanges(ranges);
|
4295
4483
|
}
|
@@ -4335,7 +4523,7 @@ wysihtml5.polyfills(window, document);
|
|
4335
4523
|
function removeMarkerElement(doc, markerId) {
|
4336
4524
|
var markerEl = gEBI(markerId, doc);
|
4337
4525
|
if (markerEl) {
|
4338
|
-
|
4526
|
+
removeNode(markerEl);
|
4339
4527
|
}
|
4340
4528
|
}
|
4341
4529
|
|
@@ -4364,6 +4552,7 @@ wysihtml5.polyfills(window, document);
|
|
4364
4552
|
});
|
4365
4553
|
});
|
4366
4554
|
|
4555
|
+
return rangy;
|
4367
4556
|
}, this);;/*
|
4368
4557
|
Base.js, version 1.1a
|
4369
4558
|
Copyright 2006-2010, Dean Edwards
|
@@ -5096,6 +5285,29 @@ wysihtml5.browser = (function() {
|
|
5096
5285
|
return this;
|
5097
5286
|
},
|
5098
5287
|
|
5288
|
+
difference: function (otherObj) {
|
5289
|
+
var diffObj = {};
|
5290
|
+
|
5291
|
+
// Get old values not in comparing object
|
5292
|
+
for (var i in obj) {
|
5293
|
+
if (obj.hasOwnProperty(i)) {
|
5294
|
+
if (!otherObj.hasOwnProperty(i)) {
|
5295
|
+
diffObj[i] = obj[i];
|
5296
|
+
}
|
5297
|
+
}
|
5298
|
+
}
|
5299
|
+
|
5300
|
+
// Get new and different values in comparing object
|
5301
|
+
for (var o in otherObj) {
|
5302
|
+
if (otherObj.hasOwnProperty(o)) {
|
5303
|
+
if (!obj.hasOwnProperty(o) || obj[o] !== otherObj[o]) {
|
5304
|
+
diffObj[0] = obj[0];
|
5305
|
+
}
|
5306
|
+
}
|
5307
|
+
}
|
5308
|
+
return diffObj;
|
5309
|
+
},
|
5310
|
+
|
5099
5311
|
get: function() {
|
5100
5312
|
return obj;
|
5101
5313
|
},
|
@@ -5147,6 +5359,20 @@ wysihtml5.browser = (function() {
|
|
5147
5359
|
|
5148
5360
|
isPlainObject: function () {
|
5149
5361
|
return obj && Object.prototype.toString.call(obj) === '[object Object]' && !(("Node" in window) ? obj instanceof Node : obj instanceof Element || obj instanceof Text);
|
5362
|
+
},
|
5363
|
+
|
5364
|
+
/**
|
5365
|
+
* @example
|
5366
|
+
* wysihtml5.lang.object({}).isEmpty();
|
5367
|
+
* // => true
|
5368
|
+
*/
|
5369
|
+
isEmpty: function() {
|
5370
|
+
for (var i in obj) {
|
5371
|
+
if (obj.hasOwnProperty(i)) {
|
5372
|
+
return false;
|
5373
|
+
}
|
5374
|
+
}
|
5375
|
+
return true;
|
5150
5376
|
}
|
5151
5377
|
};
|
5152
5378
|
};
|
@@ -5403,6 +5629,9 @@ wysihtml5.browser = (function() {
|
|
5403
5629
|
if (documentElement.contains) {
|
5404
5630
|
return function(container, element) {
|
5405
5631
|
if (element.nodeType !== wysihtml5.ELEMENT_NODE) {
|
5632
|
+
if (element.parentNode === container) {
|
5633
|
+
return true;
|
5634
|
+
}
|
5406
5635
|
element = element.parentNode;
|
5407
5636
|
}
|
5408
5637
|
return container !== element && container.contains(element);
|
@@ -5663,12 +5892,15 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
|
|
5663
5892
|
wysihtml5.dom.domNode = function(node) {
|
5664
5893
|
var defaultNodeTypes = [wysihtml5.ELEMENT_NODE, wysihtml5.TEXT_NODE];
|
5665
5894
|
|
5666
|
-
var _isBlankText = function(node) {
|
5667
|
-
return node.nodeType === wysihtml5.TEXT_NODE && (/^\s*$/g).test(node.data);
|
5668
|
-
};
|
5669
|
-
|
5670
5895
|
return {
|
5671
5896
|
|
5897
|
+
is: {
|
5898
|
+
emptyTextNode: function(ignoreWhitespace) {
|
5899
|
+
var regx = ignoreWhitespace ? (/^\s*$/g) : (/^[\r\n]*$/g);
|
5900
|
+
return node.nodeType === wysihtml5.TEXT_NODE && (regx).test(node.data);
|
5901
|
+
}
|
5902
|
+
},
|
5903
|
+
|
5672
5904
|
// var node = wysihtml5.dom.domNode(element).prev({nodeTypes: [1,3], ignoreBlankTexts: true});
|
5673
5905
|
prev: function(options) {
|
5674
5906
|
var prevNode = node.previousSibling,
|
@@ -5680,7 +5912,7 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
|
|
5680
5912
|
|
5681
5913
|
if (
|
5682
5914
|
(!wysihtml5.lang.array(types).contains(prevNode.nodeType)) || // nodeTypes check.
|
5683
|
-
(options && options.ignoreBlankTexts &&
|
5915
|
+
(options && options.ignoreBlankTexts && wysihtml5.dom.domNode(prevNode).is.emptyTextNode(true)) // Blank text nodes bypassed if set
|
5684
5916
|
) {
|
5685
5917
|
return wysihtml5.dom.domNode(prevNode).prev(options);
|
5686
5918
|
}
|
@@ -5699,7 +5931,7 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
|
|
5699
5931
|
|
5700
5932
|
if (
|
5701
5933
|
(!wysihtml5.lang.array(types).contains(nextNode.nodeType)) || // nodeTypes check.
|
5702
|
-
(options && options.ignoreBlankTexts &&
|
5934
|
+
(options && options.ignoreBlankTexts && wysihtml5.dom.domNode(nextNode).is.emptyTextNode(true)) // blank text nodes bypassed if set
|
5703
5935
|
) {
|
5704
5936
|
return wysihtml5.dom.domNode(nextNode).next(options);
|
5705
5937
|
}
|
@@ -5736,6 +5968,67 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
|
|
5736
5968
|
return wysihtml5.dom.domNode(lastChild).lastLeafNode(options);
|
5737
5969
|
},
|
5738
5970
|
|
5971
|
+
// Splits element at childnode and extracts the childNode out of the element context
|
5972
|
+
// Example:
|
5973
|
+
// var node = wysihtml5.dom.domNode(node).escapeParent(parentNode);
|
5974
|
+
escapeParent: function(element, newWrapper) {
|
5975
|
+
var parent, split2, nodeWrap,
|
5976
|
+
curNode = node;
|
5977
|
+
|
5978
|
+
// Stop if node is not a descendant of element
|
5979
|
+
if (!wysihtml5.dom.contains(element, node)) {
|
5980
|
+
throw new Error("Child is not a descendant of node.");
|
5981
|
+
}
|
5982
|
+
|
5983
|
+
// Climb up the node tree untill node is reached
|
5984
|
+
do {
|
5985
|
+
// Get current parent of node
|
5986
|
+
parent = curNode.parentNode;
|
5987
|
+
|
5988
|
+
// Move after nodes to new clone wrapper
|
5989
|
+
split2 = parent.cloneNode(false);
|
5990
|
+
while (parent.lastChild && parent.lastChild !== curNode) {
|
5991
|
+
split2.insertBefore(parent.lastChild, split2.firstChild);
|
5992
|
+
}
|
5993
|
+
|
5994
|
+
// Move node up a level. If parent is not yet the container to escape, clone the parent around node, so inner nodes are escaped out too
|
5995
|
+
if (parent !== element) {
|
5996
|
+
nodeWrap = parent.cloneNode(false);
|
5997
|
+
nodeWrap.appendChild(curNode);
|
5998
|
+
curNode = nodeWrap;
|
5999
|
+
}
|
6000
|
+
parent.parentNode.insertBefore(curNode, parent.nextSibling);
|
6001
|
+
|
6002
|
+
// Add after nodes (unless empty)
|
6003
|
+
if (split2.innerHTML !== '') {
|
6004
|
+
// if contents are empty insert without wrap
|
6005
|
+
if ((/^\s+$/).test(split2.innerHTML)) {
|
6006
|
+
while (split2.lastChild) {
|
6007
|
+
parent.parentNode.insertBefore(split2.lastChild, curNode.nextSibling);
|
6008
|
+
}
|
6009
|
+
} else {
|
6010
|
+
parent.parentNode.insertBefore(split2, curNode.nextSibling);
|
6011
|
+
}
|
6012
|
+
}
|
6013
|
+
|
6014
|
+
// If the node left behind before the split (parent) is now empty then remove
|
6015
|
+
if (parent.innerHTML === '') {
|
6016
|
+
parent.parentNode.removeChild(parent);
|
6017
|
+
} else if ((/^\s+$/).test(parent.innerHTML)) {
|
6018
|
+
while (parent.firstChild) {
|
6019
|
+
parent.parentNode.insertBefore(parent.firstChild, parent);
|
6020
|
+
}
|
6021
|
+
parent.parentNode.removeChild(parent);
|
6022
|
+
}
|
6023
|
+
|
6024
|
+
} while (parent && parent !== element);
|
6025
|
+
|
6026
|
+
if (newWrapper && curNode) {
|
6027
|
+
curNode.parentNode.insertBefore(newWrapper, curNode);
|
6028
|
+
newWrapper.appendChild(curNode);
|
6029
|
+
}
|
6030
|
+
},
|
6031
|
+
|
5739
6032
|
/*
|
5740
6033
|
Tests a node against properties, and returns true if matches.
|
5741
6034
|
Tests on principle that all properties defined must have at least one match.
|
@@ -5814,7 +6107,7 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
|
|
5814
6107
|
}
|
5815
6108
|
} else {
|
5816
6109
|
// style value as string
|
5817
|
-
if (properties.styleValue === node.style[prop].trim()) {
|
6110
|
+
if (properties.styleValue === node.style[prop].trim().replace(/, /g, ",")) {
|
5818
6111
|
hasOneStyle = true;
|
5819
6112
|
break;
|
5820
6113
|
}
|
@@ -5830,6 +6123,37 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
|
|
5830
6123
|
}
|
5831
6124
|
}
|
5832
6125
|
|
6126
|
+
if (properties.attribute) {
|
6127
|
+
var attr = wysihtml5.dom.getAttributes(node),
|
6128
|
+
attrList = [],
|
6129
|
+
hasOneAttribute = false;
|
6130
|
+
|
6131
|
+
if (Array.isArray(properties.attribute)) {
|
6132
|
+
attrList = properties.attribute;
|
6133
|
+
} else {
|
6134
|
+
attrList[properties.attribute] = properties.attributeValue;
|
6135
|
+
}
|
6136
|
+
|
6137
|
+
for (var a in attrList) {
|
6138
|
+
if (attrList.hasOwnProperty(a)) {
|
6139
|
+
if (typeof attrList[a] === "undefined") {
|
6140
|
+
if (typeof attr[a] !== "undefined") {
|
6141
|
+
hasOneAttribute = true;
|
6142
|
+
break;
|
6143
|
+
}
|
6144
|
+
} else if (attr[a] === attrList[a]) {
|
6145
|
+
hasOneAttribute = true;
|
6146
|
+
break;
|
6147
|
+
}
|
6148
|
+
}
|
6149
|
+
}
|
6150
|
+
|
6151
|
+
if (!hasOneAttribute) {
|
6152
|
+
return false;
|
6153
|
+
}
|
6154
|
+
|
6155
|
+
}
|
6156
|
+
|
5833
6157
|
return true;
|
5834
6158
|
}
|
5835
6159
|
|
@@ -9253,7 +9577,6 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
9253
9577
|
*/
|
9254
9578
|
getBookmark: function() {
|
9255
9579
|
var range = this.getRange();
|
9256
|
-
if (range) expandRangeToSurround(range);
|
9257
9580
|
return range && range.cloneRange();
|
9258
9581
|
},
|
9259
9582
|
|
@@ -9359,13 +9682,15 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
9359
9682
|
* callback is an optional parameter accepting a function to execute when selection ahs been set
|
9360
9683
|
*/
|
9361
9684
|
setAfter: function(node, notVisual, callback) {
|
9362
|
-
var
|
9685
|
+
var win = this.win,
|
9686
|
+
range = rangy.createRange(this.doc),
|
9363
9687
|
fixWebkitSelection = function() {
|
9364
9688
|
// Webkit fails to add selection if there are no textnodes in that region
|
9365
9689
|
// (like an uneditable container at the end of content).
|
9366
9690
|
var parent = node.parentNode,
|
9367
9691
|
lastSibling = parent ? parent.childNodes[parent.childNodes.length - 1] : null;
|
9368
|
-
|
9692
|
+
|
9693
|
+
if (!sel || (lastSibling === node && node.nodeType === 1 && win.getComputedStyle(node).display === "block")) {
|
9369
9694
|
if (notVisual) {
|
9370
9695
|
// If setAfter is used as internal between actions, self-removing caretPlaceholder has simpler implementation
|
9371
9696
|
// and remove itself in call stack end instead on user interaction
|
@@ -9876,7 +10201,7 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
9876
10201
|
splitElementAtCaret: function (element, insertNode) {
|
9877
10202
|
var sel = this.getSelection(),
|
9878
10203
|
range, contentAfterRangeStart,
|
9879
|
-
firstChild, lastChild;
|
10204
|
+
firstChild, lastChild, childNodes;
|
9880
10205
|
|
9881
10206
|
if (sel.rangeCount > 0) {
|
9882
10207
|
range = sel.getRangeAt(0).cloneRange(); // Create a copy of the selection range to work with
|
@@ -9884,19 +10209,43 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
9884
10209
|
range.setEndAfter(element); // Place the end of the range after the element
|
9885
10210
|
contentAfterRangeStart = range.extractContents(); // Extract the contents of the element after the caret into a fragment
|
9886
10211
|
|
10212
|
+
childNodes = contentAfterRangeStart.childNodes;
|
10213
|
+
|
10214
|
+
// Empty elements are cleaned up from extracted content
|
10215
|
+
for (var i = childNodes.length; i --;) {
|
10216
|
+
if (childNodes[i].nodeType === 1 && (/^\s*$/).test(childNodes[i].innerHTML)) {
|
10217
|
+
contentAfterRangeStart.removeChild(childNodes[i]);
|
10218
|
+
}
|
10219
|
+
}
|
10220
|
+
|
9887
10221
|
element.parentNode.insertBefore(contentAfterRangeStart, element.nextSibling);
|
9888
10222
|
|
9889
|
-
|
9890
|
-
|
10223
|
+
if (insertNode) {
|
10224
|
+
firstChild = insertNode.firstChild || insertNode;
|
10225
|
+
lastChild = insertNode.lastChild || insertNode;
|
9891
10226
|
|
9892
|
-
|
10227
|
+
element.parentNode.insertBefore(insertNode, element.nextSibling);
|
10228
|
+
|
10229
|
+
// Select inserted node contents
|
10230
|
+
if (firstChild && lastChild) {
|
10231
|
+
range.setStartBefore(firstChild);
|
10232
|
+
range.setEndAfter(lastChild);
|
10233
|
+
this.setSelection(range);
|
10234
|
+
}
|
10235
|
+
} else {
|
10236
|
+
range.setStartAfter(element);
|
10237
|
+
range.setEndAfter(element);
|
10238
|
+
}
|
9893
10239
|
|
9894
|
-
|
9895
|
-
|
9896
|
-
|
9897
|
-
|
9898
|
-
|
10240
|
+
if ((/^\s*$/).test(element.innerHTML)) {
|
10241
|
+
if (element.innerHTML === '') {
|
10242
|
+
element.parentNode.removeChild(element);
|
10243
|
+
} else {
|
10244
|
+
wysihtml5.dom.unwrap(element);
|
10245
|
+
}
|
9899
10246
|
}
|
10247
|
+
|
10248
|
+
|
9900
10249
|
}
|
9901
10250
|
},
|
9902
10251
|
|
@@ -10098,6 +10447,24 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
10098
10447
|
}
|
10099
10448
|
},
|
10100
10449
|
|
10450
|
+
// Gets all the elements in selection with nodeType
|
10451
|
+
// Ignores the elements not belonging to current editable area
|
10452
|
+
// If filter is defined nodes must pass the filter function with true to be included in list
|
10453
|
+
getOwnNodes: function(nodeType, filter, splitBounds) {
|
10454
|
+
var ranges = this.getOwnRanges(),
|
10455
|
+
nodes = [];
|
10456
|
+
for (var r = 0, rmax = ranges.length; r < rmax; r++) {
|
10457
|
+
if (ranges[r]) {
|
10458
|
+
if (splitBounds) {
|
10459
|
+
ranges[r].splitBoundaries();
|
10460
|
+
}
|
10461
|
+
nodes = nodes.concat(ranges[r].getNodes(Array.isArray(nodeType) ? nodeType : [nodeType], filter));
|
10462
|
+
}
|
10463
|
+
}
|
10464
|
+
|
10465
|
+
return nodes;
|
10466
|
+
},
|
10467
|
+
|
10101
10468
|
fixRangeOverflow: function(range) {
|
10102
10469
|
if (this.contain && this.contain.firstChild && range) {
|
10103
10470
|
var containment = range.compareNode(this.contain);
|
@@ -10982,6 +11349,16 @@ wysihtml5.Commands = Base.extend(
|
|
10982
11349
|
return result;
|
10983
11350
|
},
|
10984
11351
|
|
11352
|
+
remove: function(command, commandValue) {
|
11353
|
+
var obj = wysihtml5.commands[command],
|
11354
|
+
args = wysihtml5.lang.array(arguments).get(),
|
11355
|
+
method = obj && obj.remove;
|
11356
|
+
if (method) {
|
11357
|
+
args.unshift(this.composer);
|
11358
|
+
return method.apply(obj, args);
|
11359
|
+
}
|
11360
|
+
},
|
11361
|
+
|
10985
11362
|
/**
|
10986
11363
|
* Check whether the current command is active
|
10987
11364
|
* If the caret is within a bold text, then calling this with command "bold" should return true
|
@@ -11022,216 +11399,106 @@ wysihtml5.Commands = Base.extend(
|
|
11022
11399
|
}
|
11023
11400
|
}
|
11024
11401
|
});
|
11025
|
-
;(function(wysihtml5){
|
11402
|
+
;(function(wysihtml5) {
|
11403
|
+
|
11404
|
+
var nodeOptions = {
|
11405
|
+
nodeName: "B",
|
11406
|
+
toggle: true
|
11407
|
+
};
|
11408
|
+
|
11026
11409
|
wysihtml5.commands.bold = {
|
11027
11410
|
exec: function(composer, command) {
|
11028
|
-
wysihtml5.commands.formatInline.
|
11411
|
+
wysihtml5.commands.formatInline.exec(composer, command, nodeOptions);
|
11029
11412
|
},
|
11030
11413
|
|
11031
11414
|
state: function(composer, command) {
|
11032
|
-
|
11033
|
-
// firefox: only <b>
|
11034
|
-
// chrome: <b>, <strong>, <h1>, <h2>, ...
|
11035
|
-
// ie: <b>, <strong>
|
11036
|
-
// opera: <b>, <strong>
|
11037
|
-
return wysihtml5.commands.formatInline.state(composer, command, "b");
|
11415
|
+
return wysihtml5.commands.formatInline.state(composer, command, nodeOptions);
|
11038
11416
|
}
|
11039
11417
|
};
|
11418
|
+
|
11040
11419
|
}(wysihtml5));
|
11041
11420
|
;(function(wysihtml5) {
|
11042
|
-
var undef,
|
11043
|
-
NODE_NAME = "A",
|
11044
|
-
dom = wysihtml5.dom;
|
11045
|
-
|
11046
|
-
function _format(composer, attributes) {
|
11047
|
-
var doc = composer.doc,
|
11048
|
-
tempClass = "_wysihtml5-temp-" + (+new Date()),
|
11049
|
-
tempClassRegExp = /non-matching-class/g,
|
11050
|
-
i = 0,
|
11051
|
-
length,
|
11052
|
-
anchors,
|
11053
|
-
anchor,
|
11054
|
-
hasElementChild,
|
11055
|
-
isEmpty,
|
11056
|
-
elementToSetCaretAfter,
|
11057
|
-
textContent,
|
11058
|
-
whiteSpace,
|
11059
|
-
j;
|
11060
|
-
wysihtml5.commands.formatInline.exec(composer, undef, NODE_NAME, tempClass, tempClassRegExp, undef, undef, true, true);
|
11061
|
-
anchors = doc.querySelectorAll(NODE_NAME + "." + tempClass);
|
11062
|
-
length = anchors.length;
|
11063
|
-
for (; i<length; i++) {
|
11064
|
-
anchor = anchors[i];
|
11065
|
-
anchor.removeAttribute("class");
|
11066
|
-
for (j in attributes) {
|
11067
|
-
// Do not set attribute "text" as it is meant for setting string value if created link has no textual data
|
11068
|
-
if (j !== "text") {
|
11069
|
-
anchor.setAttribute(j, attributes[j]);
|
11070
|
-
}
|
11071
|
-
}
|
11072
|
-
}
|
11073
|
-
|
11074
|
-
elementToSetCaretAfter = anchor;
|
11075
|
-
if (length === 1) {
|
11076
|
-
textContent = dom.getTextContent(anchor);
|
11077
|
-
hasElementChild = !!anchor.querySelector("*");
|
11078
|
-
isEmpty = textContent === "" || textContent === wysihtml5.INVISIBLE_SPACE;
|
11079
|
-
if (!hasElementChild && isEmpty) {
|
11080
|
-
dom.setTextContent(anchor, attributes.text || anchor.href);
|
11081
|
-
whiteSpace = doc.createTextNode(" ");
|
11082
|
-
composer.selection.setAfter(anchor);
|
11083
|
-
dom.insert(whiteSpace).after(anchor);
|
11084
|
-
elementToSetCaretAfter = whiteSpace;
|
11085
|
-
}
|
11086
|
-
}
|
11087
|
-
composer.selection.setAfter(elementToSetCaretAfter);
|
11088
|
-
}
|
11089
|
-
|
11090
|
-
// Changes attributes of links
|
11091
|
-
function _changeLinks(composer, anchors, attributes) {
|
11092
|
-
var oldAttrs;
|
11093
|
-
for (var a = anchors.length; a--;) {
|
11094
|
-
|
11095
|
-
// Remove all old attributes
|
11096
|
-
oldAttrs = anchors[a].attributes;
|
11097
|
-
for (var oa = oldAttrs.length; oa--;) {
|
11098
|
-
anchors[a].removeAttribute(oldAttrs.item(oa).name);
|
11099
|
-
}
|
11100
11421
|
|
11101
|
-
|
11102
|
-
|
11103
|
-
|
11104
|
-
|
11105
|
-
}
|
11106
|
-
}
|
11422
|
+
var nodeOptions = {
|
11423
|
+
nodeName: "A",
|
11424
|
+
toggle: false
|
11425
|
+
};
|
11107
11426
|
|
11108
|
-
|
11427
|
+
function getOptions(value) {
|
11428
|
+
var options = typeof value === 'object' ? value : {'href': value};
|
11429
|
+
return wysihtml5.lang.object({}).merge(nodeOptions).merge({'attribute': value}).get();
|
11109
11430
|
}
|
11110
11431
|
|
11111
|
-
wysihtml5.commands.createLink
|
11112
|
-
/**
|
11113
|
-
* TODO: Use HTMLApplier or formatInline here
|
11114
|
-
*
|
11115
|
-
* Turns selection into a link
|
11116
|
-
* If selection is already a link, it just changes the attributes
|
11117
|
-
*
|
11118
|
-
* @example
|
11119
|
-
* // either ...
|
11120
|
-
* wysihtml5.commands.createLink.exec(composer, "createLink", "http://www.google.de");
|
11121
|
-
* // ... or ...
|
11122
|
-
* wysihtml5.commands.createLink.exec(composer, "createLink", { href: "http://www.google.de", target: "_blank" });
|
11123
|
-
*/
|
11432
|
+
wysihtml5.commands.createLink = {
|
11124
11433
|
exec: function(composer, command, value) {
|
11125
|
-
var
|
11126
|
-
if (anchors) {
|
11127
|
-
// remove <a> tag if there's no attributes provided.
|
11128
|
-
if ((!value || !value.href) && anchors.length !== null && anchors.length !== undefined && anchors.length > 0)
|
11129
|
-
{
|
11130
|
-
for(var i=0; i < anchors.length; i++)
|
11131
|
-
{
|
11132
|
-
wysihtml5.dom.unwrap(anchors[i]);
|
11133
|
-
}
|
11134
|
-
return;
|
11135
|
-
}
|
11434
|
+
var opts = getOptions(value);
|
11136
11435
|
|
11137
|
-
|
11138
|
-
composer.
|
11139
|
-
|
11140
|
-
|
11141
|
-
} else {
|
11142
|
-
// Create links
|
11143
|
-
if (value && value.href) {
|
11144
|
-
value = typeof(value) === "object" ? value : { href: value };
|
11145
|
-
_format(composer, value);
|
11146
|
-
}
|
11436
|
+
if (composer.selection.isCollapsed() && !this.state(composer, command)) {
|
11437
|
+
var textNode = composer.doc.createTextNode(opts.attribute.href);
|
11438
|
+
composer.selection.insertNode(textNode);
|
11439
|
+
composer.selection.selectNode(textNode);
|
11147
11440
|
}
|
11441
|
+
wysihtml5.commands.formatInline.exec(composer, command, opts);
|
11148
11442
|
},
|
11149
11443
|
|
11150
11444
|
state: function(composer, command) {
|
11151
|
-
return wysihtml5.commands.formatInline.state(composer, command,
|
11445
|
+
return wysihtml5.commands.formatInline.state(composer, command, nodeOptions);
|
11152
11446
|
}
|
11153
11447
|
};
|
11448
|
+
|
11154
11449
|
})(wysihtml5);
|
11155
11450
|
;(function(wysihtml5) {
|
11156
|
-
var dom = wysihtml5.dom;
|
11157
11451
|
|
11158
|
-
|
11159
|
-
|
11160
|
-
|
11161
|
-
anchor,
|
11162
|
-
codeElement,
|
11163
|
-
textContent;
|
11164
|
-
for (; i<length; i++) {
|
11165
|
-
anchor = anchors[i];
|
11166
|
-
codeElement = dom.getParentElement(anchor, { query: "code" });
|
11167
|
-
textContent = dom.getTextContent(anchor);
|
11168
|
-
|
11169
|
-
// if <a> contains url-like text content, rename it to <code> to prevent re-autolinking
|
11170
|
-
// else replace <a> with its childNodes
|
11171
|
-
if (textContent.match(dom.autoLink.URL_REG_EXP) && !codeElement) {
|
11172
|
-
// <code> element is used to prevent later auto-linking of the content
|
11173
|
-
codeElement = dom.renameElement(anchor, "code");
|
11174
|
-
} else {
|
11175
|
-
dom.replaceWithChildNodes(anchor);
|
11176
|
-
}
|
11177
|
-
}
|
11178
|
-
}
|
11452
|
+
var nodeOptions = {
|
11453
|
+
nodeName: "A"
|
11454
|
+
};
|
11179
11455
|
|
11180
11456
|
wysihtml5.commands.removeLink = {
|
11181
|
-
/*
|
11182
|
-
* If selection is a link, it removes the link and wraps it with a <code> element
|
11183
|
-
* The <code> element is needed to avoid auto linking
|
11184
|
-
*
|
11185
|
-
* @example
|
11186
|
-
* wysihtml5.commands.createLink.exec(composer, "removeLink");
|
11187
|
-
*/
|
11188
|
-
|
11189
11457
|
exec: function(composer, command) {
|
11190
|
-
|
11191
|
-
if (anchors) {
|
11192
|
-
composer.selection.executeAndRestore(function() {
|
11193
|
-
_removeFormat(composer, anchors);
|
11194
|
-
});
|
11195
|
-
}
|
11458
|
+
wysihtml5.commands.formatInline.remove(composer, command, nodeOptions);
|
11196
11459
|
},
|
11197
11460
|
|
11198
11461
|
state: function(composer, command) {
|
11199
|
-
return wysihtml5.commands.formatInline.state(composer, command,
|
11462
|
+
return wysihtml5.commands.formatInline.state(composer, command, nodeOptions);
|
11200
11463
|
}
|
11201
11464
|
};
|
11465
|
+
|
11202
11466
|
})(wysihtml5);
|
11203
11467
|
;/**
|
11204
|
-
*
|
11205
|
-
* which we don't want
|
11206
|
-
* Instead we set a css class
|
11468
|
+
* Set font size css class
|
11207
11469
|
*/
|
11208
11470
|
(function(wysihtml5) {
|
11209
11471
|
var REG_EXP = /wysiwyg-font-size-[0-9a-z\-]+/g;
|
11210
11472
|
|
11211
11473
|
wysihtml5.commands.fontSize = {
|
11212
11474
|
exec: function(composer, command, size) {
|
11213
|
-
wysihtml5.commands.formatInline.
|
11475
|
+
wysihtml5.commands.formatInline.exec(composer, command, {className: "wysiwyg-font-size-" + size, classRegExp: REG_EXP, toggle: true});
|
11214
11476
|
},
|
11215
11477
|
|
11216
11478
|
state: function(composer, command, size) {
|
11217
|
-
return wysihtml5.commands.formatInline.state(composer, command,
|
11479
|
+
return wysihtml5.commands.formatInline.state(composer, command, {className: "wysiwyg-font-size-" + size});
|
11218
11480
|
}
|
11219
11481
|
};
|
11220
11482
|
})(wysihtml5);
|
11221
|
-
|
11483
|
+
;/**
|
11484
|
+
* Set font size by inline style
|
11485
|
+
*/
|
11222
11486
|
(function(wysihtml5) {
|
11223
|
-
var REG_EXP = /(\s|^)font-size\s*:\s*[^;\s]+;?/gi;
|
11224
11487
|
|
11225
11488
|
wysihtml5.commands.fontSizeStyle = {
|
11226
11489
|
exec: function(composer, command, size) {
|
11227
|
-
size =
|
11490
|
+
size = size.size || size;
|
11228
11491
|
if (!(/^\s*$/).test(size)) {
|
11229
|
-
wysihtml5.commands.formatInline.
|
11492
|
+
wysihtml5.commands.formatInline.exec(composer, command, {styleProperty: "fontSize", styleValue: size, toggle: true});
|
11230
11493
|
}
|
11231
11494
|
},
|
11232
11495
|
|
11233
11496
|
state: function(composer, command, size) {
|
11234
|
-
return wysihtml5.commands.formatInline.state(composer, command, "
|
11497
|
+
return wysihtml5.commands.formatInline.state(composer, command, {styleProperty: "fontSize", styleValue: size});
|
11498
|
+
},
|
11499
|
+
|
11500
|
+
remove: function(composer, command) {
|
11501
|
+
return wysihtml5.commands.formatInline.remove(composer, command, {styleProperty: "fontSize"});
|
11235
11502
|
},
|
11236
11503
|
|
11237
11504
|
stateValue: function(composer, command) {
|
@@ -11253,52 +11520,57 @@ wysihtml5.Commands = Base.extend(
|
|
11253
11520
|
};
|
11254
11521
|
})(wysihtml5);
|
11255
11522
|
;/**
|
11256
|
-
*
|
11257
|
-
* which we don't want
|
11258
|
-
* Instead we set a css class
|
11523
|
+
* Set color css class
|
11259
11524
|
*/
|
11260
11525
|
(function(wysihtml5) {
|
11261
11526
|
var REG_EXP = /wysiwyg-color-[0-9a-z]+/g;
|
11262
11527
|
|
11263
11528
|
wysihtml5.commands.foreColor = {
|
11264
11529
|
exec: function(composer, command, color) {
|
11265
|
-
wysihtml5.commands.formatInline.
|
11530
|
+
wysihtml5.commands.formatInline.exec(composer, command, {className: "wysiwyg-color-" + color, classRegExp: REG_EXP, toggle: true});
|
11266
11531
|
},
|
11267
11532
|
|
11268
11533
|
state: function(composer, command, color) {
|
11269
|
-
return wysihtml5.commands.formatInline.state(composer, command,
|
11534
|
+
return wysihtml5.commands.formatInline.state(composer, command, {className: "wysiwyg-color-" + color});
|
11270
11535
|
}
|
11271
11536
|
};
|
11272
11537
|
})(wysihtml5);
|
11273
11538
|
;/**
|
11274
|
-
*
|
11275
|
-
* which we don't want
|
11276
|
-
* Instead we set a css class
|
11539
|
+
* Sets text color by inline styles
|
11277
11540
|
*/
|
11278
11541
|
(function(wysihtml5) {
|
11279
|
-
var REG_EXP = /(\s|^)color\s*:\s*[^;\s]+;?/gi;
|
11280
11542
|
|
11281
11543
|
wysihtml5.commands.foreColorStyle = {
|
11282
11544
|
exec: function(composer, command, color) {
|
11283
|
-
var colorVals = wysihtml5.quirks.styleParser.parseColor(
|
11545
|
+
var colorVals = wysihtml5.quirks.styleParser.parseColor("color:" + (color.color || color), "color"),
|
11284
11546
|
colString;
|
11285
11547
|
|
11286
11548
|
if (colorVals) {
|
11287
|
-
colString = "
|
11288
|
-
|
11289
|
-
colString += "color: rgba(" + colorVals[0] + ',' + colorVals[1] + ',' + colorVals[2] + ',' + colorVals[3] + ');';
|
11290
|
-
}
|
11291
|
-
wysihtml5.commands.formatInline.execWithToggle(composer, command, "span", false, false, colString, REG_EXP);
|
11549
|
+
colString = (colorVals[3] === 1 ? "rgb(" + [colorVals[0], colorVals[1], colorVals[2]].join(', ') : "rgba(" + colorVals.join(', ')) + ')';
|
11550
|
+
wysihtml5.commands.formatInline.exec(composer, command, {styleProperty: 'color', styleValue: colString});
|
11292
11551
|
}
|
11293
11552
|
},
|
11294
11553
|
|
11295
|
-
state: function(composer, command) {
|
11296
|
-
|
11554
|
+
state: function(composer, command, color) {
|
11555
|
+
var colorVals = color ? wysihtml5.quirks.styleParser.parseColor("color:" + (color.color || color), "color") : null,
|
11556
|
+
colString;
|
11557
|
+
|
11558
|
+
|
11559
|
+
if (colorVals) {
|
11560
|
+
colString = (colorVals[3] === 1 ? "rgb(" + [colorVals[0], colorVals[1], colorVals[2]].join(', ') : "rgba(" + colorVals.join(', ')) + ')';
|
11561
|
+
}
|
11562
|
+
|
11563
|
+
return wysihtml5.commands.formatInline.state(composer, command, {styleProperty: 'color', styleValue: colString});
|
11564
|
+
},
|
11565
|
+
|
11566
|
+
remove: function(composer, command) {
|
11567
|
+
return wysihtml5.commands.formatInline.remove(composer, command, {styleProperty: 'color'});
|
11297
11568
|
},
|
11298
11569
|
|
11299
11570
|
stateValue: function(composer, command, props) {
|
11300
11571
|
var st = this.state(composer, command),
|
11301
|
-
colorStr
|
11572
|
+
colorStr,
|
11573
|
+
val = false;
|
11302
11574
|
|
11303
11575
|
if (st && wysihtml5.lang.object(st).isArray()) {
|
11304
11576
|
st = st[0];
|
@@ -11307,10 +11579,8 @@ wysihtml5.Commands = Base.extend(
|
|
11307
11579
|
if (st) {
|
11308
11580
|
colorStr = st.getAttribute('style');
|
11309
11581
|
if (colorStr) {
|
11310
|
-
|
11311
|
-
|
11312
|
-
return wysihtml5.quirks.styleParser.unparseColor(val, props);
|
11313
|
-
}
|
11582
|
+
val = wysihtml5.quirks.styleParser.parseColor(colorStr, "color");
|
11583
|
+
return wysihtml5.quirks.styleParser.unparseColor(val, props);
|
11314
11584
|
}
|
11315
11585
|
}
|
11316
11586
|
return false;
|
@@ -11318,26 +11588,36 @@ wysihtml5.Commands = Base.extend(
|
|
11318
11588
|
|
11319
11589
|
};
|
11320
11590
|
})(wysihtml5);
|
11321
|
-
|
11591
|
+
;/**
|
11592
|
+
* Sets text background color by inline styles
|
11593
|
+
*/
|
11322
11594
|
(function(wysihtml5) {
|
11323
|
-
var REG_EXP = /(\s|^)background-color\s*:\s*[^;\s]+;?/gi;
|
11324
11595
|
|
11325
11596
|
wysihtml5.commands.bgColorStyle = {
|
11326
11597
|
exec: function(composer, command, color) {
|
11327
|
-
var colorVals = wysihtml5.quirks.styleParser.parseColor(
|
11598
|
+
var colorVals = wysihtml5.quirks.styleParser.parseColor("background-color:" + (color.color || color), "background-color"),
|
11328
11599
|
colString;
|
11329
11600
|
|
11330
11601
|
if (colorVals) {
|
11331
|
-
colString = "
|
11332
|
-
|
11333
|
-
colString += "background-color: rgba(" + colorVals[0] + ',' + colorVals[1] + ',' + colorVals[2] + ',' + colorVals[3] + ');';
|
11334
|
-
}
|
11335
|
-
wysihtml5.commands.formatInline.execWithToggle(composer, command, "span", false, false, colString, REG_EXP);
|
11602
|
+
colString = (colorVals[3] === 1 ? "rgb(" + [colorVals[0], colorVals[1], colorVals[2]].join(', ') : "rgba(" + colorVals.join(', ')) + ')';
|
11603
|
+
wysihtml5.commands.formatInline.exec(composer, command, {styleProperty: 'backgroundColor', styleValue: colString});
|
11336
11604
|
}
|
11337
11605
|
},
|
11338
11606
|
|
11339
|
-
state: function(composer, command) {
|
11340
|
-
|
11607
|
+
state: function(composer, command, color) {
|
11608
|
+
var colorVals = color ? wysihtml5.quirks.styleParser.parseColor("background-color:" + (color.color || color), "background-color") : null,
|
11609
|
+
colString;
|
11610
|
+
|
11611
|
+
|
11612
|
+
if (colorVals) {
|
11613
|
+
colString = (colorVals[3] === 1 ? "rgb(" + [colorVals[0], colorVals[1], colorVals[2]].join(', ') : "rgba(" + colorVals.join(', ')) + ')';
|
11614
|
+
}
|
11615
|
+
|
11616
|
+
return wysihtml5.commands.formatInline.state(composer, command, {styleProperty: 'backgroundColor', styleValue: colString});
|
11617
|
+
},
|
11618
|
+
|
11619
|
+
remove: function(composer, command) {
|
11620
|
+
return wysihtml5.commands.formatInline.remove(composer, command, {styleProperty: 'backgroundColor'});
|
11341
11621
|
},
|
11342
11622
|
|
11343
11623
|
stateValue: function(composer, command, props) {
|
@@ -11780,154 +12060,665 @@ wysihtml5.Commands = Base.extend(
|
|
11780
12060
|
};
|
11781
12061
|
}(wysihtml5));
|
11782
12062
|
;/**
|
11783
|
-
*
|
11784
|
-
*
|
11785
|
-
* #1 caret in unformatted text:
|
11786
|
-
* abcdefg|
|
11787
|
-
* output:
|
11788
|
-
* abcdefg<b>|</b>
|
11789
|
-
*
|
11790
|
-
* #2 unformatted text selected:
|
11791
|
-
* abc|deg|h
|
11792
|
-
* output:
|
11793
|
-
* abc<b>|deg|</b>h
|
11794
|
-
*
|
11795
|
-
* #3 unformatted text selected across boundaries:
|
11796
|
-
* ab|c <span>defg|h</span>
|
11797
|
-
* output:
|
11798
|
-
* ab<b>|c </b><span><b>defg</b>|h</span>
|
11799
|
-
*
|
11800
|
-
* #4 formatted text entirely selected
|
11801
|
-
* <b>|abc|</b>
|
11802
|
-
* output:
|
11803
|
-
* |abc|
|
11804
|
-
*
|
11805
|
-
* #5 formatted text partially selected
|
11806
|
-
* <b>ab|c|</b>
|
11807
|
-
* output:
|
11808
|
-
* <b>ab</b>|c|
|
11809
|
-
*
|
11810
|
-
* #6 formatted text selected across boundaries
|
11811
|
-
* <span>ab|c</span> <b>de|fgh</b>
|
11812
|
-
* output:
|
11813
|
-
* <span>ab|c</span> de|<b>fgh</b>
|
12063
|
+
* Unifies all inline tags additions and removals
|
12064
|
+
* See https://github.com/Voog/wysihtml/pull/169 for specification of action
|
11814
12065
|
*/
|
12066
|
+
|
11815
12067
|
(function(wysihtml5) {
|
11816
|
-
var // Treat <b> as <strong> and vice versa
|
11817
|
-
ALIAS_MAPPING = {
|
11818
|
-
"strong": "b",
|
11819
|
-
"em": "i",
|
11820
|
-
"b": "strong",
|
11821
|
-
"i": "em"
|
11822
|
-
},
|
11823
|
-
htmlApplier = {};
|
11824
12068
|
|
11825
|
-
|
11826
|
-
|
11827
|
-
|
12069
|
+
var defaultTag = "SPAN",
|
12070
|
+
INLINE_ELEMENTS = "b, big, i, small, tt, abbr, acronym, cite, code, dfn, em, kbd, strong, samp, var, a, bdo, br, q, span, sub, sup, button, label, textarea, input, select",
|
12071
|
+
queryAliasMap = {
|
12072
|
+
"b": "b, strong",
|
12073
|
+
"strong": "b, strong",
|
12074
|
+
"em": "em, i",
|
12075
|
+
"i": "em, i"
|
12076
|
+
};
|
12077
|
+
|
12078
|
+
function hasNoClass(element) {
|
12079
|
+
return (/^\s*$/).test(element.className);
|
11828
12080
|
}
|
11829
12081
|
|
11830
|
-
function
|
11831
|
-
|
11832
|
-
|
11833
|
-
|
11834
|
-
|
12082
|
+
function hasNoStyle(element) {
|
12083
|
+
return !element.getAttribute('style') || (/^\s*$/).test(element.getAttribute('style'));
|
12084
|
+
}
|
12085
|
+
|
12086
|
+
// Associative arrays in javascript are really objects and do not have length defined
|
12087
|
+
// Thus have to check emptyness in a different way
|
12088
|
+
function hasNoAttributes(element) {
|
12089
|
+
var attr = wysihtml5.dom.getAttributes(element);
|
12090
|
+
return wysihtml5.lang.object(attr).isEmpty();
|
12091
|
+
}
|
12092
|
+
|
12093
|
+
// compares two nodes if they are semantically the same
|
12094
|
+
// Used in cleanup to find consequent semantically similar elements for merge
|
12095
|
+
function isSameNode(element1, element2) {
|
12096
|
+
var classes1, classes2,
|
12097
|
+
attr1, attr2;
|
12098
|
+
|
12099
|
+
if (element1.nodeType !== 1 || element2.nodeType !== 1) {
|
12100
|
+
return false;
|
11835
12101
|
}
|
11836
|
-
|
11837
|
-
|
12102
|
+
|
12103
|
+
if (element1.nodeName !== element2.nodeName) {
|
12104
|
+
return false;
|
11838
12105
|
}
|
11839
12106
|
|
11840
|
-
|
11841
|
-
|
12107
|
+
classes1 = element1.className.trim().replace(/\s+/g, ' ').split(' ');
|
12108
|
+
classes2 = element2.className.trim().replace(/\s+/g, ' ').split(' ');
|
12109
|
+
if (wysihtml5.lang.array(classes1).without(classes2).length > 0) {
|
12110
|
+
return false;
|
11842
12111
|
}
|
11843
12112
|
|
11844
|
-
|
12113
|
+
attr1 = wysihtml5.dom.getAttributes(element1);
|
12114
|
+
attr2 = wysihtml5.dom.getAttributes(element2);
|
12115
|
+
|
12116
|
+
if (attr1.length !== attr2.length || !wysihtml5.lang.object(wysihtml5.lang.object(attr1).difference(attr2)).isEmpty()) {
|
12117
|
+
return false;
|
12118
|
+
}
|
12119
|
+
|
12120
|
+
return true;
|
11845
12121
|
}
|
11846
12122
|
|
11847
|
-
|
11848
|
-
|
11849
|
-
|
11850
|
-
ownRanges = composer.selection.getOwnRanges();
|
12123
|
+
function createWrapNode(textNode, options) {
|
12124
|
+
var nodeName = options && options.nodeName || defaultTag,
|
12125
|
+
element = textNode.ownerDocument.createElement(nodeName);
|
11851
12126
|
|
11852
|
-
|
11853
|
-
|
12127
|
+
// Remove similar classes before applying className
|
12128
|
+
if (options.classRegExp) {
|
12129
|
+
element.className = element.className.replace(options.classRegExp, "");
|
12130
|
+
}
|
12131
|
+
|
12132
|
+
if (options.className) {
|
12133
|
+
element.classList.add(options.className);
|
12134
|
+
}
|
12135
|
+
|
12136
|
+
if (options.styleProperty && typeof options.styleValue !== "undefined") {
|
12137
|
+
element.style[wysihtml5.browser.fixStyleKey(options.styleProperty)] = options.styleValue;
|
12138
|
+
}
|
12139
|
+
|
12140
|
+
if (options.attribute) {
|
12141
|
+
if (typeof options.attribute === "object") {
|
12142
|
+
for (var a in options.attribute) {
|
12143
|
+
if (options.attribute.hasOwnProperty(a)) {
|
12144
|
+
element.setAttribute(a, options.attribute[a]);
|
12145
|
+
}
|
12146
|
+
}
|
12147
|
+
} else if (typeof options.attributeValue !== "undefined") {
|
12148
|
+
element.setAttribute(options.attribute, options.attributeValue);
|
11854
12149
|
}
|
11855
|
-
|
12150
|
+
}
|
11856
12151
|
|
11857
|
-
|
12152
|
+
return element;
|
12153
|
+
}
|
11858
12154
|
|
11859
|
-
|
11860
|
-
|
11861
|
-
|
11862
|
-
|
11863
|
-
|
11864
|
-
)
|
11865
|
-
|
11866
|
-
|
11867
|
-
|
11868
|
-
|
12155
|
+
// Tests if attr2 list contains all attributes present in attr1
|
12156
|
+
// Note: attr 1 can have more attributes than attr2
|
12157
|
+
function containsSameAttributes(attr1, attr2) {
|
12158
|
+
for (var a in attr1) {
|
12159
|
+
if (attr1.hasOwnProperty(a)) {
|
12160
|
+
if (typeof attr2[a] === undefined || attr2[a] !== attr1[a]) {
|
12161
|
+
return false;
|
12162
|
+
}
|
12163
|
+
}
|
12164
|
+
}
|
12165
|
+
return true;
|
12166
|
+
}
|
12167
|
+
|
12168
|
+
// If attrbutes and values are the same > remove
|
12169
|
+
// if attributes or values
|
12170
|
+
function updateElementAttributes(element, newAttributes, toggle) {
|
12171
|
+
var attr = wysihtml5.dom.getAttributes(element),
|
12172
|
+
fullContain = containsSameAttributes(newAttributes, attr),
|
12173
|
+
attrDifference = wysihtml5.lang.object(attr).difference(newAttributes),
|
12174
|
+
a, b;
|
12175
|
+
|
12176
|
+
if (fullContain && toggle !== false) {
|
12177
|
+
for (a in newAttributes) {
|
12178
|
+
if (newAttributes.hasOwnProperty(a)) {
|
12179
|
+
element.removeAttribute(a);
|
12180
|
+
}
|
12181
|
+
}
|
12182
|
+
} else {
|
12183
|
+
|
12184
|
+
/*if (!wysihtml5.lang.object(attrDifference).isEmpty()) {
|
12185
|
+
for (b in attrDifference) {
|
12186
|
+
if (attrDifference.hasOwnProperty(b)) {
|
12187
|
+
element.removeAttribute(b);
|
11869
12188
|
}
|
11870
|
-
}
|
11871
|
-
}
|
11872
|
-
|
12189
|
+
}
|
12190
|
+
}*/
|
12191
|
+
|
12192
|
+
for (a in newAttributes) {
|
12193
|
+
if (newAttributes.hasOwnProperty(a)) {
|
12194
|
+
element.setAttribute(a, newAttributes[a]);
|
12195
|
+
}
|
11873
12196
|
}
|
11874
|
-
}
|
12197
|
+
}
|
12198
|
+
}
|
11875
12199
|
|
11876
|
-
|
11877
|
-
|
11878
|
-
// This works on built in contenteditable inline format commands
|
11879
|
-
execWithToggle: function(composer, command, tagName, className, classRegExp, cssStyle, styleRegExp) {
|
11880
|
-
var that = this;
|
12200
|
+
function updateFormatOfElement(element, options) {
|
12201
|
+
var attr, newNode, a, newAttributes, nodeNameQuery;
|
11881
12202
|
|
11882
|
-
|
11883
|
-
|
11884
|
-
|
11885
|
-
|
11886
|
-
|
11887
|
-
var state_element = that.state(composer, command, tagName, className, classRegExp)[0];
|
11888
|
-
composer.selection.executeAndRestoreRangy(function() {
|
11889
|
-
var parent = state_element.parentNode;
|
11890
|
-
composer.selection.selectNode(state_element, true);
|
11891
|
-
wysihtml5.commands.formatInline.exec(composer, command, tagName, className, classRegExp, cssStyle, styleRegExp, true, true);
|
11892
|
-
});
|
12203
|
+
|
12204
|
+
|
12205
|
+
if (options.className) {
|
12206
|
+
if (options.toggle !== false && element.classList.contains(options.className)) {
|
12207
|
+
element.classList.remove(options.className);
|
11893
12208
|
} else {
|
11894
|
-
|
11895
|
-
|
11896
|
-
|
11897
|
-
|
12209
|
+
element.classList.add(options.className);
|
12210
|
+
}
|
12211
|
+
if (hasNoClass(element)) {
|
12212
|
+
element.removeAttribute('class');
|
12213
|
+
}
|
12214
|
+
}
|
12215
|
+
|
12216
|
+
// change/remove style
|
12217
|
+
if (options.styleProperty) {
|
12218
|
+
if (options.toggle !== false && element.style[wysihtml5.browser.fixStyleKey(options.styleProperty)].trim().replace(/, /g, ",") === options.styleValue) {
|
12219
|
+
element.style[wysihtml5.browser.fixStyleKey(options.styleProperty)] = '';
|
12220
|
+
} else {
|
12221
|
+
element.style[wysihtml5.browser.fixStyleKey(options.styleProperty)] = options.styleValue;
|
12222
|
+
}
|
12223
|
+
}
|
12224
|
+
if (hasNoStyle(element)) {
|
12225
|
+
element.removeAttribute('style');
|
12226
|
+
}
|
12227
|
+
|
12228
|
+
if (options.attribute) {
|
12229
|
+
if (typeof options.attribute === "object") {
|
12230
|
+
newAttributes = options.attribute;
|
12231
|
+
} else {
|
12232
|
+
newAttributes = {};
|
12233
|
+
newAttributes[options.attribute] = options.attributeValue || '';
|
12234
|
+
}
|
12235
|
+
updateElementAttributes(element, newAttributes, options.toggle);
|
12236
|
+
}
|
12237
|
+
|
12238
|
+
// Handle similar semanticallys ame elements (queryAliasMap)
|
12239
|
+
nodeNameQuery = options.nodeName ? queryAliasMap[options.nodeName.toLowerCase()] || options.nodeName.toLowerCase() : null;
|
12240
|
+
|
12241
|
+
if ((options.nodeName && wysihtml5.dom.domNode(element).test({ query: nodeNameQuery })) || (!options.nodeName && element.nodeName === defaultTag)) {
|
12242
|
+
|
12243
|
+
|
12244
|
+
if (hasNoClass(element) && hasNoStyle(element) && hasNoAttributes(element)) {
|
12245
|
+
wysihtml5.dom.unwrap(element);
|
12246
|
+
} else if (!options.nodeName) {
|
12247
|
+
newNode = element.ownerDocument.createElement(defaultTag);
|
12248
|
+
|
12249
|
+
// pass present attributes
|
12250
|
+
attr = wysihtml5.dom.getAttributes(element);
|
12251
|
+
for (a in attr) {
|
12252
|
+
if (attr.hasOwnProperty(a)) {
|
12253
|
+
newNode.setAttribute(a, attr[a]);
|
12254
|
+
}
|
12255
|
+
}
|
12256
|
+
|
12257
|
+
while (element.firstChild) {
|
12258
|
+
newNode.appendChild(element.firstChild);
|
12259
|
+
}
|
12260
|
+
element.parentNode.insertBefore(newNode, element);
|
12261
|
+
element.parentNode.removeChild(element);
|
12262
|
+
}
|
12263
|
+
|
12264
|
+
}
|
12265
|
+
}
|
12266
|
+
|
12267
|
+
// Fetch all textnodes in selection
|
12268
|
+
// Empty textnodes are ignored except the one containing text caret
|
12269
|
+
function getSelectedTextNodes(selection, splitBounds) {
|
12270
|
+
var textNodes = [];
|
12271
|
+
|
12272
|
+
if (!selection.isCollapsed()) {
|
12273
|
+
textNodes = textNodes.concat(selection.getOwnNodes([3], function(node) {
|
12274
|
+
// Exclude empty nodes except caret node
|
12275
|
+
return (!wysihtml5.dom.domNode(node).is.emptyTextNode());
|
12276
|
+
}, splitBounds));
|
12277
|
+
}
|
12278
|
+
|
12279
|
+
return textNodes;
|
12280
|
+
}
|
12281
|
+
|
12282
|
+
function findSimilarTextNodeWrapper(textNode, options, container, exact) {
|
12283
|
+
var node = textNode,
|
12284
|
+
similarOptions = exact ? options : correctOptionsForSimilarityCheck(options);
|
12285
|
+
|
12286
|
+
do {
|
12287
|
+
if (node.nodeType === 1 && isSimilarNode(node, similarOptions)) {
|
12288
|
+
return node;
|
12289
|
+
}
|
12290
|
+
node = node.parentNode;
|
12291
|
+
} while (node && node !== container);
|
12292
|
+
|
12293
|
+
return null;
|
12294
|
+
}
|
12295
|
+
|
12296
|
+
function correctOptionsForSimilarityCheck(options) {
|
12297
|
+
return {
|
12298
|
+
nodeName: options.nodeName || null,
|
12299
|
+
className: (!options.classRegExp) ? options.className || null : null,
|
12300
|
+
classRegExp: options.classRegExp || null,
|
12301
|
+
styleProperty: options.styleProperty || null
|
12302
|
+
};
|
12303
|
+
}
|
12304
|
+
|
12305
|
+
// Finds inline node with similar nodeName/style/className
|
12306
|
+
// If nodeName is specified inline node with the same (or alias) nodeName is expected to prove similar regardless of attributes
|
12307
|
+
function isSimilarNode(node, options) {
|
12308
|
+
var o;
|
12309
|
+
if (options.nodeName) {
|
12310
|
+
var query = queryAliasMap[options.nodeName.toLowerCase()] || options.nodeName.toLowerCase();
|
12311
|
+
return wysihtml5.dom.domNode(node).test({ query: query });
|
12312
|
+
} else {
|
12313
|
+
o = wysihtml5.lang.object(options).clone();
|
12314
|
+
o.query = INLINE_ELEMENTS; // make sure only inline elements with styles and classes are counted
|
12315
|
+
return wysihtml5.dom.domNode(node).test(o);
|
12316
|
+
}
|
12317
|
+
}
|
12318
|
+
|
12319
|
+
function selectRange(composer, range) {
|
12320
|
+
var d = document.documentElement || document.body,
|
12321
|
+
oldScrollTop = d.scrollTop,
|
12322
|
+
oldScrollLeft = d.scrollLeft,
|
12323
|
+
selection = rangy.getSelection(composer.win);
|
12324
|
+
|
12325
|
+
rangy.getSelection(composer.win).removeAllRanges();
|
12326
|
+
|
12327
|
+
// IE looses focus of contenteditable on removeallranges and can not set new selection unless contenteditable is focused again
|
12328
|
+
try {
|
12329
|
+
rangy.getSelection(composer.win).addRange(range);
|
12330
|
+
} catch (e) {}
|
12331
|
+
if (!composer.doc.activeElement || !wysihtml5.dom.contains(composer.element, composer.doc.activeElement)) {
|
12332
|
+
composer.element.focus();
|
12333
|
+
d.scrollTop = oldScrollTop;
|
12334
|
+
d.scrollLeft = oldScrollLeft;
|
12335
|
+
rangy.getSelection(composer.win).addRange(range);
|
12336
|
+
}
|
12337
|
+
}
|
12338
|
+
|
12339
|
+
function selectTextNodes(textNodes, composer) {
|
12340
|
+
var range = rangy.createRange(composer.doc),
|
12341
|
+
lastText = textNodes[textNodes.length - 1];
|
12342
|
+
|
12343
|
+
if (textNodes[0] && lastText) {
|
12344
|
+
range.setStart(textNodes[0], 0);
|
12345
|
+
range.setEnd(lastText, lastText.length);
|
12346
|
+
selectRange(composer, range);
|
12347
|
+
}
|
12348
|
+
|
12349
|
+
}
|
12350
|
+
|
12351
|
+
function selectTextNode(composer, node, start, end) {
|
12352
|
+
var range = rangy.createRange(composer.doc);
|
12353
|
+
if (node) {
|
12354
|
+
range.setStart(node, start);
|
12355
|
+
range.setEnd(node, typeof end !== 'undefined' ? end : start);
|
12356
|
+
selectRange(composer, range);
|
12357
|
+
}
|
12358
|
+
}
|
12359
|
+
|
12360
|
+
function getState(composer, options, exact) {
|
12361
|
+
var searchNodes = getSelectedTextNodes(composer.selection),
|
12362
|
+
nodes = [],
|
12363
|
+
partial = false,
|
12364
|
+
node, range, caretNode;
|
12365
|
+
|
12366
|
+
if (searchNodes.length === 0 && composer.selection.isCollapsed()) {
|
12367
|
+
caretNode = composer.selection.getSelection().anchorNode;
|
12368
|
+
if (!caretNode) {
|
12369
|
+
// selection not in editor
|
12370
|
+
return {
|
12371
|
+
nodes: [],
|
12372
|
+
partial: false
|
12373
|
+
};
|
12374
|
+
}
|
12375
|
+
if (caretNode.nodeType === 3) {
|
12376
|
+
searchNodes = [caretNode];
|
12377
|
+
}
|
12378
|
+
}
|
12379
|
+
|
12380
|
+
// Handle collapsed selection caret
|
12381
|
+
if (!searchNodes.length) {
|
12382
|
+
range = composer.selection.getOwnRanges()[0];
|
12383
|
+
if (range) {
|
12384
|
+
searchNodes = [range.endContainer];
|
12385
|
+
}
|
12386
|
+
}
|
12387
|
+
|
12388
|
+
for (var i = 0, maxi = searchNodes.length; i < maxi; i++) {
|
12389
|
+
node = findSimilarTextNodeWrapper(searchNodes[i], options, composer.element, exact);
|
12390
|
+
if (node) {
|
12391
|
+
nodes.push(node);
|
12392
|
+
} else {
|
12393
|
+
partial = true;
|
12394
|
+
}
|
12395
|
+
}
|
12396
|
+
|
12397
|
+
return {
|
12398
|
+
nodes: nodes,
|
12399
|
+
partial: partial
|
12400
|
+
};
|
12401
|
+
}
|
12402
|
+
|
12403
|
+
// Returns if caret is inside a word in textnode (not on boundary)
|
12404
|
+
// If selection anchornode is not text node, returns false
|
12405
|
+
function caretIsInsideWord(selection) {
|
12406
|
+
var anchor, offset, beforeChar, afterChar;
|
12407
|
+
if (selection) {
|
12408
|
+
anchor = selection.anchorNode;
|
12409
|
+
offset = selection.anchorOffset;
|
12410
|
+
if (anchor && anchor.nodeType === 3 && offset > 0 && offset < anchor.data.length) {
|
12411
|
+
beforeChar = anchor.data[offset - 1];
|
12412
|
+
afterChar = anchor.data[offset];
|
12413
|
+
return (/\w/).test(beforeChar) && (/\w/).test(afterChar);
|
12414
|
+
}
|
12415
|
+
}
|
12416
|
+
return false;
|
12417
|
+
}
|
12418
|
+
|
12419
|
+
// Returns a range and textnode containing object from caret position covering a whole word
|
12420
|
+
// wordOffsety describes the original position of caret in the new textNode
|
12421
|
+
// Caret has to be inside a textNode.
|
12422
|
+
function getRangeForWord(selection) {
|
12423
|
+
var anchor, offset, doc, range, offsetStart, offsetEnd, beforeChar, afterChar,
|
12424
|
+
txtNodes = [];
|
12425
|
+
if (selection) {
|
12426
|
+
anchor = selection.anchorNode;
|
12427
|
+
offset = offsetStart = offsetEnd = selection.anchorOffset;
|
12428
|
+
doc = anchor.ownerDocument;
|
12429
|
+
range = rangy.createRange(doc);
|
12430
|
+
|
12431
|
+
if (anchor && anchor.nodeType === 3) {
|
12432
|
+
|
12433
|
+
while (offsetStart > 0 && (/\w/).test(anchor.data[offsetStart - 1])) {
|
12434
|
+
offsetStart--;
|
12435
|
+
}
|
12436
|
+
|
12437
|
+
while (offsetEnd < anchor.data.length && (/\w/).test(anchor.data[offsetEnd])) {
|
12438
|
+
offsetEnd++;
|
12439
|
+
}
|
12440
|
+
|
12441
|
+
range.setStartAndEnd(anchor, offsetStart, offsetEnd);
|
12442
|
+
range.splitBoundaries();
|
12443
|
+
txtNodes = range.getNodes([3], function(node) {
|
12444
|
+
return (!wysihtml5.dom.domNode(node).is.emptyTextNode());
|
12445
|
+
});
|
12446
|
+
|
12447
|
+
return {
|
12448
|
+
wordOffset: offset - offsetStart,
|
12449
|
+
range: range,
|
12450
|
+
textNode: txtNodes[0]
|
12451
|
+
};
|
12452
|
+
|
12453
|
+
}
|
12454
|
+
}
|
12455
|
+
return false;
|
12456
|
+
}
|
12457
|
+
|
12458
|
+
// Contents of 2 elements are merged to fitst element. second element is removed as consequence
|
12459
|
+
function mergeContents(element1, element2) {
|
12460
|
+
while (element2.firstChild) {
|
12461
|
+
element1.appendChild(element2.firstChild);
|
12462
|
+
}
|
12463
|
+
element2.parentNode.removeChild(element2);
|
12464
|
+
}
|
12465
|
+
|
12466
|
+
function mergeConsequentSimilarElements(elements) {
|
12467
|
+
for (var i = elements.length; i--;) {
|
12468
|
+
|
12469
|
+
if (elements[i] && elements[i].parentNode) { // Test if node is not allready removed in cleanup
|
12470
|
+
|
12471
|
+
if (elements[i].nextSibling && isSameNode(elements[i], elements[i].nextSibling)) {
|
12472
|
+
mergeContents(elements[i], elements[i].nextSibling);
|
12473
|
+
}
|
12474
|
+
|
12475
|
+
if (elements[i].previousSibling && isSameNode(elements[i] , elements[i].previousSibling)) {
|
12476
|
+
mergeContents(elements[i].previousSibling, elements[i]);
|
12477
|
+
}
|
12478
|
+
|
12479
|
+
}
|
12480
|
+
}
|
12481
|
+
}
|
12482
|
+
|
12483
|
+
function cleanupAndSetSelection(composer, textNodes, options) {
|
12484
|
+
if (textNodes.length > 0) {
|
12485
|
+
selectTextNodes(textNodes, composer);
|
12486
|
+
}
|
12487
|
+
mergeConsequentSimilarElements(getState(composer, options).nodes);
|
12488
|
+
if (textNodes.length > 0) {
|
12489
|
+
selectTextNodes(textNodes, composer);
|
12490
|
+
}
|
12491
|
+
}
|
12492
|
+
|
12493
|
+
function cleanupAndSetCaret(composer, textNode, offset, options) {
|
12494
|
+
selectTextNode(composer, textNode, offset);
|
12495
|
+
mergeConsequentSimilarElements(getState(composer, options).nodes);
|
12496
|
+
selectTextNode(composer, textNode, offset);
|
12497
|
+
}
|
12498
|
+
|
12499
|
+
// Formats a textnode with given options
|
12500
|
+
function formatTextNode(textNode, options) {
|
12501
|
+
var wrapNode = createWrapNode(textNode, options);
|
12502
|
+
|
12503
|
+
textNode.parentNode.insertBefore(wrapNode, textNode);
|
12504
|
+
wrapNode.appendChild(textNode);
|
12505
|
+
}
|
12506
|
+
|
12507
|
+
// Changes/toggles format of a textnode
|
12508
|
+
function unformatTextNode(textNode, composer, options) {
|
12509
|
+
var container = composer.element,
|
12510
|
+
wrapNode = findSimilarTextNodeWrapper(textNode, options, container),
|
12511
|
+
newWrapNode;
|
12512
|
+
|
12513
|
+
if (wrapNode) {
|
12514
|
+
newWrapNode = wrapNode.cloneNode(false);
|
12515
|
+
|
12516
|
+
wysihtml5.dom.domNode(textNode).escapeParent(wrapNode, newWrapNode);
|
12517
|
+
updateFormatOfElement(newWrapNode, options);
|
12518
|
+
}
|
12519
|
+
}
|
12520
|
+
|
12521
|
+
// Removes the format around textnode
|
12522
|
+
function removeFormatFromTextNode(textNode, composer, options) {
|
12523
|
+
var container = composer.element,
|
12524
|
+
wrapNode = findSimilarTextNodeWrapper(textNode, options, container);
|
12525
|
+
|
12526
|
+
if (wrapNode) {
|
12527
|
+
wysihtml5.dom.domNode(textNode).escapeParent(wrapNode);
|
12528
|
+
}
|
12529
|
+
}
|
12530
|
+
|
12531
|
+
// Creates node around caret formated with options
|
12532
|
+
function formatTextRange(range, composer, options) {
|
12533
|
+
var wrapNode = createWrapNode(range.endContainer, options);
|
12534
|
+
|
12535
|
+
range.surroundContents(wrapNode);
|
12536
|
+
composer.selection.selectNode(wrapNode);
|
12537
|
+
}
|
12538
|
+
|
12539
|
+
// Changes/toggles format of whole selection
|
12540
|
+
function updateFormat(composer, textNodes, state, options) {
|
12541
|
+
var exactState = getState(composer, options, true),
|
12542
|
+
selection = composer.selection.getSelection(),
|
12543
|
+
wordObj, textNode, newNode, i;
|
12544
|
+
|
12545
|
+
if (!textNodes.length) {
|
12546
|
+
// Selection is caret
|
12547
|
+
|
12548
|
+
|
12549
|
+
if (options.toggle !== false) {
|
12550
|
+
if (caretIsInsideWord(selection)) {
|
12551
|
+
|
12552
|
+
// Unformat whole word
|
12553
|
+
wordObj = getRangeForWord(selection);
|
12554
|
+
textNode = wordObj.textNode;
|
12555
|
+
unformatTextNode(wordObj.textNode, composer, options);
|
12556
|
+
cleanupAndSetCaret(composer, wordObj.textNode, wordObj.wordOffset, options);
|
12557
|
+
|
11898
12558
|
} else {
|
11899
|
-
|
12559
|
+
|
12560
|
+
// Escape caret out of format
|
12561
|
+
textNode = composer.doc.createTextNode(wysihtml5.INVISIBLE_SPACE);
|
12562
|
+
newNode = state.nodes[0].cloneNode(false);
|
12563
|
+
newNode.appendChild(textNode);
|
12564
|
+
composer.selection.splitElementAtCaret(state.nodes[0], newNode);
|
12565
|
+
updateFormatOfElement(newNode, options);
|
12566
|
+
cleanupAndSetSelection(composer, [textNode], options);
|
12567
|
+
var s = composer.selection.getSelection();
|
12568
|
+
if (s.anchorNode && s.focusNode) {
|
12569
|
+
// Has an error in IE when collapsing selection. probably from rangy
|
12570
|
+
try {
|
12571
|
+
s.collapseToEnd();
|
12572
|
+
} catch (e) {}
|
12573
|
+
}
|
12574
|
+
}
|
12575
|
+
} else {
|
12576
|
+
// In non-toggle mode the closest state element has to be found and the state updated differently
|
12577
|
+
for (i = state.nodes.length; i--;) {
|
12578
|
+
updateFormatOfElement(state.nodes[i], options);
|
11900
12579
|
}
|
11901
12580
|
}
|
11902
|
-
},
|
11903
12581
|
|
11904
|
-
|
11905
|
-
|
11906
|
-
|
11907
|
-
|
12582
|
+
} else {
|
12583
|
+
|
12584
|
+
if (!exactState.partial && options.toggle !== false) {
|
12585
|
+
|
12586
|
+
// If whole selection (all textnodes) are in the applied format
|
12587
|
+
// remove the format from selection
|
12588
|
+
// Non-toggle mode never removes. Remove has to be called explicitly
|
12589
|
+
for (i = textNodes.length; i--;) {
|
12590
|
+
unformatTextNode(textNodes[i], composer, options);
|
12591
|
+
}
|
12592
|
+
|
12593
|
+
} else {
|
12594
|
+
|
12595
|
+
// Selection is partially in format
|
12596
|
+
// change it to new if format if textnode allreafy in similar state
|
12597
|
+
// else just apply
|
12598
|
+
|
12599
|
+
for (i = textNodes.length; i--;) {
|
12600
|
+
|
12601
|
+
if (findSimilarTextNodeWrapper(textNodes[i], options, composer.element)) {
|
12602
|
+
unformatTextNode(textNodes[i], composer, options);
|
12603
|
+
}
|
12604
|
+
|
12605
|
+
if (!findSimilarTextNodeWrapper(textNodes[i], options, composer.element)) {
|
12606
|
+
formatTextNode(textNodes[i], options);
|
12607
|
+
}
|
12608
|
+
}
|
11908
12609
|
|
11909
|
-
// Check whether the document contains a node with the desired tagName
|
11910
|
-
if (!wysihtml5.dom.hasElementWithTagName(doc, tagName) &&
|
11911
|
-
!wysihtml5.dom.hasElementWithTagName(doc, aliasTagName)) {
|
11912
|
-
return false;
|
11913
12610
|
}
|
11914
12611
|
|
11915
|
-
|
11916
|
-
|
11917
|
-
|
12612
|
+
cleanupAndSetSelection(composer, textNodes, options);
|
12613
|
+
}
|
12614
|
+
}
|
12615
|
+
|
12616
|
+
// Removes format from selection
|
12617
|
+
function removeFormat(composer, textNodes, state, options) {
|
12618
|
+
var textNode, textOffset, newNode, i,
|
12619
|
+
selection = composer.selection.getSelection();
|
12620
|
+
|
12621
|
+
if (!textNodes.length) {
|
12622
|
+
textNode = selection.anchorNode;
|
12623
|
+
textOffset = selection.anchorOffset;
|
12624
|
+
|
12625
|
+
for (i = state.nodes.length; i--;) {
|
12626
|
+
wysihtml5.dom.unwrap(state.nodes[i]);
|
11918
12627
|
}
|
11919
12628
|
|
11920
|
-
|
12629
|
+
cleanupAndSetCaret(composer, textNode, textOffset, options);
|
12630
|
+
} else {
|
12631
|
+
for (i = textNodes.length; i--;) {
|
12632
|
+
removeFormatFromTextNode(textNodes[i], composer, options);
|
12633
|
+
}
|
12634
|
+
cleanupAndSetSelection(composer, textNodes, options);
|
12635
|
+
}
|
12636
|
+
}
|
11921
12637
|
|
11922
|
-
|
11923
|
-
|
12638
|
+
// Adds format to selection
|
12639
|
+
function applyFormat(composer, textNodes, options) {
|
12640
|
+
var wordObj, i,
|
12641
|
+
selection = composer.selection.getSelection();
|
12642
|
+
|
12643
|
+
if (!textNodes.length) {
|
12644
|
+
// Handle collapsed selection caret and return
|
12645
|
+
if (caretIsInsideWord(selection)) {
|
12646
|
+
|
12647
|
+
wordObj = getRangeForWord(selection);
|
12648
|
+
formatTextNode(wordObj.textNode, options);
|
12649
|
+
cleanupAndSetCaret(composer, wordObj.textNode, wordObj.wordOffset, options);
|
12650
|
+
|
12651
|
+
} else {
|
12652
|
+
var r = composer.selection.getOwnRanges()[0];
|
12653
|
+
if (r) {
|
12654
|
+
formatTextRange(r, composer, options);
|
12655
|
+
}
|
12656
|
+
}
|
12657
|
+
|
12658
|
+
} else {
|
12659
|
+
// Handle textnodes in selection and apply format
|
12660
|
+
for (i = textNodes.length; i--;) {
|
12661
|
+
formatTextNode(textNodes[i], options);
|
11924
12662
|
}
|
12663
|
+
cleanupAndSetSelection(composer, textNodes, options);
|
12664
|
+
}
|
12665
|
+
}
|
12666
|
+
|
12667
|
+
// If properties is passed as a string, correct options with that nodeName
|
12668
|
+
function fixOptions(options) {
|
12669
|
+
options = (typeof options === "string") ? { nodeName: options } : options;
|
12670
|
+
if (options.nodeName) { options.nodeName = options.nodeName.toUpperCase(); }
|
12671
|
+
return options;
|
12672
|
+
}
|
12673
|
+
|
12674
|
+
wysihtml5.commands.formatInline = {
|
12675
|
+
|
12676
|
+
// Basics:
|
12677
|
+
// In case of plain text or inline state not set wrap all non-empty textnodes with
|
12678
|
+
// In case a similar inline wrapper node is detected on one of textnodes, the wrapper node is changed (if fully contained) or split and changed (partially contained)
|
12679
|
+
// In case of changing mode every textnode is addressed separatly
|
12680
|
+
exec: function(composer, command, options) {
|
12681
|
+
options = fixOptions(options);
|
12682
|
+
|
12683
|
+
// Join adjactent textnodes first
|
12684
|
+
composer.element.normalize();
|
12685
|
+
|
12686
|
+
var textNodes = getSelectedTextNodes(composer.selection, true),
|
12687
|
+
state = getState(composer, options);
|
12688
|
+
if (state.nodes.length > 0) {
|
12689
|
+
// Text allready has the format applied
|
12690
|
+
updateFormat(composer, textNodes, state, options);
|
12691
|
+
} else {
|
12692
|
+
// Selection is not in the applied format
|
12693
|
+
applyFormat(composer, textNodes, options);
|
12694
|
+
}
|
12695
|
+
composer.element.normalize();
|
12696
|
+
},
|
12697
|
+
|
12698
|
+
remove: function(composer, command, options) {
|
12699
|
+
options = fixOptions(options);
|
12700
|
+
composer.element.normalize();
|
11925
12701
|
|
11926
|
-
|
12702
|
+
var textNodes = getSelectedTextNodes(composer.selection, true),
|
12703
|
+
state = getState(composer, options);
|
11927
12704
|
|
11928
|
-
|
12705
|
+
if (state.nodes.length > 0) {
|
12706
|
+
// Text allready has the format applied
|
12707
|
+
removeFormat(composer, textNodes, state, options);
|
12708
|
+
}
|
12709
|
+
|
12710
|
+
composer.element.normalize();
|
12711
|
+
},
|
12712
|
+
|
12713
|
+
state: function(composer, command, options) {
|
12714
|
+
options = fixOptions(options);
|
12715
|
+
|
12716
|
+
var nodes = getState(composer, options, true).nodes;
|
12717
|
+
|
12718
|
+
return (nodes.length === 0) ? false : nodes;
|
11929
12719
|
}
|
11930
12720
|
};
|
12721
|
+
|
11931
12722
|
})(wysihtml5);
|
11932
12723
|
;(function(wysihtml5) {
|
11933
12724
|
|
@@ -12275,20 +13066,22 @@ wysihtml5.Commands = Base.extend(
|
|
12275
13066
|
|
12276
13067
|
})(wysihtml5);
|
12277
13068
|
;(function(wysihtml5){
|
13069
|
+
|
13070
|
+
var nodeOptions = {
|
13071
|
+
nodeName: "I",
|
13072
|
+
toggle: true
|
13073
|
+
};
|
13074
|
+
|
12278
13075
|
wysihtml5.commands.italic = {
|
12279
13076
|
exec: function(composer, command) {
|
12280
|
-
wysihtml5.commands.formatInline.
|
13077
|
+
wysihtml5.commands.formatInline.exec(composer, command, nodeOptions);
|
12281
13078
|
},
|
12282
13079
|
|
12283
13080
|
state: function(composer, command) {
|
12284
|
-
|
12285
|
-
// firefox: only <i>
|
12286
|
-
// chrome: <i>, <em>, <blockquote>, ...
|
12287
|
-
// ie: <i>, <em>
|
12288
|
-
// opera: only <i>
|
12289
|
-
return wysihtml5.commands.formatInline.state(composer, command, "i");
|
13081
|
+
return wysihtml5.commands.formatInline.state(composer, command, nodeOptions);
|
12290
13082
|
}
|
12291
13083
|
};
|
13084
|
+
|
12292
13085
|
}(wysihtml5));
|
12293
13086
|
;(function(wysihtml5) {
|
12294
13087
|
|
@@ -12431,15 +13224,22 @@ wysihtml5.Commands = Base.extend(
|
|
12431
13224
|
};
|
12432
13225
|
}(wysihtml5));
|
12433
13226
|
;(function(wysihtml5){
|
13227
|
+
|
13228
|
+
var nodeOptions = {
|
13229
|
+
nodeName: "U",
|
13230
|
+
toggle: true
|
13231
|
+
};
|
13232
|
+
|
12434
13233
|
wysihtml5.commands.underline = {
|
12435
13234
|
exec: function(composer, command) {
|
12436
|
-
wysihtml5.commands.formatInline.
|
13235
|
+
wysihtml5.commands.formatInline.exec(composer, command, nodeOptions);
|
12437
13236
|
},
|
12438
13237
|
|
12439
13238
|
state: function(composer, command) {
|
12440
|
-
return wysihtml5.commands.formatInline.state(composer, command,
|
13239
|
+
return wysihtml5.commands.formatInline.state(composer, command, nodeOptions);
|
12441
13240
|
}
|
12442
13241
|
};
|
13242
|
+
|
12443
13243
|
}(wysihtml5));
|
12444
13244
|
;(function(wysihtml5){
|
12445
13245
|
wysihtml5.commands.undo = {
|
@@ -12703,24 +13503,36 @@ wysihtml5.Commands = Base.extend(
|
|
12703
13503
|
};
|
12704
13504
|
}(wysihtml5));
|
12705
13505
|
;(function(wysihtml5){
|
13506
|
+
|
13507
|
+
var nodeOptions = {
|
13508
|
+
nodeName: "SUB",
|
13509
|
+
toggle: true
|
13510
|
+
};
|
13511
|
+
|
12706
13512
|
wysihtml5.commands.subscript = {
|
12707
13513
|
exec: function(composer, command) {
|
12708
|
-
wysihtml5.commands.formatInline.
|
13514
|
+
wysihtml5.commands.formatInline.exec(composer, command, nodeOptions);
|
12709
13515
|
},
|
12710
13516
|
|
12711
13517
|
state: function(composer, command) {
|
12712
|
-
return wysihtml5.commands.formatInline.state(composer, command,
|
13518
|
+
return wysihtml5.commands.formatInline.state(composer, command, nodeOptions);
|
12713
13519
|
}
|
12714
13520
|
};
|
12715
13521
|
}(wysihtml5));
|
12716
|
-
;(function(wysihtml5){
|
13522
|
+
;(function(wysihtml5) {
|
13523
|
+
|
13524
|
+
var nodeOptions = {
|
13525
|
+
nodeName: "SUP",
|
13526
|
+
toggle: true
|
13527
|
+
};
|
13528
|
+
|
12717
13529
|
wysihtml5.commands.superscript = {
|
12718
13530
|
exec: function(composer, command) {
|
12719
|
-
wysihtml5.commands.formatInline.
|
13531
|
+
wysihtml5.commands.formatInline.exec(composer, command, nodeOptions);
|
12720
13532
|
},
|
12721
13533
|
|
12722
13534
|
state: function(composer, command) {
|
12723
|
-
return wysihtml5.commands.formatInline.state(composer, command,
|
13535
|
+
return wysihtml5.commands.formatInline.state(composer, command, nodeOptions);
|
12724
13536
|
}
|
12725
13537
|
};
|
12726
13538
|
}(wysihtml5));
|