wysihtml-rails 0.5.0.beta11 → 0.5.0.beta12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/wysihtml/rails/version.rb +1 -1
- data/vendor/assets/javascripts/wysihtml-toolbar.js +550 -255
- data/vendor/assets/javascripts/wysihtml.js +421 -170
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64171b06f3c46b4089c9c548bb95a507de396ea4
|
4
|
+
data.tar.gz: 7559f9afd8744d42fc5d180e8df237055b35dd5d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c6f3f07ac3e718c699fd894e94812c6cc06da6f099c750bf4355d85f2c4e1b1c2484f035ffe663e11c7ddfb3c09fe0cbf78c60846dc34718f369535c7cc2de8
|
7
|
+
data.tar.gz: efecb729c9262b867e0dcc0b7aaa6b85f1470f0d51e145e03aa571d641df54f19f4b523d12fc6b4a5dfd644d2e585721476fc8ef3575778d0c412382bfbdb751
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license wysihtml v0.5.0-
|
2
|
+
* @license wysihtml v0.5.0-beta12
|
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-beta12",
|
14
14
|
|
15
15
|
// namespaces
|
16
16
|
commands: {},
|
@@ -5890,6 +5890,20 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
|
|
5890
5890
|
})(wysihtml5);
|
5891
5891
|
;// TODO: Refactor dom tree traversing here
|
5892
5892
|
(function(wysihtml5) {
|
5893
|
+
|
5894
|
+
// Finds parents of a node, returning the outermost node first in Array
|
5895
|
+
// if contain node is given parents search is stopped at the container
|
5896
|
+
function parents(node, container) {
|
5897
|
+
var nodes = [node], n = node;
|
5898
|
+
|
5899
|
+
// iterate parents while parent exists and it is not container element
|
5900
|
+
while((container && n && n !== container) || (!container && n)) {
|
5901
|
+
nodes.unshift(n);
|
5902
|
+
n = n.parentNode;
|
5903
|
+
}
|
5904
|
+
return nodes;
|
5905
|
+
}
|
5906
|
+
|
5893
5907
|
wysihtml5.dom.domNode = function(node) {
|
5894
5908
|
var defaultNodeTypes = [wysihtml5.ELEMENT_NODE, wysihtml5.TEXT_NODE];
|
5895
5909
|
|
@@ -5951,6 +5965,30 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
|
|
5951
5965
|
return nextNode;
|
5952
5966
|
},
|
5953
5967
|
|
5968
|
+
// Finds the common acnestor container of two nodes
|
5969
|
+
// If container given stops search at the container
|
5970
|
+
// If no common ancestor found returns null
|
5971
|
+
// var node = wysihtml5.dom.domNode(element).commonAncestor(node2, container);
|
5972
|
+
commonAncestor: function(node2, container) {
|
5973
|
+
var parents1 = parents(node, container),
|
5974
|
+
parents2 = parents(node2, container);
|
5975
|
+
|
5976
|
+
// Ensure we have found a common ancestor, which will be the first one if anything
|
5977
|
+
if (parents1[0] != parents2[0]) {
|
5978
|
+
return null;
|
5979
|
+
}
|
5980
|
+
|
5981
|
+
// Traverse up the hierarchy of parents until we reach where they're no longer
|
5982
|
+
// the same. Then return previous which was the common ancestor.
|
5983
|
+
for (var i = 0; i < parents1.length; i++) {
|
5984
|
+
if (parents1[i] != parents2[i]) {
|
5985
|
+
return parents1[i - 1];
|
5986
|
+
}
|
5987
|
+
}
|
5988
|
+
|
5989
|
+
return null;
|
5990
|
+
},
|
5991
|
+
|
5954
5992
|
// Traverses a node for last children and their chidren (including itself), and finds the last node that has no children.
|
5955
5993
|
// Array of classes for forced last-leaves (ex: uneditable-container) can be defined (options = {leafClasses: [...]})
|
5956
5994
|
// Useful for finding the actually visible element before cursor
|
@@ -7443,9 +7481,10 @@ wysihtml5.dom.removeEmptyTextNodes = function(node) {
|
|
7443
7481
|
childNodes = wysihtml5.lang.array(node.childNodes).get(),
|
7444
7482
|
childNodesLength = childNodes.length,
|
7445
7483
|
i = 0;
|
7484
|
+
|
7446
7485
|
for (; i<childNodesLength; i++) {
|
7447
7486
|
childNode = childNodes[i];
|
7448
|
-
if (childNode.nodeType === wysihtml5.TEXT_NODE && childNode.data
|
7487
|
+
if (childNode.nodeType === wysihtml5.TEXT_NODE && (/^[\n\r]*$/).test(childNode.data)) {
|
7449
7488
|
childNode.parentNode.removeChild(childNode);
|
7450
7489
|
}
|
7451
7490
|
}
|
@@ -7913,7 +7952,7 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
|
|
7913
7952
|
|
7914
7953
|
// initiates an allready existent contenteditable
|
7915
7954
|
_bindElement: function(contentEditable) {
|
7916
|
-
contentEditable.className =
|
7955
|
+
contentEditable.className = contentEditable.className ? contentEditable.className + " wysihtml5-sandbox" : "wysihtml5-sandbox";
|
7917
7956
|
this._loadElement(contentEditable, true);
|
7918
7957
|
return contentEditable;
|
7919
7958
|
},
|
@@ -9430,71 +9469,140 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
9430
9469
|
|
9431
9470
|
};
|
9432
9471
|
;(function(wysihtml5) {
|
9433
|
-
|
9434
|
-
|
9435
|
-
|
9436
|
-
|
9472
|
+
|
9473
|
+
// List of supported color format parsing methods
|
9474
|
+
// If radix is not defined 10 is expected as default
|
9475
|
+
var colorParseMethods = {
|
9476
|
+
rgba : {
|
9477
|
+
regex: /^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*([\d\.]+)\s*\)/i,
|
9478
|
+
name: "rgba"
|
9479
|
+
},
|
9480
|
+
rgb : {
|
9481
|
+
regex: /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/i,
|
9482
|
+
name: "rgb"
|
9483
|
+
},
|
9484
|
+
hex6 : {
|
9485
|
+
regex: /^#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])/i,
|
9486
|
+
name: "hex",
|
9487
|
+
radix: 16
|
9488
|
+
},
|
9489
|
+
hex3 : {
|
9490
|
+
regex: /^#([0-9a-f])([0-9a-f])([0-9a-f])/i,
|
9491
|
+
name: "hex",
|
9492
|
+
radix: 16
|
9493
|
+
}
|
9494
|
+
},
|
9495
|
+
// Takes a style key name as an argument and makes a regex that can be used to the match key:value pair from style string
|
9496
|
+
makeParamRegExp = function (p) {
|
9497
|
+
return new RegExp("(^|\\s|;)" + p + "\\s*:\\s*[^;$]+", "gi");
|
9498
|
+
};
|
9437
9499
|
|
9438
|
-
|
9439
|
-
|
9440
|
-
|
9500
|
+
// Takes color string value ("#abc", "rgb(1,2,3)", ...) as an argument and returns suitable parsing method for it
|
9501
|
+
function getColorParseMethod (colorStr) {
|
9502
|
+
var prop, colorTypeConf;
|
9503
|
+
|
9504
|
+
for (prop in colorParseMethods) {
|
9505
|
+
if (!colorParseMethods.hasOwnProperty(prop)) { continue; }
|
9506
|
+
|
9507
|
+
colorTypeConf = colorParseMethods[prop];
|
9508
|
+
|
9509
|
+
if (colorTypeConf.regex.test(colorStr)) {
|
9510
|
+
return colorTypeConf;
|
9511
|
+
}
|
9512
|
+
}
|
9513
|
+
}
|
9514
|
+
|
9515
|
+
// Takes color string value ("#abc", "rgb(1,2,3)", ...) as an argument and returns the type of that color format "hex", "rgb", "rgba".
|
9516
|
+
function getColorFormat (colorStr) {
|
9517
|
+
var type = getColorParseMethod(colorStr);
|
9441
9518
|
|
9519
|
+
return type ? type.name : undefined;
|
9520
|
+
}
|
9521
|
+
|
9522
|
+
// Public API functions for styleParser
|
9442
9523
|
wysihtml5.quirks.styleParser = {
|
9443
9524
|
|
9444
|
-
|
9445
|
-
|
9446
|
-
params = stylesStr.match(paramRegex),
|
9447
|
-
radix = 10,
|
9448
|
-
str, colorMatch;
|
9525
|
+
// Takes color string value as an argument and returns suitable parsing method for it
|
9526
|
+
getColorParseMethod : getColorParseMethod,
|
9449
9527
|
|
9450
|
-
|
9451
|
-
|
9452
|
-
|
9453
|
-
|
9454
|
-
|
9455
|
-
|
9456
|
-
|
9457
|
-
|
9458
|
-
|
9459
|
-
|
9460
|
-
|
9461
|
-
|
9462
|
-
|
9463
|
-
|
9464
|
-
|
9465
|
-
|
9466
|
-
|
9467
|
-
|
9468
|
-
return (idx < 3) ? (parseInt(d, 16) * 16) + parseInt(d, 16): parseFloat(d);
|
9469
|
-
});
|
9470
|
-
}
|
9528
|
+
// Takes color string value as an argument and returns the type of that color format "hex", "rgb", "rgba".
|
9529
|
+
getColorFormat : getColorFormat,
|
9530
|
+
|
9531
|
+
/* Parses a color string to and array of [red, green, blue, alpha].
|
9532
|
+
* paramName: optional argument to parse color value directly from style string parameter
|
9533
|
+
*
|
9534
|
+
* Examples:
|
9535
|
+
* var colorArray = wysihtml5.quirks.styleParser.parseColor("#ABC"); // [170, 187, 204, 1]
|
9536
|
+
* var colorArray = wysihtml5.quirks.styleParser.parseColor("#AABBCC"); // [170, 187, 204, 1]
|
9537
|
+
* var colorArray = wysihtml5.quirks.styleParser.parseColor("rgb(1,2,3)"); // [1, 2, 3, 1]
|
9538
|
+
* var colorArray = wysihtml5.quirks.styleParser.parseColor("rgba(1,2,3,0.5)"); // [1, 2, 3, 0.5]
|
9539
|
+
*
|
9540
|
+
* var colorArray = wysihtml5.quirks.styleParser.parseColor("background-color: #ABC; color: #000;", "background-color"); // [170, 187, 204, 1]
|
9541
|
+
* var colorArray = wysihtml5.quirks.styleParser.parseColor("background-color: #ABC; color: #000;", "color"); // [0, 0, 0, 1]
|
9542
|
+
*/
|
9543
|
+
parseColor : function (stylesStr, paramName) {
|
9544
|
+
var paramsRegex, params, colorType, colorMatch, radix,
|
9545
|
+
colorStr = stylesStr;
|
9471
9546
|
|
9472
|
-
|
9473
|
-
|
9474
|
-
|
9475
|
-
|
9476
|
-
|
9477
|
-
|
9478
|
-
|
9479
|
-
});
|
9480
|
-
}
|
9547
|
+
if (paramName) {
|
9548
|
+
paramsRegex = makeParamRegExp(paramName);
|
9549
|
+
|
9550
|
+
if (!(params = stylesStr.match(paramsRegex))) { return false; }
|
9551
|
+
|
9552
|
+
params = params.pop().split(":")[1];
|
9553
|
+
colorStr = wysihtml5.lang.string(params).trim();
|
9481
9554
|
}
|
9482
|
-
|
9555
|
+
|
9556
|
+
if (!(colorType = getColorParseMethod(colorStr))) { return false; }
|
9557
|
+
if (!(colorMatch = colorStr.match(colorType.regex))) { return false; }
|
9558
|
+
|
9559
|
+
radix = colorType.radix || 10;
|
9560
|
+
|
9561
|
+
if (colorType === colorParseMethods.hex3) {
|
9562
|
+
colorMatch.shift();
|
9563
|
+
colorMatch.push(1);
|
9564
|
+
return wysihtml5.lang.array(colorMatch).map(function(d, idx) {
|
9565
|
+
return (idx < 3) ? (parseInt(d, radix) * radix) + parseInt(d, radix): parseFloat(d);
|
9566
|
+
});
|
9567
|
+
}
|
9568
|
+
|
9569
|
+
colorMatch.shift();
|
9570
|
+
|
9571
|
+
if (!colorMatch[3]) {
|
9572
|
+
colorMatch.push(1);
|
9573
|
+
}
|
9574
|
+
|
9575
|
+
return wysihtml5.lang.array(colorMatch).map(function(d, idx) {
|
9576
|
+
return (idx < 3) ? parseInt(d, radix): parseFloat(d);
|
9577
|
+
});
|
9483
9578
|
},
|
9484
9579
|
|
9485
|
-
|
9486
|
-
|
9487
|
-
|
9488
|
-
|
9489
|
-
|
9490
|
-
|
9491
|
-
|
9492
|
-
|
9493
|
-
|
9494
|
-
|
9495
|
-
|
9496
|
-
|
9497
|
-
|
9580
|
+
/* Takes rgba color array [r,g,b,a] as a value and formats it to color string with given format type
|
9581
|
+
* If no format is given, rgba/rgb is returned based on alpha value
|
9582
|
+
*
|
9583
|
+
* Example:
|
9584
|
+
* var colorStr = wysihtml5.quirks.styleParser.unparseColor([170, 187, 204, 1], "hash"); // "#AABBCC"
|
9585
|
+
* var colorStr = wysihtml5.quirks.styleParser.unparseColor([170, 187, 204, 1], "hex"); // "AABBCC"
|
9586
|
+
* var colorStr = wysihtml5.quirks.styleParser.unparseColor([170, 187, 204, 1], "csv"); // "170, 187, 204, 1"
|
9587
|
+
* var colorStr = wysihtml5.quirks.styleParser.unparseColor([170, 187, 204, 1], "rgba"); // "rgba(170,187,204,1)"
|
9588
|
+
* var colorStr = wysihtml5.quirks.styleParser.unparseColor([170, 187, 204, 1], "rgb"); // "rgb(170,187,204)"
|
9589
|
+
*
|
9590
|
+
* var colorStr = wysihtml5.quirks.styleParser.unparseColor([170, 187, 204, 0.5]); // "rgba(170,187,204,0.5)"
|
9591
|
+
* var colorStr = wysihtml5.quirks.styleParser.unparseColor([170, 187, 204, 1]); // "rgb(170,187,204)"
|
9592
|
+
*/
|
9593
|
+
unparseColor: function(val, colorFormat) {
|
9594
|
+
var hexRadix = 16;
|
9595
|
+
|
9596
|
+
if (colorFormat === "hex") {
|
9597
|
+
return (val[0].toString(hexRadix) + val[1].toString(hexRadix) + val[2].toString(hexRadix)).toUpperCase();
|
9598
|
+
} else if (colorFormat === "hash") {
|
9599
|
+
return "#" + (val[0].toString(hexRadix) + val[1].toString(hexRadix) + val[2].toString(hexRadix)).toUpperCase();
|
9600
|
+
} else if (colorFormat === "rgb") {
|
9601
|
+
return "rgb(" + val[0] + "," + val[1] + "," + val[2] + ")";
|
9602
|
+
} else if (colorFormat === "rgba") {
|
9603
|
+
return "rgba(" + val[0] + "," + val[1] + "," + val[2] + "," + val[3] + ")";
|
9604
|
+
} else if (colorFormat === "csv") {
|
9605
|
+
return val[0] + "," + val[1] + "," + val[2] + "," + val[3];
|
9498
9606
|
}
|
9499
9607
|
|
9500
9608
|
if (val[3] && val[3] !== 1) {
|
@@ -9504,10 +9612,11 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
9504
9612
|
}
|
9505
9613
|
},
|
9506
9614
|
|
9615
|
+
// Parses font size value from style string
|
9507
9616
|
parseFontSize: function(stylesStr) {
|
9508
|
-
var params = stylesStr.match(
|
9617
|
+
var params = stylesStr.match(makeParamRegExp("font-size"));
|
9509
9618
|
if (params) {
|
9510
|
-
return wysihtml5.lang.string(params[params.length - 1].split(
|
9619
|
+
return wysihtml5.lang.string(params[params.length - 1].split(":")[1]).trim();
|
9511
9620
|
}
|
9512
9621
|
return false;
|
9513
9622
|
}
|
@@ -9546,6 +9655,50 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
9546
9655
|
return ret;
|
9547
9656
|
}
|
9548
9657
|
|
9658
|
+
function getWebkitSelectionFixNode(container) {
|
9659
|
+
var blankNode = document.createElement('span');
|
9660
|
+
|
9661
|
+
var placeholderRemover = function(event) {
|
9662
|
+
// Self-destructs the caret and keeps the text inserted into it by user
|
9663
|
+
var lastChild;
|
9664
|
+
|
9665
|
+
container.removeEventListener('mouseup', placeholderRemover);
|
9666
|
+
container.removeEventListener('keydown', placeholderRemover);
|
9667
|
+
container.removeEventListener('touchstart', placeholderRemover);
|
9668
|
+
container.removeEventListener('focus', placeholderRemover);
|
9669
|
+
container.removeEventListener('blur', placeholderRemover);
|
9670
|
+
container.removeEventListener('paste', delayedPlaceholderRemover);
|
9671
|
+
container.removeEventListener('drop', delayedPlaceholderRemover);
|
9672
|
+
container.removeEventListener('beforepaste', delayedPlaceholderRemover);
|
9673
|
+
|
9674
|
+
if (blankNode && blankNode.parentNode) {
|
9675
|
+
blankNode.parentNode.removeChild(blankNode);
|
9676
|
+
}
|
9677
|
+
},
|
9678
|
+
delayedPlaceholderRemover = function (event) {
|
9679
|
+
if (blankNode && blankNode.parentNode) {
|
9680
|
+
setTimeout(placeholderRemover, 0);
|
9681
|
+
}
|
9682
|
+
};
|
9683
|
+
|
9684
|
+
blankNode.appendChild(document.createTextNode(wysihtml5.INVISIBLE_SPACE));
|
9685
|
+
blankNode.className = '_wysihtml5-temp-caret-fix';
|
9686
|
+
blankNode.style.display = 'block';
|
9687
|
+
blankNode.style.minWidth = '1px';
|
9688
|
+
blankNode.style.height = '0px';
|
9689
|
+
|
9690
|
+
container.addEventListener('mouseup', placeholderRemover);
|
9691
|
+
container.addEventListener('keydown', placeholderRemover);
|
9692
|
+
container.addEventListener('touchstart', placeholderRemover);
|
9693
|
+
container.addEventListener('focus', placeholderRemover);
|
9694
|
+
container.addEventListener('blur', placeholderRemover);
|
9695
|
+
container.addEventListener('paste', delayedPlaceholderRemover);
|
9696
|
+
container.addEventListener('drop', delayedPlaceholderRemover);
|
9697
|
+
container.addEventListener('beforepaste', delayedPlaceholderRemover);
|
9698
|
+
|
9699
|
+
return blankNode;
|
9700
|
+
}
|
9701
|
+
|
9549
9702
|
// Should fix the obtained ranges that cannot surrond contents normally to apply changes upon
|
9550
9703
|
// Being considerate to firefox that sets range start start out of span and end inside on doubleclick initiated selection
|
9551
9704
|
function expandRangeToSurround(range) {
|
@@ -10218,6 +10371,20 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
10218
10371
|
}
|
10219
10372
|
},
|
10220
10373
|
|
10374
|
+
canAppendChild: function (node) {
|
10375
|
+
var anchorNode, anchorNodeTagNameLower,
|
10376
|
+
voidElements = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"],
|
10377
|
+
range = this.getRange();
|
10378
|
+
|
10379
|
+
anchorNode = node || range.startContainer;
|
10380
|
+
|
10381
|
+
if (anchorNode) {
|
10382
|
+
anchorNodeTagNameLower = (anchorNode.tagName || anchorNode.nodeName).toLowerCase();
|
10383
|
+
}
|
10384
|
+
|
10385
|
+
return voidElements.indexOf(anchorNodeTagNameLower) === -1;
|
10386
|
+
},
|
10387
|
+
|
10221
10388
|
splitElementAtCaret: function (element, insertNode) {
|
10222
10389
|
var sel = this.getSelection(),
|
10223
10390
|
range, contentAfterRangeStart,
|
@@ -10598,6 +10765,52 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
10598
10765
|
return (selection && selection.anchorNode && selection.focusNode) ? selection : null;
|
10599
10766
|
},
|
10600
10767
|
|
10768
|
+
|
10769
|
+
|
10770
|
+
// Webkit has an ancient error of not selecting all contents when uneditable block element is first or last in editable area
|
10771
|
+
selectAll: function() {
|
10772
|
+
var range = this.createRange(),
|
10773
|
+
composer = this.composer,
|
10774
|
+
that = this,
|
10775
|
+
blankEndNode = getWebkitSelectionFixNode(this.composer.element),
|
10776
|
+
blankStartNode = getWebkitSelectionFixNode(this.composer.element),
|
10777
|
+
s;
|
10778
|
+
|
10779
|
+
var doSelect = function() {
|
10780
|
+
range.setStart(composer.element, 0);
|
10781
|
+
range.setEnd(composer.element, composer.element.childNodes.length);
|
10782
|
+
s = that.setSelection(range);
|
10783
|
+
};
|
10784
|
+
|
10785
|
+
var notSelected = function() {
|
10786
|
+
return !s || (s.nativeSelection && s.nativeSelection.type && (s.nativeSelection.type === "Caret" || s.nativeSelection.type === "None"));
|
10787
|
+
}
|
10788
|
+
|
10789
|
+
wysihtml5.dom.removeInvisibleSpaces(this.composer.element);
|
10790
|
+
doSelect();
|
10791
|
+
|
10792
|
+
if (this.composer.element.firstChild && notSelected()) {
|
10793
|
+
// Try fixing end
|
10794
|
+
this.composer.element.appendChild(blankEndNode);
|
10795
|
+
doSelect();
|
10796
|
+
|
10797
|
+
if (notSelected()) {
|
10798
|
+
// Remove end fix
|
10799
|
+
blankEndNode.parentNode.removeChild(blankEndNode);
|
10800
|
+
|
10801
|
+
// Try fixing beginning
|
10802
|
+
this.composer.element.insertBefore(blankStartNode, this.composer.element.firstChild);
|
10803
|
+
doSelect();
|
10804
|
+
|
10805
|
+
if (notSelected()) {
|
10806
|
+
// Try fixing both
|
10807
|
+
this.composer.element.appendChild(blankEndNode);
|
10808
|
+
doSelect();
|
10809
|
+
}
|
10810
|
+
}
|
10811
|
+
}
|
10812
|
+
},
|
10813
|
+
|
10601
10814
|
createRange: function() {
|
10602
10815
|
return rangy.createRange(this.doc);
|
10603
10816
|
},
|
@@ -10656,6 +10869,25 @@ wysihtml5.quirks.ensureProperClearing = (function() {
|
|
10656
10869
|
return (wysihtml5.lang.array(nodeNames).contains(parentElement.nodeName)) ? parentElement : false;
|
10657
10870
|
},
|
10658
10871
|
|
10872
|
+
isInThisEditable: function() {
|
10873
|
+
var sel = this.getSelection(),
|
10874
|
+
fnode = sel.focusNode,
|
10875
|
+
anode = sel.anchorNode;
|
10876
|
+
|
10877
|
+
// In IE node contains will not work for textnodes, thus taking parentNode
|
10878
|
+
if (fnode && fnode.nodeType !== 1) {
|
10879
|
+
fnode = fnode.parentNode;
|
10880
|
+
}
|
10881
|
+
|
10882
|
+
if (anode && anode.nodeType !== 1) {
|
10883
|
+
anode = anode.parentNode;
|
10884
|
+
}
|
10885
|
+
|
10886
|
+
return anode && fnode &&
|
10887
|
+
(wysihtml5.dom.contains(this.composer.element, fnode) || this.composer.element === fnode) &&
|
10888
|
+
(wysihtml5.dom.contains(this.composer.element, anode) || this.composer.element === anode);
|
10889
|
+
},
|
10890
|
+
|
10659
10891
|
deselect: function() {
|
10660
10892
|
var sel = this.getSelection();
|
10661
10893
|
sel && sel.removeAllRanges();
|
@@ -11509,12 +11741,12 @@ wysihtml5.Commands = Base.extend(
|
|
11509
11741
|
exec: function(composer, command, size) {
|
11510
11742
|
size = size.size || size;
|
11511
11743
|
if (!(/^\s*$/).test(size)) {
|
11512
|
-
wysihtml5.commands.formatInline.exec(composer, command, {styleProperty: "fontSize", styleValue: size, toggle:
|
11744
|
+
wysihtml5.commands.formatInline.exec(composer, command, {styleProperty: "fontSize", styleValue: size, toggle: false});
|
11513
11745
|
}
|
11514
11746
|
},
|
11515
11747
|
|
11516
11748
|
state: function(composer, command, size) {
|
11517
|
-
return wysihtml5.commands.formatInline.state(composer, command, {styleProperty: "fontSize", styleValue: size});
|
11749
|
+
return wysihtml5.commands.formatInline.state(composer, command, {styleProperty: "fontSize", styleValue: size || undefined});
|
11518
11750
|
},
|
11519
11751
|
|
11520
11752
|
remove: function(composer, command) {
|
@@ -11522,15 +11754,14 @@ wysihtml5.Commands = Base.extend(
|
|
11522
11754
|
},
|
11523
11755
|
|
11524
11756
|
stateValue: function(composer, command) {
|
11525
|
-
var
|
11526
|
-
|
11527
|
-
val = false;
|
11757
|
+
var styleStr,
|
11758
|
+
st = this.state(composer, command);
|
11528
11759
|
|
11529
11760
|
if (st && wysihtml5.lang.object(st).isArray()) {
|
11530
11761
|
st = st[0];
|
11531
11762
|
}
|
11532
11763
|
if (st) {
|
11533
|
-
styleStr = st.getAttribute(
|
11764
|
+
styleStr = st.getAttribute("style");
|
11534
11765
|
if (styleStr) {
|
11535
11766
|
return wysihtml5.quirks.styleParser.parseFontSize(styleStr);
|
11536
11767
|
}
|
@@ -11562,12 +11793,15 @@ wysihtml5.Commands = Base.extend(
|
|
11562
11793
|
|
11563
11794
|
wysihtml5.commands.foreColorStyle = {
|
11564
11795
|
exec: function(composer, command, color) {
|
11565
|
-
var colorVals
|
11566
|
-
|
11796
|
+
var colorVals, colString;
|
11797
|
+
|
11798
|
+
if (!color) { return; }
|
11799
|
+
|
11800
|
+
colorVals = wysihtml5.quirks.styleParser.parseColor("color:" + (color.color || color), "color");
|
11567
11801
|
|
11568
11802
|
if (colorVals) {
|
11569
|
-
colString = (colorVals[3] === 1 ? "rgb(" + [colorVals[0], colorVals[1], colorVals[2]].join(
|
11570
|
-
wysihtml5.commands.formatInline.exec(composer, command, {styleProperty:
|
11803
|
+
colString = (colorVals[3] === 1 ? "rgb(" + [colorVals[0], colorVals[1], colorVals[2]].join(", ") : "rgba(" + colorVals.join(', ')) + ')';
|
11804
|
+
wysihtml5.commands.formatInline.exec(composer, command, {styleProperty: "color", styleValue: colString});
|
11571
11805
|
}
|
11572
11806
|
},
|
11573
11807
|
|
@@ -11577,14 +11811,14 @@ wysihtml5.Commands = Base.extend(
|
|
11577
11811
|
|
11578
11812
|
|
11579
11813
|
if (colorVals) {
|
11580
|
-
colString = (colorVals[3] === 1 ? "rgb(" + [colorVals[0], colorVals[1], colorVals[2]].join(
|
11814
|
+
colString = (colorVals[3] === 1 ? "rgb(" + [colorVals[0], colorVals[1], colorVals[2]].join(", ") : "rgba(" + colorVals.join(', ')) + ')';
|
11581
11815
|
}
|
11582
11816
|
|
11583
|
-
return wysihtml5.commands.formatInline.state(composer, command, {styleProperty:
|
11817
|
+
return wysihtml5.commands.formatInline.state(composer, command, {styleProperty: "color", styleValue: colString});
|
11584
11818
|
},
|
11585
11819
|
|
11586
11820
|
remove: function(composer, command) {
|
11587
|
-
return wysihtml5.commands.formatInline.remove(composer, command, {styleProperty:
|
11821
|
+
return wysihtml5.commands.formatInline.remove(composer, command, {styleProperty: "color"});
|
11588
11822
|
},
|
11589
11823
|
|
11590
11824
|
stateValue: function(composer, command, props) {
|
@@ -11597,7 +11831,7 @@ wysihtml5.Commands = Base.extend(
|
|
11597
11831
|
}
|
11598
11832
|
|
11599
11833
|
if (st) {
|
11600
|
-
colorStr = st.getAttribute(
|
11834
|
+
colorStr = st.getAttribute("style");
|
11601
11835
|
if (colorStr) {
|
11602
11836
|
val = wysihtml5.quirks.styleParser.parseColor(colorStr, "color");
|
11603
11837
|
return wysihtml5.quirks.styleParser.unparseColor(val, props);
|
@@ -11675,6 +11909,14 @@ wysihtml5.Commands = Base.extend(
|
|
11675
11909
|
BLOCK_ELEMENTS = "h1, h2, h3, h4, h5, h6, p, pre, div, blockquote",
|
11676
11910
|
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, u";
|
11677
11911
|
|
11912
|
+
function correctOptionsForSimilarityCheck(options) {
|
11913
|
+
return {
|
11914
|
+
nodeName: options.nodeName || null,
|
11915
|
+
className: (!options.classRegExp) ? options.className || null : null,
|
11916
|
+
classRegExp: options.classRegExp || null,
|
11917
|
+
styleProperty: options.styleProperty || null
|
11918
|
+
};
|
11919
|
+
}
|
11678
11920
|
|
11679
11921
|
// Removes empty block level elements
|
11680
11922
|
function cleanup(composer) {
|
@@ -11684,7 +11926,7 @@ wysihtml5.Commands = Base.extend(
|
|
11684
11926
|
elements = wysihtml5.lang.array(allElements).without(uneditables);
|
11685
11927
|
|
11686
11928
|
for (var i = elements.length; i--;) {
|
11687
|
-
if (elements[i].innerHTML === "") {
|
11929
|
+
if (elements[i].innerHTML.replace(/[\uFEFF]/g, '') === "") {
|
11688
11930
|
elements[i].parentNode.removeChild(elements[i]);
|
11689
11931
|
}
|
11690
11932
|
}
|
@@ -11811,7 +12053,7 @@ wysihtml5.Commands = Base.extend(
|
|
11811
12053
|
|
11812
12054
|
for (var i = contentBlocks.length; i--;) {
|
11813
12055
|
if (!contentBlocks[i].nextSibling || contentBlocks[i].nextSibling.nodeType !== 1 || contentBlocks[i].nextSibling.nodeName !== 'BR') {
|
11814
|
-
if ((contentBlocks[i].innerHTML || contentBlocks[i].nodeValue).trim() !==
|
12056
|
+
if ((contentBlocks[i].innerHTML || contentBlocks[i].nodeValue || '').trim() !== '') {
|
11815
12057
|
contentBlocks[i].parentNode.insertBefore(contentBlocks[i].ownerDocument.createElement('BR'), contentBlocks[i].nextSibling);
|
11816
12058
|
}
|
11817
12059
|
}
|
@@ -11877,8 +12119,10 @@ wysihtml5.Commands = Base.extend(
|
|
11877
12119
|
rangeStartContainer = r.startContainer,
|
11878
12120
|
content = r.extractContents(),
|
11879
12121
|
fragment = composer.doc.createDocumentFragment(),
|
12122
|
+
similarOptions = defaultOptions ? correctOptionsForSimilarityCheck(defaultOptions) : null,
|
12123
|
+
similarOuterBlock = similarOptions ? wysihtml5.dom.getParentElement(rangeStartContainer, similarOptions, null, composer.element) : null,
|
11880
12124
|
splitAllBlocks = !defaultOptions || (defaultName === "BLOCKQUOTE" && defaultOptions.nodeName && defaultOptions.nodeName === "BLOCKQUOTE"),
|
11881
|
-
firstOuterBlock = findOuterBlock(rangeStartContainer, composer.element, splitAllBlocks), // The outermost un-nestable block element parent of selection start
|
12125
|
+
firstOuterBlock = similarOuterBlock || findOuterBlock(rangeStartContainer, composer.element, splitAllBlocks), // The outermost un-nestable block element parent of selection start
|
11882
12126
|
wrapper, blocks, children;
|
11883
12127
|
|
11884
12128
|
if (options && options.nodeName && options.nodeName === "BLOCKQUOTE") {
|
@@ -12003,7 +12247,7 @@ wysihtml5.Commands = Base.extend(
|
|
12003
12247
|
|
12004
12248
|
if (composer.selection.isCollapsed()) {
|
12005
12249
|
parent = wysihtml5.dom.getParentElement(composer.selection.getOwnRanges()[0].startContainer, {
|
12006
|
-
query:
|
12250
|
+
query: UNNESTABLE_BLOCK_ELEMENTS + ', ' + (options && options.nodeName ? options.nodeName.toLowerCase() : 'div'),
|
12007
12251
|
}, null, composer.element);
|
12008
12252
|
if (parent) {
|
12009
12253
|
bookmark = rangy.saveSelection(composer.win);
|
@@ -12016,7 +12260,7 @@ wysihtml5.Commands = Base.extend(
|
|
12016
12260
|
}
|
12017
12261
|
}
|
12018
12262
|
|
12019
|
-
// And get all selection ranges of current composer and
|
12263
|
+
// And get all selection ranges of current composer and iterate
|
12020
12264
|
ranges = composer.selection.getOwnRanges();
|
12021
12265
|
for (var i = ranges.length; i--;) {
|
12022
12266
|
newBlockElements = newBlockElements.concat(wrapRangeWithElement(ranges[i], options, getParentBlockNodeName(ranges[i].startContainer, composer), composer));
|
@@ -12026,6 +12270,13 @@ wysihtml5.Commands = Base.extend(
|
|
12026
12270
|
|
12027
12271
|
// Remove empty block elements that may be left behind
|
12028
12272
|
cleanup(composer);
|
12273
|
+
// If cleanup removed some new block elements. remove them from array too
|
12274
|
+
for (var e = newBlockElements.length; e--;) {
|
12275
|
+
if (!newBlockElements[e].parentNode) {
|
12276
|
+
newBlockElements.splice(e, 1);
|
12277
|
+
}
|
12278
|
+
}
|
12279
|
+
|
12029
12280
|
// Restore correct selection
|
12030
12281
|
if (bookmark) {
|
12031
12282
|
rangy.restoreSelection(bookmark);
|
@@ -12081,8 +12332,9 @@ wysihtml5.Commands = Base.extend(
|
|
12081
12332
|
wysihtml5.commands.formatCode = {
|
12082
12333
|
|
12083
12334
|
exec: function(composer, command, classname) {
|
12084
|
-
var pre = this.state(composer),
|
12335
|
+
var pre = this.state(composer)[0],
|
12085
12336
|
code, range, selectedNodes;
|
12337
|
+
|
12086
12338
|
if (pre) {
|
12087
12339
|
// caret is already within a <pre><code>...</code></pre>
|
12088
12340
|
composer.selection.executeAndRestore(function() {
|
@@ -12111,12 +12363,13 @@ wysihtml5.Commands = Base.extend(
|
|
12111
12363
|
},
|
12112
12364
|
|
12113
12365
|
state: function(composer) {
|
12114
|
-
var selectedNode = composer.selection.getSelectedNode();
|
12366
|
+
var selectedNode = composer.selection.getSelectedNode(), node;
|
12115
12367
|
if (selectedNode && selectedNode.nodeName && selectedNode.nodeName == "PRE"&&
|
12116
12368
|
selectedNode.firstChild && selectedNode.firstChild.nodeName && selectedNode.firstChild.nodeName == "CODE") {
|
12117
|
-
return selectedNode;
|
12369
|
+
return [selectedNode];
|
12118
12370
|
} else {
|
12119
|
-
|
12371
|
+
node = wysihtml5.dom.getParentElement(selectedNode, { query: "pre code" });
|
12372
|
+
return node ? [node.parentNode] : false;
|
12120
12373
|
}
|
12121
12374
|
}
|
12122
12375
|
};
|
@@ -12260,9 +12513,7 @@ wysihtml5.Commands = Base.extend(
|
|
12260
12513
|
}
|
12261
12514
|
|
12262
12515
|
function updateFormatOfElement(element, options) {
|
12263
|
-
var attr, newNode, a, newAttributes, nodeNameQuery;
|
12264
|
-
|
12265
|
-
|
12516
|
+
var attr, newNode, a, newAttributes, nodeNameQuery, nodeQueryMatch;
|
12266
12517
|
|
12267
12518
|
if (options.className) {
|
12268
12519
|
if (options.toggle !== false && element.classList.contains(options.className)) {
|
@@ -12297,30 +12548,19 @@ wysihtml5.Commands = Base.extend(
|
|
12297
12548
|
updateElementAttributes(element, newAttributes, options.toggle);
|
12298
12549
|
}
|
12299
12550
|
|
12300
|
-
|
12551
|
+
|
12552
|
+
// Handle similar semantically same elements (queryAliasMap)
|
12301
12553
|
nodeNameQuery = options.nodeName ? queryAliasMap[options.nodeName.toLowerCase()] || options.nodeName.toLowerCase() : null;
|
12554
|
+
nodeQueryMatch = nodeNameQuery ? wysihtml5.dom.domNode(element).test({ query: nodeNameQuery }) : false;
|
12302
12555
|
|
12303
|
-
|
12304
|
-
|
12305
|
-
|
12306
|
-
if (
|
12556
|
+
// Unwrap element if no attributes present and node name given
|
12557
|
+
// or no attributes and if no nodename set but node is the default
|
12558
|
+
if (!options.nodeName || options.nodeName === defaultTag || nodeQueryMatch) {
|
12559
|
+
if (
|
12560
|
+
((options.toggle !== false && nodeQueryMatch) || (!options.nodeName && element.nodeName === defaultTag)) &&
|
12561
|
+
hasNoClass(element) && hasNoStyle(element) && hasNoAttributes(element)
|
12562
|
+
) {
|
12307
12563
|
wysihtml5.dom.unwrap(element);
|
12308
|
-
} else if (!options.nodeName) {
|
12309
|
-
newNode = element.ownerDocument.createElement(defaultTag);
|
12310
|
-
|
12311
|
-
// pass present attributes
|
12312
|
-
attr = wysihtml5.dom.getAttributes(element);
|
12313
|
-
for (a in attr) {
|
12314
|
-
if (attr.hasOwnProperty(a)) {
|
12315
|
-
newNode.setAttribute(a, attr[a]);
|
12316
|
-
}
|
12317
|
-
}
|
12318
|
-
|
12319
|
-
while (element.firstChild) {
|
12320
|
-
newNode.appendChild(element.firstChild);
|
12321
|
-
}
|
12322
|
-
element.parentNode.insertBefore(newNode, element);
|
12323
|
-
element.parentNode.removeChild(element);
|
12324
12564
|
}
|
12325
12565
|
|
12326
12566
|
}
|
@@ -12425,35 +12665,39 @@ wysihtml5.Commands = Base.extend(
|
|
12425
12665
|
partial = false,
|
12426
12666
|
node, range, caretNode;
|
12427
12667
|
|
12428
|
-
if (
|
12429
|
-
|
12430
|
-
if (
|
12431
|
-
|
12432
|
-
|
12433
|
-
|
12434
|
-
|
12435
|
-
|
12436
|
-
|
12437
|
-
|
12438
|
-
|
12668
|
+
if (composer.selection.isInThisEditable()) {
|
12669
|
+
|
12670
|
+
if (searchNodes.length === 0 && composer.selection.isCollapsed()) {
|
12671
|
+
caretNode = composer.selection.getSelection().anchorNode;
|
12672
|
+
if (!caretNode) {
|
12673
|
+
// selection not in editor
|
12674
|
+
return {
|
12675
|
+
nodes: [],
|
12676
|
+
partial: false
|
12677
|
+
};
|
12678
|
+
}
|
12679
|
+
if (caretNode.nodeType === 3) {
|
12680
|
+
searchNodes = [caretNode];
|
12681
|
+
}
|
12439
12682
|
}
|
12440
|
-
}
|
12441
12683
|
|
12442
|
-
|
12443
|
-
|
12444
|
-
|
12445
|
-
|
12446
|
-
|
12684
|
+
// Handle collapsed selection caret
|
12685
|
+
if (!searchNodes.length) {
|
12686
|
+
range = composer.selection.getOwnRanges()[0];
|
12687
|
+
if (range) {
|
12688
|
+
searchNodes = [range.endContainer];
|
12689
|
+
}
|
12447
12690
|
}
|
12448
|
-
}
|
12449
12691
|
|
12450
|
-
|
12451
|
-
|
12452
|
-
|
12453
|
-
|
12454
|
-
|
12455
|
-
|
12692
|
+
for (var i = 0, maxi = searchNodes.length; i < maxi; i++) {
|
12693
|
+
node = findSimilarTextNodeWrapper(searchNodes[i], options, composer.element, exact);
|
12694
|
+
if (node) {
|
12695
|
+
nodes.push(node);
|
12696
|
+
} else {
|
12697
|
+
partial = true;
|
12698
|
+
}
|
12456
12699
|
}
|
12700
|
+
|
12457
12701
|
}
|
12458
12702
|
|
12459
12703
|
return {
|
@@ -12774,9 +13018,7 @@ wysihtml5.Commands = Base.extend(
|
|
12774
13018
|
|
12775
13019
|
state: function(composer, command, options) {
|
12776
13020
|
options = fixOptions(options);
|
12777
|
-
|
12778
13021
|
var nodes = getState(composer, options, true).nodes;
|
12779
|
-
|
12780
13022
|
return (nodes.length === 0) ? false : nodes;
|
12781
13023
|
}
|
12782
13024
|
};
|
@@ -14635,14 +14877,14 @@ wysihtml5.views.View = Base.extend(
|
|
14635
14877
|
// Deletion with caret in the beginning of headings needs special attention
|
14636
14878
|
// Heading does not concate text to previous block node correctly (browsers do unexpected miracles here especially webkit)
|
14637
14879
|
var fixDeleteInTheBeginnigOfHeading = function(composer) {
|
14638
|
-
var selection = composer.selection
|
14880
|
+
var selection = composer.selection,
|
14881
|
+
prevNode = selection.getPreviousNode();
|
14639
14882
|
|
14640
14883
|
if (selection.caretIsFirstInSelection() &&
|
14641
|
-
|
14642
|
-
|
14643
|
-
(
|
14884
|
+
prevNode &&
|
14885
|
+
prevNode.nodeType === 1 &&
|
14886
|
+
(/block/).test(composer.win.getComputedStyle(prevNode).display)
|
14644
14887
|
) {
|
14645
|
-
var prevNode = selection.getPreviousNode();
|
14646
14888
|
if ((/^\s*$/).test(prevNode.textContent || prevNode.innerText)) {
|
14647
14889
|
// If heading is empty remove the heading node
|
14648
14890
|
prevNode.parentNode.removeChild(prevNode);
|
@@ -14650,20 +14892,23 @@ wysihtml5.views.View = Base.extend(
|
|
14650
14892
|
} else {
|
14651
14893
|
if (prevNode.lastChild) {
|
14652
14894
|
var selNode = prevNode.lastChild,
|
14653
|
-
|
14654
|
-
|
14895
|
+
selectedNode = selection.getSelectedNode(),
|
14896
|
+
commonAncestorNode = wysihtml5.dom.domNode(prevNode).commonAncestor(selectedNode, composer.element);
|
14897
|
+
curNode = commonAncestorNode ? wysihtml5.dom.getParentElement(selectedNode, {
|
14898
|
+
query: "h1, h2, h3, h4, h5, h6, p, pre, div, blockquote"
|
14899
|
+
}, false, commonAncestorNode) : null;
|
14900
|
+
|
14655
14901
|
if (curNode) {
|
14656
14902
|
while (curNode.firstChild) {
|
14657
14903
|
prevNode.appendChild(curNode.firstChild);
|
14658
14904
|
}
|
14659
14905
|
selection.setAfter(selNode);
|
14660
14906
|
return true;
|
14661
|
-
} else if (
|
14662
|
-
prevNode.appendChild(
|
14907
|
+
} else if (selectedNode.nodeType === 3) {
|
14908
|
+
prevNode.appendChild(selectedNode);
|
14663
14909
|
selection.setAfter(selNode);
|
14664
14910
|
return true;
|
14665
14911
|
}
|
14666
|
-
}
|
14667
14912
|
}
|
14668
14913
|
}
|
14669
14914
|
}
|
@@ -14675,23 +14920,17 @@ wysihtml5.views.View = Base.extend(
|
|
14675
14920
|
element = composer.element;
|
14676
14921
|
|
14677
14922
|
if (selection.isCollapsed()) {
|
14678
|
-
if (
|
14679
|
-
// delete in the beginnig of LI will outdent not delete
|
14923
|
+
if (fixDeleteInTheBeginnigOfHeading(composer)) {
|
14680
14924
|
event.preventDefault();
|
14681
|
-
|
14682
|
-
}
|
14683
|
-
|
14684
|
-
|
14685
|
-
|
14686
|
-
|
14687
|
-
|
14688
|
-
|
14689
|
-
|
14690
|
-
}
|
14691
|
-
if (handleUneditableDeletion(composer)) {
|
14692
|
-
event.preventDefault();
|
14693
|
-
return;
|
14694
|
-
}
|
14925
|
+
return;
|
14926
|
+
}
|
14927
|
+
if (fixLastBrDeletionInTable(composer)) {
|
14928
|
+
event.preventDefault();
|
14929
|
+
return;
|
14930
|
+
}
|
14931
|
+
if (handleUneditableDeletion(composer)) {
|
14932
|
+
event.preventDefault();
|
14933
|
+
return;
|
14695
14934
|
}
|
14696
14935
|
} else {
|
14697
14936
|
if (selection.containsUneditable()) {
|
@@ -14701,11 +14940,15 @@ wysihtml5.views.View = Base.extend(
|
|
14701
14940
|
}
|
14702
14941
|
};
|
14703
14942
|
|
14704
|
-
var handleTabKeyDown = function(composer, element) {
|
14943
|
+
var handleTabKeyDown = function(composer, element, shiftKey) {
|
14705
14944
|
if (!composer.selection.isCollapsed()) {
|
14706
14945
|
composer.selection.deleteContents();
|
14707
14946
|
} else if (composer.selection.caretIsInTheBeginnig('li')) {
|
14708
|
-
if (
|
14947
|
+
if (shiftKey) {
|
14948
|
+
if (composer.commands.exec('outdentList')) return;
|
14949
|
+
} else {
|
14950
|
+
if (composer.commands.exec('indentList')) return;
|
14951
|
+
}
|
14709
14952
|
}
|
14710
14953
|
|
14711
14954
|
// Is   close enough to tab. Could not find enough counter arguments for now.
|
@@ -14721,9 +14964,9 @@ wysihtml5.views.View = Base.extend(
|
|
14721
14964
|
|
14722
14965
|
// Listens to "drop", "paste", "mouseup", "focus", "keyup" events and fires
|
14723
14966
|
var handleUserInteraction = function (event) {
|
14724
|
-
this.parent.fire("beforeinteraction").fire("beforeinteraction:composer");
|
14967
|
+
this.parent.fire("beforeinteraction", event).fire("beforeinteraction:composer", event);
|
14725
14968
|
setTimeout((function() {
|
14726
|
-
this.parent.fire("interaction").fire("interaction:composer");
|
14969
|
+
this.parent.fire("interaction", event).fire("interaction:composer", event);
|
14727
14970
|
}).bind(this), 0);
|
14728
14971
|
};
|
14729
14972
|
|
@@ -14837,6 +15080,13 @@ wysihtml5.views.View = Base.extend(
|
|
14837
15080
|
command = shortcuts[keyCode],
|
14838
15081
|
target, parent;
|
14839
15082
|
|
15083
|
+
// Select all (meta/ctrl + a)
|
15084
|
+
if ((event.ctrlKey || event.metaKey) && keyCode === 65) {
|
15085
|
+
this.selection.selectAll();
|
15086
|
+
event.preventDefault();
|
15087
|
+
return;
|
15088
|
+
}
|
15089
|
+
|
14840
15090
|
// Shortcut logic
|
14841
15091
|
if ((event.ctrlKey || event.metaKey) && !event.altKey && command) {
|
14842
15092
|
this.commands.exec(command);
|
@@ -14859,16 +15109,16 @@ wysihtml5.views.View = Base.extend(
|
|
14859
15109
|
if (parent.nodeName === "A" && !parent.firstChild) {
|
14860
15110
|
parent.parentNode.removeChild(parent);
|
14861
15111
|
}
|
14862
|
-
setTimeout(function() {
|
15112
|
+
setTimeout((function() {
|
14863
15113
|
wysihtml5.quirks.redraw(this.element);
|
14864
|
-
}, 0);
|
15114
|
+
}).bind(this), 0);
|
14865
15115
|
}
|
14866
15116
|
}
|
14867
15117
|
|
14868
15118
|
if (this.config.handleTabKey && keyCode === wysihtml5.TAB_KEY) {
|
14869
15119
|
// TAB key handling
|
14870
15120
|
event.preventDefault();
|
14871
|
-
handleTabKeyDown(this, this.element);
|
15121
|
+
handleTabKeyDown(this, this.element, event.shiftKey);
|
14872
15122
|
}
|
14873
15123
|
|
14874
15124
|
};
|
@@ -15227,6 +15477,8 @@ wysihtml5.views.View = Base.extend(
|
|
15227
15477
|
// Whether toolbar is displayed after init by script automatically.
|
15228
15478
|
// Can be set to false if toolobar is set to display only on editable area focus
|
15229
15479
|
showToolbarAfterInit: true,
|
15480
|
+
// With default toolbar it shows dialogs in toolbar when their related text format state becomes active (click on link in text opens link dialogue)
|
15481
|
+
showToolbarDialogsOnSelection: true,
|
15230
15482
|
// Whether urls, entered by the user should automatically become clickable-links
|
15231
15483
|
autoLink: true,
|
15232
15484
|
// Includes table editing events and cell selection tracking
|
@@ -15400,8 +15652,7 @@ wysihtml5.views.View = Base.extend(
|
|
15400
15652
|
* - Observes for paste and drop
|
15401
15653
|
*/
|
15402
15654
|
_initParser: function() {
|
15403
|
-
var oldHtml
|
15404
|
-
cleanHtml;
|
15655
|
+
var oldHtml;
|
15405
15656
|
|
15406
15657
|
if (wysihtml5.browser.supportsModernPaste()) {
|
15407
15658
|
this.on("paste:composer", function(event) {
|
@@ -15510,28 +15761,18 @@ wysihtml5.views.View = Base.extend(
|
|
15510
15761
|
callbackWrapper(event);
|
15511
15762
|
}
|
15512
15763
|
if (keyCode === wysihtml5.ESCAPE_KEY) {
|
15513
|
-
that.
|
15514
|
-
that.hide();
|
15764
|
+
that.cancel();
|
15515
15765
|
}
|
15516
15766
|
});
|
15517
15767
|
|
15518
15768
|
dom.delegate(this.container, "[data-wysihtml5-dialog-action=save]", "click", callbackWrapper);
|
15519
15769
|
|
15520
15770
|
dom.delegate(this.container, "[data-wysihtml5-dialog-action=cancel]", "click", function(event) {
|
15521
|
-
that.
|
15522
|
-
that.hide();
|
15771
|
+
that.cancel();
|
15523
15772
|
event.preventDefault();
|
15524
15773
|
event.stopPropagation();
|
15525
15774
|
});
|
15526
15775
|
|
15527
|
-
var formElements = this.container.querySelectorAll(SELECTOR_FORM_ELEMENTS),
|
15528
|
-
i = 0,
|
15529
|
-
length = formElements.length,
|
15530
|
-
_clearInterval = function() { clearInterval(that.interval); };
|
15531
|
-
for (; i<length; i++) {
|
15532
|
-
dom.observe(formElements[i], "change", _clearInterval);
|
15533
|
-
}
|
15534
|
-
|
15535
15776
|
this._observed = true;
|
15536
15777
|
},
|
15537
15778
|
|
@@ -15597,25 +15838,25 @@ wysihtml5.views.View = Base.extend(
|
|
15597
15838
|
}
|
15598
15839
|
},
|
15599
15840
|
|
15841
|
+
update: function (elementToChange) {
|
15842
|
+
this.elementToChange = elementToChange ? elementToChange : this.elementToChange;
|
15843
|
+
this._interpolate();
|
15844
|
+
},
|
15845
|
+
|
15600
15846
|
/**
|
15601
15847
|
* Show the dialog element
|
15602
15848
|
*/
|
15603
15849
|
show: function(elementToChange) {
|
15604
|
-
|
15605
|
-
return;
|
15606
|
-
}
|
15850
|
+
var firstField = this.container.querySelector(SELECTOR_FORM_ELEMENTS);
|
15607
15851
|
|
15608
|
-
var that = this,
|
15609
|
-
firstField = this.container.querySelector(SELECTOR_FORM_ELEMENTS);
|
15610
|
-
this.elementToChange = elementToChange;
|
15611
15852
|
this._observe();
|
15612
|
-
this.
|
15613
|
-
|
15614
|
-
this.interval = setInterval(function() { that._interpolate(true); }, 500);
|
15615
|
-
}
|
15853
|
+
this.update(elementToChange);
|
15854
|
+
|
15616
15855
|
dom.addClass(this.link, CLASS_NAME_OPENED);
|
15617
15856
|
this.container.style.display = "";
|
15857
|
+
this.isOpen = true;
|
15618
15858
|
this.fire("show");
|
15859
|
+
|
15619
15860
|
if (firstField && !elementToChange) {
|
15620
15861
|
try {
|
15621
15862
|
firstField.focus();
|
@@ -15626,15 +15867,24 @@ wysihtml5.views.View = Base.extend(
|
|
15626
15867
|
/**
|
15627
15868
|
* Hide the dialog element
|
15628
15869
|
*/
|
15629
|
-
|
15630
|
-
clearInterval(this.interval);
|
15870
|
+
_hide: function(focus) {
|
15631
15871
|
this.elementToChange = null;
|
15632
15872
|
dom.removeClass(this.link, CLASS_NAME_OPENED);
|
15633
15873
|
this.container.style.display = "none";
|
15874
|
+
this.isOpen = false;
|
15875
|
+
},
|
15876
|
+
|
15877
|
+
hide: function() {
|
15878
|
+
this._hide();
|
15879
|
+
this.fire("hide");
|
15880
|
+
},
|
15881
|
+
|
15882
|
+
cancel: function() {
|
15883
|
+
this._hide();
|
15634
15884
|
this.fire("cancel");
|
15635
15885
|
}
|
15636
15886
|
});
|
15637
|
-
})(wysihtml5);
|
15887
|
+
})(wysihtml5); //jshint ignore:line
|
15638
15888
|
;/**
|
15639
15889
|
* Converts speech-to-text and inserts this into the editor
|
15640
15890
|
* As of now (2011/03/25) this only is supported in Chrome >= 11
|
@@ -15817,8 +16067,7 @@ wysihtml5.views.View = Base.extend(
|
|
15817
16067
|
_getDialog: function(link, command) {
|
15818
16068
|
var that = this,
|
15819
16069
|
dialogElement = this.container.querySelector("[data-wysihtml5-dialog='" + command + "']"),
|
15820
|
-
dialog,
|
15821
|
-
caretBookmark;
|
16070
|
+
dialog, caretBookmark;
|
15822
16071
|
|
15823
16072
|
if (dialogElement) {
|
15824
16073
|
if (wysihtml5.toolbar["Dialog_" + command]) {
|
@@ -15829,7 +16078,6 @@ wysihtml5.views.View = Base.extend(
|
|
15829
16078
|
|
15830
16079
|
dialog.on("show", function() {
|
15831
16080
|
caretBookmark = that.composer.selection.getBookmark();
|
15832
|
-
|
15833
16081
|
that.editor.fire("show:dialog", { command: command, dialogContainer: dialogElement, commandLink: link });
|
15834
16082
|
});
|
15835
16083
|
|
@@ -15838,14 +16086,27 @@ wysihtml5.views.View = Base.extend(
|
|
15838
16086
|
that.composer.selection.setBookmark(caretBookmark);
|
15839
16087
|
}
|
15840
16088
|
that._execCommand(command, attributes);
|
15841
|
-
|
15842
16089
|
that.editor.fire("save:dialog", { command: command, dialogContainer: dialogElement, commandLink: link });
|
16090
|
+
that._hideAllDialogs();
|
16091
|
+
that._preventInstantFocus();
|
16092
|
+
caretBookmark = undefined;
|
16093
|
+
|
15843
16094
|
});
|
15844
16095
|
|
15845
16096
|
dialog.on("cancel", function() {
|
15846
|
-
|
16097
|
+
if (caretBookmark) {
|
16098
|
+
that.composer.selection.setBookmark(caretBookmark);
|
16099
|
+
}
|
15847
16100
|
that.editor.fire("cancel:dialog", { command: command, dialogContainer: dialogElement, commandLink: link });
|
16101
|
+
caretBookmark = undefined;
|
16102
|
+
that._preventInstantFocus();
|
15848
16103
|
});
|
16104
|
+
|
16105
|
+
dialog.on("hide", function() {
|
16106
|
+
that.editor.fire("hide:dialog", { command: command, dialogContainer: dialogElement, commandLink: link });
|
16107
|
+
caretBookmark = undefined;
|
16108
|
+
});
|
16109
|
+
|
15849
16110
|
}
|
15850
16111
|
return dialog;
|
15851
16112
|
},
|
@@ -15861,14 +16122,7 @@ wysihtml5.views.View = Base.extend(
|
|
15861
16122
|
return;
|
15862
16123
|
}
|
15863
16124
|
|
15864
|
-
|
15865
|
-
|
15866
|
-
// Show dialog when available
|
15867
|
-
if (commandObj && commandObj.dialog && !commandObj.state) {
|
15868
|
-
commandObj.dialog.show();
|
15869
|
-
} else {
|
15870
|
-
this._execCommand(command, commandValue);
|
15871
|
-
}
|
16125
|
+
this._execCommand(command, commandValue);
|
15872
16126
|
},
|
15873
16127
|
|
15874
16128
|
_execCommand: function(command, commandValue) {
|
@@ -15918,10 +16172,19 @@ wysihtml5.views.View = Base.extend(
|
|
15918
16172
|
dom.delegate(container, "[data-wysihtml5-command], [data-wysihtml5-action]", "mousedown", function(event) { event.preventDefault(); });
|
15919
16173
|
|
15920
16174
|
dom.delegate(container, "[data-wysihtml5-command]", "click", function(event) {
|
15921
|
-
var
|
16175
|
+
var state,
|
16176
|
+
link = this,
|
15922
16177
|
command = link.getAttribute("data-wysihtml5-command"),
|
15923
|
-
commandValue = link.getAttribute("data-wysihtml5-command-value")
|
15924
|
-
|
16178
|
+
commandValue = link.getAttribute("data-wysihtml5-command-value"),
|
16179
|
+
commandObj = that.commandMapping[command + ":" + commandValue];
|
16180
|
+
|
16181
|
+
if (commandValue || !commandObj.dialog) {
|
16182
|
+
that.execCommand(command, commandValue);
|
16183
|
+
} else {
|
16184
|
+
state = getCommandState(that.composer, commandObj);
|
16185
|
+
commandObj.dialog.show(state);
|
16186
|
+
}
|
16187
|
+
|
15925
16188
|
event.preventDefault();
|
15926
16189
|
});
|
15927
16190
|
|
@@ -15931,21 +16194,26 @@ wysihtml5.views.View = Base.extend(
|
|
15931
16194
|
event.preventDefault();
|
15932
16195
|
});
|
15933
16196
|
|
15934
|
-
editor.on("interaction:composer", function() {
|
16197
|
+
editor.on("interaction:composer", function(event) {
|
16198
|
+
if (!that.preventFocus) {
|
15935
16199
|
that._updateLinkStates();
|
16200
|
+
}
|
15936
16201
|
});
|
15937
16202
|
|
15938
|
-
|
15939
|
-
that.
|
15940
|
-
|
16203
|
+
this.container.ownerDocument.addEventListener("click", function(event) {
|
16204
|
+
if (!wysihtml5.dom.contains(that.container, event.target) && !wysihtml5.dom.contains(that.composer.element, event.target)) {
|
16205
|
+
that._updateLinkStates();
|
16206
|
+
that._preventInstantFocus();
|
16207
|
+
}
|
16208
|
+
}, false);
|
15941
16209
|
|
15942
16210
|
if (this.editor.config.handleTables) {
|
15943
|
-
|
15944
|
-
|
15945
|
-
|
15946
|
-
|
15947
|
-
|
15948
|
-
|
16211
|
+
editor.on("tableselect:composer", function() {
|
16212
|
+
that.container.querySelectorAll('[data-wysihtml5-hiddentools="table"]')[0].style.display = "";
|
16213
|
+
});
|
16214
|
+
editor.on("tableunselect:composer", function() {
|
16215
|
+
that.container.querySelectorAll('[data-wysihtml5-hiddentools="table"]')[0].style.display = "none";
|
16216
|
+
});
|
15949
16217
|
}
|
15950
16218
|
|
15951
16219
|
editor.on("change_view", function(currentView) {
|
@@ -15962,15 +16230,28 @@ wysihtml5.views.View = Base.extend(
|
|
15962
16230
|
});
|
15963
16231
|
},
|
15964
16232
|
|
16233
|
+
_hideAllDialogs: function() {
|
16234
|
+
var commandMapping = this.commandMapping;
|
16235
|
+
for (var i in commandMapping) {
|
16236
|
+
if (commandMapping[i].dialog) {
|
16237
|
+
commandMapping[i].dialog.hide();
|
16238
|
+
}
|
16239
|
+
}
|
16240
|
+
},
|
16241
|
+
|
16242
|
+
_preventInstantFocus: function() {
|
16243
|
+
this.preventFocus = true;
|
16244
|
+
setTimeout(function() {
|
16245
|
+
this.preventFocus = false;
|
16246
|
+
}.bind(this),0);
|
16247
|
+
},
|
16248
|
+
|
15965
16249
|
_updateLinkStates: function() {
|
15966
16250
|
|
15967
|
-
var
|
15968
|
-
|
15969
|
-
|
15970
|
-
|
15971
|
-
state,
|
15972
|
-
action,
|
15973
|
-
command;
|
16251
|
+
var i, state, action, command, displayDialogAttributeValue,
|
16252
|
+
commandMapping = this.commandMapping,
|
16253
|
+
composer = this.composer,
|
16254
|
+
actionMapping = this.actionMapping;
|
15974
16255
|
// every millisecond counts... this is executed quite often
|
15975
16256
|
for (i in commandMapping) {
|
15976
16257
|
command = commandMapping[i];
|
@@ -16003,18 +16284,21 @@ wysihtml5.views.View = Base.extend(
|
|
16003
16284
|
if (command.group) {
|
16004
16285
|
dom.addClass(command.group, CLASS_NAME_COMMAND_ACTIVE);
|
16005
16286
|
}
|
16006
|
-
|
16007
|
-
|
16008
|
-
|
16009
|
-
|
16010
|
-
|
16011
|
-
|
16012
|
-
|
16013
|
-
|
16014
|
-
|
16015
|
-
|
16287
|
+
// commands with fixed value can not have a dialog.
|
16288
|
+
if (command.dialog && (typeof command.value === "undefined" || command.value === null)) {
|
16289
|
+
if (state && typeof state === "object") {
|
16290
|
+
state = getCommandState(composer, command);
|
16291
|
+
command.state = state;
|
16292
|
+
|
16293
|
+
// If dialog has dataset.showdialogonselection set as true,
|
16294
|
+
// Dialog displays on text state becoming active regardless of clobal showToolbarDialogsOnSelection options value
|
16295
|
+
displayDialogAttributeValue = command.dialog.container.dataset ? command.dialog.container.dataset.showdialogonselection : false;
|
16296
|
+
|
16297
|
+
if (composer.config.showToolbarDialogsOnSelection || displayDialogAttributeValue) {
|
16298
|
+
command.dialog.show(state);
|
16299
|
+
} else {
|
16300
|
+
command.dialog.update(state);
|
16016
16301
|
}
|
16017
|
-
command.dialog.show(state);
|
16018
16302
|
} else {
|
16019
16303
|
command.dialog.hide();
|
16020
16304
|
}
|
@@ -16028,7 +16312,8 @@ wysihtml5.views.View = Base.extend(
|
|
16028
16312
|
if (command.group) {
|
16029
16313
|
dom.removeClass(command.group, CLASS_NAME_COMMAND_ACTIVE);
|
16030
16314
|
}
|
16031
|
-
|
16315
|
+
// commands with fixed value can not have a dialog.
|
16316
|
+
if (command.dialog && !command.value) {
|
16032
16317
|
command.dialog.hide();
|
16033
16318
|
}
|
16034
16319
|
}
|
@@ -16058,6 +16343,20 @@ wysihtml5.views.View = Base.extend(
|
|
16058
16343
|
}
|
16059
16344
|
});
|
16060
16345
|
|
16346
|
+
function getCommandState (composer, command) {
|
16347
|
+
var state = composer.commands.state(command.name, command.value);
|
16348
|
+
|
16349
|
+
// Grab first and only object/element in state array, otherwise convert state into boolean
|
16350
|
+
// to avoid showing a dialog for multiple selected elements which may have different attributes
|
16351
|
+
// eg. when two links with different href are selected, the state will be an array consisting of both link elements
|
16352
|
+
// but the dialog interface can only update one
|
16353
|
+
if (!command.dialog.multiselect && wysihtml5.lang.object(state).isArray()) {
|
16354
|
+
state = state.length === 1 ? state[0] : true;
|
16355
|
+
}
|
16356
|
+
|
16357
|
+
return state;
|
16358
|
+
}
|
16359
|
+
|
16061
16360
|
})(wysihtml5);
|
16062
16361
|
;(function(wysihtml5) {
|
16063
16362
|
wysihtml5.toolbar.Dialog_createTable = wysihtml5.toolbar.Dialog.extend({
|
@@ -16067,8 +16366,7 @@ wysihtml5.views.View = Base.extend(
|
|
16067
16366
|
});
|
16068
16367
|
})(wysihtml5);
|
16069
16368
|
;(function(wysihtml5) {
|
16070
|
-
var
|
16071
|
-
SELECTOR_FIELDS = "[data-wysihtml5-dialog-field]",
|
16369
|
+
var SELECTOR_FIELDS = "[data-wysihtml5-dialog-field]",
|
16072
16370
|
ATTRIBUTE_FIELDS = "data-wysihtml5-dialog-field";
|
16073
16371
|
|
16074
16372
|
wysihtml5.toolbar.Dialog_foreColorStyle = wysihtml5.toolbar.Dialog.extend({
|
@@ -16087,16 +16385,15 @@ wysihtml5.views.View = Base.extend(
|
|
16087
16385
|
},
|
16088
16386
|
|
16089
16387
|
_interpolate: function(avoidHiddenFields) {
|
16090
|
-
var field,
|
16091
|
-
|
16092
|
-
newValue,
|
16388
|
+
var field, colourMode,
|
16389
|
+
styleParser = wysihtml5.quirks.styleParser,
|
16093
16390
|
focusedElement = document.querySelector(":focus"),
|
16094
16391
|
fields = this.container.querySelectorAll(SELECTOR_FIELDS),
|
16095
16392
|
length = fields.length,
|
16096
16393
|
i = 0,
|
16097
16394
|
firstElement = (this.elementToChange) ? ((wysihtml5.lang.object(this.elementToChange).isArray()) ? this.elementToChange[0] : this.elementToChange) : null,
|
16098
|
-
|
16099
|
-
|
16395
|
+
colourStr = (firstElement) ? firstElement.getAttribute("style") : null,
|
16396
|
+
colour = (colourStr) ? styleParser.parseColor(colourStr, "color") : null;
|
16100
16397
|
|
16101
16398
|
for (; i<length; i++) {
|
16102
16399
|
field = fields[i];
|
@@ -16109,14 +16406,13 @@ wysihtml5.views.View = Base.extend(
|
|
16109
16406
|
continue;
|
16110
16407
|
}
|
16111
16408
|
if (field.getAttribute(ATTRIBUTE_FIELDS) === "color") {
|
16112
|
-
|
16113
|
-
|
16114
|
-
|
16115
|
-
|
16116
|
-
|
16117
|
-
}
|
16409
|
+
colourMode = (field.dataset.colormode || "rgb").toLowerCase();
|
16410
|
+
colourMode = colourMode === "hex" ? "hash" : colourMode;
|
16411
|
+
|
16412
|
+
if (colour) {
|
16413
|
+
field.value = styleParser.unparseColor(colour, colourMode);
|
16118
16414
|
} else {
|
16119
|
-
field.value =
|
16415
|
+
field.value = styleParser.unparseColor([0, 0, 0], colourMode);
|
16120
16416
|
}
|
16121
16417
|
}
|
16122
16418
|
}
|
@@ -16147,6 +16443,5 @@ wysihtml5.views.View = Base.extend(
|
|
16147
16443
|
field.value = size;
|
16148
16444
|
}
|
16149
16445
|
}
|
16150
|
-
|
16151
16446
|
});
|
16152
16447
|
})(wysihtml5);
|