wysihtml-rails 0.6.0.beta → 0.6.0.beta2
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.js +516 -351
- data/vendor/assets/javascripts/wysihtml/all_commands.js +1 -0
- data/vendor/assets/javascripts/wysihtml/extra_commands/insertHorizontalRule.js +27 -0
- data/vendor/assets/javascripts/wysihtml/table_editing.js +3 -3
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28edad758722675d4832f0c387cb4b89b84697f1
|
4
|
+
data.tar.gz: 4bb7c150b90be7e92db95b36093ce4bbef02f3f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 554f22de0d93cdc3f3fdee7fa6c237a4d24dd147a5b50c8cf7b41bb384ab54832cff79fdb2c8ddafe900bff6b29bc811bb006a6c3739e488ea6d37426e76d4b9
|
7
|
+
data.tar.gz: 3bd893e4fad07835b6cba778913dbe408f3e4859aa0b62e927b850f343c885696e67285e9f44462c0ab60dcc380310f2521b64d419be5ba67d8cb8efc5bde949
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license wysihtml v0.6.0-
|
2
|
+
* @license wysihtml v0.6.0-beta2
|
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 wysihtml = {
|
13
|
-
version:
|
13
|
+
version: '0.6.0-beta1',
|
14
14
|
|
15
15
|
// namespaces
|
16
16
|
commands: {},
|
@@ -26,10 +26,11 @@ var wysihtml = {
|
|
26
26
|
this.editorExtenders.push(extender);
|
27
27
|
},
|
28
28
|
|
29
|
-
INVISIBLE_SPACE:
|
29
|
+
INVISIBLE_SPACE: '\uFEFF',
|
30
30
|
INVISIBLE_SPACE_REG_EXP: /\uFEFF/g,
|
31
31
|
|
32
|
-
VOID_ELEMENTS:
|
32
|
+
VOID_ELEMENTS: 'area, base, br, col, embed, hr, img, input, keygen, link, meta, param, source, track, wbr',
|
33
|
+
PERMITTED_PHRASING_CONTENT_ONLY: 'h1, h2, h3, h4, h5, h6, p, pre',
|
33
34
|
|
34
35
|
EMPTY_FUNCTION: function() {},
|
35
36
|
|
@@ -46,260 +47,308 @@ var wysihtml = {
|
|
46
47
|
|
47
48
|
wysihtml.polyfills = function(win, doc) {
|
48
49
|
|
49
|
-
|
50
|
+
var methods = {
|
51
|
+
|
52
|
+
// Safary has a bug of not restoring selection after node.normalize correctly.
|
53
|
+
// Detects the misbegaviour and patches it
|
54
|
+
normalizeHasCaretError: function() {
|
55
|
+
if ("createRange" in doc && "getSelection" in win) {
|
56
|
+
var originalTarget,
|
57
|
+
scrollTop = window.pageYOffset,
|
58
|
+
scrollLeft = window.pageXOffset,
|
59
|
+
e = doc.createElement('div'),
|
60
|
+
t1 = doc.createTextNode('a'),
|
61
|
+
t2 = doc.createTextNode('a'),
|
62
|
+
t3 = doc.createTextNode('a'),
|
63
|
+
r = doc.createRange(),
|
64
|
+
s, ret;
|
65
|
+
|
66
|
+
if (document.activeElement) {
|
67
|
+
if (document.activeElement.nodeType === 1 && ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'].indexOf(document.activeElement.nodeName) > -1) {
|
68
|
+
originalTarget = {
|
69
|
+
type: 'form',
|
70
|
+
node: document.activeElement,
|
71
|
+
start: document.activeElement.selectionStart,
|
72
|
+
end: document.activeElement.selectionEnd,
|
73
|
+
};
|
74
|
+
} else {
|
75
|
+
s = win.getSelection();
|
76
|
+
if (s && s.anchorNode) {
|
77
|
+
originalTarget = {
|
78
|
+
type: 'range',
|
79
|
+
anchorNode: s.anchorNode,
|
80
|
+
anchorOffset: s.anchorOffset,
|
81
|
+
focusNode: s.focusNode,
|
82
|
+
focusOffset: s.focusOffset
|
83
|
+
};
|
84
|
+
}
|
85
|
+
}
|
86
|
+
}
|
50
87
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
index = 0;
|
88
|
+
e.setAttribute('contenteditable', 'true');
|
89
|
+
e.appendChild(t1);
|
90
|
+
e.appendChild(t2);
|
91
|
+
e.appendChild(t3);
|
92
|
+
doc.body.appendChild(e);
|
93
|
+
r.setStart(t2, 1);
|
94
|
+
r.setEnd(t2, 1);
|
59
95
|
|
60
|
-
|
61
|
-
|
62
|
-
|
96
|
+
s = win.getSelection();
|
97
|
+
s.removeAllRanges();
|
98
|
+
s.addRange(r);
|
99
|
+
e.normalize();
|
100
|
+
s = win.getSelection();
|
63
101
|
|
64
|
-
|
65
|
-
|
102
|
+
ret = (e.childNodes.length !== 1 || s.anchorNode !== e.firstChild || s.anchorOffset !== 2);
|
103
|
+
e.parentNode.removeChild(e);
|
104
|
+
s.removeAllRanges();
|
66
105
|
|
67
|
-
|
68
|
-
|
106
|
+
if (originalTarget) {
|
107
|
+
if (originalTarget.type === 'form') {
|
108
|
+
// The selection parameters are not present for all form elements
|
109
|
+
if (typeof originalTarget.start !== 'undefined' && typeof originalTarget.end !== 'undefined') {
|
110
|
+
originalTarget.node.setSelectionRange(originalTarget.start, originalTarget.end);
|
111
|
+
}
|
112
|
+
originalTarget.node.focus();
|
113
|
+
} else if (originalTarget.type === 'range') {
|
114
|
+
r = doc.createRange();
|
115
|
+
r.setStart(originalTarget.anchorNode, originalTarget.anchorOffset);
|
116
|
+
r.setEnd(originalTarget.focusNode, originalTarget.focusOffset);
|
117
|
+
s.addRange(r);
|
118
|
+
}
|
119
|
+
}
|
69
120
|
|
70
|
-
|
71
|
-
|
72
|
-
break;
|
121
|
+
if (scrollTop !== window.pageYOffset || scrollLeft !== window.pageXOffset) {
|
122
|
+
win.scrollTo(scrollLeft, scrollTop);
|
73
123
|
}
|
74
124
|
|
75
|
-
|
125
|
+
return ret;
|
76
126
|
}
|
127
|
+
},
|
77
128
|
|
78
|
-
|
79
|
-
|
129
|
+
apply: function() {
|
130
|
+
// closest, matches, and remove polyfill
|
131
|
+
// https://github.com/jonathantneal/closest
|
132
|
+
(function (ELEMENT) {
|
133
|
+
ELEMENT.matches = ELEMENT.matches || ELEMENT.mozMatchesSelector || ELEMENT.msMatchesSelector || ELEMENT.oMatchesSelector || ELEMENT.webkitMatchesSelector || function matches(selector) {
|
134
|
+
var
|
135
|
+
element = this,
|
136
|
+
elements = (element.document || element.ownerDocument).querySelectorAll(selector),
|
137
|
+
index = 0;
|
80
138
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
}
|
85
|
-
};
|
139
|
+
while (elements[index] && elements[index] !== element) {
|
140
|
+
++index;
|
141
|
+
}
|
86
142
|
|
87
|
-
|
143
|
+
return elements[index] ? true : false;
|
144
|
+
};
|
88
145
|
|
89
|
-
|
90
|
-
|
91
|
-
get: function() {
|
92
|
-
var self = this;
|
93
|
-
function update(fn) {
|
94
|
-
return function(value) {
|
95
|
-
var classes = self.className.split(/\s+/),
|
96
|
-
index = classes.indexOf(value);
|
146
|
+
ELEMENT.closest = ELEMENT.closest || function closest(selector) {
|
147
|
+
var element = this;
|
97
148
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
149
|
+
while (element) {
|
150
|
+
if (element.matches(selector)) {
|
151
|
+
break;
|
152
|
+
}
|
102
153
|
|
103
|
-
|
104
|
-
|
105
|
-
~index || classes.push(value);
|
106
|
-
}),
|
154
|
+
element = element.parentElement;
|
155
|
+
}
|
107
156
|
|
108
|
-
|
109
|
-
|
110
|
-
}),
|
157
|
+
return element;
|
158
|
+
};
|
111
159
|
|
112
|
-
|
113
|
-
|
114
|
-
|
160
|
+
ELEMENT.remove = ELEMENT.remove || function remove() {
|
161
|
+
if (this.parentNode) {
|
162
|
+
this.parentNode.removeChild(this);
|
163
|
+
}
|
164
|
+
};
|
115
165
|
|
116
|
-
|
117
|
-
return !!~self.className.split(/\s+/).indexOf(value);
|
118
|
-
},
|
166
|
+
}(win.Element.prototype));
|
119
167
|
|
120
|
-
|
121
|
-
|
168
|
+
if (!('classList' in doc.documentElement) && win.Object.defineProperty && typeof win.HTMLElement !== 'undefined') {
|
169
|
+
win.Object.defineProperty(win.HTMLElement.prototype, 'classList', {
|
170
|
+
get: function() {
|
171
|
+
var self = this;
|
172
|
+
function update(fn) {
|
173
|
+
return function(value) {
|
174
|
+
var classes = self.className.split(/\s+/),
|
175
|
+
index = classes.indexOf(value);
|
176
|
+
|
177
|
+
fn(classes, index, value);
|
178
|
+
self.className = classes.join(' ');
|
179
|
+
};
|
122
180
|
}
|
123
|
-
};
|
124
181
|
|
125
|
-
|
126
|
-
|
127
|
-
|
182
|
+
var ret = {
|
183
|
+
add: update(function(classes, index, value) {
|
184
|
+
~index || classes.push(value);
|
185
|
+
}),
|
186
|
+
|
187
|
+
remove: update(function(classes, index) {
|
188
|
+
~index && classes.splice(index, 1);
|
189
|
+
}),
|
190
|
+
|
191
|
+
toggle: update(function(classes, index, value) {
|
192
|
+
~index ? classes.splice(index, 1) : classes.push(value);
|
193
|
+
}),
|
194
|
+
|
195
|
+
contains: function(value) {
|
196
|
+
return !!~self.className.split(/\s+/).indexOf(value);
|
197
|
+
},
|
198
|
+
|
199
|
+
item: function(i) {
|
200
|
+
return self.className.split(/\s+/)[i] || null;
|
201
|
+
}
|
202
|
+
};
|
203
|
+
|
204
|
+
win.Object.defineProperty(ret, 'length', {
|
205
|
+
get: function() {
|
206
|
+
return self.className.split(/\s+/).length;
|
207
|
+
}
|
208
|
+
});
|
209
|
+
|
210
|
+
return ret;
|
128
211
|
}
|
129
212
|
});
|
130
|
-
|
131
|
-
return ret;
|
132
213
|
}
|
133
|
-
});
|
134
|
-
}
|
135
214
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
e.setAttribute('contenteditable', 'true');
|
148
|
-
e.appendChild(t1);
|
149
|
-
e.appendChild(t2);
|
150
|
-
e.appendChild(t3);
|
151
|
-
doc.body.appendChild(e);
|
152
|
-
r.setStart(t2, 1);
|
153
|
-
r.setEnd(t2, 1);
|
154
|
-
|
155
|
-
s = win.getSelection();
|
156
|
-
s.removeAllRanges();
|
157
|
-
s.addRange(r);
|
158
|
-
e.normalize();
|
159
|
-
s = win.getSelection();
|
160
|
-
|
161
|
-
ret = (e.childNodes.length !== 1 || s.anchorNode !== e.firstChild || s.anchorOffset !== 2);
|
162
|
-
e.parentNode.removeChild(e);
|
163
|
-
s.removeAllRanges();
|
164
|
-
return ret;
|
165
|
-
}
|
166
|
-
};
|
215
|
+
var getTextNodes = function(node){
|
216
|
+
var all = [];
|
217
|
+
for (node=node.firstChild;node;node=node.nextSibling){
|
218
|
+
if (node.nodeType == 3) {
|
219
|
+
all.push(node);
|
220
|
+
} else {
|
221
|
+
all = all.concat(getTextNodes(node));
|
222
|
+
}
|
223
|
+
}
|
224
|
+
return all;
|
225
|
+
};
|
167
226
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
};
|
227
|
+
var isInDom = function(node) {
|
228
|
+
var doc = node.ownerDocument,
|
229
|
+
n = node;
|
230
|
+
|
231
|
+
do {
|
232
|
+
if (n === doc) {
|
233
|
+
return true;
|
234
|
+
}
|
235
|
+
n = n.parentNode;
|
236
|
+
} while(n);
|
179
237
|
|
180
|
-
|
181
|
-
|
182
|
-
n = node;
|
238
|
+
return false;
|
239
|
+
};
|
183
240
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
241
|
+
var normalizeFix = function() {
|
242
|
+
var f = win.Node.prototype.normalize;
|
243
|
+
var nf = function() {
|
244
|
+
var texts = getTextNodes(this),
|
245
|
+
s = this.ownerDocument.defaultView.getSelection(),
|
246
|
+
anode = s.anchorNode,
|
247
|
+
aoffset = s.anchorOffset,
|
248
|
+
aelement = anode && anode.nodeType === 1 && anode.childNodes.length > 0 ? anode.childNodes[aoffset] : undefined,
|
249
|
+
fnode = s.focusNode,
|
250
|
+
foffset = s.focusOffset,
|
251
|
+
felement = fnode && fnode.nodeType === 1 && foffset > 0 ? fnode.childNodes[foffset -1] : undefined,
|
252
|
+
r = this.ownerDocument.createRange(),
|
253
|
+
prevTxt = texts.shift(),
|
254
|
+
curText = prevTxt ? texts.shift() : null;
|
255
|
+
|
256
|
+
if (felement && felement.nodeType === 3) {
|
257
|
+
fnode = felement;
|
258
|
+
foffset = felement.nodeValue.length;
|
259
|
+
felement = undefined;
|
260
|
+
}
|
190
261
|
|
191
|
-
|
192
|
-
|
262
|
+
if (aelement && aelement.nodeType === 3) {
|
263
|
+
anode = aelement;
|
264
|
+
aoffset = 0;
|
265
|
+
aelement = undefined;
|
266
|
+
}
|
193
267
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
var texts = getTextNodes(this),
|
198
|
-
s = this.ownerDocument.defaultView.getSelection(),
|
199
|
-
anode = s.anchorNode,
|
200
|
-
aoffset = s.anchorOffset,
|
201
|
-
aelement = anode && anode.nodeType === 1 && anode.childNodes.length > 0 ? anode.childNodes[aoffset] : undefined,
|
202
|
-
fnode = s.focusNode,
|
203
|
-
foffset = s.focusOffset,
|
204
|
-
felement = fnode && fnode.nodeType === 1 && foffset > 0 ? fnode.childNodes[foffset -1] : undefined,
|
205
|
-
r = this.ownerDocument.createRange(),
|
206
|
-
prevTxt = texts.shift(),
|
207
|
-
curText = prevTxt ? texts.shift() : null;
|
208
|
-
|
209
|
-
if (felement && felement.nodeType === 3) {
|
210
|
-
fnode = felement;
|
211
|
-
foffset = felement.nodeValue.length;
|
212
|
-
felement = undefined;
|
213
|
-
}
|
214
|
-
|
215
|
-
if (aelement && aelement.nodeType === 3) {
|
216
|
-
anode = aelement;
|
217
|
-
aoffset = 0;
|
218
|
-
aelement = undefined;
|
219
|
-
}
|
220
|
-
|
221
|
-
if ((anode === fnode && foffset < aoffset) || (anode !== fnode && (anode.compareDocumentPosition(fnode) & win.Node.DOCUMENT_POSITION_PRECEDING) && !(anode.compareDocumentPosition(fnode) & win.Node.DOCUMENT_POSITION_CONTAINS))) {
|
222
|
-
fnode = [anode, anode = fnode][0];
|
223
|
-
foffset = [aoffset, aoffset = foffset][0];
|
224
|
-
}
|
225
|
-
|
226
|
-
while(prevTxt && curText) {
|
227
|
-
if (curText.previousSibling && curText.previousSibling === prevTxt) {
|
228
|
-
if (anode === curText) {
|
229
|
-
anode = prevTxt;
|
230
|
-
aoffset = prevTxt.nodeValue.length + aoffset;
|
268
|
+
if ((anode === fnode && foffset < aoffset) || (anode !== fnode && (anode.compareDocumentPosition(fnode) & win.Node.DOCUMENT_POSITION_PRECEDING) && !(anode.compareDocumentPosition(fnode) & win.Node.DOCUMENT_POSITION_CONTAINS))) {
|
269
|
+
fnode = [anode, anode = fnode][0];
|
270
|
+
foffset = [aoffset, aoffset = foffset][0];
|
231
271
|
}
|
232
|
-
|
233
|
-
|
234
|
-
|
272
|
+
|
273
|
+
while(prevTxt && curText) {
|
274
|
+
if (curText.previousSibling && curText.previousSibling === prevTxt) {
|
275
|
+
if (anode === curText) {
|
276
|
+
anode = prevTxt;
|
277
|
+
aoffset = prevTxt.nodeValue.length + aoffset;
|
278
|
+
}
|
279
|
+
if (fnode === curText) {
|
280
|
+
fnode = prevTxt;
|
281
|
+
foffset = prevTxt.nodeValue.length + foffset;
|
282
|
+
}
|
283
|
+
prevTxt.nodeValue = prevTxt.nodeValue + curText.nodeValue;
|
284
|
+
curText.parentNode.removeChild(curText);
|
285
|
+
curText = texts.shift();
|
286
|
+
} else {
|
287
|
+
prevTxt = curText;
|
288
|
+
curText = texts.shift();
|
289
|
+
}
|
235
290
|
}
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
291
|
+
|
292
|
+
if (felement) {
|
293
|
+
foffset = Array.prototype.indexOf.call(felement.parentNode.childNodes, felement) + 1;
|
294
|
+
}
|
295
|
+
|
296
|
+
if (aelement) {
|
297
|
+
aoffset = Array.prototype.indexOf.call(aelement.parentNode.childNodes, aelement);
|
298
|
+
}
|
299
|
+
|
300
|
+
if (isInDom(this) && anode && anode.parentNode && fnode && fnode.parentNode) {
|
301
|
+
r.setStart(anode, aoffset);
|
302
|
+
r.setEnd(fnode, foffset);
|
303
|
+
s.removeAllRanges();
|
304
|
+
s.addRange(r);
|
305
|
+
}
|
306
|
+
};
|
307
|
+
win.Node.prototype.normalize = nf;
|
308
|
+
};
|
309
|
+
|
310
|
+
var F = function() {
|
311
|
+
win.removeEventListener("load", F);
|
312
|
+
if ("Node" in win && "normalize" in win.Node.prototype && methods.normalizeHasCaretError()) {
|
313
|
+
normalizeFix();
|
242
314
|
}
|
243
|
-
}
|
315
|
+
};
|
244
316
|
|
245
|
-
if (
|
246
|
-
|
317
|
+
if (doc.readyState !== "complete") {
|
318
|
+
win.addEventListener("load", F);
|
319
|
+
} else {
|
320
|
+
F();
|
247
321
|
}
|
248
322
|
|
249
|
-
|
250
|
-
|
323
|
+
// CustomEvent for ie9 and up
|
324
|
+
function nativeCustomEventSupported() {
|
325
|
+
try {
|
326
|
+
var p = new win.CustomEvent('cat', {detail: {foo: 'bar'}});
|
327
|
+
return 'cat' === p.type && 'bar' === p.detail.foo;
|
328
|
+
} catch (e) {}
|
329
|
+
return false;
|
251
330
|
}
|
252
331
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
normalizeFix();
|
332
|
+
// Polyfills CustomEvent object for IE9 and up
|
333
|
+
(function() {
|
334
|
+
if (!nativeCustomEventSupported() && "CustomEvent" in win) {
|
335
|
+
function CustomEvent(event, params) {
|
336
|
+
params = params || {bubbles: false, cancelable: false, detail: undefined};
|
337
|
+
var evt = doc.createEvent('CustomEvent');
|
338
|
+
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
|
339
|
+
return evt;
|
340
|
+
}
|
341
|
+
CustomEvent.prototype = win.Event.prototype;
|
342
|
+
win.CustomEvent = CustomEvent;
|
343
|
+
}
|
344
|
+
})();
|
267
345
|
}
|
268
|
-
};
|
269
|
-
|
270
|
-
if (doc.readyState !== "complete") {
|
271
|
-
win.addEventListener("load", F);
|
272
|
-
} else {
|
273
|
-
F();
|
274
346
|
}
|
275
347
|
|
276
|
-
|
277
|
-
function nativeCustomEventSupported() {
|
278
|
-
try {
|
279
|
-
var p = new CustomEvent('cat', {detail: {foo: 'bar'}});
|
280
|
-
return 'cat' === p.type && 'bar' === p.detail.foo;
|
281
|
-
} catch (e) {}
|
282
|
-
return false;
|
283
|
-
}
|
284
|
-
var customEventSupported = nativeCustomEventSupported();
|
285
|
-
|
286
|
-
// Polyfills CustomEvent object for IE9 and up
|
287
|
-
(function() {
|
288
|
-
if (!customEventSupported && "CustomEvent" in win) {
|
289
|
-
function CustomEvent(event, params) {
|
290
|
-
params = params || {bubbles: false, cancelable: false, detail: undefined};
|
291
|
-
var evt = doc.createEvent('CustomEvent');
|
292
|
-
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
|
293
|
-
return evt;
|
294
|
-
}
|
295
|
-
CustomEvent.prototype = win.Event.prototype;
|
296
|
-
win.CustomEvent = CustomEvent;
|
297
|
-
customEventSupported = true;
|
298
|
-
}
|
299
|
-
})();
|
348
|
+
return methods;
|
300
349
|
};
|
301
350
|
|
302
|
-
wysihtml.polyfills(window, document);
|
351
|
+
wysihtml.polyfills(window, document).apply();
|
303
352
|
|
304
353
|
/*
|
305
354
|
Base.js, version 1.1a
|
@@ -313,7 +362,7 @@ var Base = function() {
|
|
313
362
|
|
314
363
|
Base.extend = function(_instance, _static) { // subclass
|
315
364
|
var extend = Base.prototype.extend;
|
316
|
-
|
365
|
+
|
317
366
|
// build the prototype
|
318
367
|
Base._prototyping = true;
|
319
368
|
var proto = new this;
|
@@ -322,7 +371,7 @@ Base.extend = function(_instance, _static) { // subclass
|
|
322
371
|
// call this method from any other method to invoke that method's ancestor
|
323
372
|
};
|
324
373
|
delete Base._prototyping;
|
325
|
-
|
374
|
+
|
326
375
|
// create the wrapper for the constructor function
|
327
376
|
//var constructor = proto.constructor.valueOf(); //-dean
|
328
377
|
var constructor = proto.constructor;
|
@@ -337,7 +386,7 @@ Base.extend = function(_instance, _static) { // subclass
|
|
337
386
|
}
|
338
387
|
}
|
339
388
|
};
|
340
|
-
|
389
|
+
|
341
390
|
// build the class interface
|
342
391
|
klass.ancestor = this;
|
343
392
|
klass.extend = this.extend;
|
@@ -355,7 +404,7 @@ Base.extend = function(_instance, _static) { // subclass
|
|
355
404
|
return klass;
|
356
405
|
};
|
357
406
|
|
358
|
-
Base.prototype = {
|
407
|
+
Base.prototype = {
|
359
408
|
extend: function(source, value) {
|
360
409
|
if (arguments.length > 1) { // extending with a name/value pair
|
361
410
|
var ancestor = this[source];
|
@@ -414,7 +463,7 @@ Base = Base.extend({
|
|
414
463
|
}, {
|
415
464
|
ancestor: Object,
|
416
465
|
version: "1.1",
|
417
|
-
|
466
|
+
|
418
467
|
forEach: function(object, block, context) {
|
419
468
|
for (var key in object) {
|
420
469
|
if (this.prototype[key] === undefined) {
|
@@ -422,7 +471,7 @@ Base = Base.extend({
|
|
422
471
|
}
|
423
472
|
}
|
424
473
|
},
|
425
|
-
|
474
|
+
|
426
475
|
implement: function() {
|
427
476
|
for (var i = 0; i < arguments.length; i++) {
|
428
477
|
if (typeof arguments[i] == "function") {
|
@@ -435,7 +484,7 @@ Base = Base.extend({
|
|
435
484
|
}
|
436
485
|
return this;
|
437
486
|
},
|
438
|
-
|
487
|
+
|
439
488
|
toString: function() {
|
440
489
|
return String(this.valueOf());
|
441
490
|
}
|
@@ -4244,7 +4293,7 @@ var rangy;
|
|
4244
4293
|
win = null;
|
4245
4294
|
});
|
4246
4295
|
});
|
4247
|
-
|
4296
|
+
|
4248
4297
|
|
4249
4298
|
/*----------------------------------------------------------------------------------------------------------------*/
|
4250
4299
|
|
@@ -6849,6 +6898,14 @@ wysihtml.browser = (function() {
|
|
6849
6898
|
|
6850
6899
|
usesControlRanges: function() {
|
6851
6900
|
return document.body && "createControlRange" in document.body;
|
6901
|
+
},
|
6902
|
+
|
6903
|
+
// Webkit browsers have an issue that when caret is at the end of link it is moved outside of link while inserting new characters,
|
6904
|
+
// so all inserted content will be after link. Selection before inserion is reported to be in link though.
|
6905
|
+
// This makes changing link texts from problematic to impossible (if link is just 1 characer long) for the user.
|
6906
|
+
// TODO: needs to be tested better than just browser as it some day might get fixed
|
6907
|
+
hasCaretAtLinkEndInsertionProblems: function() {
|
6908
|
+
return isWebKit;
|
6852
6909
|
}
|
6853
6910
|
};
|
6854
6911
|
})();
|
@@ -7674,7 +7731,7 @@ wysihtml.dom.copyAttributes = function(attributesToCopy) {
|
|
7674
7731
|
return {
|
7675
7732
|
from: function(elementToCopyFrom) {
|
7676
7733
|
return {
|
7677
|
-
to: function(elementToCopyTo) {
|
7734
|
+
to: function pasteElementAttributesTo(elementToCopyTo) {
|
7678
7735
|
var attribute,
|
7679
7736
|
i = 0,
|
7680
7737
|
length = attributesToCopy.length;
|
@@ -7684,7 +7741,7 @@ wysihtml.dom.copyAttributes = function(attributesToCopy) {
|
|
7684
7741
|
elementToCopyTo[attribute] = elementToCopyFrom[attribute];
|
7685
7742
|
}
|
7686
7743
|
}
|
7687
|
-
return { andTo:
|
7744
|
+
return { andTo: pasteElementAttributesTo };
|
7688
7745
|
}
|
7689
7746
|
};
|
7690
7747
|
}
|
@@ -7755,9 +7812,9 @@ wysihtml.dom.copyAttributes = function(attributesToCopy) {
|
|
7755
7812
|
}
|
7756
7813
|
|
7757
7814
|
return {
|
7758
|
-
to: function(element) {
|
7815
|
+
to: function pasteStylesTo(element) {
|
7759
7816
|
dom.setStyles(cssText).on(element);
|
7760
|
-
return { andTo:
|
7817
|
+
return { andTo: pasteStylesTo };
|
7761
7818
|
}
|
7762
7819
|
};
|
7763
7820
|
}
|
@@ -7858,7 +7915,7 @@ wysihtml.dom.copyAttributes = function(attributesToCopy) {
|
|
7858
7915
|
prev: function(options) {
|
7859
7916
|
var prevNode = node.previousSibling,
|
7860
7917
|
types = (options && options.nodeTypes) ? options.nodeTypes : defaultNodeTypes;
|
7861
|
-
|
7918
|
+
|
7862
7919
|
if (!prevNode) {
|
7863
7920
|
return null;
|
7864
7921
|
}
|
@@ -7870,7 +7927,7 @@ wysihtml.dom.copyAttributes = function(attributesToCopy) {
|
|
7870
7927
|
) {
|
7871
7928
|
return wysihtml.dom.domNode(prevNode).prev(options);
|
7872
7929
|
}
|
7873
|
-
|
7930
|
+
|
7874
7931
|
return prevNode;
|
7875
7932
|
},
|
7876
7933
|
|
@@ -7878,7 +7935,7 @@ wysihtml.dom.copyAttributes = function(attributesToCopy) {
|
|
7878
7935
|
next: function(options) {
|
7879
7936
|
var nextNode = node.nextSibling,
|
7880
7937
|
types = (options && options.nodeTypes) ? options.nodeTypes : defaultNodeTypes;
|
7881
|
-
|
7938
|
+
|
7882
7939
|
if (!nextNode) {
|
7883
7940
|
return null;
|
7884
7941
|
}
|
@@ -7890,7 +7947,7 @@ wysihtml.dom.copyAttributes = function(attributesToCopy) {
|
|
7890
7947
|
) {
|
7891
7948
|
return wysihtml.dom.domNode(nextNode).next(options);
|
7892
7949
|
}
|
7893
|
-
|
7950
|
+
|
7894
7951
|
return nextNode;
|
7895
7952
|
},
|
7896
7953
|
|
@@ -7953,7 +8010,7 @@ wysihtml.dom.copyAttributes = function(attributesToCopy) {
|
|
7953
8010
|
escapeParent: function(element, newWrapper) {
|
7954
8011
|
var parent, split2, nodeWrap,
|
7955
8012
|
curNode = node;
|
7956
|
-
|
8013
|
+
|
7957
8014
|
// Stop if node is not a descendant of element
|
7958
8015
|
if (!wysihtml.dom.contains(element, node)) {
|
7959
8016
|
throw new Error("Child is not a descendant of node.");
|
@@ -8036,7 +8093,7 @@ wysihtml.dom.copyAttributes = function(attributesToCopy) {
|
|
8036
8093
|
Tests on principle that all properties defined must have at least one match.
|
8037
8094
|
styleValue parameter works in context of styleProperty and has no effect otherwise.
|
8038
8095
|
Returns true if element matches and false if it does not.
|
8039
|
-
|
8096
|
+
|
8040
8097
|
Properties for filtering element:
|
8041
8098
|
{
|
8042
8099
|
query: selector string,
|
@@ -8326,12 +8383,12 @@ wysihtml.dom.getParentElement = (function() {
|
|
8326
8383
|
|
8327
8384
|
})();
|
8328
8385
|
|
8329
|
-
/*
|
8386
|
+
/*
|
8330
8387
|
* Methods for fetching pasted html before it gets inserted into content
|
8331
8388
|
**/
|
8332
8389
|
|
8333
8390
|
/* Modern event.clipboardData driven approach.
|
8334
|
-
* Advantage is that it does not have to loose selection or modify dom to catch the data.
|
8391
|
+
* Advantage is that it does not have to loose selection or modify dom to catch the data.
|
8335
8392
|
* IE does not support though.
|
8336
8393
|
**/
|
8337
8394
|
wysihtml.dom.getPastedHtml = function(event) {
|
@@ -8352,7 +8409,7 @@ wysihtml.dom.getPastedHtmlWithDiv = function (composer, f) {
|
|
8352
8409
|
doc = composer.element.ownerDocument,
|
8353
8410
|
cleanerDiv = doc.createElement('DIV'),
|
8354
8411
|
scrollPos = composer.getScrollPos();
|
8355
|
-
|
8412
|
+
|
8356
8413
|
doc.body.appendChild(cleanerDiv);
|
8357
8414
|
|
8358
8415
|
cleanerDiv.style.width = "1px";
|
@@ -9650,7 +9707,7 @@ wysihtml.dom.renameElement = function(element, newNodeName) {
|
|
9650
9707
|
newElement.appendChild(firstChild);
|
9651
9708
|
}
|
9652
9709
|
wysihtml.dom.copyAttributes(["align", "className"]).from(element).to(newElement);
|
9653
|
-
|
9710
|
+
|
9654
9711
|
if (element.parentNode) {
|
9655
9712
|
element.parentNode.replaceChild(newElement, element);
|
9656
9713
|
}
|
@@ -9981,7 +10038,7 @@ wysihtml.dom.replaceWithChildNodes = function(node) {
|
|
9981
10038
|
}
|
9982
10039
|
|
9983
10040
|
if (wysihtml.polyfills) {
|
9984
|
-
wysihtml.polyfills(iframeWindow, iframeDocument);
|
10041
|
+
wysihtml.polyfills(iframeWindow, iframeDocument).apply();
|
9985
10042
|
}
|
9986
10043
|
|
9987
10044
|
this.loaded = true;
|
@@ -10333,7 +10390,7 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
10333
10390
|
})(wysihtml);
|
10334
10391
|
|
10335
10392
|
(function(wysihtml) {
|
10336
|
-
|
10393
|
+
|
10337
10394
|
// List of supported color format parsing methods
|
10338
10395
|
// If radix is not defined 10 is expected as default
|
10339
10396
|
var colorParseMethods = {
|
@@ -10376,7 +10433,7 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
10376
10433
|
}
|
10377
10434
|
}
|
10378
10435
|
|
10379
|
-
// Takes color string value ("#abc", "rgb(1,2,3)", ...) as an argument and returns the type of that color format "hex", "rgb", "rgba".
|
10436
|
+
// Takes color string value ("#abc", "rgb(1,2,3)", ...) as an argument and returns the type of that color format "hex", "rgb", "rgba".
|
10380
10437
|
function getColorFormat (colorStr) {
|
10381
10438
|
var type = getColorParseMethod(colorStr);
|
10382
10439
|
|
@@ -10389,9 +10446,9 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
10389
10446
|
// Takes color string value as an argument and returns suitable parsing method for it
|
10390
10447
|
getColorParseMethod : getColorParseMethod,
|
10391
10448
|
|
10392
|
-
// Takes color string value as an argument and returns the type of that color format "hex", "rgb", "rgba".
|
10449
|
+
// Takes color string value as an argument and returns the type of that color format "hex", "rgb", "rgba".
|
10393
10450
|
getColorFormat : getColorFormat,
|
10394
|
-
|
10451
|
+
|
10395
10452
|
/* Parses a color string to and array of [red, green, blue, alpha].
|
10396
10453
|
* paramName: optional argument to parse color value directly from style string parameter
|
10397
10454
|
*
|
@@ -10731,7 +10788,7 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
10731
10788
|
if (!sel || (lastSibling === node && node.nodeType === 1 && win.getComputedStyle(node).display === "block")) {
|
10732
10789
|
if (notVisual) {
|
10733
10790
|
// If setAfter is used as internal between actions, self-removing caretPlaceholder has simpler implementation
|
10734
|
-
// and remove itself in call stack end instead on user interaction
|
10791
|
+
// and remove itself in call stack end instead on user interaction
|
10735
10792
|
var caretPlaceholder = this.doc.createTextNode(wysihtml.INVISIBLE_SPACE);
|
10736
10793
|
node.parentNode.insertBefore(caretPlaceholder, node.nextSibling);
|
10737
10794
|
this.selectNode(caretPlaceholder);
|
@@ -10898,11 +10955,11 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
10898
10955
|
this.deleteRangeContents(range);
|
10899
10956
|
this.setSelection(range);
|
10900
10957
|
},
|
10901
|
-
|
10958
|
+
|
10902
10959
|
// Makes sure all uneditable sare notified before deleting contents
|
10903
10960
|
deleteRangeContents: function (range) {
|
10904
10961
|
var startParent, endParent, uneditables, ev;
|
10905
|
-
|
10962
|
+
|
10906
10963
|
if (this.unselectableClass) {
|
10907
10964
|
if ((startParent = wysihtml.dom.getParentElement(range.startContainer, { query: "." + this.unselectableClass }, false, this.contain))) {
|
10908
10965
|
range.setStartBefore(startParent);
|
@@ -10998,7 +11055,7 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
10998
11055
|
if (r[0].startOffset === 0 && r[0].startContainer.previousSibling) {
|
10999
11056
|
caretNode = r[0].startContainer.previousSibling;
|
11000
11057
|
if (caretNode.nodeType === 3) {
|
11001
|
-
offset = caretNode.data.length;
|
11058
|
+
offset = caretNode.data.length;
|
11002
11059
|
}
|
11003
11060
|
} else {
|
11004
11061
|
caretNode = r[0].startContainer;
|
@@ -11033,6 +11090,22 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
11033
11090
|
},
|
11034
11091
|
|
11035
11092
|
getRangeToNodeEnd: function() {
|
11093
|
+
if (this.isCollapsed()) {
|
11094
|
+
var range = this.getRange(),
|
11095
|
+
sNode, pos, lastR;
|
11096
|
+
if (range) {
|
11097
|
+
sNode = range.startContainer;
|
11098
|
+
pos = range.startOffset;
|
11099
|
+
lastR = rangy.createRange(this.doc);
|
11100
|
+
|
11101
|
+
lastR.selectNodeContents(sNode);
|
11102
|
+
lastR.setStart(sNode, pos);
|
11103
|
+
return lastR;
|
11104
|
+
}
|
11105
|
+
}
|
11106
|
+
},
|
11107
|
+
|
11108
|
+
getRangeToNodeBeginning: function() {
|
11036
11109
|
if (this.isCollapsed()) {
|
11037
11110
|
var range = this.getRange(),
|
11038
11111
|
sNode = range.startContainer,
|
@@ -11040,18 +11113,36 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
11040
11113
|
lastR = rangy.createRange(this.doc);
|
11041
11114
|
|
11042
11115
|
lastR.selectNodeContents(sNode);
|
11043
|
-
lastR.
|
11116
|
+
lastR.setEnd(sNode, pos);
|
11044
11117
|
return lastR;
|
11045
11118
|
}
|
11046
11119
|
},
|
11047
11120
|
|
11048
|
-
|
11121
|
+
// This function returns if caret is last in a node (no textual visible content follows)
|
11122
|
+
caretIsInTheEndOfNode: function(ignoreIfSpaceIsBeforeCaret) {
|
11049
11123
|
var r = rangy.createRange(this.doc),
|
11050
11124
|
s = this.getSelection(),
|
11051
|
-
|
11052
|
-
endtxt
|
11053
|
-
|
11054
|
-
|
11125
|
+
rangeToNodeEnd = this.getRangeToNodeEnd(),
|
11126
|
+
endc, endtxt, beginc, begintxt;
|
11127
|
+
|
11128
|
+
if (rangeToNodeEnd) {
|
11129
|
+
endc = rangeToNodeEnd.cloneContents();
|
11130
|
+
endtxt = endc.textContent;
|
11131
|
+
|
11132
|
+
if ((/^\s*$/).test(endtxt)) {
|
11133
|
+
if (ignoreIfSpaceIsBeforeCaret) {
|
11134
|
+
beginc = this.getRangeToNodeBeginning().cloneContents();
|
11135
|
+
begintxt = beginc.textContent;
|
11136
|
+
return !(/[\u00A0 ][\s\uFEFF]*$/).test(begintxt);
|
11137
|
+
} else {
|
11138
|
+
return true;
|
11139
|
+
}
|
11140
|
+
} else {
|
11141
|
+
return false;
|
11142
|
+
}
|
11143
|
+
} else {
|
11144
|
+
return false;
|
11145
|
+
}
|
11055
11146
|
},
|
11056
11147
|
|
11057
11148
|
caretIsFirstInSelection: function(includeLineBreaks) {
|
@@ -11059,7 +11150,7 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
11059
11150
|
s = this.getSelection(),
|
11060
11151
|
range = this.getRange(),
|
11061
11152
|
startNode = getRangeNode(range.startContainer, range.startOffset);
|
11062
|
-
|
11153
|
+
|
11063
11154
|
if (startNode) {
|
11064
11155
|
if (startNode.nodeType === wysihtml.TEXT_NODE) {
|
11065
11156
|
if (!startNode.parentNode) {
|
@@ -11284,7 +11375,7 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
11284
11375
|
node = this.doc.createElement('DIV'),
|
11285
11376
|
fragment = this.doc.createDocumentFragment(),
|
11286
11377
|
lastChild, lastEditorElement;
|
11287
|
-
|
11378
|
+
|
11288
11379
|
if (range) {
|
11289
11380
|
range.deleteContents();
|
11290
11381
|
node.innerHTML = html;
|
@@ -11294,7 +11385,7 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
11294
11385
|
fragment.appendChild(node.firstChild);
|
11295
11386
|
}
|
11296
11387
|
range.insertNode(fragment);
|
11297
|
-
|
11388
|
+
|
11298
11389
|
lastEditorElement = this.contain.lastChild;
|
11299
11390
|
while (lastEditorElement && lastEditorElement.nodeType === 3 && lastEditorElement.previousSibling && (/^\s*$/).test(lastEditorElement.data)) {
|
11300
11391
|
lastEditorElement = lastEditorElement.previousSibling;
|
@@ -11320,6 +11411,7 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
11320
11411
|
insertNode: function(node) {
|
11321
11412
|
var range = this.getRange();
|
11322
11413
|
if (range) {
|
11414
|
+
range.deleteContents();
|
11323
11415
|
range.insertNode(node);
|
11324
11416
|
}
|
11325
11417
|
},
|
@@ -11464,7 +11556,7 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
11464
11556
|
this._selectLineUniversal();
|
11465
11557
|
}
|
11466
11558
|
},
|
11467
|
-
|
11559
|
+
|
11468
11560
|
includeRangyRangeHelpers: function() {
|
11469
11561
|
var s = this.getSelection(),
|
11470
11562
|
r = s.getRangeAt(0),
|
@@ -11480,7 +11572,7 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
11480
11572
|
},
|
11481
11573
|
anode = s.anchorNode.nodeType === 1 ? s.anchorNode.childNodes[s.anchorOffset] : s.anchorNode,
|
11482
11574
|
fnode = s.focusNode.nodeType === 1 ? s.focusNode.childNodes[s.focusOffset] : s.focusNode;
|
11483
|
-
|
11575
|
+
|
11484
11576
|
if (fnode && s.focusOffset === getNodeLength(fnode) && fnode.nextSibling && isHelperNode(fnode.nextSibling)) {
|
11485
11577
|
r.setEndAfter(fnode.nextSibling);
|
11486
11578
|
}
|
@@ -11496,10 +11588,10 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
11496
11588
|
_selectLine_W3C: function() {
|
11497
11589
|
var selection = this.win.getSelection(),
|
11498
11590
|
initialBoundry = [selection.anchorNode, selection.anchorOffset, selection.focusNode, selection.focusOffset];
|
11499
|
-
|
11591
|
+
|
11500
11592
|
selection.modify("move", "left", "lineboundary");
|
11501
11593
|
selection.modify("extend", "right", "lineboundary");
|
11502
|
-
|
11594
|
+
|
11503
11595
|
// IF lineboundary extending did not change selection try universal fallback (FF fails sometimes without a reason)
|
11504
11596
|
if (selection.anchorNode === initialBoundry[0] &&
|
11505
11597
|
selection.anchorOffset === initialBoundry[1] &&
|
@@ -11601,14 +11693,14 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
11601
11693
|
if (!r.collapsed) {
|
11602
11694
|
r.insertNode(this.doc.createTextNode(wysihtml.INVISIBLE_SPACE));
|
11603
11695
|
}
|
11604
|
-
|
11696
|
+
|
11605
11697
|
// Is probably just empty line as can not be expanded
|
11606
11698
|
rect = r.nativeRange.getBoundingClientRect();
|
11607
11699
|
// If startnode is not line break allready move the start position of range by -1 character until clientRect top changes;
|
11608
11700
|
do {
|
11609
11701
|
amount = r.moveStart('character', -1);
|
11610
11702
|
testRect = r.nativeRange.getBoundingClientRect();
|
11611
|
-
|
11703
|
+
|
11612
11704
|
if (!testRect || Math.floor(testRect.top) !== Math.floor(rect.top)) {
|
11613
11705
|
r.moveStart('character', 1);
|
11614
11706
|
found = true;
|
@@ -11618,7 +11710,7 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
11618
11710
|
count = 0;
|
11619
11711
|
found = false;
|
11620
11712
|
rect = r.nativeRange.getBoundingClientRect();
|
11621
|
-
|
11713
|
+
|
11622
11714
|
if (r.endContainer !== this.contain || (this.contain.lastChild && this.contain.childNodes[r.endOffset] !== this.contain.lastChild)) {
|
11623
11715
|
do {
|
11624
11716
|
amount = r.moveEnd('character', 1);
|
@@ -11812,7 +11904,7 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
11812
11904
|
|
11813
11905
|
wysihtml.dom.removeInvisibleSpaces(this.composer.element);
|
11814
11906
|
doSelect();
|
11815
|
-
|
11907
|
+
|
11816
11908
|
if (this.composer.element.firstChild && notSelected()) {
|
11817
11909
|
// Try fixing end
|
11818
11910
|
this.composer.element.appendChild(blankEndNode);
|
@@ -11821,11 +11913,11 @@ wysihtml.quirks.ensureProperClearing = (function() {
|
|
11821
11913
|
if (notSelected()) {
|
11822
11914
|
// Remove end fix
|
11823
11915
|
blankEndNode.parentNode.removeChild(blankEndNode);
|
11824
|
-
|
11916
|
+
|
11825
11917
|
// Try fixing beginning
|
11826
11918
|
this.composer.element.insertBefore(blankStartNode, this.composer.element.firstChild);
|
11827
11919
|
doSelect();
|
11828
|
-
|
11920
|
+
|
11829
11921
|
if (notSelected()) {
|
11830
11922
|
// Try fixing both
|
11831
11923
|
this.composer.element.appendChild(blankEndNode);
|
@@ -11960,7 +12052,7 @@ wysihtml.Commands = Base.extend(
|
|
11960
12052
|
result = null;
|
11961
12053
|
|
11962
12054
|
// If composer ahs placeholder unset it before command
|
11963
|
-
// Do not apply on commands that are behavioral
|
12055
|
+
// Do not apply on commands that are behavioral
|
11964
12056
|
if (this.composer.hasPlaceholderSet() && !wysihtml.lang.array(['styleWithCSS', 'enableObjectResizing', 'enableInlineTableEditing']).contains(command)) {
|
11965
12057
|
this.composer.element.innerHTML = "";
|
11966
12058
|
this.composer.selection.selectNode(this.composer.element);
|
@@ -12065,9 +12157,9 @@ wysihtml.Commands = Base.extend(
|
|
12065
12157
|
})(wysihtml);
|
12066
12158
|
|
12067
12159
|
/* Formatblock
|
12068
|
-
* Is used to insert block level elements
|
12160
|
+
* Is used to insert block level elements
|
12069
12161
|
* It tries to solve the case that some block elements should not contain other block level elements (h1-6, p, ...)
|
12070
|
-
*
|
12162
|
+
*
|
12071
12163
|
*/
|
12072
12164
|
(function(wysihtml) {
|
12073
12165
|
|
@@ -12135,7 +12227,7 @@ wysihtml.Commands = Base.extend(
|
|
12135
12227
|
elements[i].parentNode.removeChild(elements[i]);
|
12136
12228
|
}
|
12137
12229
|
}
|
12138
|
-
|
12230
|
+
|
12139
12231
|
return newBlockElements;
|
12140
12232
|
}
|
12141
12233
|
|
@@ -12147,7 +12239,7 @@ wysihtml.Commands = Base.extend(
|
|
12147
12239
|
function findOuterBlock(node, container, allBlocks) {
|
12148
12240
|
var n = node,
|
12149
12241
|
block = null;
|
12150
|
-
|
12242
|
+
|
12151
12243
|
while (n && container && n !== container) {
|
12152
12244
|
if (n.nodeType === 1 && n.matches(allBlocks ? BLOCK_ELEMENTS : UNNESTABLE_BLOCK_ELEMENTS)) {
|
12153
12245
|
block = n;
|
@@ -12272,7 +12364,7 @@ wysihtml.Commands = Base.extend(
|
|
12272
12364
|
for (var i = blocks.length; i--;) {
|
12273
12365
|
nextEl = wysihtml.dom.domNode(blocks[i]).next({nodeTypes: [1,3], ignoreBlankTexts: true}),
|
12274
12366
|
prevEl = wysihtml.dom.domNode(blocks[i]).prev({nodeTypes: [1,3], ignoreBlankTexts: true});
|
12275
|
-
|
12367
|
+
|
12276
12368
|
if (nextEl && nextEl.nodeType !== 1 && nextEl.nodeName !== 'BR') {
|
12277
12369
|
if ((blocks[i].innerHTML || blocks[i].nodeValue || '').trim() !== '') {
|
12278
12370
|
blocks[i].parentNode.insertBefore(blocks[i].ownerDocument.createElement('BR'), nextEl);
|
@@ -12314,7 +12406,7 @@ wysihtml.Commands = Base.extend(
|
|
12314
12406
|
}
|
12315
12407
|
return;
|
12316
12408
|
}
|
12317
|
-
|
12409
|
+
|
12318
12410
|
// If range ends outside of node and starts inside at textrange and covers the whole node visually, extend start to cover the node start too
|
12319
12411
|
if (end && end.nodeType === 1 && start.nodeType === 3) {
|
12320
12412
|
if (end.firstChild === start && range.startOffset === 0) {
|
@@ -12325,7 +12417,7 @@ wysihtml.Commands = Base.extend(
|
|
12325
12417
|
return;
|
12326
12418
|
}
|
12327
12419
|
|
12328
|
-
// If range covers a whole textnode and the textnode is the only child of node, extend range to node
|
12420
|
+
// If range covers a whole textnode and the textnode is the only child of node, extend range to node
|
12329
12421
|
if (start && start.nodeType === 3 && start === end && start.parentNode.childNodes.length === 1) {
|
12330
12422
|
if (range.endOffset == end.data.length && range.startOffset === 0) {
|
12331
12423
|
node = start.parentNode;
|
@@ -12337,16 +12429,16 @@ wysihtml.Commands = Base.extend(
|
|
12337
12429
|
return;
|
12338
12430
|
}
|
12339
12431
|
}
|
12340
|
-
|
12432
|
+
|
12341
12433
|
// Scans ranges array for insertion points that are not allowed to insert block tags fixes/splits illegal ranges
|
12342
12434
|
// Some places do not allow block level elements inbetween (inside ul and outside li)
|
12343
12435
|
// TODO: might need extending for other nodes besides li (maybe dd,dl,dt)
|
12344
12436
|
function fixNotPermittedInsertionPoints(ranges) {
|
12345
12437
|
var newRanges = [],
|
12346
12438
|
lis, j, maxj, tmpRange, rangePos, closestLI;
|
12347
|
-
|
12439
|
+
|
12348
12440
|
for (var i = 0, maxi = ranges.length; i < maxi; i++) {
|
12349
|
-
|
12441
|
+
|
12350
12442
|
// Fixes range start and end positions if inside UL or OL element (outside of LI)
|
12351
12443
|
if (ranges[i].startContainer.nodeType === 1 && ranges[i].startContainer.matches('ul, ol')) {
|
12352
12444
|
ranges[i].setStart(ranges[i].startContainer.childNodes[ranges[i].startOffset], 0);
|
@@ -12366,7 +12458,7 @@ wysihtml.Commands = Base.extend(
|
|
12366
12458
|
return node.nodeName === "LI";
|
12367
12459
|
});
|
12368
12460
|
if (lis.length > 0) {
|
12369
|
-
|
12461
|
+
|
12370
12462
|
for (j = 0, maxj = lis.length; j < maxj; j++) {
|
12371
12463
|
rangePos = ranges[i].compareNode(lis[j]);
|
12372
12464
|
|
@@ -12376,7 +12468,7 @@ wysihtml.Commands = Base.extend(
|
|
12376
12468
|
|
12377
12469
|
tmpRange = ranges[i].cloneRange();
|
12378
12470
|
closestLI = wysihtml.dom.domNode(lis[j]).prev({nodeTypes: [1]});
|
12379
|
-
|
12471
|
+
|
12380
12472
|
if (closestLI) {
|
12381
12473
|
tmpRange.setEnd(closestLI, closestLI.childNodes.length);
|
12382
12474
|
} else if (lis[j].closest('ul, ol')) {
|
@@ -12387,16 +12479,16 @@ wysihtml.Commands = Base.extend(
|
|
12387
12479
|
newRanges.push(tmpRange);
|
12388
12480
|
ranges[i].setStart(lis[j], 0);
|
12389
12481
|
}
|
12390
|
-
|
12482
|
+
|
12391
12483
|
// Fixes end of range that crosses li border
|
12392
12484
|
if (rangePos === ranges[i].NODE_BEFORE || rangePos === ranges[i].NODE_INSIDE) {
|
12393
12485
|
// Range starts inside the node and ends after node
|
12394
|
-
|
12486
|
+
|
12395
12487
|
tmpRange = ranges[i].cloneRange();
|
12396
12488
|
tmpRange.setEnd(lis[j], lis[j].childNodes.length);
|
12397
12489
|
newRanges.push(tmpRange);
|
12398
|
-
|
12399
|
-
// Find next LI in list and if present set range to it, else
|
12490
|
+
|
12491
|
+
// Find next LI in list and if present set range to it, else
|
12400
12492
|
closestLI = wysihtml.dom.domNode(lis[j]).next({nodeTypes: [1]});
|
12401
12493
|
if (closestLI) {
|
12402
12494
|
ranges[i].setStart(closestLI, 0);
|
@@ -12404,7 +12496,7 @@ wysihtml.Commands = Base.extend(
|
|
12404
12496
|
ranges[i].setStartAfter(lis[j].closest('ul, ol'));
|
12405
12497
|
} else {
|
12406
12498
|
ranges[i].setStartAfter(lis[j]);
|
12407
|
-
}
|
12499
|
+
}
|
12408
12500
|
}
|
12409
12501
|
}
|
12410
12502
|
newRanges.push(ranges[i]);
|
@@ -12414,17 +12506,17 @@ wysihtml.Commands = Base.extend(
|
|
12414
12506
|
}
|
12415
12507
|
return newRanges;
|
12416
12508
|
}
|
12417
|
-
|
12509
|
+
|
12418
12510
|
// Return options object with nodeName set if original did not have any
|
12419
12511
|
// Node name is set to local or global default
|
12420
12512
|
function getOptionsWithNodename(options, defaultName, composer) {
|
12421
12513
|
var correctedOptions = (options) ? wysihtml.lang.object(options).clone(true) : null;
|
12422
|
-
if (correctedOptions) {
|
12514
|
+
if (correctedOptions) {
|
12423
12515
|
correctedOptions.nodeName = correctedOptions.nodeName || defaultName || defaultNodeName(composer);
|
12424
12516
|
}
|
12425
12517
|
return correctedOptions;
|
12426
12518
|
}
|
12427
|
-
|
12519
|
+
|
12428
12520
|
// Injects document fragment to range ensuring outer elements are split to a place where block elements are allowed to be inserted
|
12429
12521
|
// Also wraps empty clones of split parent tags around fragment to keep formatting
|
12430
12522
|
// If firstOuterBlock is given assume that instead of finding outer (useful for solving cases of some blocks are allowed into others while others are not)
|
@@ -12432,7 +12524,7 @@ wysihtml.Commands = Base.extend(
|
|
12432
12524
|
var rangeStartContainer = range.startContainer,
|
12433
12525
|
firstOuterBlock = firstOuterBlock || findOuterBlock(rangeStartContainer, composer.element, true),
|
12434
12526
|
outerInlines, first, last, prev, next;
|
12435
|
-
|
12527
|
+
|
12436
12528
|
if (firstOuterBlock) {
|
12437
12529
|
// If selection starts inside un-nestable block, split-escape the unnestable point and insert node between
|
12438
12530
|
first = fragment.firstChild;
|
@@ -12473,7 +12565,7 @@ wysihtml.Commands = Base.extend(
|
|
12473
12565
|
}
|
12474
12566
|
}
|
12475
12567
|
}
|
12476
|
-
|
12568
|
+
|
12477
12569
|
// Removes all block formatting from range
|
12478
12570
|
function clearRangeBlockFromating(range, closestBlockName, composer) {
|
12479
12571
|
var r = range.cloneRange(),
|
@@ -12483,16 +12575,16 @@ wysihtml.Commands = Base.extend(
|
|
12483
12575
|
fragment = composer.doc.createDocumentFragment(),
|
12484
12576
|
children, blocks,
|
12485
12577
|
first = true;
|
12486
|
-
|
12578
|
+
|
12487
12579
|
while(content.firstChild) {
|
12488
12580
|
// Iterate over all selection content first level childNodes
|
12489
12581
|
if (content.firstChild.nodeType === 1 && content.firstChild.matches(BLOCK_ELEMENTS)) {
|
12490
12582
|
// If node is a block element
|
12491
12583
|
// Split block formating and add new block to wrap caret
|
12492
|
-
|
12584
|
+
|
12493
12585
|
unwrapBlocksFromContent(content.firstChild);
|
12494
12586
|
children = wysihtml.dom.unwrap(content.firstChild);
|
12495
|
-
|
12587
|
+
|
12496
12588
|
// Add line break before if needed
|
12497
12589
|
if (children.length > 0) {
|
12498
12590
|
if (
|
@@ -12502,11 +12594,11 @@ wysihtml.Commands = Base.extend(
|
|
12502
12594
|
fragment.appendChild(composer.doc.createElement('BR'));
|
12503
12595
|
}
|
12504
12596
|
}
|
12505
|
-
|
12597
|
+
|
12506
12598
|
for (var c = 0, cmax = children.length; c < cmax; c++) {
|
12507
12599
|
fragment.appendChild(children[c]);
|
12508
12600
|
}
|
12509
|
-
|
12601
|
+
|
12510
12602
|
// Add line break after if needed
|
12511
12603
|
if (children.length > 0) {
|
12512
12604
|
if (fragment.lastChild.nodeType !== 1 || !isLineBreaking(fragment.lastChild, composer)) {
|
@@ -12515,18 +12607,18 @@ wysihtml.Commands = Base.extend(
|
|
12515
12607
|
}
|
12516
12608
|
}
|
12517
12609
|
}
|
12518
|
-
|
12610
|
+
|
12519
12611
|
} else {
|
12520
12612
|
fragment.appendChild(content.firstChild);
|
12521
12613
|
}
|
12522
|
-
|
12614
|
+
|
12523
12615
|
first = false;
|
12524
12616
|
}
|
12525
12617
|
blocks = wysihtml.lang.array(fragment.childNodes).get();
|
12526
12618
|
injectFragmentToRange(fragment, r, composer);
|
12527
12619
|
return blocks;
|
12528
12620
|
}
|
12529
|
-
|
12621
|
+
|
12530
12622
|
// When block node is inserted, look surrounding nodes and remove surplous linebreak tags (as block format breaks line itself)
|
12531
12623
|
function removeSurroundingLineBreaks(prevNode, nextNode, composer) {
|
12532
12624
|
var prevPrev = prevNode && wysihtml.dom.domNode(prevNode).prev({nodeTypes: [1,3], ignoreBlankTexts: true});
|
@@ -12629,25 +12721,25 @@ wysihtml.Commands = Base.extend(
|
|
12629
12721
|
trimBlankTextsAndBreaks(content);
|
12630
12722
|
|
12631
12723
|
if (options && options.nodeName === "BLOCKQUOTE") {
|
12632
|
-
|
12724
|
+
|
12633
12725
|
// If blockquote is to be inserted no quessing just add it as outermost block on line or selection
|
12634
12726
|
var tmpEl = applyOptionsToElement(null, options, composer);
|
12635
12727
|
tmpEl.appendChild(content);
|
12636
12728
|
fragment.appendChild(tmpEl);
|
12637
12729
|
blocks = [tmpEl];
|
12638
|
-
|
12730
|
+
|
12639
12731
|
} else {
|
12640
12732
|
|
12641
12733
|
if (!content.firstChild) {
|
12642
|
-
// IF selection is caret (can happen if line is empty) add format around tag
|
12734
|
+
// IF selection is caret (can happen if line is empty) add format around tag
|
12643
12735
|
fragment.appendChild(applyOptionsToElement(null, options, composer));
|
12644
12736
|
} else {
|
12645
12737
|
|
12646
12738
|
while(content.firstChild) {
|
12647
12739
|
// Iterate over all selection content first level childNodes
|
12648
|
-
|
12740
|
+
|
12649
12741
|
if (content.firstChild.nodeType == 1 && content.firstChild.matches(BLOCK_ELEMENTS)) {
|
12650
|
-
|
12742
|
+
|
12651
12743
|
// If node is a block element
|
12652
12744
|
// Escape(split) block formatting at caret
|
12653
12745
|
applyOptionsToElement(content.firstChild, options, composer);
|
@@ -12655,9 +12747,9 @@ wysihtml.Commands = Base.extend(
|
|
12655
12747
|
unwrapBlocksFromContent(content.firstChild);
|
12656
12748
|
}
|
12657
12749
|
fragment.appendChild(content.firstChild);
|
12658
|
-
|
12750
|
+
|
12659
12751
|
} else {
|
12660
|
-
|
12752
|
+
|
12661
12753
|
// Wrap subsequent non-block nodes inside new block element
|
12662
12754
|
wrapper = applyOptionsToElement(null, getOptionsWithNodename(options, closestBlockName, composer), composer);
|
12663
12755
|
while(content.firstChild && (content.firstChild.nodeType !== 1 || !content.firstChild.matches(BLOCK_ELEMENTS))) {
|
@@ -12696,7 +12788,7 @@ wysihtml.Commands = Base.extend(
|
|
12696
12788
|
|
12697
12789
|
return (parentNode) ? parentNode.nodeName : null;
|
12698
12790
|
}
|
12699
|
-
|
12791
|
+
|
12700
12792
|
// Expands caret to cover the closest block that:
|
12701
12793
|
// * cannot contain other block level elements (h1-6,p, etc)
|
12702
12794
|
// * Has the same nodeName that is to be inserted
|
@@ -12718,7 +12810,7 @@ wysihtml.Commands = Base.extend(
|
|
12718
12810
|
composer.selection.selectLine();
|
12719
12811
|
}
|
12720
12812
|
}
|
12721
|
-
|
12813
|
+
|
12722
12814
|
// Set selection to begin inside first created block element (beginning of it) and end inside (and after content) of last block element
|
12723
12815
|
// TODO: Checking nodetype might be unnescescary as nodes inserted by formatBlock are nodetype 1 anyway
|
12724
12816
|
function selectElements(newBlockElements, composer) {
|
@@ -12730,18 +12822,18 @@ wysihtml.Commands = Base.extend(
|
|
12730
12822
|
range.setEnd(lastEl, lastOffset);
|
12731
12823
|
range.select();
|
12732
12824
|
}
|
12733
|
-
|
12825
|
+
|
12734
12826
|
// Get all ranges from selection (takes out uneditables and out of editor parts) and apply format to each
|
12735
|
-
// Return created/modified block level elements
|
12827
|
+
// Return created/modified block level elements
|
12736
12828
|
// Method can be either "apply" or "remove"
|
12737
12829
|
function formatSelection(method, composer, options) {
|
12738
12830
|
var ranges = composer.selection.getOwnRanges(),
|
12739
12831
|
newBlockElements = [],
|
12740
12832
|
closestBlockName;
|
12741
|
-
|
12833
|
+
|
12742
12834
|
// Some places do not allow block level elements inbetween (inside ul and outside li, inside table and outside of td/th)
|
12743
12835
|
ranges = fixNotPermittedInsertionPoints(ranges);
|
12744
|
-
|
12836
|
+
|
12745
12837
|
for (var i = ranges.length; i--;) {
|
12746
12838
|
fixRangeCoverage(ranges[i], composer);
|
12747
12839
|
closestBlockName = getParentBlockNodeName(ranges[i].startContainer, composer);
|
@@ -12753,8 +12845,8 @@ wysihtml.Commands = Base.extend(
|
|
12753
12845
|
}
|
12754
12846
|
return newBlockElements;
|
12755
12847
|
}
|
12756
|
-
|
12757
|
-
// If properties is passed as a string, look for tag with that tagName/query
|
12848
|
+
|
12849
|
+
// If properties is passed as a string, look for tag with that tagName/query
|
12758
12850
|
function parseOptions(options) {
|
12759
12851
|
if (typeof options === "string") {
|
12760
12852
|
options = {
|
@@ -12821,13 +12913,13 @@ wysihtml.Commands = Base.extend(
|
|
12821
12913
|
// Options == null means block formatting should be removed from selection
|
12822
12914
|
newBlockElements = formatSelection("remove", composer);
|
12823
12915
|
}
|
12824
|
-
|
12916
|
+
|
12825
12917
|
}
|
12826
12918
|
|
12827
12919
|
// Remove empty block elements that may be left behind
|
12828
12920
|
// Also remove them from new blocks list
|
12829
12921
|
newBlockElements = cleanup(composer, newBlockElements);
|
12830
|
-
|
12922
|
+
|
12831
12923
|
// Restore selection
|
12832
12924
|
if (bookmark) {
|
12833
12925
|
rangy.restoreSelection(bookmark);
|
@@ -12835,21 +12927,21 @@ wysihtml.Commands = Base.extend(
|
|
12835
12927
|
selectElements(newBlockElements, composer);
|
12836
12928
|
}
|
12837
12929
|
},
|
12838
|
-
|
12930
|
+
|
12839
12931
|
// Removes all block formatting from selection
|
12840
12932
|
remove: function(composer, command, options) {
|
12841
12933
|
options = parseOptions(options);
|
12842
12934
|
var newBlockElements, bookmark;
|
12843
|
-
|
12935
|
+
|
12844
12936
|
// If selection is caret expand it to cover nearest suitable block element or row if none found
|
12845
12937
|
if (composer.selection.isCollapsed()) {
|
12846
12938
|
bookmark = rangy.saveSelection(composer.win);
|
12847
12939
|
expandCaretToBlock(composer, options && options.nodeName ? options.nodeName.toUpperCase() : undefined);
|
12848
12940
|
}
|
12849
|
-
|
12941
|
+
|
12850
12942
|
newBlockElements = formatSelection("remove", composer);
|
12851
12943
|
newBlockElements = cleanup(composer, newBlockElements);
|
12852
|
-
|
12944
|
+
|
12853
12945
|
// Restore selection
|
12854
12946
|
if (bookmark) {
|
12855
12947
|
rangy.restoreSelection(bookmark);
|
@@ -12989,7 +13081,7 @@ wysihtml.Commands = Base.extend(
|
|
12989
13081
|
}
|
12990
13082
|
|
12991
13083
|
// If attrbutes and values are the same > remove
|
12992
|
-
// if attributes or values
|
13084
|
+
// if attributes or values
|
12993
13085
|
function updateElementAttributes(element, newAttributes, toggle) {
|
12994
13086
|
var attr = wysihtml.dom.getAttributes(element),
|
12995
13087
|
fullContain = containsSameAttributes(newAttributes, attr),
|
@@ -13063,7 +13155,7 @@ wysihtml.Commands = Base.extend(
|
|
13063
13155
|
// Handle similar semantically same elements (queryAliasMap)
|
13064
13156
|
nodeNameQuery = options.nodeName ? queryAliasMap[options.nodeName.toLowerCase()] || options.nodeName.toLowerCase() : null;
|
13065
13157
|
nodeQueryMatch = nodeNameQuery ? wysihtml.dom.domNode(element).test({ query: nodeNameQuery }) : false;
|
13066
|
-
|
13158
|
+
|
13067
13159
|
// Unwrap element if no attributes present and node name given
|
13068
13160
|
// or no attributes and if no nodename set but node is the default
|
13069
13161
|
if (!options.nodeName || options.nodeName === defaultTag || nodeQueryMatch) {
|
@@ -13136,7 +13228,7 @@ wysihtml.Commands = Base.extend(
|
|
13136
13228
|
selection = rangy.getSelection(composer.win);
|
13137
13229
|
|
13138
13230
|
rangy.getSelection(composer.win).removeAllRanges();
|
13139
|
-
|
13231
|
+
|
13140
13232
|
// IE looses focus of contenteditable on removeallranges and can not set new selection unless contenteditable is focused again
|
13141
13233
|
try {
|
13142
13234
|
rangy.getSelection(composer.win).addRange(range);
|
@@ -13158,7 +13250,7 @@ wysihtml.Commands = Base.extend(
|
|
13158
13250
|
range.setEnd(lastText, lastText.length);
|
13159
13251
|
selectRange(composer, range);
|
13160
13252
|
}
|
13161
|
-
|
13253
|
+
|
13162
13254
|
}
|
13163
13255
|
|
13164
13256
|
function selectTextNode(composer, node, start, end) {
|
@@ -13210,7 +13302,7 @@ wysihtml.Commands = Base.extend(
|
|
13210
13302
|
}
|
13211
13303
|
|
13212
13304
|
}
|
13213
|
-
|
13305
|
+
|
13214
13306
|
return {
|
13215
13307
|
nodes: nodes,
|
13216
13308
|
partial: partial
|
@@ -13234,7 +13326,7 @@ wysihtml.Commands = Base.extend(
|
|
13234
13326
|
}
|
13235
13327
|
|
13236
13328
|
// Returns a range and textnode containing object from caret position covering a whole word
|
13237
|
-
// wordOffsety describes the original position of caret in the new textNode
|
13329
|
+
// wordOffsety describes the original position of caret in the new textNode
|
13238
13330
|
// Caret has to be inside a textNode.
|
13239
13331
|
function getRangeForWord(selection) {
|
13240
13332
|
var anchor, offset, doc, range, offsetStart, offsetEnd, beforeChar, afterChar,
|
@@ -13282,7 +13374,7 @@ wysihtml.Commands = Base.extend(
|
|
13282
13374
|
|
13283
13375
|
function mergeConsequentSimilarElements(elements) {
|
13284
13376
|
for (var i = elements.length; i--;) {
|
13285
|
-
|
13377
|
+
|
13286
13378
|
if (elements[i] && elements[i].parentNode) { // Test if node is not allready removed in cleanup
|
13287
13379
|
|
13288
13380
|
if (elements[i].nextSibling && isSameNode(elements[i], elements[i].nextSibling)) {
|
@@ -13366,7 +13458,7 @@ wysihtml.Commands = Base.extend(
|
|
13366
13458
|
if (options.toggle !== false) {
|
13367
13459
|
if (caretIsInsideWord(selection)) {
|
13368
13460
|
|
13369
|
-
// Unformat whole word
|
13461
|
+
// Unformat whole word
|
13370
13462
|
wordObj = getRangeForWord(selection);
|
13371
13463
|
textNode = wordObj.textNode;
|
13372
13464
|
unformatTextNode(wordObj.textNode, composer, options);
|
@@ -13408,13 +13500,13 @@ wysihtml.Commands = Base.extend(
|
|
13408
13500
|
}
|
13409
13501
|
|
13410
13502
|
} else {
|
13411
|
-
|
13503
|
+
|
13412
13504
|
// Selection is partially in format
|
13413
13505
|
// change it to new if format if textnode allreafy in similar state
|
13414
13506
|
// else just apply
|
13415
|
-
|
13507
|
+
|
13416
13508
|
for (i = textNodes.length; i--;) {
|
13417
|
-
|
13509
|
+
|
13418
13510
|
if (findSimilarTextNodeWrapper(textNodes[i], options, composer.element)) {
|
13419
13511
|
unformatTextNode(textNodes[i], composer, options);
|
13420
13512
|
}
|
@@ -13435,7 +13527,7 @@ wysihtml.Commands = Base.extend(
|
|
13435
13527
|
var textNode, textOffset, newNode, i,
|
13436
13528
|
selection = composer.selection.getSelection();
|
13437
13529
|
|
13438
|
-
if (!textNodes.length) {
|
13530
|
+
if (!textNodes.length) {
|
13439
13531
|
textNode = selection.anchorNode;
|
13440
13532
|
textOffset = selection.anchorOffset;
|
13441
13533
|
|
@@ -13456,7 +13548,7 @@ wysihtml.Commands = Base.extend(
|
|
13456
13548
|
function applyFormat(composer, textNodes, options) {
|
13457
13549
|
var wordObj, i,
|
13458
13550
|
selection = composer.selection.getSelection();
|
13459
|
-
|
13551
|
+
|
13460
13552
|
if (!textNodes.length) {
|
13461
13553
|
// Handle collapsed selection caret and return
|
13462
13554
|
if (caretIsInsideWord(selection)) {
|
@@ -13471,7 +13563,7 @@ wysihtml.Commands = Base.extend(
|
|
13471
13563
|
formatTextRange(r, composer, options);
|
13472
13564
|
}
|
13473
13565
|
}
|
13474
|
-
|
13566
|
+
|
13475
13567
|
} else {
|
13476
13568
|
// Handle textnodes in selection and apply format
|
13477
13569
|
for (i = textNodes.length; i--;) {
|
@@ -13480,7 +13572,7 @@ wysihtml.Commands = Base.extend(
|
|
13480
13572
|
cleanupAndSetSelection(composer, textNodes, options);
|
13481
13573
|
}
|
13482
13574
|
}
|
13483
|
-
|
13575
|
+
|
13484
13576
|
// If properties is passed as a string, correct options with that nodeName
|
13485
13577
|
function fixOptions(options) {
|
13486
13578
|
options = (typeof options === "string") ? { nodeName: options } : options;
|
@@ -13523,7 +13615,7 @@ wysihtml.Commands = Base.extend(
|
|
13523
13615
|
// Text allready has the format applied
|
13524
13616
|
removeFormat(composer, textNodes, state, options);
|
13525
13617
|
}
|
13526
|
-
|
13618
|
+
|
13527
13619
|
composer.element.normalize();
|
13528
13620
|
},
|
13529
13621
|
|
@@ -14849,7 +14941,7 @@ wysihtml.views.View = Base.extend(
|
|
14849
14941
|
|
14850
14942
|
// --------- restore focus ---------
|
14851
14943
|
if (originalActiveElement) {
|
14852
|
-
originalActiveElement
|
14944
|
+
focusWithoutScrolling(originalActiveElement);
|
14853
14945
|
} else {
|
14854
14946
|
textareaElement.blur();
|
14855
14947
|
}
|
@@ -14925,7 +15017,7 @@ wysihtml.views.View = Base.extend(
|
|
14925
15017
|
|
14926
15018
|
// Override for giving user ability to delete last line break in table cell
|
14927
15019
|
fixLastBrDeletionInTable: function(composer, force) {
|
14928
|
-
if (composer.selection.
|
15020
|
+
if (composer.selection.caretIsInTheEndOfNode()) {
|
14929
15021
|
var sel = composer.selection.getSelection(),
|
14930
15022
|
aNode = sel.anchorNode;
|
14931
15023
|
if (aNode && aNode.nodeType === 1 && (wysihtml.dom.getParentElement(aNode, {query: 'td, th'}, false, composer.element) || force)) {
|
@@ -15191,6 +15283,18 @@ wysihtml.views.View = Base.extend(
|
|
15191
15283
|
}
|
15192
15284
|
}
|
15193
15285
|
}
|
15286
|
+
|
15287
|
+
if (browser.hasCaretAtLinkEndInsertionProblems() && composer.selection.caretIsInTheEndOfNode()) {
|
15288
|
+
var target = composer.selection.getSelectedNode(true),
|
15289
|
+
targetEl = (target && target.nodeType === 3) ? target.parentNode : target, // target guaranteed to be an Element
|
15290
|
+
invisibleSpace, space;
|
15291
|
+
|
15292
|
+
if (targetEl && targetEl.closest('a') && target.nodeType === 3 && target === targetEl.lastChild) {
|
15293
|
+
// Seems like enter was pressed and caret was at the end of link node
|
15294
|
+
// This means user wants to escape the link now (caret is last in link node too).
|
15295
|
+
composer.selection.setAfter(targetEl);
|
15296
|
+
}
|
15297
|
+
}
|
15194
15298
|
};
|
15195
15299
|
|
15196
15300
|
var handleTabKeyDown = function(composer, element, shiftKey) {
|
@@ -15335,7 +15439,9 @@ wysihtml.views.View = Base.extend(
|
|
15335
15439
|
var handleKeyDown = function(event) {
|
15336
15440
|
var keyCode = event.keyCode,
|
15337
15441
|
command = shortcuts[keyCode],
|
15338
|
-
target,
|
15442
|
+
target = this.selection.getSelectedNode(true),
|
15443
|
+
targetEl = (target && target.nodeType === 3) ? target.parentNode : target, // target guaranteed to be an Element
|
15444
|
+
parent;
|
15339
15445
|
|
15340
15446
|
// Select all (meta/ctrl + a)
|
15341
15447
|
if ((event.ctrlKey || event.metaKey) && !event.altKey && keyCode === 65) {
|
@@ -15357,7 +15463,6 @@ wysihtml.views.View = Base.extend(
|
|
15357
15463
|
|
15358
15464
|
// Make sure that when pressing backspace/delete on selected images deletes the image and it's anchor
|
15359
15465
|
if (keyCode === wysihtml.BACKSPACE_KEY || keyCode === wysihtml.DELETE_KEY) {
|
15360
|
-
target = this.selection.getSelectedNode(true);
|
15361
15466
|
if (target && target.nodeName === "IMG") {
|
15362
15467
|
event.preventDefault();
|
15363
15468
|
parent = target.parentNode;
|
@@ -15384,6 +15489,64 @@ wysihtml.views.View = Base.extend(
|
|
15384
15489
|
|
15385
15490
|
};
|
15386
15491
|
|
15492
|
+
var handleKeyPress = function(event) {
|
15493
|
+
|
15494
|
+
// This block should run only if some character is inserted (nor command keys like delete, backspace, enter, etc.)
|
15495
|
+
if (event.which !== 0) {
|
15496
|
+
|
15497
|
+
// Test if caret is last in a link in webkit and try to fix webkit problem,
|
15498
|
+
// that all inserted content is added outside of link.
|
15499
|
+
// This issue was added as a not thought through fix for getting caret after link in contenteditable if it is last in editable area.
|
15500
|
+
// Allthough it fixes this minor case it actually introduces a cascade of problems when editing links.
|
15501
|
+
// The standard approachi in other wysiwygs seems as a step backwards - introducing a separate modal for managing links content text.
|
15502
|
+
// I find it to be too big of a tradeoff in terms of expected simple UI flow, thus trying to fight against it.
|
15503
|
+
// Also adds link escaping by double space with caret at the end of link for all browsers
|
15504
|
+
|
15505
|
+
if (this.selection.caretIsInTheEndOfNode()) {
|
15506
|
+
var target = this.selection.getSelectedNode(true),
|
15507
|
+
targetEl = (target && target.nodeType === 3) ? target.parentNode : target, // target guaranteed to be an Element
|
15508
|
+
invisibleSpace, space;
|
15509
|
+
|
15510
|
+
if (targetEl && targetEl.closest('a') && target === targetEl.lastChild) {
|
15511
|
+
|
15512
|
+
if (event.which !== 32 || this.selection.caretIsInTheEndOfNode(true) && browser.hasCaretAtLinkEndInsertionProblems()) {
|
15513
|
+
// Executed if there is no whitespace before caret in textnode in case of pressing space.
|
15514
|
+
// Whitespace before marks that user wants to escape the node by pressing double space.
|
15515
|
+
// Otherwise insert the character in the link not out as it would like to go natively
|
15516
|
+
|
15517
|
+
invisibleSpace = this.doc.createTextNode(wysihtml.INVISIBLE_SPACE);
|
15518
|
+
this.selection.insertNode(invisibleSpace);
|
15519
|
+
this.selection.setBefore(invisibleSpace);
|
15520
|
+
setTimeout(function() {
|
15521
|
+
|
15522
|
+
if (invisibleSpace.textContent.length > 1) {
|
15523
|
+
invisibleSpace.textContent = invisibleSpace.textContent.replace(wysihtml.INVISIBLE_SPACE_REG_EXP, '');
|
15524
|
+
this.selection.setAfter(invisibleSpace);
|
15525
|
+
} else {
|
15526
|
+
invisibleSpace.remove();
|
15527
|
+
}
|
15528
|
+
|
15529
|
+
}.bind(this), 0);
|
15530
|
+
} else if (event.which === 32) {
|
15531
|
+
// Seems like space was pressed and there was a space before the caret allready
|
15532
|
+
// This means user wants to escape the link now (caret is last in link node too) so we let the native browser do it-s job and escape.
|
15533
|
+
// But lets move the trailing space too out of link if present
|
15534
|
+
|
15535
|
+
if (target.nodeType === 3 && (/[\u00A0 ]$/).test(target.textContent)) {
|
15536
|
+
|
15537
|
+
target.textContent = target.textContent.replace(/[\u00A0 ]$/, '');
|
15538
|
+
space = this.doc.createTextNode(' ');
|
15539
|
+
targetEl.parentNode.insertBefore(space, targetEl.nextSibling);
|
15540
|
+
this.selection.setAfter(space, false);
|
15541
|
+
event.preventDefault();
|
15542
|
+
|
15543
|
+
}
|
15544
|
+
}
|
15545
|
+
}
|
15546
|
+
}
|
15547
|
+
}
|
15548
|
+
}
|
15549
|
+
|
15387
15550
|
var handleIframeFocus = function(event) {
|
15388
15551
|
setTimeout((function() {
|
15389
15552
|
if (this.doc.querySelector(":focus") !== this.element) {
|
@@ -15408,6 +15571,7 @@ wysihtml.views.View = Base.extend(
|
|
15408
15571
|
focusBlurElement = (browser.supportsEventsInIframeCorrectly() || this.sandbox.getContentEditable) ? this.element : this.sandbox.getWindow();
|
15409
15572
|
|
15410
15573
|
this.focusState = this.getValue(false, false);
|
15574
|
+
this.actions = actions;
|
15411
15575
|
|
15412
15576
|
// --------- destroy:composer event ---------
|
15413
15577
|
container.addEventListener(["DOMNodeRemoved"], handleDomNodeRemoved.bind(this), false);
|
@@ -15422,17 +15586,18 @@ wysihtml.views.View = Base.extend(
|
|
15422
15586
|
}, 250);
|
15423
15587
|
}
|
15424
15588
|
|
15425
|
-
actions.addListeners(focusBlurElement, [
|
15426
|
-
focusBlurElement.addEventListener(
|
15427
|
-
focusBlurElement.addEventListener(
|
15589
|
+
actions.addListeners(focusBlurElement, ['drop', 'paste', 'mouseup', 'focus', 'keyup'], handleUserInteraction.bind(this));
|
15590
|
+
focusBlurElement.addEventListener('focus', handleFocus.bind(this), false);
|
15591
|
+
focusBlurElement.addEventListener('blur', handleBlur.bind(this), false);
|
15428
15592
|
|
15429
|
-
actions.addListeners(this.element, [
|
15430
|
-
this.element.addEventListener(
|
15431
|
-
this.element.addEventListener(
|
15432
|
-
this.element.addEventListener(
|
15433
|
-
this.element.addEventListener(
|
15434
|
-
this.element.addEventListener(
|
15435
|
-
this.element.addEventListener(
|
15593
|
+
actions.addListeners(this.element, ['drop', 'paste', 'beforepaste'], handlePaste.bind(this), false);
|
15594
|
+
this.element.addEventListener('copy', handleCopy.bind(this), false);
|
15595
|
+
this.element.addEventListener('mousedown', handleMouseDown.bind(this), false);
|
15596
|
+
this.element.addEventListener('click', handleClick.bind(this), false);
|
15597
|
+
this.element.addEventListener('drop', handleDrop.bind(this), false);
|
15598
|
+
this.element.addEventListener('keyup', handleKeyUp.bind(this), false);
|
15599
|
+
this.element.addEventListener('keydown', handleKeyDown.bind(this), false);
|
15600
|
+
this.element.addEventListener('keypress', handleKeyPress.bind(this), false);
|
15436
15601
|
|
15437
15602
|
// IE controlselect madness fix
|
15438
15603
|
if (wysihtml.browser.usesControlRanges()) {
|
@@ -15752,12 +15917,12 @@ wysihtml.views.Textarea = wysihtml.views.View.extend(
|
|
15752
15917
|
uneditableContainer: "wysihtml-uneditable-container"
|
15753
15918
|
},
|
15754
15919
|
// Browsers that support copied source handling will get a marking of the origin of the copied source (for determinig code cleanup rules on paste)
|
15755
|
-
// Also copied source is based directly on selection -
|
15920
|
+
// Also copied source is based directly on selection -
|
15756
15921
|
// (very useful for webkit based browsers where copy will otherwise contain a lot of code and styles based on whatever and not actually in selection).
|
15757
15922
|
// If falsy value is passed source override is also disabled
|
15758
15923
|
copyedFromMarking: '<meta name="copied-from" content="wysihtml">'
|
15759
15924
|
},
|
15760
|
-
|
15925
|
+
|
15761
15926
|
constructor: function(editableElement, config) {
|
15762
15927
|
this.editableElement = typeof(editableElement) === "string" ? document.getElementById(editableElement) : editableElement;
|
15763
15928
|
this.config = wysihtml.lang.object({}).merge(this.defaults).merge(config).get();
|
@@ -15805,7 +15970,7 @@ wysihtml.views.Textarea = wysihtml.views.View.extend(
|
|
15805
15970
|
}
|
15806
15971
|
this.runEditorExtenders();
|
15807
15972
|
},
|
15808
|
-
|
15973
|
+
|
15809
15974
|
runEditorExtenders: function() {
|
15810
15975
|
wysihtml.editorExtenders.forEach(function(extender) {
|
15811
15976
|
extender(this);
|