bootstrap-wysihtml5-rails 0.2.4 → 0.2.5
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.
- data/Rakefile +1 -0
- data/lib/bootstrap-wysihtml5-rails/version.rb +1 -1
- data/vendor/assets/javascripts/bootstrap-wysihtml5.js +162 -17
- data/vendor/assets/javascripts/wysihtml5.js +364 -367
- metadata +4 -4
data/Rakefile
CHANGED
|
@@ -19,14 +19,54 @@
|
|
|
19
19
|
//,+ "<a class='btn' data-wysihtml5-command='underline' title='CTRL+U'>Underline</a>"
|
|
20
20
|
+ "</div>"
|
|
21
21
|
+ "</li>",
|
|
22
|
-
"lists":
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
"lists": "<li>"
|
|
23
|
+
+ "<div class='btn-group'>"
|
|
24
|
+
+ "<a class='btn' data-wysihtml5-command='insertUnorderedList' title='Unordered List'><i class='icon-list'></i></a>"
|
|
25
|
+
+ "<a class='btn' data-wysihtml5-command='insertOrderedList' title='Ordered List'><i class='icon-th-list'></i></a>"
|
|
26
|
+
+ "<a class='btn' data-wysihtml5-command='Outdent' title='Outdent'><i class='icon-indent-right'></i></a>"
|
|
27
|
+
+ "<a class='btn' data-wysihtml5-command='Indent' title='Indent'><i class='icon-indent-left'></i></a>"
|
|
28
|
+
+ "</div>"
|
|
29
|
+
+ "</li>",
|
|
30
|
+
|
|
31
|
+
"link": "<li>"
|
|
32
|
+
|
|
33
|
+
+ "<div class='bootstrap-wysihtml5-insert-link-modal modal hide fade'>"
|
|
34
|
+
+ "<div class='modal-header'>"
|
|
35
|
+
+ "<a class='close' data-dismiss='modal'>×</a>"
|
|
36
|
+
+ "<h3>Insert Link</h3>"
|
|
37
|
+
+ "</div>"
|
|
38
|
+
+ "<div class='modal-body'>"
|
|
39
|
+
+ "<input value='http://' class='bootstrap-wysihtml5-insert-link-url input-xlarge'>"
|
|
40
|
+
+ "</div>"
|
|
41
|
+
+ "<div class='modal-footer'>"
|
|
42
|
+
+ "<a href='#' class='btn' data-dismiss='modal'>Cancel</a>"
|
|
43
|
+
+ "<a href='#' class='btn btn-primary' data-dismiss='modal'>Insert link</a>"
|
|
44
|
+
+ "</div>"
|
|
45
|
+
+ "</div>"
|
|
46
|
+
|
|
47
|
+
+ "<a class='btn' data-wysihtml5-command='createLink' title='Link'><i class='icon-share'></i></a>"
|
|
48
|
+
|
|
49
|
+
+ "</li>",
|
|
50
|
+
|
|
51
|
+
"image": "<li>"
|
|
52
|
+
|
|
53
|
+
+ "<div class='bootstrap-wysihtml5-insert-image-modal modal hide fade'>"
|
|
54
|
+
+ "<div class='modal-header'>"
|
|
55
|
+
+ "<a class='close' data-dismiss='modal'>×</a>"
|
|
56
|
+
+ "<h3>Insert Image</h3>"
|
|
57
|
+
+ "</div>"
|
|
58
|
+
+ "<div class='modal-body'>"
|
|
59
|
+
+ "<input value='http://' class='bootstrap-wysihtml5-insert-link-url input-xlarge'>"
|
|
60
|
+
+ "</div>"
|
|
61
|
+
+ "<div class='modal-footer'>"
|
|
62
|
+
+ "<a href='#' class='btn' data-dismiss='modal'>Cancel</a>"
|
|
63
|
+
+ "<a href='#' class='btn btn-primary' data-dismiss='modal'>Insert image</a>"
|
|
64
|
+
+ "</div>"
|
|
65
|
+
+ "</div>"
|
|
66
|
+
|
|
67
|
+
+ "<a class='btn' data-wysihtml5-command='insertImage' title='Insert image'><i class='icon-picture'></i></a>"
|
|
68
|
+
|
|
69
|
+
+ "</li>",
|
|
30
70
|
|
|
31
71
|
"html":
|
|
32
72
|
"<li>"
|
|
@@ -41,6 +81,8 @@
|
|
|
41
81
|
"emphasis": true,
|
|
42
82
|
"lists": true,
|
|
43
83
|
"html": false,
|
|
84
|
+
"link": true,
|
|
85
|
+
"image": false,
|
|
44
86
|
events: {},
|
|
45
87
|
parserRules: {
|
|
46
88
|
tags: {
|
|
@@ -53,6 +95,14 @@
|
|
|
53
95
|
"h1": {},
|
|
54
96
|
"h2": {},
|
|
55
97
|
"u": 1,
|
|
98
|
+
"img": {
|
|
99
|
+
"check_attributes": {
|
|
100
|
+
"width": "numbers",
|
|
101
|
+
"alt": "alt",
|
|
102
|
+
"src": "url",
|
|
103
|
+
"height": "numbers"
|
|
104
|
+
}
|
|
105
|
+
},
|
|
56
106
|
"a": {
|
|
57
107
|
set_attributes: {
|
|
58
108
|
target: "_blank",
|
|
@@ -70,6 +120,8 @@
|
|
|
70
120
|
this.el = el;
|
|
71
121
|
this.toolbar = this.createToolbar(el, options || defaultOptions);
|
|
72
122
|
this.editor = this.createEditor(options);
|
|
123
|
+
|
|
124
|
+
window.editor = this.editor;
|
|
73
125
|
|
|
74
126
|
$('iframe.wysihtml5-sandbox').each(function(i, el){
|
|
75
127
|
$(el.contentWindow).off('focus.wysihtml5').on({
|
|
@@ -78,6 +130,8 @@
|
|
|
78
130
|
}
|
|
79
131
|
});
|
|
80
132
|
});
|
|
133
|
+
|
|
134
|
+
|
|
81
135
|
};
|
|
82
136
|
|
|
83
137
|
Wysihtml5.prototype = {
|
|
@@ -105,11 +159,12 @@
|
|
|
105
159
|
},
|
|
106
160
|
|
|
107
161
|
createToolbar: function(el, options) {
|
|
162
|
+
var self = this;
|
|
108
163
|
var toolbar = $("<ul/>", {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
164
|
+
'id' : el.attr('id') + "-wysihtml5-toolbar",
|
|
165
|
+
'class' : "wysihtml5-toolbar",
|
|
166
|
+
'style': "display:none"
|
|
167
|
+
});
|
|
113
168
|
|
|
114
169
|
for(var key in defaultOptions) {
|
|
115
170
|
var value = false;
|
|
@@ -126,10 +181,15 @@
|
|
|
126
181
|
toolbar.append(templates[key]);
|
|
127
182
|
|
|
128
183
|
if(key == "html") {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
184
|
+
this.initHtml(toolbar);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if(key == "link") {
|
|
188
|
+
this.initInsertLink(toolbar);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if(key == "image") {
|
|
192
|
+
this.initInsertImage(toolbar);
|
|
133
193
|
}
|
|
134
194
|
}
|
|
135
195
|
}
|
|
@@ -144,6 +204,91 @@
|
|
|
144
204
|
this.el.before(toolbar);
|
|
145
205
|
|
|
146
206
|
return toolbar;
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
initHtml: function(toolbar) {
|
|
210
|
+
var changeViewSelector = "a[data-wysihtml5-action='change_view']";
|
|
211
|
+
toolbar.find(changeViewSelector).click(function(e) {
|
|
212
|
+
toolbar.find('a.btn').not(changeViewSelector).toggleClass('disabled');
|
|
213
|
+
});
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
initInsertImage: function(toolbar) {
|
|
217
|
+
var self = this;
|
|
218
|
+
var insertImageModal = toolbar.find('.bootstrap-wysihtml5-insert-image-modal');
|
|
219
|
+
var urlInput = insertImageModal.find('.bootstrap-wysihtml5-insert-image-url');
|
|
220
|
+
var insertButton = insertImageModal.find('a.btn-primary');
|
|
221
|
+
|
|
222
|
+
var insertImage = function() {
|
|
223
|
+
var url = urlInput.val();
|
|
224
|
+
urlInput.val('');
|
|
225
|
+
self.editor.composer.commands.exec("createLink", {
|
|
226
|
+
href: url,
|
|
227
|
+
target: "_blank",
|
|
228
|
+
rel: "nofollow"
|
|
229
|
+
});
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
urlInput.keypress(function(e) {
|
|
233
|
+
if(e.which == 13) {
|
|
234
|
+
insertImage();
|
|
235
|
+
insertImageModal.modal('hide');
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
insertButton.click(insertImage);
|
|
240
|
+
|
|
241
|
+
insertImageModal.on('shown', function() {
|
|
242
|
+
urlInput.focus();
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
insertImageModal.on('hide', function() {
|
|
246
|
+
self.editor.currentView.element.focus();
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
toolbar.find('a[data-wysihtml5-command=insertImage]').click(function() {
|
|
250
|
+
insertImageModal.modal('show');
|
|
251
|
+
});
|
|
252
|
+
},
|
|
253
|
+
|
|
254
|
+
initInsertLink: function(toolbar) {
|
|
255
|
+
var self = this;
|
|
256
|
+
var insertLinkModal = toolbar.find('.bootstrap-wysihtml5-insert-link-modal');
|
|
257
|
+
var urlInput = insertLinkModal.find('.bootstrap-wysihtml5-insert-link-url');
|
|
258
|
+
var insertButton = insertLinkModal.find('a.btn-primary');
|
|
259
|
+
var initialValue = urlInput.val();
|
|
260
|
+
|
|
261
|
+
var insertLink = function() {
|
|
262
|
+
var url = urlInput.val();
|
|
263
|
+
urlInput.val(initialValue);
|
|
264
|
+
self.editor.composer.commands.exec("createLink", {
|
|
265
|
+
href: url,
|
|
266
|
+
target: "_blank",
|
|
267
|
+
rel: "nofollow"
|
|
268
|
+
});
|
|
269
|
+
};
|
|
270
|
+
var pressedEnter = false;
|
|
271
|
+
|
|
272
|
+
urlInput.keypress(function(e) {
|
|
273
|
+
if(e.which == 13) {
|
|
274
|
+
insertLink();
|
|
275
|
+
insertLinkModal.modal('hide');
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
insertButton.click(insertLink);
|
|
280
|
+
|
|
281
|
+
insertLinkModal.on('shown', function() {
|
|
282
|
+
urlInput.focus();
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
insertLinkModal.on('hide', function() {
|
|
286
|
+
self.editor.currentView.element.focus();
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
toolbar.find('a[data-wysihtml5-command=createLink]').click(function() {
|
|
290
|
+
insertLinkModal.modal('show');
|
|
291
|
+
});
|
|
147
292
|
}
|
|
148
293
|
};
|
|
149
294
|
|
|
@@ -156,4 +301,4 @@
|
|
|
156
301
|
|
|
157
302
|
$.fn.wysihtml5.Constructor = Wysihtml5;
|
|
158
303
|
|
|
159
|
-
}(window.jQuery, window.wysihtml5);
|
|
304
|
+
}(window.jQuery, window.wysihtml5);
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license wysihtml5 v0.3.
|
|
2
|
+
* @license wysihtml5 v0.3.0_rc2
|
|
3
3
|
* https://github.com/xing/wysihtml5
|
|
4
4
|
*
|
|
5
5
|
* Author: Christopher Blum (https://github.com/tiff)
|
|
6
6
|
*
|
|
7
|
-
* Copyright (C)
|
|
8
|
-
* Licensed under
|
|
7
|
+
* Copyright (C) 2012 XING AG
|
|
8
|
+
* Licensed under the MIT license (MIT)
|
|
9
9
|
*
|
|
10
10
|
*/
|
|
11
11
|
var wysihtml5 = {
|
|
12
|
-
version: "0.3.
|
|
12
|
+
version: "0.3.0_rc2",
|
|
13
13
|
|
|
14
14
|
// namespaces
|
|
15
15
|
commands: {},
|
|
@@ -3383,8 +3383,6 @@ Base = Base.extend({
|
|
|
3383
3383
|
}
|
|
3384
3384
|
});/**
|
|
3385
3385
|
* Detect browser support for specific features
|
|
3386
|
-
*
|
|
3387
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
3388
3386
|
*/
|
|
3389
3387
|
wysihtml5.browser = (function() {
|
|
3390
3388
|
var userAgent = navigator.userAgent,
|
|
@@ -3393,6 +3391,7 @@ wysihtml5.browser = (function() {
|
|
|
3393
3391
|
isIE = userAgent.indexOf("MSIE") !== -1 && userAgent.indexOf("Opera") === -1,
|
|
3394
3392
|
isGecko = userAgent.indexOf("Gecko") !== -1 && userAgent.indexOf("KHTML") === -1,
|
|
3395
3393
|
isWebKit = userAgent.indexOf("AppleWebKit/") !== -1,
|
|
3394
|
+
isChrome = userAgent.indexOf("Chrome/") !== -1,
|
|
3396
3395
|
isOpera = userAgent.indexOf("Opera/") !== -1;
|
|
3397
3396
|
|
|
3398
3397
|
function iosVersion(userAgent) {
|
|
@@ -3716,6 +3715,24 @@ wysihtml5.browser = (function() {
|
|
|
3716
3715
|
*/
|
|
3717
3716
|
crashesWhenDefineProperty: function(property) {
|
|
3718
3717
|
return isIE && (property === "XMLHttpRequest" || property === "XDomainRequest");
|
|
3718
|
+
},
|
|
3719
|
+
|
|
3720
|
+
/**
|
|
3721
|
+
* IE is the only browser who fires the "focus" event not immediately when .focus() is called on an element
|
|
3722
|
+
*/
|
|
3723
|
+
doesAsyncFocus: function() {
|
|
3724
|
+
return isIE;
|
|
3725
|
+
},
|
|
3726
|
+
|
|
3727
|
+
/**
|
|
3728
|
+
* In IE it's impssible for the user and for the selection library to set the caret after an <img> when it's the lastChild in the document
|
|
3729
|
+
*/
|
|
3730
|
+
hasProblemsSettingCaretAfterImg: function() {
|
|
3731
|
+
return isIE;
|
|
3732
|
+
},
|
|
3733
|
+
|
|
3734
|
+
hasUndoInContextMenu: function() {
|
|
3735
|
+
return isGecko || isChrome || isOpera;
|
|
3719
3736
|
}
|
|
3720
3737
|
};
|
|
3721
3738
|
})();wysihtml5.lang.array = function(arr) {
|
|
@@ -3905,7 +3922,7 @@ wysihtml5.browser = (function() {
|
|
|
3905
3922
|
* Inspired by http://james.padolsey.com/javascript/find-and-replace-text-with-javascript/
|
|
3906
3923
|
*
|
|
3907
3924
|
* @param {Element} element Container element in which to search for urls
|
|
3908
|
-
*
|
|
3925
|
+
*
|
|
3909
3926
|
* @example
|
|
3910
3927
|
* <div id="text-container">Please click here: www.google.com</div>
|
|
3911
3928
|
* <script>wysihtml5.dom.autoLink(document.getElementById("text-container"));</script>
|
|
@@ -4089,7 +4106,6 @@ wysihtml5.dom.contains = (function() {
|
|
|
4089
4106
|
})();/**
|
|
4090
4107
|
* Converts an HTML fragment/element into a unordered/ordered list
|
|
4091
4108
|
*
|
|
4092
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
4093
4109
|
* @param {Element} element The element which should be turned into a list
|
|
4094
4110
|
* @param {String} listType The list type in which to convert the tree (either "ul" or "ol")
|
|
4095
4111
|
* @return {Element} The created list
|
|
@@ -4170,8 +4186,6 @@ wysihtml5.dom.convertToList = (function() {
|
|
|
4170
4186
|
})();/**
|
|
4171
4187
|
* Copy a set of attributes from one element to another
|
|
4172
4188
|
*
|
|
4173
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
4174
|
-
*
|
|
4175
4189
|
* @param {Array} attributesToCopy List of attributes which should be copied
|
|
4176
4190
|
* @return {Object} Returns an object which offers the "from" method which can be invoked with the element where to
|
|
4177
4191
|
* copy the attributes from., this again returns an object which provides a method named "to" which can be invoked
|
|
@@ -4210,8 +4224,6 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
|
|
|
4210
4224
|
*
|
|
4211
4225
|
* Interesting article on how to copy styles
|
|
4212
4226
|
*
|
|
4213
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
4214
|
-
*
|
|
4215
4227
|
* @param {Array} stylesToCopy List of styles which should be copied
|
|
4216
4228
|
* @return {Object} Returns an object which offers the "from" method which can be invoked with the element where to
|
|
4217
4229
|
* copy the styles from., this again returns an object which provides a method named "to" which can be invoked
|
|
@@ -4306,7 +4318,6 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
|
|
|
4306
4318
|
* Fixing IE's inability to treat unknown elements (HTML5 section, article, ...) correctly
|
|
4307
4319
|
* when inserted via innerHTML
|
|
4308
4320
|
*
|
|
4309
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
4310
4321
|
* @param {String} html The html which should be wrapped in a dom element
|
|
4311
4322
|
* @param {Obejct} [context] Document object of the context the html belongs to
|
|
4312
4323
|
*
|
|
@@ -4368,7 +4379,6 @@ wysihtml5.dom.getAsDom = (function() {
|
|
|
4368
4379
|
* Walks the dom tree from the given node up until it finds a match
|
|
4369
4380
|
* Designed for optimal performance.
|
|
4370
4381
|
*
|
|
4371
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
4372
4382
|
* @param {Element} node The from which to check the parent nodes
|
|
4373
4383
|
* @param {Object} matchingSet Object to match against (possible properties: nodeName, className, classRegExp)
|
|
4374
4384
|
* @param {Number} [levels] How many parents should the function check up from the current node (defaults to 50)
|
|
@@ -4446,7 +4456,7 @@ wysihtml5.dom.getParentElement = (function() {
|
|
|
4446
4456
|
*
|
|
4447
4457
|
* @param {Element} element The element on which to retrieve the style
|
|
4448
4458
|
* @param {String} property The CSS property to retrieve ("float", "display", "text-align", ...)
|
|
4449
|
-
*
|
|
4459
|
+
*
|
|
4450
4460
|
* @example
|
|
4451
4461
|
* wysihtml5.dom.getStyle("display").from(document.body);
|
|
4452
4462
|
* // => "block"
|
|
@@ -4485,11 +4495,11 @@ wysihtml5.dom.getStyle = (function() {
|
|
|
4485
4495
|
// gives you the original "50%".
|
|
4486
4496
|
// Opera supports both, currentStyle and window.getComputedStyle, that's why checking for currentStyle should have higher prio
|
|
4487
4497
|
if (currentStyle) {
|
|
4488
|
-
|
|
4498
|
+
try {
|
|
4489
4499
|
return currentStyle[camelizedProperty];
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4500
|
+
} catch(e) {
|
|
4501
|
+
//ie will occasionally fail for unknown reasons. swallowing exception
|
|
4502
|
+
}
|
|
4493
4503
|
}
|
|
4494
4504
|
|
|
4495
4505
|
var win = doc.defaultView || doc.parentWindow,
|
|
@@ -4518,7 +4528,6 @@ wysihtml5.dom.getStyle = (function() {
|
|
|
4518
4528
|
* Optimized for being heavily executed
|
|
4519
4529
|
* Unleashes the power of live node lists
|
|
4520
4530
|
*
|
|
4521
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
4522
4531
|
* @param {Object} doc The document object of the context where to check
|
|
4523
4532
|
* @param {String} tagName Upper cased tag name
|
|
4524
4533
|
* @example
|
|
@@ -4546,7 +4555,6 @@ wysihtml5.dom.hasElementWithTagName = (function() {
|
|
|
4546
4555
|
* Optimized for being heavily executed
|
|
4547
4556
|
* Unleashes the power of live node lists
|
|
4548
4557
|
*
|
|
4549
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
4550
4558
|
* @param {Object} doc The document object of the context where to check
|
|
4551
4559
|
* @param {String} tagName Upper cased tag name
|
|
4552
4560
|
* @example
|
|
@@ -4614,8 +4622,6 @@ wysihtml5.dom.insert = function(elementToInsert) {
|
|
|
4614
4622
|
};/**
|
|
4615
4623
|
* Method to set dom events
|
|
4616
4624
|
*
|
|
4617
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
4618
|
-
*
|
|
4619
4625
|
* @example
|
|
4620
4626
|
* wysihtml5.dom.observe(iframe.contentWindow.document.body, ["focus", "blur"], function() { ... });
|
|
4621
4627
|
*/
|
|
@@ -4668,8 +4674,6 @@ wysihtml5.dom.observe = function(element, eventNames, handler) {
|
|
|
4668
4674
|
* HTML Sanitizer
|
|
4669
4675
|
* Rewrites the HTML based on given rules
|
|
4670
4676
|
*
|
|
4671
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
4672
|
-
*
|
|
4673
4677
|
* @param {Element|String} elementOrHtml HTML String to be sanitized OR element whose content should be sanitized
|
|
4674
4678
|
* @param {Object} [rules] List of rules for rewriting the HTML, if there's no rule for an element it will
|
|
4675
4679
|
* be converted to a "span". Each rule is a key/value pair where key is the tag to convert, and value the
|
|
@@ -5115,7 +5119,6 @@ wysihtml5.dom.parse = (function() {
|
|
|
5115
5119
|
})();/**
|
|
5116
5120
|
* Checks for empty text node childs and removes them
|
|
5117
5121
|
*
|
|
5118
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
5119
5122
|
* @param {Element} node The element in which to cleanup
|
|
5120
5123
|
* @example
|
|
5121
5124
|
* wysihtml5.dom.removeEmptyTextNodes(element);
|
|
@@ -5135,7 +5138,6 @@ wysihtml5.dom.removeEmptyTextNodes = function(node) {
|
|
|
5135
5138
|
/**
|
|
5136
5139
|
* Renames an element (eg. a <div> to a <p>) and keeps its childs
|
|
5137
5140
|
*
|
|
5138
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
5139
5141
|
* @param {Element} element The list element which should be renamed
|
|
5140
5142
|
* @param {Element} newNodeName The desired tag name
|
|
5141
5143
|
*
|
|
@@ -5170,7 +5172,6 @@ wysihtml5.dom.renameElement = function(element, newNodeName) {
|
|
|
5170
5172
|
};/**
|
|
5171
5173
|
* Takes an element, removes it and replaces it with it's childs
|
|
5172
5174
|
*
|
|
5173
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
5174
5175
|
* @param {Object} node The node which to replace with it's child nodes
|
|
5175
5176
|
* @example
|
|
5176
5177
|
* <div id="foo">
|
|
@@ -5201,7 +5202,6 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
|
|
|
5201
5202
|
/**
|
|
5202
5203
|
* Unwraps an unordered/ordered list
|
|
5203
5204
|
*
|
|
5204
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
5205
5205
|
* @param {Element} element The list element which should be unwrapped
|
|
5206
5206
|
*
|
|
5207
5207
|
* @example
|
|
@@ -5285,10 +5285,8 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
|
|
|
5285
5285
|
* - therefore the "allow-scripts" flag is needed, which then would deactivate any security, as the js executed inside the iframe
|
|
5286
5286
|
* can do anything as if the sandbox attribute wasn't set
|
|
5287
5287
|
*
|
|
5288
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
5289
|
-
*
|
|
5290
5288
|
* @param {Function} [readyCallback] Method that gets invoked when the sandbox is ready
|
|
5291
|
-
* @param {Object} [config] Optional parameters
|
|
5289
|
+
* @param {Object} [config] Optional parameters
|
|
5292
5290
|
*
|
|
5293
5291
|
* @example
|
|
5294
5292
|
* new wysihtml5.dom.Sandbox(function(sandbox) {
|
|
@@ -5299,9 +5297,6 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
|
|
|
5299
5297
|
var /**
|
|
5300
5298
|
* Default configuration
|
|
5301
5299
|
*/
|
|
5302
|
-
defaultConfig = {
|
|
5303
|
-
uaCompatible: "IE=Edge" // X-UA-Compatible meta tag value (Document compatibility mode)
|
|
5304
|
-
},
|
|
5305
5300
|
doc = document,
|
|
5306
5301
|
/**
|
|
5307
5302
|
* Properties to unset/protect on the window object
|
|
@@ -5332,7 +5327,7 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
|
|
|
5332
5327
|
|
|
5333
5328
|
constructor: function(readyCallback, config) {
|
|
5334
5329
|
this.callback = readyCallback || wysihtml5.EMPTY_FUNCTION;
|
|
5335
|
-
this.config = wysihtml5.lang.object({}).merge(
|
|
5330
|
+
this.config = wysihtml5.lang.object({}).merge(config).get();
|
|
5336
5331
|
this.iframe = this._createIframe();
|
|
5337
5332
|
},
|
|
5338
5333
|
|
|
@@ -5429,12 +5424,11 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
|
|
|
5429
5424
|
|
|
5430
5425
|
var that = this,
|
|
5431
5426
|
iframeWindow = iframe.contentWindow,
|
|
5432
|
-
iframeDocument = iframe.
|
|
5427
|
+
iframeDocument = iframe.contentWindow.document,
|
|
5433
5428
|
charset = doc.characterSet || doc.charset || "utf-8",
|
|
5434
5429
|
sandboxHtml = this._getHtml({
|
|
5435
5430
|
charset: charset,
|
|
5436
|
-
stylesheets: this.config.stylesheets
|
|
5437
|
-
uaCompatible: this.config.uaCompatible
|
|
5431
|
+
stylesheets: this.config.stylesheets
|
|
5438
5432
|
});
|
|
5439
5433
|
|
|
5440
5434
|
// Create the basic dom tree including proper DOCTYPE and charset
|
|
@@ -5442,8 +5436,8 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
|
|
|
5442
5436
|
iframeDocument.write(sandboxHtml);
|
|
5443
5437
|
iframeDocument.close();
|
|
5444
5438
|
|
|
5445
|
-
this.getWindow = function() { return
|
|
5446
|
-
this.getDocument = function() { return
|
|
5439
|
+
this.getWindow = function() { return iframe.contentWindow; };
|
|
5440
|
+
this.getDocument = function() { return iframe.contentWindow.document; };
|
|
5447
5441
|
|
|
5448
5442
|
// Catch js errors and pass them to the parent's onerror event
|
|
5449
5443
|
// addEventListener("error") doesn't work properly in some browsers
|
|
@@ -5496,7 +5490,7 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
|
|
|
5496
5490
|
|
|
5497
5491
|
return wysihtml5.lang.string(
|
|
5498
5492
|
'<!DOCTYPE html><html><head>'
|
|
5499
|
-
+ '<meta
|
|
5493
|
+
+ '<meta charset="#{charset}">#{stylesheets}</head>'
|
|
5500
5494
|
+ '<body></body></html>'
|
|
5501
5495
|
).interpolate(templateVars);
|
|
5502
5496
|
},
|
|
@@ -5567,8 +5561,6 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
|
|
|
5567
5561
|
* - div[contentEditable] elements don't support it
|
|
5568
5562
|
* - older browsers (such as IE8 and Firefox 3.6) don't support it at all
|
|
5569
5563
|
*
|
|
5570
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
5571
|
-
*
|
|
5572
5564
|
* @param {Object} parent Instance of main wysihtml5.Editor class
|
|
5573
5565
|
* @param {Element} view Instance of wysihtml5.views.* class
|
|
5574
5566
|
* @param {String} placeholderText
|
|
@@ -5679,7 +5671,6 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
5679
5671
|
})();/**
|
|
5680
5672
|
* IE and Opera leave an empty paragraph in the contentEditable element after clearing it
|
|
5681
5673
|
*
|
|
5682
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
5683
5674
|
* @param {Object} contentEditableElement The contentEditable element to observe for clearing events
|
|
5684
5675
|
* @exaple
|
|
5685
5676
|
* wysihtml5.quirks.ensureProperClearing(myContentEditableElement);
|
|
@@ -5699,8 +5690,8 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
5699
5690
|
}, 0);
|
|
5700
5691
|
};
|
|
5701
5692
|
|
|
5702
|
-
return function(
|
|
5703
|
-
dom.observe(
|
|
5693
|
+
return function(composer) {
|
|
5694
|
+
dom.observe(composer.element, ["cut", "keydown"], clearIfNecessary);
|
|
5704
5695
|
};
|
|
5705
5696
|
})();
|
|
5706
5697
|
|
|
@@ -5709,7 +5700,6 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
5709
5700
|
/**
|
|
5710
5701
|
* In Opera when the caret is in the first and only item of a list (<ul><li>|</li></ul>) and the list is the first child of the contentEditable element, it's impossible to delete the list by hitting backspace
|
|
5711
5702
|
*
|
|
5712
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
5713
5703
|
* @param {Object} contentEditableElement The contentEditable element to observe for clearing events
|
|
5714
5704
|
* @exaple
|
|
5715
5705
|
* wysihtml5.quirks.ensureProperClearing(myContentEditableElement);
|
|
@@ -5745,14 +5735,14 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
5745
5735
|
list.parentNode.removeChild(list);
|
|
5746
5736
|
};
|
|
5747
5737
|
|
|
5748
|
-
return function(
|
|
5749
|
-
dom.observe(
|
|
5738
|
+
return function(composer) {
|
|
5739
|
+
dom.observe(composer.element, "keydown", function(event) {
|
|
5750
5740
|
if (event.keyCode !== wysihtml5.BACKSPACE_KEY) {
|
|
5751
5741
|
return;
|
|
5752
5742
|
}
|
|
5753
5743
|
|
|
5754
|
-
var element =
|
|
5755
|
-
clearIfNecessary(element,
|
|
5744
|
+
var element = composer.selection.getSelectedNode();
|
|
5745
|
+
clearIfNecessary(element, composer.element);
|
|
5756
5746
|
});
|
|
5757
5747
|
};
|
|
5758
5748
|
})();
|
|
@@ -5792,8 +5782,6 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
5792
5782
|
* - Opera & IE insert new <p> on return
|
|
5793
5783
|
* - Chrome & Safari insert new <div> on return
|
|
5794
5784
|
* - Firefox inserts <br> on return (yippie!)
|
|
5795
|
-
|
|
5796
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
5797
5785
|
*
|
|
5798
5786
|
* @param {Element} element
|
|
5799
5787
|
*
|
|
@@ -5805,72 +5793,71 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
5805
5793
|
USE_NATIVE_LINE_BREAK_WHEN_CARET_INSIDE_TAGS = ["LI", "P", "H1", "H2", "H3", "H4", "H5", "H6"],
|
|
5806
5794
|
LIST_TAGS = ["UL", "OL", "MENU"];
|
|
5807
5795
|
|
|
5808
|
-
function
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
function keyDown(event) {
|
|
5821
|
-
var keyCode = event.keyCode;
|
|
5822
|
-
if (event.shiftKey || (keyCode !== wysihtml5.ENTER_KEY && keyCode !== wysihtml5.BACKSPACE_KEY)) {
|
|
5823
|
-
return;
|
|
5796
|
+
wysihtml5.quirks.insertLineBreakOnReturn = function(composer) {
|
|
5797
|
+
function unwrap(selectedNode) {
|
|
5798
|
+
var parentElement = dom.getParentElement(selectedNode, { nodeName: ["P", "DIV"] }, 2);
|
|
5799
|
+
if (!parentElement) {
|
|
5800
|
+
return;
|
|
5801
|
+
}
|
|
5802
|
+
|
|
5803
|
+
var invisibleSpace = document.createTextNode(wysihtml5.INVISIBLE_SPACE);
|
|
5804
|
+
dom.insert(invisibleSpace).before(parentElement);
|
|
5805
|
+
dom.replaceWithChildNodes(parentElement);
|
|
5806
|
+
composer.selection.selectNode(invisibleSpace);
|
|
5824
5807
|
}
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5808
|
+
|
|
5809
|
+
function keyDown(event) {
|
|
5810
|
+
var keyCode = event.keyCode;
|
|
5811
|
+
if (event.shiftKey || (keyCode !== wysihtml5.ENTER_KEY && keyCode !== wysihtml5.BACKSPACE_KEY)) {
|
|
5812
|
+
return;
|
|
5813
|
+
}
|
|
5814
|
+
|
|
5815
|
+
var element = event.target,
|
|
5816
|
+
selectedNode = composer.selection.getSelectedNode(),
|
|
5817
|
+
blockElement = dom.getParentElement(selectedNode, { nodeName: USE_NATIVE_LINE_BREAK_WHEN_CARET_INSIDE_TAGS }, 4);
|
|
5818
|
+
if (blockElement) {
|
|
5819
|
+
// Some browsers create <p> elements after leaving a list
|
|
5820
|
+
// check after keydown of backspace and return whether a <p> got inserted and unwrap it
|
|
5821
|
+
if (blockElement.nodeName === "LI" && (keyCode === wysihtml5.ENTER_KEY || keyCode === wysihtml5.BACKSPACE_KEY)) {
|
|
5822
|
+
setTimeout(function() {
|
|
5823
|
+
var selectedNode = composer.selection.getSelectedNode(),
|
|
5824
|
+
list,
|
|
5825
|
+
div;
|
|
5826
|
+
if (!selectedNode) {
|
|
5827
|
+
return;
|
|
5828
|
+
}
|
|
5829
|
+
|
|
5830
|
+
list = dom.getParentElement(selectedNode, {
|
|
5831
|
+
nodeName: LIST_TAGS
|
|
5832
|
+
}, 2);
|
|
5833
|
+
|
|
5834
|
+
if (list) {
|
|
5835
|
+
return;
|
|
5836
|
+
}
|
|
5837
|
+
|
|
5838
|
+
unwrap(selectedNode);
|
|
5839
|
+
}, 0);
|
|
5840
|
+
} else if (blockElement.nodeName.match(/H[1-6]/) && keyCode === wysihtml5.ENTER_KEY) {
|
|
5841
|
+
setTimeout(function() {
|
|
5842
|
+
unwrap(composer.selection.getSelectedNode());
|
|
5843
|
+
}, 0);
|
|
5844
|
+
}
|
|
5845
|
+
return;
|
|
5846
|
+
}
|
|
5847
|
+
|
|
5848
|
+
if (keyCode === wysihtml5.ENTER_KEY && !wysihtml5.browser.insertsLineBreaksOnReturn()) {
|
|
5849
|
+
composer.commands.exec("insertLineBreak");
|
|
5850
|
+
event.preventDefault();
|
|
5851
|
+
}
|
|
5857
5852
|
}
|
|
5858
5853
|
|
|
5859
|
-
if (keyCode === wysihtml5.ENTER_KEY && !wysihtml5.browser.insertsLineBreaksOnReturn()) {
|
|
5860
|
-
wysihtml5.commands.exec("insertLineBreak");
|
|
5861
|
-
event.preventDefault();
|
|
5862
|
-
}
|
|
5863
|
-
}
|
|
5864
|
-
|
|
5865
|
-
wysihtml5.quirks.insertLineBreakOnReturn = function(element) {
|
|
5866
5854
|
// keypress doesn't fire when you hit backspace
|
|
5867
|
-
dom.observe(element.ownerDocument, "keydown", keyDown);
|
|
5855
|
+
dom.observe(composer.element.ownerDocument, "keydown", keyDown);
|
|
5868
5856
|
};
|
|
5869
5857
|
})(wysihtml5);/**
|
|
5870
5858
|
* Force rerendering of a given element
|
|
5871
5859
|
* Needed to fix display misbehaviors of IE
|
|
5872
5860
|
*
|
|
5873
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
5874
5861
|
* @param {Element} element The element object which needs to be rerendered
|
|
5875
5862
|
* @example
|
|
5876
5863
|
* wysihtml5.quirks.redraw(document.body);
|
|
@@ -5889,7 +5876,13 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
5889
5876
|
doc.execCommand("italic", false, null);
|
|
5890
5877
|
} catch(e) {}
|
|
5891
5878
|
};
|
|
5892
|
-
})(wysihtml5)
|
|
5879
|
+
})(wysihtml5);/**
|
|
5880
|
+
* Selection API
|
|
5881
|
+
*
|
|
5882
|
+
* @example
|
|
5883
|
+
* var selection = new wysihtml5.Selection(editor);
|
|
5884
|
+
*/
|
|
5885
|
+
(function(wysihtml5) {
|
|
5893
5886
|
var dom = wysihtml5.dom;
|
|
5894
5887
|
|
|
5895
5888
|
function _getCumulativeOffsetTop(element) {
|
|
@@ -5903,18 +5896,15 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
5903
5896
|
return top;
|
|
5904
5897
|
}
|
|
5905
5898
|
|
|
5906
|
-
wysihtml5.
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
* Setup selection for editor
|
|
5910
|
-
*
|
|
5911
|
-
* @param {Object} doc Document object of the context
|
|
5912
|
-
*/
|
|
5913
|
-
initialize: function(doc) {
|
|
5899
|
+
wysihtml5.Selection = Base.extend(
|
|
5900
|
+
/** @scope wysihtml5.Selection.prototype */ {
|
|
5901
|
+
constructor: function(editor) {
|
|
5914
5902
|
// Make sure that our external range library is initialized
|
|
5915
5903
|
window.rangy.init();
|
|
5916
5904
|
|
|
5917
|
-
this.
|
|
5905
|
+
this.editor = editor;
|
|
5906
|
+
this.composer = editor.composer;
|
|
5907
|
+
this.doc = this.composer.doc;
|
|
5918
5908
|
},
|
|
5919
5909
|
|
|
5920
5910
|
/**
|
|
@@ -5928,7 +5918,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
5928
5918
|
},
|
|
5929
5919
|
|
|
5930
5920
|
/**
|
|
5931
|
-
* Restore a selection retrieved via wysihtml5.
|
|
5921
|
+
* Restore a selection retrieved via wysihtml5.Selection.prototype.getBookmark
|
|
5932
5922
|
*
|
|
5933
5923
|
* @param {Object} bookmark An object that represents the current selection
|
|
5934
5924
|
*/
|
|
@@ -5945,7 +5935,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
5945
5935
|
*
|
|
5946
5936
|
* @param {Object} node The element or text node where to position the caret in front of
|
|
5947
5937
|
* @example
|
|
5948
|
-
*
|
|
5938
|
+
* selection.setBefore(myElement);
|
|
5949
5939
|
*/
|
|
5950
5940
|
setBefore: function(node) {
|
|
5951
5941
|
var range = rangy.createRange(this.doc);
|
|
@@ -5959,7 +5949,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
5959
5949
|
*
|
|
5960
5950
|
* @param {Object} node The element or text node where to position the caret in front of
|
|
5961
5951
|
* @example
|
|
5962
|
-
*
|
|
5952
|
+
* selection.setBefore(myElement);
|
|
5963
5953
|
*/
|
|
5964
5954
|
setAfter: function(node) {
|
|
5965
5955
|
var range = rangy.createRange(this.doc);
|
|
@@ -5973,7 +5963,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
5973
5963
|
*
|
|
5974
5964
|
* @param {Element} node The node/element to select
|
|
5975
5965
|
* @example
|
|
5976
|
-
*
|
|
5966
|
+
* selection.selectNode(document.getElementById("my-image"));
|
|
5977
5967
|
*/
|
|
5978
5968
|
selectNode: function(node) {
|
|
5979
5969
|
var range = rangy.createRange(this.doc),
|
|
@@ -6011,7 +6001,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
6011
6001
|
* @param {Boolean} [controlRange] (only IE) Whether it should return the selected ControlRange element when the selection type is a "ControlRange"
|
|
6012
6002
|
* @return {Object} The node that contains the caret
|
|
6013
6003
|
* @example
|
|
6014
|
-
* var nodeThatContainsCaret =
|
|
6004
|
+
* var nodeThatContainsCaret = selection.getSelectedNode();
|
|
6015
6005
|
*/
|
|
6016
6006
|
getSelectedNode: function(controlRange) {
|
|
6017
6007
|
var selection,
|
|
@@ -6128,7 +6118,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
6128
6118
|
*
|
|
6129
6119
|
* @param {String} html HTML string to insert
|
|
6130
6120
|
* @example
|
|
6131
|
-
*
|
|
6121
|
+
* selection.insertHTML("<p>foobar</p>");
|
|
6132
6122
|
*/
|
|
6133
6123
|
insertHTML: function(html) {
|
|
6134
6124
|
var range = rangy.createRange(this.doc),
|
|
@@ -6145,7 +6135,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
6145
6135
|
*
|
|
6146
6136
|
* @param {Object} node HTML string to insert
|
|
6147
6137
|
* @example
|
|
6148
|
-
*
|
|
6138
|
+
* selection.insertNode(document.createTextNode("foobar"));
|
|
6149
6139
|
*/
|
|
6150
6140
|
insertNode: function(node) {
|
|
6151
6141
|
var range = this.getRange();
|
|
@@ -6180,11 +6170,10 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
6180
6170
|
* Scroll the current caret position into the view
|
|
6181
6171
|
* FIXME: This is a bit hacky, there might be a smarter way of doing this
|
|
6182
6172
|
*
|
|
6183
|
-
* @param {Object} element A scrollable element in which the caret is currently positioned
|
|
6184
6173
|
* @example
|
|
6185
|
-
*
|
|
6174
|
+
* selection.scrollIntoView();
|
|
6186
6175
|
*/
|
|
6187
|
-
scrollIntoView: function(
|
|
6176
|
+
scrollIntoView: function() {
|
|
6188
6177
|
var doc = this.doc,
|
|
6189
6178
|
hasScrollBars = doc.documentElement.scrollHeight > doc.documentElement.offsetHeight,
|
|
6190
6179
|
tempElement = doc._wysihtml5ScrollIntoViewElement = doc._wysihtml5ScrollIntoViewElement || (function() {
|
|
@@ -6199,8 +6188,8 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
6199
6188
|
this.insertNode(tempElement);
|
|
6200
6189
|
offsetTop = _getCumulativeOffsetTop(tempElement);
|
|
6201
6190
|
tempElement.parentNode.removeChild(tempElement);
|
|
6202
|
-
if (offsetTop >
|
|
6203
|
-
|
|
6191
|
+
if (offsetTop > doc.body.scrollTop) {
|
|
6192
|
+
doc.body.scrollTop = offsetTop;
|
|
6204
6193
|
}
|
|
6205
6194
|
}
|
|
6206
6195
|
},
|
|
@@ -6302,18 +6291,16 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
6302
6291
|
selection = rangy.getSelection(win);
|
|
6303
6292
|
return selection.setSingleRange(range);
|
|
6304
6293
|
}
|
|
6305
|
-
};
|
|
6294
|
+
});
|
|
6306
6295
|
|
|
6307
6296
|
})(wysihtml5);
|
|
6308
|
-
|
|
6309
6297
|
/**
|
|
6310
|
-
*
|
|
6311
|
-
*
|
|
6298
|
+
* Inspired by the rangy CSS Applier module written by Tim Down and licensed under the MIT license.
|
|
6299
|
+
* http://code.google.com/p/rangy/
|
|
6300
|
+
*
|
|
6301
|
+
* changed in order to be able ...
|
|
6312
6302
|
* - to use custom tags
|
|
6313
6303
|
* - to detect and replace similar css classes via reg exp
|
|
6314
|
-
*
|
|
6315
|
-
* Inspired by the rangy CSS Applier module written by Tim Down and licensed under the MIT license.
|
|
6316
|
-
* http://code.google.com/p/rangy/
|
|
6317
6304
|
*/
|
|
6318
6305
|
(function(wysihtml5, rangy) {
|
|
6319
6306
|
var defaultTagName = "span";
|
|
@@ -6742,22 +6729,23 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
|
|
|
6742
6729
|
})(wysihtml5, rangy);/**
|
|
6743
6730
|
* Rich Text Query/Formatting Commands
|
|
6744
6731
|
*
|
|
6745
|
-
* @
|
|
6732
|
+
* @example
|
|
6733
|
+
* var commands = new wysihtml5.Commands(editor);
|
|
6746
6734
|
*/
|
|
6747
|
-
wysihtml5.
|
|
6748
|
-
|
|
6735
|
+
wysihtml5.Commands = Base.extend(
|
|
6736
|
+
/** @scope wysihtml5.Commands.prototype */ {
|
|
6737
|
+
constructor: function(editor) {
|
|
6749
6738
|
this.editor = editor;
|
|
6750
|
-
this.
|
|
6751
|
-
this.doc = this.
|
|
6739
|
+
this.composer = editor.composer;
|
|
6740
|
+
this.doc = this.composer.doc;
|
|
6752
6741
|
},
|
|
6753
6742
|
|
|
6754
6743
|
/**
|
|
6755
6744
|
* Check whether the browser supports the given command
|
|
6756
6745
|
*
|
|
6757
|
-
* @param {Object} element The element which has contentEditable=true
|
|
6758
6746
|
* @param {String} command The command string which to check (eg. "bold", "italic", "insertUnorderedList")
|
|
6759
6747
|
* @example
|
|
6760
|
-
*
|
|
6748
|
+
* commands.supports("createLink");
|
|
6761
6749
|
*/
|
|
6762
6750
|
support: function(command) {
|
|
6763
6751
|
return wysihtml5.browser.supportsCommand(this.doc, command);
|
|
@@ -6766,20 +6754,19 @@ wysihtml5.commands = {
|
|
|
6766
6754
|
/**
|
|
6767
6755
|
* Check whether the browser supports the given command
|
|
6768
6756
|
*
|
|
6769
|
-
* @param {Object} element The element which has contentEditable=true
|
|
6770
6757
|
* @param {String} command The command string which to execute (eg. "bold", "italic", "insertUnorderedList")
|
|
6771
6758
|
* @param {String} [value] The command value parameter, needed for some commands ("createLink", "insertImage", ...), optional for commands that don't require one ("bold", "underline", ...)
|
|
6772
6759
|
* @example
|
|
6773
|
-
*
|
|
6760
|
+
* commands.exec("insertImage", "http://a1.twimg.com/profile_images/113868655/schrei_twitter_reasonably_small.jpg");
|
|
6774
6761
|
*/
|
|
6775
6762
|
exec: function(command, value) {
|
|
6776
|
-
var obj =
|
|
6763
|
+
var obj = wysihtml5.commands[command],
|
|
6777
6764
|
method = obj && obj.exec;
|
|
6778
6765
|
|
|
6779
6766
|
this.editor.fire("beforecommand:composer");
|
|
6780
6767
|
|
|
6781
6768
|
if (method) {
|
|
6782
|
-
return method.call(obj, this.
|
|
6769
|
+
return method.call(obj, this.composer, command, value);
|
|
6783
6770
|
} else {
|
|
6784
6771
|
try {
|
|
6785
6772
|
// try/catch for buggy firefox
|
|
@@ -6794,18 +6781,17 @@ wysihtml5.commands = {
|
|
|
6794
6781
|
* Check whether the current command is active
|
|
6795
6782
|
* If the caret is within a bold text, then calling this with command "bold" should return true
|
|
6796
6783
|
*
|
|
6797
|
-
* @param {Object} element The element which has contentEditable=true
|
|
6798
6784
|
* @param {String} command The command string which to check (eg. "bold", "italic", "insertUnorderedList")
|
|
6799
6785
|
* @param {String} [commandValue] The command value parameter (eg. for "insertImage" the image src)
|
|
6800
6786
|
* @return {Boolean} Whether the command is active
|
|
6801
6787
|
* @example
|
|
6802
|
-
* var isCurrentSelectionBold =
|
|
6788
|
+
* var isCurrentSelectionBold = commands.state("bold");
|
|
6803
6789
|
*/
|
|
6804
6790
|
state: function(command, commandValue) {
|
|
6805
|
-
var obj =
|
|
6791
|
+
var obj = wysihtml5.commands[command],
|
|
6806
6792
|
method = obj && obj.state;
|
|
6807
6793
|
if (method) {
|
|
6808
|
-
return method.call(obj, this.
|
|
6794
|
+
return method.call(obj, this.composer, command, commandValue);
|
|
6809
6795
|
} else {
|
|
6810
6796
|
try {
|
|
6811
6797
|
// try/catch for buggy firefox
|
|
@@ -6819,17 +6805,16 @@ wysihtml5.commands = {
|
|
|
6819
6805
|
/**
|
|
6820
6806
|
* Get the current command's value
|
|
6821
6807
|
*
|
|
6822
|
-
* @param {Object} element The element which has contentEditable=true
|
|
6823
6808
|
* @param {String} command The command string which to check (eg. "formatBlock")
|
|
6824
6809
|
* @return {String} The command value
|
|
6825
6810
|
* @example
|
|
6826
|
-
* var currentBlockElement =
|
|
6811
|
+
* var currentBlockElement = commands.value("formatBlock");
|
|
6827
6812
|
*/
|
|
6828
6813
|
value: function(command) {
|
|
6829
|
-
var obj =
|
|
6814
|
+
var obj = wysihtml5.commands[command],
|
|
6830
6815
|
method = obj && obj.value;
|
|
6831
6816
|
if (method) {
|
|
6832
|
-
method(this.
|
|
6817
|
+
return method.call(obj, this.composer, command);
|
|
6833
6818
|
} else {
|
|
6834
6819
|
try {
|
|
6835
6820
|
// try/catch for buggy firefox
|
|
@@ -6839,21 +6824,21 @@ wysihtml5.commands = {
|
|
|
6839
6824
|
}
|
|
6840
6825
|
}
|
|
6841
6826
|
}
|
|
6842
|
-
};(function(wysihtml5) {
|
|
6827
|
+
});(function(wysihtml5) {
|
|
6843
6828
|
var undef;
|
|
6844
6829
|
|
|
6845
6830
|
wysihtml5.commands.bold = {
|
|
6846
|
-
exec: function(
|
|
6847
|
-
return wysihtml5.commands.formatInline.exec(
|
|
6831
|
+
exec: function(composer, command) {
|
|
6832
|
+
return wysihtml5.commands.formatInline.exec(composer, command, "b");
|
|
6848
6833
|
},
|
|
6849
6834
|
|
|
6850
|
-
state: function(
|
|
6835
|
+
state: function(composer, command, color) {
|
|
6851
6836
|
// element.ownerDocument.queryCommandState("bold") results:
|
|
6852
6837
|
// firefox: only <b>
|
|
6853
6838
|
// chrome: <b>, <strong>, <h1>, <h2>, ...
|
|
6854
6839
|
// ie: <b>, <strong>
|
|
6855
6840
|
// opera: <b>, <strong>
|
|
6856
|
-
return wysihtml5.commands.formatInline.state(
|
|
6841
|
+
return wysihtml5.commands.formatInline.state(composer, command, "b");
|
|
6857
6842
|
},
|
|
6858
6843
|
|
|
6859
6844
|
value: function() {
|
|
@@ -6867,9 +6852,9 @@ wysihtml5.commands = {
|
|
|
6867
6852
|
NODE_NAME = "A",
|
|
6868
6853
|
dom = wysihtml5.dom;
|
|
6869
6854
|
|
|
6870
|
-
function _removeFormat(
|
|
6871
|
-
var length
|
|
6872
|
-
i
|
|
6855
|
+
function _removeFormat(composer, anchors) {
|
|
6856
|
+
var length = anchors.length,
|
|
6857
|
+
i = 0,
|
|
6873
6858
|
anchor,
|
|
6874
6859
|
codeElement,
|
|
6875
6860
|
textContent;
|
|
@@ -6889,8 +6874,8 @@ wysihtml5.commands = {
|
|
|
6889
6874
|
}
|
|
6890
6875
|
}
|
|
6891
6876
|
|
|
6892
|
-
function _format(
|
|
6893
|
-
var doc =
|
|
6877
|
+
function _format(composer, attributes) {
|
|
6878
|
+
var doc = composer.doc,
|
|
6894
6879
|
tempClass = "_wysihtml5-temp-" + (+new Date()),
|
|
6895
6880
|
tempClassRegExp = /non-matching-class/g,
|
|
6896
6881
|
i = 0,
|
|
@@ -6903,7 +6888,7 @@ wysihtml5.commands = {
|
|
|
6903
6888
|
textContent,
|
|
6904
6889
|
whiteSpace,
|
|
6905
6890
|
j;
|
|
6906
|
-
wysihtml5.commands.formatInline.exec(
|
|
6891
|
+
wysihtml5.commands.formatInline.exec(composer, undef, NODE_NAME, tempClass, tempClassRegExp);
|
|
6907
6892
|
anchors = doc.querySelectorAll(NODE_NAME + "." + tempClass);
|
|
6908
6893
|
length = anchors.length;
|
|
6909
6894
|
for (; i<length; i++) {
|
|
@@ -6922,12 +6907,12 @@ wysihtml5.commands = {
|
|
|
6922
6907
|
if (!hasElementChild && isEmpty) {
|
|
6923
6908
|
dom.setTextContent(anchor, anchor.href);
|
|
6924
6909
|
whiteSpace = doc.createTextNode(" ");
|
|
6925
|
-
|
|
6926
|
-
|
|
6910
|
+
composer.selection.setAfter(anchor);
|
|
6911
|
+
composer.selection.insertNode(whiteSpace);
|
|
6927
6912
|
elementToSetCaretAfter = whiteSpace;
|
|
6928
6913
|
}
|
|
6929
6914
|
}
|
|
6930
|
-
|
|
6915
|
+
composer.selection.setAfter(elementToSetCaretAfter);
|
|
6931
6916
|
}
|
|
6932
6917
|
|
|
6933
6918
|
wysihtml5.commands.createLink = {
|
|
@@ -6940,28 +6925,26 @@ wysihtml5.commands = {
|
|
|
6940
6925
|
*
|
|
6941
6926
|
* @example
|
|
6942
6927
|
* // either ...
|
|
6943
|
-
* wysihtml5.commands.createLink.exec(
|
|
6928
|
+
* wysihtml5.commands.createLink.exec(composer, "createLink", "http://www.google.de");
|
|
6944
6929
|
* // ... or ...
|
|
6945
|
-
* wysihtml5.commands.createLink.exec(
|
|
6930
|
+
* wysihtml5.commands.createLink.exec(composer, "createLink", { href: "http://www.google.de", target: "_blank" });
|
|
6946
6931
|
*/
|
|
6947
|
-
exec: function(
|
|
6948
|
-
var
|
|
6949
|
-
anchors = this.state(element, command);
|
|
6950
|
-
|
|
6932
|
+
exec: function(composer, command, value) {
|
|
6933
|
+
var anchors = this.state(composer, command);
|
|
6951
6934
|
if (anchors) {
|
|
6952
6935
|
// Selection contains links
|
|
6953
|
-
|
|
6954
|
-
_removeFormat(
|
|
6936
|
+
composer.selection.executeAndRestore(function() {
|
|
6937
|
+
_removeFormat(composer, anchors);
|
|
6955
6938
|
});
|
|
6956
6939
|
} else {
|
|
6957
6940
|
// Create links
|
|
6958
6941
|
value = typeof(value) === "object" ? value : { href: value };
|
|
6959
|
-
_format(
|
|
6942
|
+
_format(composer, value);
|
|
6960
6943
|
}
|
|
6961
6944
|
},
|
|
6962
6945
|
|
|
6963
|
-
state: function(
|
|
6964
|
-
return wysihtml5.commands.formatInline.state(
|
|
6946
|
+
state: function(composer, command) {
|
|
6947
|
+
return wysihtml5.commands.formatInline.state(composer, command, "A");
|
|
6965
6948
|
},
|
|
6966
6949
|
|
|
6967
6950
|
value: function() {
|
|
@@ -6978,12 +6961,12 @@ wysihtml5.commands = {
|
|
|
6978
6961
|
REG_EXP = /wysiwyg-font-size-[a-z]+/g;
|
|
6979
6962
|
|
|
6980
6963
|
wysihtml5.commands.fontSize = {
|
|
6981
|
-
exec: function(
|
|
6982
|
-
return wysihtml5.commands.formatInline.exec(
|
|
6964
|
+
exec: function(composer, command, size) {
|
|
6965
|
+
return wysihtml5.commands.formatInline.exec(composer, command, "span", "wysiwyg-font-size-" + size, REG_EXP);
|
|
6983
6966
|
},
|
|
6984
6967
|
|
|
6985
|
-
state: function(
|
|
6986
|
-
return wysihtml5.commands.formatInline.state(
|
|
6968
|
+
state: function(composer, command, size) {
|
|
6969
|
+
return wysihtml5.commands.formatInline.state(composer, command, "span", "wysiwyg-font-size-" + size, REG_EXP);
|
|
6987
6970
|
},
|
|
6988
6971
|
|
|
6989
6972
|
value: function() {
|
|
@@ -7001,12 +6984,12 @@ wysihtml5.commands = {
|
|
|
7001
6984
|
REG_EXP = /wysiwyg-color-[a-z]+/g;
|
|
7002
6985
|
|
|
7003
6986
|
wysihtml5.commands.foreColor = {
|
|
7004
|
-
exec: function(
|
|
7005
|
-
return wysihtml5.commands.formatInline.exec(
|
|
6987
|
+
exec: function(composer, command, color) {
|
|
6988
|
+
return wysihtml5.commands.formatInline.exec(composer, command, "span", "wysiwyg-color-" + color, REG_EXP);
|
|
7006
6989
|
},
|
|
7007
6990
|
|
|
7008
|
-
state: function(
|
|
7009
|
-
return wysihtml5.commands.formatInline.state(
|
|
6991
|
+
state: function(composer, command, color) {
|
|
6992
|
+
return wysihtml5.commands.formatInline.state(composer, command, "span", "wysiwyg-color-" + color, REG_EXP);
|
|
7010
6993
|
},
|
|
7011
6994
|
|
|
7012
6995
|
value: function() {
|
|
@@ -7016,7 +6999,6 @@ wysihtml5.commands = {
|
|
|
7016
6999
|
})(wysihtml5);(function(wysihtml5) {
|
|
7017
7000
|
var undef,
|
|
7018
7001
|
dom = wysihtml5.dom,
|
|
7019
|
-
selection = wysihtml5.selection,
|
|
7020
7002
|
DEFAULT_NODE_NAME = "DIV",
|
|
7021
7003
|
// Following elements are grouped
|
|
7022
7004
|
// when the caret is within a H1 and the H4 is invoked, the H1 should turn into H4
|
|
@@ -7140,7 +7122,7 @@ wysihtml5.commands = {
|
|
|
7140
7122
|
if (target.nodeType !== wysihtml5.ELEMENT_NODE) {
|
|
7141
7123
|
return;
|
|
7142
7124
|
}
|
|
7143
|
-
displayStyle
|
|
7125
|
+
displayStyle = dom.getStyle("display").from(target);
|
|
7144
7126
|
if (displayStyle.substr(0, 6) !== "inline") {
|
|
7145
7127
|
// Make sure that only block elements receive the given class
|
|
7146
7128
|
target.className += " " + className;
|
|
@@ -7153,12 +7135,12 @@ wysihtml5.commands = {
|
|
|
7153
7135
|
}
|
|
7154
7136
|
}
|
|
7155
7137
|
|
|
7156
|
-
function _selectLineAndWrap(element) {
|
|
7157
|
-
selection.selectLine();
|
|
7158
|
-
selection.surround(element);
|
|
7138
|
+
function _selectLineAndWrap(composer, element) {
|
|
7139
|
+
composer.selection.selectLine();
|
|
7140
|
+
composer.selection.surround(element);
|
|
7159
7141
|
_removeLineBreakBeforeAndAfter(element);
|
|
7160
7142
|
_removeLastChildIfLineBreak(element);
|
|
7161
|
-
selection.selectNode(element);
|
|
7143
|
+
composer.selection.selectNode(element);
|
|
7162
7144
|
}
|
|
7163
7145
|
|
|
7164
7146
|
function _hasClasses(element) {
|
|
@@ -7166,15 +7148,15 @@ wysihtml5.commands = {
|
|
|
7166
7148
|
}
|
|
7167
7149
|
|
|
7168
7150
|
wysihtml5.commands.formatBlock = {
|
|
7169
|
-
exec: function(
|
|
7170
|
-
var doc =
|
|
7171
|
-
blockElement = this.state(
|
|
7151
|
+
exec: function(composer, command, nodeName, className, classRegExp) {
|
|
7152
|
+
var doc = composer.doc,
|
|
7153
|
+
blockElement = this.state(composer, command, nodeName, className, classRegExp),
|
|
7172
7154
|
selectedNode;
|
|
7173
7155
|
|
|
7174
7156
|
nodeName = typeof(nodeName) === "string" ? nodeName.toUpperCase() : nodeName;
|
|
7175
7157
|
|
|
7176
7158
|
if (blockElement) {
|
|
7177
|
-
selection.executeAndRestoreSimple(function() {
|
|
7159
|
+
composer.selection.executeAndRestoreSimple(function() {
|
|
7178
7160
|
if (classRegExp) {
|
|
7179
7161
|
_removeClass(blockElement, classRegExp);
|
|
7180
7162
|
}
|
|
@@ -7194,13 +7176,13 @@ wysihtml5.commands = {
|
|
|
7194
7176
|
|
|
7195
7177
|
// Find similiar block element and rename it (<h2 class="foo"></h2> => <h1 class="foo"></h1>)
|
|
7196
7178
|
if (nodeName === null || wysihtml5.lang.array(BLOCK_ELEMENTS_GROUP).contains(nodeName)) {
|
|
7197
|
-
selectedNode = selection.getSelectedNode();
|
|
7179
|
+
selectedNode = composer.selection.getSelectedNode();
|
|
7198
7180
|
blockElement = dom.getParentElement(selectedNode, {
|
|
7199
|
-
nodeName:
|
|
7181
|
+
nodeName: BLOCK_ELEMENTS_GROUP
|
|
7200
7182
|
});
|
|
7201
7183
|
|
|
7202
7184
|
if (blockElement) {
|
|
7203
|
-
selection.executeAndRestoreSimple(function() {
|
|
7185
|
+
composer.selection.executeAndRestoreSimple(function() {
|
|
7204
7186
|
// Rename current block element to new block element and add class
|
|
7205
7187
|
if (nodeName) {
|
|
7206
7188
|
blockElement = dom.renameElement(blockElement, nodeName);
|
|
@@ -7213,7 +7195,7 @@ wysihtml5.commands = {
|
|
|
7213
7195
|
}
|
|
7214
7196
|
}
|
|
7215
7197
|
|
|
7216
|
-
if (
|
|
7198
|
+
if (composer.commands.support(command)) {
|
|
7217
7199
|
_execCommand(doc, command, nodeName || DEFAULT_NODE_NAME, className);
|
|
7218
7200
|
return;
|
|
7219
7201
|
}
|
|
@@ -7222,12 +7204,12 @@ wysihtml5.commands = {
|
|
|
7222
7204
|
if (className) {
|
|
7223
7205
|
blockElement.className = className;
|
|
7224
7206
|
}
|
|
7225
|
-
_selectLineAndWrap(blockElement);
|
|
7207
|
+
_selectLineAndWrap(composer, blockElement);
|
|
7226
7208
|
},
|
|
7227
7209
|
|
|
7228
|
-
state: function(
|
|
7210
|
+
state: function(composer, command, nodeName, className, classRegExp) {
|
|
7229
7211
|
nodeName = typeof(nodeName) === "string" ? nodeName.toUpperCase() : nodeName;
|
|
7230
|
-
var selectedNode = selection.getSelectedNode();
|
|
7212
|
+
var selectedNode = composer.selection.getSelectedNode();
|
|
7231
7213
|
return dom.getParentElement(selectedNode, {
|
|
7232
7214
|
nodeName: nodeName,
|
|
7233
7215
|
className: className,
|
|
@@ -7297,17 +7279,17 @@ wysihtml5.commands = {
|
|
|
7297
7279
|
}
|
|
7298
7280
|
|
|
7299
7281
|
wysihtml5.commands.formatInline = {
|
|
7300
|
-
exec: function(
|
|
7301
|
-
var range =
|
|
7282
|
+
exec: function(composer, command, tagName, className, classRegExp) {
|
|
7283
|
+
var range = composer.selection.getRange();
|
|
7302
7284
|
if (!range) {
|
|
7303
7285
|
return false;
|
|
7304
7286
|
}
|
|
7305
7287
|
_getApplier(tagName, className, classRegExp).toggleRange(range);
|
|
7306
|
-
|
|
7288
|
+
composer.selection.setSelection(range);
|
|
7307
7289
|
},
|
|
7308
7290
|
|
|
7309
|
-
state: function(
|
|
7310
|
-
var doc =
|
|
7291
|
+
state: function(composer, command, tagName, className, classRegExp) {
|
|
7292
|
+
var doc = composer.doc,
|
|
7311
7293
|
aliasTagName = ALIAS_MAPPING[tagName] || tagName,
|
|
7312
7294
|
range;
|
|
7313
7295
|
|
|
@@ -7322,7 +7304,7 @@ wysihtml5.commands = {
|
|
|
7322
7304
|
return false;
|
|
7323
7305
|
}
|
|
7324
7306
|
|
|
7325
|
-
range =
|
|
7307
|
+
range = composer.selection.getRange();
|
|
7326
7308
|
if (!range) {
|
|
7327
7309
|
return false;
|
|
7328
7310
|
}
|
|
@@ -7338,11 +7320,11 @@ wysihtml5.commands = {
|
|
|
7338
7320
|
var undef;
|
|
7339
7321
|
|
|
7340
7322
|
wysihtml5.commands.insertHTML = {
|
|
7341
|
-
exec: function(
|
|
7342
|
-
if (
|
|
7343
|
-
|
|
7323
|
+
exec: function(composer, command, html) {
|
|
7324
|
+
if (composer.commands.support(command)) {
|
|
7325
|
+
composer.doc.execCommand(command, false, html);
|
|
7344
7326
|
} else {
|
|
7345
|
-
|
|
7327
|
+
composer.selection.insertHTML(html);
|
|
7346
7328
|
}
|
|
7347
7329
|
},
|
|
7348
7330
|
|
|
@@ -7364,33 +7346,34 @@ wysihtml5.commands = {
|
|
|
7364
7346
|
*
|
|
7365
7347
|
* @example
|
|
7366
7348
|
* // either ...
|
|
7367
|
-
* wysihtml5.commands.insertImage.exec(
|
|
7349
|
+
* wysihtml5.commands.insertImage.exec(composer, "insertImage", "http://www.google.de/logo.jpg");
|
|
7368
7350
|
* // ... or ...
|
|
7369
|
-
* wysihtml5.commands.insertImage.exec(
|
|
7351
|
+
* wysihtml5.commands.insertImage.exec(composer, "insertImage", { src: "http://www.google.de/logo.jpg", title: "foo" });
|
|
7370
7352
|
*/
|
|
7371
|
-
exec: function(
|
|
7353
|
+
exec: function(composer, command, value) {
|
|
7372
7354
|
value = typeof(value) === "object" ? value : { src: value };
|
|
7373
7355
|
|
|
7374
|
-
var doc
|
|
7375
|
-
image
|
|
7356
|
+
var doc = composer.doc,
|
|
7357
|
+
image = this.state(composer),
|
|
7358
|
+
textNode,
|
|
7376
7359
|
i,
|
|
7377
7360
|
parent;
|
|
7378
7361
|
|
|
7379
7362
|
if (image) {
|
|
7380
7363
|
// Image already selected, set the caret before it and delete it
|
|
7381
|
-
|
|
7364
|
+
composer.selection.setBefore(image);
|
|
7382
7365
|
parent = image.parentNode;
|
|
7383
7366
|
parent.removeChild(image);
|
|
7384
7367
|
|
|
7385
7368
|
// and it's parent <a> too if it hasn't got any other relevant child nodes
|
|
7386
7369
|
wysihtml5.dom.removeEmptyTextNodes(parent);
|
|
7387
7370
|
if (parent.nodeName === "A" && !parent.firstChild) {
|
|
7388
|
-
|
|
7371
|
+
composer.selection.setAfter(parent);
|
|
7389
7372
|
parent.parentNode.removeChild(parent);
|
|
7390
7373
|
}
|
|
7391
7374
|
|
|
7392
7375
|
// firefox and ie sometimes don't remove the image handles, even though the image got removed
|
|
7393
|
-
wysihtml5.quirks.redraw(element);
|
|
7376
|
+
wysihtml5.quirks.redraw(composer.element);
|
|
7394
7377
|
return;
|
|
7395
7378
|
}
|
|
7396
7379
|
|
|
@@ -7400,12 +7383,18 @@ wysihtml5.commands = {
|
|
|
7400
7383
|
image[i] = value[i];
|
|
7401
7384
|
}
|
|
7402
7385
|
|
|
7403
|
-
|
|
7404
|
-
wysihtml5.
|
|
7386
|
+
composer.selection.insertNode(image);
|
|
7387
|
+
if (wysihtml5.browser.hasProblemsSettingCaretAfterImg()) {
|
|
7388
|
+
textNode = doc.createTextNode(wysihtml5.INVISIBLE_SPACE);
|
|
7389
|
+
composer.selection.insertNode(textNode);
|
|
7390
|
+
composer.selection.setAfter(textNode);
|
|
7391
|
+
} else {
|
|
7392
|
+
composer.selection.setAfter(image);
|
|
7393
|
+
}
|
|
7405
7394
|
},
|
|
7406
7395
|
|
|
7407
|
-
state: function(
|
|
7408
|
-
var doc =
|
|
7396
|
+
state: function(composer) {
|
|
7397
|
+
var doc = composer.doc,
|
|
7409
7398
|
selectedNode,
|
|
7410
7399
|
text,
|
|
7411
7400
|
imagesInSelection;
|
|
@@ -7414,7 +7403,7 @@ wysihtml5.commands = {
|
|
|
7414
7403
|
return false;
|
|
7415
7404
|
}
|
|
7416
7405
|
|
|
7417
|
-
selectedNode =
|
|
7406
|
+
selectedNode = composer.selection.getSelectedNode();
|
|
7418
7407
|
if (!selectedNode) {
|
|
7419
7408
|
return false;
|
|
7420
7409
|
}
|
|
@@ -7428,13 +7417,13 @@ wysihtml5.commands = {
|
|
|
7428
7417
|
return false;
|
|
7429
7418
|
}
|
|
7430
7419
|
|
|
7431
|
-
text =
|
|
7420
|
+
text = composer.selection.getText();
|
|
7432
7421
|
text = wysihtml5.lang.string(text).trim();
|
|
7433
7422
|
if (text) {
|
|
7434
7423
|
return false;
|
|
7435
7424
|
}
|
|
7436
7425
|
|
|
7437
|
-
imagesInSelection =
|
|
7426
|
+
imagesInSelection = composer.selection.getNodes(wysihtml5.ELEMENT_NODE, function(node) {
|
|
7438
7427
|
return node.nodeName === "IMG";
|
|
7439
7428
|
});
|
|
7440
7429
|
|
|
@@ -7445,8 +7434,8 @@ wysihtml5.commands = {
|
|
|
7445
7434
|
return imagesInSelection[0];
|
|
7446
7435
|
},
|
|
7447
7436
|
|
|
7448
|
-
value: function(
|
|
7449
|
-
var image = this.state(
|
|
7437
|
+
value: function(composer) {
|
|
7438
|
+
var image = this.state(composer);
|
|
7450
7439
|
return image && image.src;
|
|
7451
7440
|
}
|
|
7452
7441
|
};
|
|
@@ -7455,14 +7444,14 @@ wysihtml5.commands = {
|
|
|
7455
7444
|
LINE_BREAK = "<br>" + (wysihtml5.browser.needsSpaceAfterLineBreak() ? " " : "");
|
|
7456
7445
|
|
|
7457
7446
|
wysihtml5.commands.insertLineBreak = {
|
|
7458
|
-
exec: function(
|
|
7459
|
-
if (
|
|
7460
|
-
|
|
7447
|
+
exec: function(composer, command) {
|
|
7448
|
+
if (composer.commands.support(command)) {
|
|
7449
|
+
composer.doc.execCommand(command, false, null);
|
|
7461
7450
|
if (!wysihtml5.browser.autoScrollsToCaret()) {
|
|
7462
|
-
|
|
7451
|
+
composer.selection.scrollIntoView();
|
|
7463
7452
|
}
|
|
7464
7453
|
} else {
|
|
7465
|
-
|
|
7454
|
+
composer.commands.exec("insertHTML", LINE_BREAK);
|
|
7466
7455
|
}
|
|
7467
7456
|
},
|
|
7468
7457
|
|
|
@@ -7478,33 +7467,33 @@ wysihtml5.commands = {
|
|
|
7478
7467
|
var undef;
|
|
7479
7468
|
|
|
7480
7469
|
wysihtml5.commands.insertOrderedList = {
|
|
7481
|
-
exec: function(
|
|
7482
|
-
var doc =
|
|
7470
|
+
exec: function(composer, command) {
|
|
7471
|
+
var doc = composer.doc,
|
|
7483
7472
|
selectedNode,
|
|
7484
7473
|
isEmpty,
|
|
7485
7474
|
tempElement,
|
|
7486
7475
|
list;
|
|
7487
7476
|
|
|
7488
|
-
if (
|
|
7477
|
+
if (composer.commands.support(command)) {
|
|
7489
7478
|
doc.execCommand(command, false, null);
|
|
7490
7479
|
} else {
|
|
7491
|
-
selectedNode =
|
|
7480
|
+
selectedNode = composer.selection.getSelectedNode();
|
|
7492
7481
|
list = wysihtml5.dom.getParentElement(selectedNode, { nodeName: ["UL", "OL"] }, 4);
|
|
7493
7482
|
if (!list) {
|
|
7494
7483
|
tempElement = doc.createElement("span");
|
|
7495
|
-
|
|
7484
|
+
composer.selection.surround(tempElement);
|
|
7496
7485
|
isEmpty = tempElement.innerHTML === "" || tempElement.innerHTML === wysihtml5.INVISIBLE_SPACE;
|
|
7497
|
-
|
|
7486
|
+
composer.selection.executeAndRestoreSimple(function() {
|
|
7498
7487
|
list = wysihtml5.dom.convertToList(tempElement, "ol");
|
|
7499
7488
|
});
|
|
7500
7489
|
|
|
7501
7490
|
if (isEmpty) {
|
|
7502
|
-
|
|
7491
|
+
composer.selection.selectNode(list.querySelector("li"));
|
|
7503
7492
|
}
|
|
7504
7493
|
return;
|
|
7505
7494
|
}
|
|
7506
7495
|
|
|
7507
|
-
|
|
7496
|
+
composer.selection.executeAndRestoreSimple(function() {
|
|
7508
7497
|
if (list.nodeName === "OL") {
|
|
7509
7498
|
// Unwrap list
|
|
7510
7499
|
// <ol><li>foo</li><li>bar</li></ol>
|
|
@@ -7522,9 +7511,9 @@ wysihtml5.commands = {
|
|
|
7522
7511
|
}
|
|
7523
7512
|
},
|
|
7524
7513
|
|
|
7525
|
-
state: function(
|
|
7514
|
+
state: function(composer, command) {
|
|
7526
7515
|
try {
|
|
7527
|
-
return
|
|
7516
|
+
return composer.doc.queryCommandState(command);
|
|
7528
7517
|
} catch(e) {
|
|
7529
7518
|
return false;
|
|
7530
7519
|
}
|
|
@@ -7538,34 +7527,34 @@ wysihtml5.commands = {
|
|
|
7538
7527
|
var undef;
|
|
7539
7528
|
|
|
7540
7529
|
wysihtml5.commands.insertUnorderedList = {
|
|
7541
|
-
exec: function(
|
|
7542
|
-
var doc =
|
|
7530
|
+
exec: function(composer, command) {
|
|
7531
|
+
var doc = composer.doc,
|
|
7543
7532
|
selectedNode,
|
|
7544
7533
|
isEmpty,
|
|
7545
7534
|
tempElement,
|
|
7546
7535
|
list;
|
|
7547
7536
|
|
|
7548
|
-
if (
|
|
7537
|
+
if (composer.commands.support(command)) {
|
|
7549
7538
|
doc.execCommand(command, false, null);
|
|
7550
7539
|
} else {
|
|
7551
|
-
selectedNode =
|
|
7540
|
+
selectedNode = composer.selection.getSelectedNode();
|
|
7552
7541
|
list = wysihtml5.dom.getParentElement(selectedNode, { nodeName: ["UL", "OL"] });
|
|
7553
7542
|
|
|
7554
7543
|
if (!list) {
|
|
7555
7544
|
tempElement = doc.createElement("span");
|
|
7556
|
-
|
|
7545
|
+
composer.selection.surround(tempElement);
|
|
7557
7546
|
isEmpty = tempElement.innerHTML === "" || tempElement.innerHTML === wysihtml5.INVISIBLE_SPACE;
|
|
7558
|
-
|
|
7547
|
+
composer.selection.executeAndRestoreSimple(function() {
|
|
7559
7548
|
list = wysihtml5.dom.convertToList(tempElement, "ul");
|
|
7560
7549
|
});
|
|
7561
7550
|
|
|
7562
7551
|
if (isEmpty) {
|
|
7563
|
-
|
|
7552
|
+
composer.selection.selectNode(list.querySelector("li"));
|
|
7564
7553
|
}
|
|
7565
7554
|
return;
|
|
7566
7555
|
}
|
|
7567
7556
|
|
|
7568
|
-
|
|
7557
|
+
composer.selection.executeAndRestoreSimple(function() {
|
|
7569
7558
|
if (list.nodeName === "UL") {
|
|
7570
7559
|
// Unwrap list
|
|
7571
7560
|
// <ul><li>foo</li><li>bar</li></ul>
|
|
@@ -7583,9 +7572,9 @@ wysihtml5.commands = {
|
|
|
7583
7572
|
}
|
|
7584
7573
|
},
|
|
7585
7574
|
|
|
7586
|
-
state: function(
|
|
7575
|
+
state: function(composer, command) {
|
|
7587
7576
|
try {
|
|
7588
|
-
return
|
|
7577
|
+
return composer.doc.queryCommandState(command);
|
|
7589
7578
|
} catch(e) {
|
|
7590
7579
|
return false;
|
|
7591
7580
|
}
|
|
@@ -7599,17 +7588,17 @@ wysihtml5.commands = {
|
|
|
7599
7588
|
var undef;
|
|
7600
7589
|
|
|
7601
7590
|
wysihtml5.commands.italic = {
|
|
7602
|
-
exec: function(
|
|
7603
|
-
return wysihtml5.commands.formatInline.exec(
|
|
7591
|
+
exec: function(composer, command) {
|
|
7592
|
+
return wysihtml5.commands.formatInline.exec(composer, command, "i");
|
|
7604
7593
|
},
|
|
7605
7594
|
|
|
7606
|
-
state: function(
|
|
7595
|
+
state: function(composer, command, color) {
|
|
7607
7596
|
// element.ownerDocument.queryCommandState("italic") results:
|
|
7608
7597
|
// firefox: only <i>
|
|
7609
7598
|
// chrome: <i>, <em>, <blockquote>, ...
|
|
7610
7599
|
// ie: <i>, <em>
|
|
7611
7600
|
// opera: only <i>
|
|
7612
|
-
return wysihtml5.commands.formatInline.state(
|
|
7601
|
+
return wysihtml5.commands.formatInline.state(composer, command, "i");
|
|
7613
7602
|
},
|
|
7614
7603
|
|
|
7615
7604
|
value: function() {
|
|
@@ -7622,12 +7611,12 @@ wysihtml5.commands = {
|
|
|
7622
7611
|
REG_EXP = /wysiwyg-text-align-[a-z]+/g;
|
|
7623
7612
|
|
|
7624
7613
|
wysihtml5.commands.justifyCenter = {
|
|
7625
|
-
exec: function(
|
|
7626
|
-
return wysihtml5.commands.formatBlock.exec(
|
|
7614
|
+
exec: function(composer, command) {
|
|
7615
|
+
return wysihtml5.commands.formatBlock.exec(composer, "formatBlock", null, CLASS_NAME, REG_EXP);
|
|
7627
7616
|
},
|
|
7628
7617
|
|
|
7629
|
-
state: function(
|
|
7630
|
-
return wysihtml5.commands.formatBlock.state(
|
|
7618
|
+
state: function(composer, command) {
|
|
7619
|
+
return wysihtml5.commands.formatBlock.state(composer, "formatBlock", null, CLASS_NAME, REG_EXP);
|
|
7631
7620
|
},
|
|
7632
7621
|
|
|
7633
7622
|
value: function() {
|
|
@@ -7640,12 +7629,12 @@ wysihtml5.commands = {
|
|
|
7640
7629
|
REG_EXP = /wysiwyg-text-align-[a-z]+/g;
|
|
7641
7630
|
|
|
7642
7631
|
wysihtml5.commands.justifyLeft = {
|
|
7643
|
-
exec: function(
|
|
7644
|
-
return wysihtml5.commands.formatBlock.exec(
|
|
7632
|
+
exec: function(composer, command) {
|
|
7633
|
+
return wysihtml5.commands.formatBlock.exec(composer, "formatBlock", null, CLASS_NAME, REG_EXP);
|
|
7645
7634
|
},
|
|
7646
7635
|
|
|
7647
|
-
state: function(
|
|
7648
|
-
return wysihtml5.commands.formatBlock.state(
|
|
7636
|
+
state: function(composer, command) {
|
|
7637
|
+
return wysihtml5.commands.formatBlock.state(composer, "formatBlock", null, CLASS_NAME, REG_EXP);
|
|
7649
7638
|
},
|
|
7650
7639
|
|
|
7651
7640
|
value: function() {
|
|
@@ -7658,12 +7647,12 @@ wysihtml5.commands = {
|
|
|
7658
7647
|
REG_EXP = /wysiwyg-text-align-[a-z]+/g;
|
|
7659
7648
|
|
|
7660
7649
|
wysihtml5.commands.justifyRight = {
|
|
7661
|
-
exec: function(
|
|
7662
|
-
return wysihtml5.commands.formatBlock.exec(
|
|
7650
|
+
exec: function(composer, command) {
|
|
7651
|
+
return wysihtml5.commands.formatBlock.exec(composer, "formatBlock", null, CLASS_NAME, REG_EXP);
|
|
7663
7652
|
},
|
|
7664
7653
|
|
|
7665
|
-
state: function(
|
|
7666
|
-
return wysihtml5.commands.formatBlock.state(
|
|
7654
|
+
state: function(composer, command) {
|
|
7655
|
+
return wysihtml5.commands.formatBlock.state(composer, "formatBlock", null, CLASS_NAME, REG_EXP);
|
|
7667
7656
|
},
|
|
7668
7657
|
|
|
7669
7658
|
value: function() {
|
|
@@ -7676,12 +7665,12 @@ wysihtml5.commands = {
|
|
|
7676
7665
|
CLASS_NAME = "wysiwyg-text-decoration-underline";
|
|
7677
7666
|
|
|
7678
7667
|
wysihtml5.commands.underline = {
|
|
7679
|
-
exec: function(
|
|
7680
|
-
return wysihtml5.commands.formatInline.exec(
|
|
7668
|
+
exec: function(composer, command) {
|
|
7669
|
+
return wysihtml5.commands.formatInline.exec(composer, command, "span", CLASS_NAME, REG_EXP);
|
|
7681
7670
|
},
|
|
7682
7671
|
|
|
7683
|
-
state: function(
|
|
7684
|
-
return wysihtml5.commands.formatInline.state(
|
|
7672
|
+
state: function(composer, command) {
|
|
7673
|
+
return wysihtml5.commands.formatInline.state(composer, command, "span", CLASS_NAME, REG_EXP);
|
|
7685
7674
|
},
|
|
7686
7675
|
|
|
7687
7676
|
value: function() {
|
|
@@ -7713,24 +7702,25 @@ wysihtml5.commands = {
|
|
|
7713
7702
|
/** @scope wysihtml5.UndoManager.prototype */ {
|
|
7714
7703
|
constructor: function(editor) {
|
|
7715
7704
|
this.editor = editor;
|
|
7716
|
-
this.
|
|
7717
|
-
this.
|
|
7705
|
+
this.composer = editor.composer;
|
|
7706
|
+
this.element = this.composer.element;
|
|
7707
|
+
this.history = [this.composer.getValue()];
|
|
7718
7708
|
this.position = 1;
|
|
7719
7709
|
|
|
7720
7710
|
// Undo manager currently only supported in browsers who have the insertHTML command (not IE)
|
|
7721
|
-
if (
|
|
7711
|
+
if (this.composer.commands.support("insertHTML")) {
|
|
7722
7712
|
this._observe();
|
|
7723
7713
|
}
|
|
7724
7714
|
},
|
|
7725
7715
|
|
|
7726
7716
|
_observe: function() {
|
|
7727
|
-
var that
|
|
7728
|
-
doc
|
|
7717
|
+
var that = this,
|
|
7718
|
+
doc = this.composer.sandbox.getDocument(),
|
|
7729
7719
|
lastKey;
|
|
7730
7720
|
|
|
7731
7721
|
// Catch CTRL+Z and CTRL+Y
|
|
7732
|
-
dom.observe(this.
|
|
7733
|
-
if (!event.ctrlKey && !event.metaKey) {
|
|
7722
|
+
dom.observe(this.element, "keydown", function(event) {
|
|
7723
|
+
if (event.altKey || (!event.ctrlKey && !event.metaKey)) {
|
|
7734
7724
|
return;
|
|
7735
7725
|
}
|
|
7736
7726
|
|
|
@@ -7748,7 +7738,7 @@ wysihtml5.commands = {
|
|
|
7748
7738
|
});
|
|
7749
7739
|
|
|
7750
7740
|
// Catch delete and backspace
|
|
7751
|
-
dom.observe(this.
|
|
7741
|
+
dom.observe(this.element, "keydown", function(event) {
|
|
7752
7742
|
var keyCode = event.keyCode;
|
|
7753
7743
|
if (keyCode === lastKey) {
|
|
7754
7744
|
return;
|
|
@@ -7761,12 +7751,6 @@ wysihtml5.commands = {
|
|
|
7761
7751
|
}
|
|
7762
7752
|
});
|
|
7763
7753
|
|
|
7764
|
-
var interval, observed, cleanUp = function() {
|
|
7765
|
-
cleanTempElements(doc);
|
|
7766
|
-
clearInterval(interval);
|
|
7767
|
-
};
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
7754
|
// Now this is very hacky:
|
|
7771
7755
|
// These days browsers don't offer a undo/redo event which we could hook into
|
|
7772
7756
|
// to be notified when the user hits undo/redo in the contextmenu.
|
|
@@ -7774,36 +7758,43 @@ wysihtml5.commands = {
|
|
|
7774
7758
|
// The last element being inserted will be immediately be removed again by a exexCommand("undo")
|
|
7775
7759
|
// => When the second element appears in the dom tree then we know the user clicked "redo" in the context menu
|
|
7776
7760
|
// => When the first element disappears from the dom tree then we know the user clicked "undo" in the context menu
|
|
7777
|
-
|
|
7778
|
-
cleanUp()
|
|
7779
|
-
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
}
|
|
7783
|
-
|
|
7784
|
-
// enable undo button in context menu
|
|
7785
|
-
doc.execCommand("insertHTML", false, UNDO_HTML);
|
|
7786
|
-
// enable redo button in context menu
|
|
7787
|
-
doc.execCommand("insertHTML", false, REDO_HTML);
|
|
7788
|
-
doc.execCommand("undo", false, null);
|
|
7789
|
-
});
|
|
7761
|
+
if (wysihtml5.browser.hasUndoInContextMenu()) {
|
|
7762
|
+
var interval, observed, cleanUp = function() {
|
|
7763
|
+
cleanTempElements(doc);
|
|
7764
|
+
clearInterval(interval);
|
|
7765
|
+
};
|
|
7790
7766
|
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
that.
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7767
|
+
dom.observe(this.element, "contextmenu", function() {
|
|
7768
|
+
cleanUp();
|
|
7769
|
+
that.composer.selection.executeAndRestoreSimple(function() {
|
|
7770
|
+
if (that.element.lastChild) {
|
|
7771
|
+
that.composer.selection.setAfter(that.element.lastChild);
|
|
7772
|
+
}
|
|
7773
|
+
|
|
7774
|
+
// enable undo button in context menu
|
|
7775
|
+
doc.execCommand("insertHTML", false, UNDO_HTML);
|
|
7776
|
+
// enable redo button in context menu
|
|
7777
|
+
doc.execCommand("insertHTML", false, REDO_HTML);
|
|
7778
|
+
doc.execCommand("undo", false, null);
|
|
7779
|
+
});
|
|
7780
|
+
|
|
7781
|
+
interval = setInterval(function() {
|
|
7782
|
+
if (doc.getElementById("_wysihtml5-redo")) {
|
|
7783
|
+
cleanUp();
|
|
7784
|
+
that.redo();
|
|
7785
|
+
} else if (!doc.getElementById("_wysihtml5-undo")) {
|
|
7786
|
+
cleanUp();
|
|
7787
|
+
that.undo();
|
|
7788
|
+
}
|
|
7789
|
+
}, 400);
|
|
7790
|
+
|
|
7791
|
+
if (!observed) {
|
|
7792
|
+
observed = true;
|
|
7793
|
+
dom.observe(document, "mousedown", cleanUp);
|
|
7794
|
+
dom.observe(doc, ["mousedown", "paste", "cut", "copy"], cleanUp);
|
|
7798
7795
|
}
|
|
7799
|
-
}
|
|
7800
|
-
|
|
7801
|
-
if (!observed) {
|
|
7802
|
-
observed = true;
|
|
7803
|
-
dom.observe(document, "mousedown", cleanUp);
|
|
7804
|
-
dom.observe(doc, ["mousedown", "paste", "cut", "copy"], cleanUp);
|
|
7805
|
-
}
|
|
7806
|
-
});
|
|
7796
|
+
});
|
|
7797
|
+
}
|
|
7807
7798
|
|
|
7808
7799
|
this.editor
|
|
7809
7800
|
.observe("newword:composer", function() {
|
|
@@ -7817,7 +7808,7 @@ wysihtml5.commands = {
|
|
|
7817
7808
|
|
|
7818
7809
|
transact: function() {
|
|
7819
7810
|
var previousHtml = this.history[this.position - 1],
|
|
7820
|
-
currentHtml = this.
|
|
7811
|
+
currentHtml = this.composer.getValue();
|
|
7821
7812
|
|
|
7822
7813
|
if (currentHtml == previousHtml) {
|
|
7823
7814
|
return;
|
|
@@ -7854,7 +7845,7 @@ wysihtml5.commands = {
|
|
|
7854
7845
|
},
|
|
7855
7846
|
|
|
7856
7847
|
set: function(html) {
|
|
7857
|
-
this.
|
|
7848
|
+
this.composer.setValue(html);
|
|
7858
7849
|
this.editor.focus(true);
|
|
7859
7850
|
}
|
|
7860
7851
|
});
|
|
@@ -7913,9 +7904,7 @@ wysihtml5.views.View = Base.extend(
|
|
|
7913
7904
|
}
|
|
7914
7905
|
});(function(wysihtml5) {
|
|
7915
7906
|
var dom = wysihtml5.dom,
|
|
7916
|
-
browser = wysihtml5.browser
|
|
7917
|
-
selection = wysihtml5.selection,
|
|
7918
|
-
commands = wysihtml5.commands;
|
|
7907
|
+
browser = wysihtml5.browser;
|
|
7919
7908
|
|
|
7920
7909
|
wysihtml5.views.Composer = wysihtml5.views.View.extend(
|
|
7921
7910
|
/** @scope wysihtml5.views.Composer.prototype */ {
|
|
@@ -7983,14 +7972,21 @@ wysihtml5.views.View = Base.extend(
|
|
|
7983
7972
|
},
|
|
7984
7973
|
|
|
7985
7974
|
focus: function(setToEnd) {
|
|
7975
|
+
// IE 8 fires the focus event after .focus()
|
|
7976
|
+
// This is needed by our simulate_placeholder.js to work
|
|
7977
|
+
// therefore we clear it ourselves this time
|
|
7978
|
+
if (wysihtml5.browser.doesAsyncFocus() && this.hasPlaceholderSet()) {
|
|
7979
|
+
this.clear();
|
|
7980
|
+
}
|
|
7981
|
+
|
|
7986
7982
|
this.base();
|
|
7987
7983
|
|
|
7988
7984
|
var lastChild = this.element.lastChild;
|
|
7989
7985
|
if (setToEnd && lastChild) {
|
|
7990
7986
|
if (lastChild.nodeName === "BR") {
|
|
7991
|
-
selection.setBefore(this.element.lastChild);
|
|
7987
|
+
this.selection.setBefore(this.element.lastChild);
|
|
7992
7988
|
} else {
|
|
7993
|
-
selection.setAfter(this.element.lastChild);
|
|
7989
|
+
this.selection.setAfter(this.element.lastChild);
|
|
7994
7990
|
}
|
|
7995
7991
|
}
|
|
7996
7992
|
},
|
|
@@ -8018,8 +8014,7 @@ wysihtml5.views.View = Base.extend(
|
|
|
8018
8014
|
this.sandbox = new dom.Sandbox(function() {
|
|
8019
8015
|
that._create();
|
|
8020
8016
|
}, {
|
|
8021
|
-
stylesheets: this.config.stylesheets
|
|
8022
|
-
uaCompatible: "IE=7"
|
|
8017
|
+
stylesheets: this.config.stylesheets
|
|
8023
8018
|
});
|
|
8024
8019
|
this.iframe = this.sandbox.getIframe();
|
|
8025
8020
|
|
|
@@ -8038,16 +8033,17 @@ wysihtml5.views.View = Base.extend(
|
|
|
8038
8033
|
_create: function() {
|
|
8039
8034
|
var that = this;
|
|
8040
8035
|
|
|
8041
|
-
this.
|
|
8036
|
+
this.doc = this.sandbox.getDocument();
|
|
8037
|
+
this.element = this.doc.body;
|
|
8042
8038
|
this.textarea = this.parent.textarea;
|
|
8043
8039
|
this.element.innerHTML = this.textarea.getValue(true);
|
|
8044
8040
|
this.enable();
|
|
8045
8041
|
|
|
8046
8042
|
// Make sure our selection handler is ready
|
|
8047
|
-
selection.
|
|
8043
|
+
this.selection = new wysihtml5.Selection(this.parent);
|
|
8048
8044
|
|
|
8049
|
-
// Make sure commands
|
|
8050
|
-
commands.
|
|
8045
|
+
// Make sure commands dispatcher is ready
|
|
8046
|
+
this.commands = new wysihtml5.Commands(this.parent);
|
|
8051
8047
|
|
|
8052
8048
|
dom.copyAttributes([
|
|
8053
8049
|
"className", "spellcheck", "title", "lang", "dir", "accessKey"
|
|
@@ -8077,7 +8073,7 @@ wysihtml5.views.View = Base.extend(
|
|
|
8077
8073
|
}
|
|
8078
8074
|
|
|
8079
8075
|
// Make sure that the browser avoids using inline styles whenever possible
|
|
8080
|
-
commands.exec("styleWithCSS", false);
|
|
8076
|
+
this.commands.exec("styleWithCSS", false);
|
|
8081
8077
|
|
|
8082
8078
|
this._initAutoLinking();
|
|
8083
8079
|
this._initObjectResizing();
|
|
@@ -8088,15 +8084,15 @@ wysihtml5.views.View = Base.extend(
|
|
|
8088
8084
|
setTimeout(function() { that.focus(); }, 100);
|
|
8089
8085
|
}
|
|
8090
8086
|
|
|
8091
|
-
wysihtml5.quirks.insertLineBreakOnReturn(this
|
|
8087
|
+
wysihtml5.quirks.insertLineBreakOnReturn(this);
|
|
8092
8088
|
|
|
8093
8089
|
// IE sometimes leaves a single paragraph, which can't be removed by the user
|
|
8094
8090
|
if (!browser.clearsContentEditableCorrectly()) {
|
|
8095
|
-
wysihtml5.quirks.ensureProperClearing(this
|
|
8091
|
+
wysihtml5.quirks.ensureProperClearing(this);
|
|
8096
8092
|
}
|
|
8097
8093
|
|
|
8098
8094
|
if (!browser.clearsListsInContentEditableCorrectly()) {
|
|
8099
|
-
wysihtml5.quirks.ensureProperClearingOfLists(this
|
|
8095
|
+
wysihtml5.quirks.ensureProperClearingOfLists(this);
|
|
8100
8096
|
}
|
|
8101
8097
|
|
|
8102
8098
|
// Set up a sync that makes sure that textarea and editor have the same content
|
|
@@ -8112,10 +8108,11 @@ wysihtml5.views.View = Base.extend(
|
|
|
8112
8108
|
},
|
|
8113
8109
|
|
|
8114
8110
|
_initAutoLinking: function() {
|
|
8115
|
-
var
|
|
8111
|
+
var that = this,
|
|
8112
|
+
supportsDisablingOfAutoLinking = browser.canDisableAutoLinking(),
|
|
8116
8113
|
supportsAutoLinking = browser.doesAutoLinkingInContentEditable();
|
|
8117
8114
|
if (supportsDisablingOfAutoLinking) {
|
|
8118
|
-
commands.exec("autoUrlDetect", false);
|
|
8115
|
+
this.commands.exec("autoUrlDetect", false);
|
|
8119
8116
|
}
|
|
8120
8117
|
|
|
8121
8118
|
if (!this.config.autoLink) {
|
|
@@ -8126,7 +8123,7 @@ wysihtml5.views.View = Base.extend(
|
|
|
8126
8123
|
// OR when he supports auto linking but we were able to turn it off (IE9+)
|
|
8127
8124
|
if (!supportsAutoLinking || (supportsAutoLinking && supportsDisablingOfAutoLinking)) {
|
|
8128
8125
|
this.parent.observe("newword:composer", function() {
|
|
8129
|
-
selection.executeAndRestore(function(startContainer, endContainer) {
|
|
8126
|
+
that.selection.executeAndRestore(function(startContainer, endContainer) {
|
|
8130
8127
|
dom.autoLink(endContainer.parentNode);
|
|
8131
8128
|
});
|
|
8132
8129
|
});
|
|
@@ -8153,7 +8150,7 @@ wysihtml5.views.View = Base.extend(
|
|
|
8153
8150
|
return;
|
|
8154
8151
|
}
|
|
8155
8152
|
|
|
8156
|
-
var selectedNode = selection.getSelectedNode(event.target.ownerDocument),
|
|
8153
|
+
var selectedNode = that.selection.getSelectedNode(event.target.ownerDocument),
|
|
8157
8154
|
link = dom.getParentElement(selectedNode, { nodeName: "A" }, 4),
|
|
8158
8155
|
textContent;
|
|
8159
8156
|
|
|
@@ -8183,8 +8180,8 @@ wysihtml5.views.View = Base.extend(
|
|
|
8183
8180
|
propertiesLength = properties.length,
|
|
8184
8181
|
element = this.element;
|
|
8185
8182
|
|
|
8186
|
-
commands.exec("enableObjectResizing", this.config.allowObjectResizing);
|
|
8187
|
-
|
|
8183
|
+
this.commands.exec("enableObjectResizing", this.config.allowObjectResizing);
|
|
8184
|
+
|
|
8188
8185
|
if (this.config.allowObjectResizing) {
|
|
8189
8186
|
// IE sets inline styles after resizing objects
|
|
8190
8187
|
// The following lines make sure that the width/height css properties
|
|
@@ -8406,8 +8403,6 @@ wysihtml5.views.View = Base.extend(
|
|
|
8406
8403
|
* - Catch paste events
|
|
8407
8404
|
* - Dispatch proprietary newword:composer event
|
|
8408
8405
|
* - Keyboard shortcuts
|
|
8409
|
-
*
|
|
8410
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
8411
8406
|
*/
|
|
8412
8407
|
(function(wysihtml5) {
|
|
8413
8408
|
var dom = wysihtml5.dom,
|
|
@@ -8470,7 +8465,7 @@ wysihtml5.views.View = Base.extend(
|
|
|
8470
8465
|
originalScrollTop = document.documentElement.scrollTop || document.body.scrollTop,
|
|
8471
8466
|
originalScrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
|
|
8472
8467
|
try {
|
|
8473
|
-
|
|
8468
|
+
that.selection.insertNode(input);
|
|
8474
8469
|
} catch(e) {
|
|
8475
8470
|
element.appendChild(input);
|
|
8476
8471
|
}
|
|
@@ -8501,7 +8496,7 @@ wysihtml5.views.View = Base.extend(
|
|
|
8501
8496
|
}
|
|
8502
8497
|
if (data) {
|
|
8503
8498
|
element.focus();
|
|
8504
|
-
|
|
8499
|
+
that.commands.exec("insertHTML", data);
|
|
8505
8500
|
that.parent.fire("paste").fire("paste:composer");
|
|
8506
8501
|
event.stopPropagation();
|
|
8507
8502
|
event.preventDefault();
|
|
@@ -8529,7 +8524,7 @@ wysihtml5.views.View = Base.extend(
|
|
|
8529
8524
|
dom.observe(element, "mousedown", function(event) {
|
|
8530
8525
|
var target = event.target;
|
|
8531
8526
|
if (target.nodeName === "IMG") {
|
|
8532
|
-
|
|
8527
|
+
that.selection.selectNode(target);
|
|
8533
8528
|
event.preventDefault();
|
|
8534
8529
|
}
|
|
8535
8530
|
});
|
|
@@ -8540,14 +8535,14 @@ wysihtml5.views.View = Base.extend(
|
|
|
8540
8535
|
var keyCode = event.keyCode,
|
|
8541
8536
|
command = shortcuts[keyCode];
|
|
8542
8537
|
if ((event.ctrlKey || event.metaKey) && command) {
|
|
8543
|
-
|
|
8538
|
+
that.commands.exec(command);
|
|
8544
8539
|
event.preventDefault();
|
|
8545
8540
|
}
|
|
8546
8541
|
});
|
|
8547
8542
|
|
|
8548
8543
|
// --------- Make sure that when pressing backspace/delete on selected images deletes the image and it's anchor ---------
|
|
8549
8544
|
dom.observe(element, "keydown", function(event) {
|
|
8550
|
-
var target =
|
|
8545
|
+
var target = that.selection.getSelectedNode(true),
|
|
8551
8546
|
keyCode = event.keyCode,
|
|
8552
8547
|
parent;
|
|
8553
8548
|
if (target && target.nodeName === "IMG" && (keyCode === wysihtml5.BACKSPACE_KEY || keyCode === wysihtml5.DELETE_KEY)) { // 8 => backspace, 46 => delete
|
|
@@ -8747,7 +8742,6 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
|
|
|
8747
8742
|
});/**
|
|
8748
8743
|
* Toolbar Dialog
|
|
8749
8744
|
*
|
|
8750
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
8751
8745
|
* @param {Element} link The toolbar link which causes the dialog to show up
|
|
8752
8746
|
* @param {Element} container The dialog container
|
|
8753
8747
|
*
|
|
@@ -8877,7 +8871,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
|
|
|
8877
8871
|
* Basically it adopted the attribute values into the corresponding input fields
|
|
8878
8872
|
*
|
|
8879
8873
|
*/
|
|
8880
|
-
_interpolate: function() {
|
|
8874
|
+
_interpolate: function(avoidHiddenFields) {
|
|
8881
8875
|
var field,
|
|
8882
8876
|
fieldName,
|
|
8883
8877
|
newValue,
|
|
@@ -8887,10 +8881,18 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
|
|
|
8887
8881
|
i = 0;
|
|
8888
8882
|
for (; i<length; i++) {
|
|
8889
8883
|
field = fields[i];
|
|
8884
|
+
|
|
8890
8885
|
// Never change elements where the user is currently typing in
|
|
8891
8886
|
if (field === focusedElement) {
|
|
8892
8887
|
continue;
|
|
8893
8888
|
}
|
|
8889
|
+
|
|
8890
|
+
// Don't update hidden fields
|
|
8891
|
+
// See https://github.com/xing/wysihtml5/pull/14
|
|
8892
|
+
if (avoidHiddenFields && field.type === "hidden") {
|
|
8893
|
+
continue;
|
|
8894
|
+
}
|
|
8895
|
+
|
|
8894
8896
|
fieldName = field.getAttribute(ATTRIBUTE_FIELDS);
|
|
8895
8897
|
newValue = this.elementToChange ? (this.elementToChange[fieldName] || "") : field.defaultValue;
|
|
8896
8898
|
field.value = newValue;
|
|
@@ -8907,7 +8909,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
|
|
|
8907
8909
|
this._observe();
|
|
8908
8910
|
this._interpolate();
|
|
8909
8911
|
if (elementToChange) {
|
|
8910
|
-
this.interval = setInterval(function() { that._interpolate(); }, 500);
|
|
8912
|
+
this.interval = setInterval(function() { that._interpolate(true); }, 500);
|
|
8911
8913
|
}
|
|
8912
8914
|
dom.addClass(this.link, CLASS_NAME_OPENED);
|
|
8913
8915
|
this.container.style.display = "";
|
|
@@ -8943,8 +8945,6 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
|
|
|
8943
8945
|
*
|
|
8944
8946
|
* "Accessing Google Speech API Chrome 11"
|
|
8945
8947
|
* http://mikepultz.com/2011/03/accessing-google-speech-api-chrome-11/
|
|
8946
|
-
*
|
|
8947
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
8948
8948
|
*/
|
|
8949
8949
|
(function(wysihtml5) {
|
|
8950
8950
|
var dom = wysihtml5.dom;
|
|
@@ -9021,7 +9021,6 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
|
|
|
9021
9021
|
})(wysihtml5);/**
|
|
9022
9022
|
* Toolbar
|
|
9023
9023
|
*
|
|
9024
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
9025
9024
|
* @param {Object} parent Reference to instance of Editor instance
|
|
9026
9025
|
* @param {Element} container Reference to the toolbar container element
|
|
9027
9026
|
*
|
|
@@ -9092,20 +9091,19 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
|
|
|
9092
9091
|
dialogElement = this.container.querySelector("[data-wysihtml5-dialog='" + command + "']"),
|
|
9093
9092
|
dialog,
|
|
9094
9093
|
caretBookmark;
|
|
9094
|
+
|
|
9095
9095
|
if (dialogElement) {
|
|
9096
9096
|
dialog = new wysihtml5.toolbar.Dialog(link, dialogElement);
|
|
9097
9097
|
|
|
9098
9098
|
dialog.observe("show", function() {
|
|
9099
|
-
caretBookmark =
|
|
9099
|
+
caretBookmark = that.composer.selection.getBookmark();
|
|
9100
9100
|
|
|
9101
9101
|
that.editor.fire("show:dialog", { command: command, dialogContainer: dialogElement, commandLink: link });
|
|
9102
9102
|
});
|
|
9103
9103
|
|
|
9104
9104
|
dialog.observe("save", function(attributes) {
|
|
9105
|
-
that.editor.focus(false);
|
|
9106
|
-
|
|
9107
9105
|
if (caretBookmark) {
|
|
9108
|
-
|
|
9106
|
+
that.composer.selection.setBookmark(caretBookmark);
|
|
9109
9107
|
}
|
|
9110
9108
|
that._execCommand(command, attributes);
|
|
9111
9109
|
|
|
@@ -9145,7 +9143,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
|
|
|
9145
9143
|
// Make sure that composer is focussed (false => don't move caret to the end)
|
|
9146
9144
|
this.editor.focus(false);
|
|
9147
9145
|
|
|
9148
|
-
|
|
9146
|
+
this.composer.commands.exec(command, commandValue);
|
|
9149
9147
|
this._updateLinkStates();
|
|
9150
9148
|
},
|
|
9151
9149
|
|
|
@@ -9240,7 +9238,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
|
|
|
9240
9238
|
command.dialog.hide();
|
|
9241
9239
|
}
|
|
9242
9240
|
} else {
|
|
9243
|
-
state =
|
|
9241
|
+
state = this.composer.commands.state(command.name, command.value);
|
|
9244
9242
|
if (wysihtml5.lang.object(state).isArray()) {
|
|
9245
9243
|
// Grab first and only object/element in state array, otherwise convert state into boolean
|
|
9246
9244
|
// to avoid showing a dialog for multiple selected elements which may have different attributes
|
|
@@ -9287,7 +9285,6 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
|
|
|
9287
9285
|
/**
|
|
9288
9286
|
* WYSIHTML5 Editor
|
|
9289
9287
|
*
|
|
9290
|
-
* @author Christopher Blum <christopher.blum@xing.com>
|
|
9291
9288
|
* @param {Element} textareaElement Reference to the textarea which should be turned into a rich text interface
|
|
9292
9289
|
* @param {Object} [config] See defaultConfig object below for explanation of each individual config option
|
|
9293
9290
|
*
|
|
@@ -9449,7 +9446,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
|
|
|
9449
9446
|
this.observe("paste:composer", function() {
|
|
9450
9447
|
var keepScrollPosition = true,
|
|
9451
9448
|
that = this;
|
|
9452
|
-
|
|
9449
|
+
that.composer.selection.executeAndRestore(function() {
|
|
9453
9450
|
wysihtml5.quirks.cleanPastedHTML(that.composer.element);
|
|
9454
9451
|
that.parse(that.composer.element);
|
|
9455
9452
|
}, keepScrollPosition);
|