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