wysihtml-rails 0.6.0.beta → 0.6.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/wysihtml/rails/version.rb +1 -1
- data/vendor/assets/javascripts/wysihtml.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);
|