wysia 0.0.3 → 0.0.4

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.
@@ -10,7 +10,7 @@
10
10
  */
11
11
  var wysihtml5 = {
12
12
  version: "0.3.0",
13
-
13
+
14
14
  // namespaces
15
15
  commands: {},
16
16
  dom: {},
@@ -19,14 +19,14 @@ var wysihtml5 = {
19
19
  lang: {},
20
20
  selection: {},
21
21
  views: {},
22
-
22
+
23
23
  INVISIBLE_SPACE: "\uFEFF",
24
-
24
+
25
25
  EMPTY_FUNCTION: function() {},
26
-
26
+
27
27
  ELEMENT_NODE: 1,
28
28
  TEXT_NODE: 3,
29
-
29
+
30
30
  BACKSPACE_KEY: 8,
31
31
  ENTER_KEY: 13,
32
32
  ESCAPE_KEY: 27,
@@ -701,7 +701,7 @@ rangy.createModule("DomUtil", function(api, module) {
701
701
  var dom = api.dom;
702
702
  var DomPosition = dom.DomPosition;
703
703
  var DOMException = api.DOMException;
704
-
704
+
705
705
  /*----------------------------------------------------------------------------------------------------------------*/
706
706
 
707
707
  // Utility functions
@@ -3255,7 +3255,7 @@ var Base = function() {
3255
3255
 
3256
3256
  Base.extend = function(_instance, _static) { // subclass
3257
3257
  var extend = Base.prototype.extend;
3258
-
3258
+
3259
3259
  // build the prototype
3260
3260
  Base._prototyping = true;
3261
3261
  var proto = new this;
@@ -3264,7 +3264,7 @@ Base.extend = function(_instance, _static) { // subclass
3264
3264
  // call this method from any other method to invoke that method's ancestor
3265
3265
  };
3266
3266
  delete Base._prototyping;
3267
-
3267
+
3268
3268
  // create the wrapper for the constructor function
3269
3269
  //var constructor = proto.constructor.valueOf(); //-dean
3270
3270
  var constructor = proto.constructor;
@@ -3279,7 +3279,7 @@ Base.extend = function(_instance, _static) { // subclass
3279
3279
  }
3280
3280
  }
3281
3281
  };
3282
-
3282
+
3283
3283
  // build the class interface
3284
3284
  klass.ancestor = this;
3285
3285
  klass.extend = this.extend;
@@ -3297,7 +3297,7 @@ Base.extend = function(_instance, _static) { // subclass
3297
3297
  return klass;
3298
3298
  };
3299
3299
 
3300
- Base.prototype = {
3300
+ Base.prototype = {
3301
3301
  extend: function(source, value) {
3302
3302
  if (arguments.length > 1) { // extending with a name/value pair
3303
3303
  var ancestor = this[source];
@@ -3356,7 +3356,7 @@ Base = Base.extend({
3356
3356
  }, {
3357
3357
  ancestor: Object,
3358
3358
  version: "1.1",
3359
-
3359
+
3360
3360
  forEach: function(object, block, context) {
3361
3361
  for (var key in object) {
3362
3362
  if (this.prototype[key] === undefined) {
@@ -3364,7 +3364,7 @@ Base = Base.extend({
3364
3364
  }
3365
3365
  }
3366
3366
  },
3367
-
3367
+
3368
3368
  implement: function() {
3369
3369
  for (var i = 0; i < arguments.length; i++) {
3370
3370
  if (typeof arguments[i] == "function") {
@@ -3377,7 +3377,7 @@ Base = Base.extend({
3377
3377
  }
3378
3378
  return this;
3379
3379
  },
3380
-
3380
+
3381
3381
  toString: function() {
3382
3382
  return String(this.valueOf());
3383
3383
  }
@@ -3393,15 +3393,15 @@ wysihtml5.browser = (function() {
3393
3393
  isWebKit = userAgent.indexOf("AppleWebKit/") !== -1,
3394
3394
  isChrome = userAgent.indexOf("Chrome/") !== -1,
3395
3395
  isOpera = userAgent.indexOf("Opera/") !== -1;
3396
-
3396
+
3397
3397
  function iosVersion(userAgent) {
3398
3398
  return ((/ipad|iphone|ipod/.test(userAgent) && userAgent.match(/ os (\d+).+? like mac os x/)) || [, 0])[1];
3399
3399
  }
3400
-
3400
+
3401
3401
  return {
3402
3402
  // Static variable needed, publicly accessible, to be able override it in unit tests
3403
3403
  USER_AGENT: userAgent,
3404
-
3404
+
3405
3405
  /**
3406
3406
  * Exclude browsers that are not capable of displaying and handling
3407
3407
  * contentEditable as desired:
@@ -3420,22 +3420,22 @@ wysihtml5.browser = (function() {
3420
3420
  hasQuerySelectorSupport = document.querySelector && document.querySelectorAll,
3421
3421
  // contentEditable is unusable in mobile browsers (tested iOS 4.2.2, Android 2.2, Opera Mobile, WebOS 3.05)
3422
3422
  isIncompatibleMobileBrowser = (this.isIos() && iosVersion(userAgent) < 5) || userAgent.indexOf("opera mobi") !== -1 || userAgent.indexOf("hpwos/") !== -1;
3423
-
3423
+
3424
3424
  return hasContentEditableSupport
3425
3425
  && hasEditingApiSupport
3426
3426
  && hasQuerySelectorSupport
3427
3427
  && !isIncompatibleMobileBrowser;
3428
3428
  },
3429
-
3429
+
3430
3430
  isTouchDevice: function() {
3431
3431
  return this.supportsEvent("touchmove");
3432
3432
  },
3433
-
3433
+
3434
3434
  isIos: function() {
3435
3435
  var userAgent = this.USER_AGENT.toLowerCase();
3436
3436
  return userAgent.indexOf("webkit") !== -1 && userAgent.indexOf("mobile") !== -1;
3437
3437
  },
3438
-
3438
+
3439
3439
  /**
3440
3440
  * Whether the browser supports sandboxed iframes
3441
3441
  * Currently only IE 6+ offers such feature <iframe security="restricted">
@@ -3509,7 +3509,7 @@ wysihtml5.browser = (function() {
3509
3509
  firesOnDropOnlyWhenOnDragOverIsCancelled: function() {
3510
3510
  return isWebKit || isGecko;
3511
3511
  },
3512
-
3512
+
3513
3513
  /**
3514
3514
  * Whether the browser supports the event.dataTransfer property in a proper way
3515
3515
  */
@@ -3560,7 +3560,7 @@ wysihtml5.browser = (function() {
3560
3560
  "insertUnorderedList": isIE || isOpera || isWebKit,
3561
3561
  "insertOrderedList": isIE || isOpera || isWebKit
3562
3562
  };
3563
-
3563
+
3564
3564
  // Firefox throws errors for queryCommandSupported, so we have to build up our own object of supported commands
3565
3565
  var supported = {
3566
3566
  "insertHTML": isGecko
@@ -3677,7 +3677,7 @@ wysihtml5.browser = (function() {
3677
3677
  supportsSelectionModify: function() {
3678
3678
  return "getSelection" in window && "modify" in window.getSelection();
3679
3679
  },
3680
-
3680
+
3681
3681
  /**
3682
3682
  * Whether the browser supports the classList object for fast className manipulation
3683
3683
  * See https://developer.mozilla.org/en/DOM/element.classList
@@ -3685,14 +3685,14 @@ wysihtml5.browser = (function() {
3685
3685
  supportsClassList: function() {
3686
3686
  return "classList" in testElement;
3687
3687
  },
3688
-
3688
+
3689
3689
  /**
3690
3690
  * Opera needs a white space after a <br> in order to position the caret correctly
3691
3691
  */
3692
3692
  needsSpaceAfterLineBreak: function() {
3693
3693
  return isOpera;
3694
3694
  },
3695
-
3695
+
3696
3696
  /**
3697
3697
  * Whether the browser supports the speech api on the given element
3698
3698
  * See http://mikepultz.com/2011/03/accessing-google-speech-api-chrome-11/
@@ -3707,7 +3707,7 @@ wysihtml5.browser = (function() {
3707
3707
  var chromeVersion = userAgent.match(/Chrome\/(\d+)/) || [, 0];
3708
3708
  return chromeVersion[1] >= 11 && ("onwebkitspeechchange" in input || "speech" in input);
3709
3709
  },
3710
-
3710
+
3711
3711
  /**
3712
3712
  * IE9 crashes when setting a getter via Object.defineProperty on XMLHttpRequest or XDomainRequest
3713
3713
  * See https://connect.microsoft.com/ie/feedback/details/650112
@@ -3716,21 +3716,21 @@ wysihtml5.browser = (function() {
3716
3716
  crashesWhenDefineProperty: function(property) {
3717
3717
  return isIE && (property === "XMLHttpRequest" || property === "XDomainRequest");
3718
3718
  },
3719
-
3719
+
3720
3720
  /**
3721
3721
  * IE is the only browser who fires the "focus" event not immediately when .focus() is called on an element
3722
3722
  */
3723
3723
  doesAsyncFocus: function() {
3724
3724
  return isIE;
3725
3725
  },
3726
-
3726
+
3727
3727
  /**
3728
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
3729
  */
3730
3730
  hasProblemsSettingCaretAfterImg: function() {
3731
3731
  return isIE;
3732
3732
  },
3733
-
3733
+
3734
3734
  hasUndoInContextMenu: function() {
3735
3735
  return isGecko || isChrome || isOpera;
3736
3736
  }
@@ -3754,7 +3754,7 @@ wysihtml5.browser = (function() {
3754
3754
  return false;
3755
3755
  }
3756
3756
  },
3757
-
3757
+
3758
3758
  /**
3759
3759
  * Substract one array from another
3760
3760
  *
@@ -3774,10 +3774,10 @@ wysihtml5.browser = (function() {
3774
3774
  }
3775
3775
  return newArr;
3776
3776
  },
3777
-
3777
+
3778
3778
  /**
3779
3779
  * Return a clean native array
3780
- *
3780
+ *
3781
3781
  * Following will convert a Live NodeList to a proper Array
3782
3782
  * @example
3783
3783
  * var childNodes = wysihtml5.lang.array(document.body.childNodes).get();
@@ -3848,11 +3848,11 @@ wysihtml5.browser = (function() {
3848
3848
  }
3849
3849
  return this;
3850
3850
  },
3851
-
3851
+
3852
3852
  get: function() {
3853
3853
  return obj;
3854
3854
  },
3855
-
3855
+
3856
3856
  /**
3857
3857
  * @example
3858
3858
  * wysihtml5.lang.object({ foo: 1 }).clone();
@@ -3866,7 +3866,7 @@ wysihtml5.browser = (function() {
3866
3866
  }
3867
3867
  return newObj;
3868
3868
  },
3869
-
3869
+
3870
3870
  /**
3871
3871
  * @example
3872
3872
  * wysihtml5.lang.object([]).isArray();
@@ -3890,7 +3890,7 @@ wysihtml5.browser = (function() {
3890
3890
  trim: function() {
3891
3891
  return str.replace(WHITE_SPACE_START, "").replace(WHITE_SPACE_END, "");
3892
3892
  },
3893
-
3893
+
3894
3894
  /**
3895
3895
  * @example
3896
3896
  * wysihtml5.lang.string("Hello #{name}").interpolate({ name: "Christopher" });
@@ -3902,7 +3902,7 @@ wysihtml5.browser = (function() {
3902
3902
  }
3903
3903
  return str;
3904
3904
  },
3905
-
3905
+
3906
3906
  /**
3907
3907
  * @example
3908
3908
  * wysihtml5.lang.string("Hello Tom").replace("Tom").with("Hans");
@@ -3946,7 +3946,7 @@ wysihtml5.browser = (function() {
3946
3946
  TRAILING_CHAR_REG_EXP = /([^\w\/\-](,?))$/i,
3947
3947
  MAX_DISPLAY_LENGTH = 100,
3948
3948
  BRACKETS = { ")": "(", "]": "[", "}": "{" };
3949
-
3949
+
3950
3950
  function autoLink(element) {
3951
3951
  if (_hasParentThatShouldBeIgnored(element)) {
3952
3952
  return element;
@@ -3958,7 +3958,7 @@ wysihtml5.browser = (function() {
3958
3958
 
3959
3959
  return _parseNode(element);
3960
3960
  }
3961
-
3961
+
3962
3962
  /**
3963
3963
  * This is basically a rebuild of
3964
3964
  * the rails auto_link_urls text helper
@@ -3982,11 +3982,11 @@ wysihtml5.browser = (function() {
3982
3982
  if (realUrl.substr(0, 4) === "www.") {
3983
3983
  realUrl = "http://" + realUrl;
3984
3984
  }
3985
-
3985
+
3986
3986
  return '<a href="' + realUrl + '">' + displayUrl + '</a>' + punctuation;
3987
3987
  });
3988
3988
  }
3989
-
3989
+
3990
3990
  /**
3991
3991
  * Creates or (if already cached) returns a temp element
3992
3992
  * for the given document object
@@ -3998,26 +3998,26 @@ wysihtml5.browser = (function() {
3998
3998
  }
3999
3999
  return tempElement;
4000
4000
  }
4001
-
4001
+
4002
4002
  /**
4003
4003
  * Replaces the original text nodes with the newly auto-linked dom tree
4004
4004
  */
4005
4005
  function _wrapMatchesInNode(textNode) {
4006
4006
  var parentNode = textNode.parentNode,
4007
4007
  tempElement = _getTempElement(parentNode.ownerDocument);
4008
-
4008
+
4009
4009
  // We need to insert an empty/temporary <span /> to fix IE quirks
4010
4010
  // Elsewise IE would strip white space in the beginning
4011
4011
  tempElement.innerHTML = "<span></span>" + _convertUrlsToLinks(textNode.data);
4012
4012
  tempElement.removeChild(tempElement.firstChild);
4013
-
4013
+
4014
4014
  while (tempElement.firstChild) {
4015
4015
  // inserts tempElement.firstChild before textNode
4016
4016
  parentNode.insertBefore(tempElement.firstChild, textNode);
4017
4017
  }
4018
4018
  parentNode.removeChild(textNode);
4019
4019
  }
4020
-
4020
+
4021
4021
  function _hasParentThatShouldBeIgnored(node) {
4022
4022
  var nodeName;
4023
4023
  while (node.parentNode) {
@@ -4031,36 +4031,36 @@ wysihtml5.browser = (function() {
4031
4031
  }
4032
4032
  return false;
4033
4033
  }
4034
-
4034
+
4035
4035
  function _parseNode(element) {
4036
4036
  if (IGNORE_URLS_IN.contains(element.nodeName)) {
4037
4037
  return;
4038
4038
  }
4039
-
4039
+
4040
4040
  if (element.nodeType === wysihtml5.TEXT_NODE && element.data.match(URL_REG_EXP)) {
4041
4041
  _wrapMatchesInNode(element);
4042
4042
  return;
4043
4043
  }
4044
-
4044
+
4045
4045
  var childNodes = wysihtml5.lang.array(element.childNodes).get(),
4046
4046
  childNodesLength = childNodes.length,
4047
4047
  i = 0;
4048
-
4048
+
4049
4049
  for (; i<childNodesLength; i++) {
4050
4050
  _parseNode(childNodes[i]);
4051
4051
  }
4052
-
4052
+
4053
4053
  return element;
4054
4054
  }
4055
-
4055
+
4056
4056
  wysihtml5.dom.autoLink = autoLink;
4057
-
4057
+
4058
4058
  // Reveal url reg exp to the outside
4059
4059
  wysihtml5.dom.autoLink.URL_REG_EXP = URL_REG_EXP;
4060
4060
  })(wysihtml5);(function(wysihtml5) {
4061
4061
  var supportsClassList = wysihtml5.browser.supportsClassList(),
4062
4062
  api = wysihtml5.dom;
4063
-
4063
+
4064
4064
  api.addClass = function(element, className) {
4065
4065
  if (supportsClassList) {
4066
4066
  return element.classList.add(className);
@@ -4070,20 +4070,20 @@ wysihtml5.browser = (function() {
4070
4070
  }
4071
4071
  element.className += " " + className;
4072
4072
  };
4073
-
4073
+
4074
4074
  api.removeClass = function(element, className) {
4075
4075
  if (supportsClassList) {
4076
4076
  return element.classList.remove(className);
4077
4077
  }
4078
-
4078
+
4079
4079
  element.className = element.className.replace(new RegExp("(^|\\s+)" + className + "(\\s+|$)"), " ");
4080
4080
  };
4081
-
4081
+
4082
4082
  api.hasClass = function(element, className) {
4083
4083
  if (supportsClassList) {
4084
4084
  return element.classList.contains(className);
4085
4085
  }
4086
-
4086
+
4087
4087
  var elementClassName = element.className;
4088
4088
  return (elementClassName.length > 0 && (elementClassName == className || new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
4089
4089
  };
@@ -4135,17 +4135,17 @@ wysihtml5.dom.convertToList = (function() {
4135
4135
  list.appendChild(listItem);
4136
4136
  return listItem;
4137
4137
  }
4138
-
4138
+
4139
4139
  function _createList(doc, type) {
4140
4140
  return doc.createElement(type);
4141
4141
  }
4142
-
4142
+
4143
4143
  function convertToList(element, listType) {
4144
4144
  if (element.nodeName === "UL" || element.nodeName === "OL" || element.nodeName === "MENU") {
4145
4145
  // Already a list
4146
4146
  return element;
4147
4147
  }
4148
-
4148
+
4149
4149
  var doc = element.ownerDocument,
4150
4150
  list = _createList(doc, listType),
4151
4151
  lineBreaks = element.querySelectorAll("br"),
@@ -4159,7 +4159,7 @@ wysihtml5.dom.convertToList = (function() {
4159
4159
  isLineBreak,
4160
4160
  currentListItem,
4161
4161
  i;
4162
-
4162
+
4163
4163
  // First find <br> at the end of inline elements and move them behind them
4164
4164
  for (i=0; i<lineBreaksLength; i++) {
4165
4165
  lineBreak = lineBreaks[i];
@@ -4171,16 +4171,16 @@ wysihtml5.dom.convertToList = (function() {
4171
4171
  wysihtml5.dom.insert(lineBreak).after(lineBreak.parentNode);
4172
4172
  }
4173
4173
  }
4174
-
4174
+
4175
4175
  childNodes = wysihtml5.lang.array(element.childNodes).get();
4176
4176
  childNodesLength = childNodes.length;
4177
-
4177
+
4178
4178
  for (i=0; i<childNodesLength; i++) {
4179
4179
  currentListItem = currentListItem || _createListItem(doc, list);
4180
4180
  childNode = childNodes[i];
4181
4181
  isBlockElement = wysihtml5.dom.getStyle("display").from(childNode) === "block";
4182
4182
  isLineBreak = childNode.nodeName === "BR";
4183
-
4183
+
4184
4184
  if (isBlockElement) {
4185
4185
  // Append blockElement to current <li> if empty, otherwise create a new one
4186
4186
  currentListItem = currentListItem.firstChild ? _createListItem(doc, list) : currentListItem;
@@ -4188,27 +4188,27 @@ wysihtml5.dom.convertToList = (function() {
4188
4188
  currentListItem = null;
4189
4189
  continue;
4190
4190
  }
4191
-
4191
+
4192
4192
  if (isLineBreak) {
4193
4193
  // Only create a new list item in the next iteration when the current one has already content
4194
4194
  currentListItem = currentListItem.firstChild ? null : currentListItem;
4195
4195
  continue;
4196
4196
  }
4197
-
4197
+
4198
4198
  currentListItem.appendChild(childNode);
4199
4199
  }
4200
-
4200
+
4201
4201
  element.parentNode.replaceChild(list, element);
4202
4202
  return list;
4203
4203
  }
4204
-
4204
+
4205
4205
  return convertToList;
4206
4206
  })();/**
4207
4207
  * Copy a set of attributes from one element to another
4208
4208
  *
4209
4209
  * @param {Array} attributesToCopy List of attributes which should be copied
4210
4210
  * @return {Object} Returns an object which offers the "from" method which can be invoked with the element where to
4211
- * copy the attributes from., this again returns an object which provides a method named "to" which can be invoked
4211
+ * copy the attributes from., this again returns an object which provides a method named "to" which can be invoked
4212
4212
  * with the element where to copy the attributes to (see example)
4213
4213
  *
4214
4214
  * @example
@@ -4246,7 +4246,7 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
4246
4246
  *
4247
4247
  * @param {Array} stylesToCopy List of styles which should be copied
4248
4248
  * @return {Object} Returns an object which offers the "from" method which can be invoked with the element where to
4249
- * copy the styles from., this again returns an object which provides a method named "to" which can be invoked
4249
+ * copy the styles from., this again returns an object which provides a method named "to" which can be invoked
4250
4250
  * with the element where to copy the styles to (see example)
4251
4251
  *
4252
4252
  * @example
@@ -4257,21 +4257,21 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
4257
4257
  *
4258
4258
  */
4259
4259
  (function(dom) {
4260
-
4260
+
4261
4261
  /**
4262
4262
  * Mozilla, WebKit and Opera recalculate the computed width when box-sizing: boder-box; is set
4263
- * So if an element has "width: 200px; -moz-box-sizing: border-box; border: 1px;" then
4263
+ * So if an element has "width: 200px; -moz-box-sizing: border-box; border: 1px;" then
4264
4264
  * its computed css width will be 198px
4265
4265
  */
4266
4266
  var BOX_SIZING_PROPERTIES = ["-webkit-box-sizing", "-moz-box-sizing", "-ms-box-sizing", "box-sizing"];
4267
-
4267
+
4268
4268
  var shouldIgnoreBoxSizingBorderBox = function(element) {
4269
4269
  if (hasBoxSizingBorderBox(element)) {
4270
4270
  return parseInt(dom.getStyle("width").from(element), 10) < element.offsetWidth;
4271
4271
  }
4272
4272
  return false;
4273
4273
  };
4274
-
4274
+
4275
4275
  var hasBoxSizingBorderBox = function(element) {
4276
4276
  var i = 0,
4277
4277
  length = BOX_SIZING_PROPERTIES.length;
@@ -4281,14 +4281,14 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
4281
4281
  }
4282
4282
  }
4283
4283
  };
4284
-
4284
+
4285
4285
  dom.copyStyles = function(stylesToCopy) {
4286
4286
  return {
4287
4287
  from: function(element) {
4288
4288
  if (shouldIgnoreBoxSizingBorderBox(element)) {
4289
4289
  stylesToCopy = wysihtml5.lang.array(stylesToCopy).without(BOX_SIZING_PROPERTIES);
4290
4290
  }
4291
-
4291
+
4292
4292
  var cssText = "",
4293
4293
  length = stylesToCopy.length,
4294
4294
  i = 0,
@@ -4297,7 +4297,7 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
4297
4297
  property = stylesToCopy[i];
4298
4298
  cssText += property + ":" + dom.getStyle(property).from(element) + ";";
4299
4299
  }
4300
-
4300
+
4301
4301
  return {
4302
4302
  to: function(element) {
4303
4303
  dom.setStyles(cssText).on(element);
@@ -4316,12 +4316,12 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
4316
4316
  * });
4317
4317
  */
4318
4318
  (function(wysihtml5) {
4319
-
4319
+
4320
4320
  wysihtml5.dom.delegate = function(container, selector, eventName, handler) {
4321
4321
  return wysihtml5.dom.observe(container, eventName, function(event) {
4322
4322
  var target = event.target,
4323
4323
  match = wysihtml5.lang.array(container.querySelectorAll(selector));
4324
-
4324
+
4325
4325
  while (target && target !== container) {
4326
4326
  if (match.contains(target)) {
4327
4327
  handler.call(target, event);
@@ -4331,13 +4331,13 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
4331
4331
  }
4332
4332
  });
4333
4333
  };
4334
-
4334
+
4335
4335
  })(wysihtml5);/**
4336
4336
  * Returns the given html wrapped in a div element
4337
4337
  *
4338
4338
  * Fixing IE's inability to treat unknown elements (HTML5 section, article, ...) correctly
4339
4339
  * when inserted via innerHTML
4340
- *
4340
+ *
4341
4341
  * @param {String} html The html which should be wrapped in a dom element
4342
4342
  * @param {Obejct} [context] Document object of the context the html belongs to
4343
4343
  *
@@ -4345,7 +4345,7 @@ wysihtml5.dom.copyAttributes = function(attributesToCopy) {
4345
4345
  * wysihtml5.dom.getAsDom("<article>foo</article>");
4346
4346
  */
4347
4347
  wysihtml5.dom.getAsDom = (function() {
4348
-
4348
+
4349
4349
  var _innerHTMLShiv = function(html, context) {
4350
4350
  var tempElement = context.createElement("div");
4351
4351
  tempElement.style.display = "none";
@@ -4355,7 +4355,7 @@ wysihtml5.dom.getAsDom = (function() {
4355
4355
  context.body.removeChild(tempElement);
4356
4356
  return tempElement;
4357
4357
  };
4358
-
4358
+
4359
4359
  /**
4360
4360
  * Make sure IE supports HTML5 tags, which is accomplished by simply creating one instance of each element
4361
4361
  */
@@ -4368,8 +4368,8 @@ wysihtml5.dom.getAsDom = (function() {
4368
4368
  }
4369
4369
  context._wysihtml5_supportsHTML5Tags = true;
4370
4370
  };
4371
-
4372
-
4371
+
4372
+
4373
4373
  /**
4374
4374
  * List of html5 tags
4375
4375
  * taken from http://simon.html5.org/html5-elements
@@ -4379,7 +4379,7 @@ wysihtml5.dom.getAsDom = (function() {
4379
4379
  "figure", "footer", "header", "hgroup", "keygen", "mark", "meter", "nav", "output", "progress",
4380
4380
  "rp", "rt", "ruby", "svg", "section", "source", "summary", "time", "track", "video", "wbr"
4381
4381
  ];
4382
-
4382
+
4383
4383
  return function(html, context) {
4384
4384
  context = context || document;
4385
4385
  var tempElement;
@@ -4411,23 +4411,23 @@ wysihtml5.dom.getAsDom = (function() {
4411
4411
  * var coloredElement = wysihtml5.dom.getParentElement(myTextNode, { nodeName: "SPAN", className: "wysiwyg-color-red", classRegExp: /wysiwyg-color-[a-z]/g });
4412
4412
  */
4413
4413
  wysihtml5.dom.getParentElement = (function() {
4414
-
4414
+
4415
4415
  function _isSameNodeName(nodeName, desiredNodeNames) {
4416
4416
  if (!desiredNodeNames || !desiredNodeNames.length) {
4417
4417
  return true;
4418
4418
  }
4419
-
4419
+
4420
4420
  if (typeof(desiredNodeNames) === "string") {
4421
4421
  return nodeName === desiredNodeNames;
4422
4422
  } else {
4423
4423
  return wysihtml5.lang.array(desiredNodeNames).contains(nodeName);
4424
4424
  }
4425
4425
  }
4426
-
4426
+
4427
4427
  function _isElement(node) {
4428
4428
  return node.nodeType === wysihtml5.ELEMENT_NODE;
4429
4429
  }
4430
-
4430
+
4431
4431
  function _hasClassName(element, className, classRegExp) {
4432
4432
  var classNames = (element.className || "").match(classRegExp) || [];
4433
4433
  if (!className) {
@@ -4435,7 +4435,7 @@ wysihtml5.dom.getParentElement = (function() {
4435
4435
  }
4436
4436
  return classNames[classNames.length - 1] === className;
4437
4437
  }
4438
-
4438
+
4439
4439
  function _getParentElementWithNodeName(node, nodeName, levels) {
4440
4440
  while (levels-- && node && node.nodeName !== "BODY") {
4441
4441
  if (_isSameNodeName(node.nodeName, nodeName)) {
@@ -4445,7 +4445,7 @@ wysihtml5.dom.getParentElement = (function() {
4445
4445
  }
4446
4446
  return null;
4447
4447
  }
4448
-
4448
+
4449
4449
  function _getParentElementWithNodeNameAndClassName(node, nodeName, className, classRegExp, levels) {
4450
4450
  while (levels-- && node && node.nodeName !== "BODY") {
4451
4451
  if (_isElement(node) &&
@@ -4457,7 +4457,7 @@ wysihtml5.dom.getParentElement = (function() {
4457
4457
  }
4458
4458
  return null;
4459
4459
  }
4460
-
4460
+
4461
4461
  return function(node, matchingSet, levels) {
4462
4462
  levels = levels || 50; // Go max 50 nodes upwards from current node
4463
4463
  if (matchingSet.className || matchingSet.classRegExp) {
@@ -4486,20 +4486,20 @@ wysihtml5.dom.getStyle = (function() {
4486
4486
  "float": ("styleFloat" in document.createElement("div").style) ? "styleFloat" : "cssFloat"
4487
4487
  },
4488
4488
  REG_EXP_CAMELIZE = /\-[a-z]/g;
4489
-
4489
+
4490
4490
  function camelize(str) {
4491
4491
  return str.replace(REG_EXP_CAMELIZE, function(match) {
4492
4492
  return match.charAt(1).toUpperCase();
4493
4493
  });
4494
4494
  }
4495
-
4495
+
4496
4496
  return function(property) {
4497
4497
  return {
4498
4498
  from: function(element) {
4499
4499
  if (element.nodeType !== wysihtml5.ELEMENT_NODE) {
4500
4500
  return;
4501
4501
  }
4502
-
4502
+
4503
4503
  var doc = element.ownerDocument,
4504
4504
  camelizedProperty = stylePropertyMapping[property] || camelize(property),
4505
4505
  style = element.style,
@@ -4508,7 +4508,7 @@ wysihtml5.dom.getStyle = (function() {
4508
4508
  if (styleValue) {
4509
4509
  return styleValue;
4510
4510
  }
4511
-
4511
+
4512
4512
  // currentStyle is no standard and only supported by Opera and IE but it has one important advantage over the standard-compliant
4513
4513
  // window.getComputedStyle, since it returns css property values in their original unit:
4514
4514
  // If you set an elements width to "50%", window.getComputedStyle will give you it's current width in px while currentStyle
@@ -4556,18 +4556,18 @@ wysihtml5.dom.getStyle = (function() {
4556
4556
  wysihtml5.dom.hasElementWithTagName = (function() {
4557
4557
  var LIVE_CACHE = {},
4558
4558
  DOCUMENT_IDENTIFIER = 1;
4559
-
4559
+
4560
4560
  function _getDocumentIdentifier(doc) {
4561
4561
  return doc._wysihtml5_identifier || (doc._wysihtml5_identifier = DOCUMENT_IDENTIFIER++);
4562
4562
  }
4563
-
4563
+
4564
4564
  return function(doc, tagName) {
4565
4565
  var key = _getDocumentIdentifier(doc) + ":" + tagName,
4566
4566
  cacheEntry = LIVE_CACHE[key];
4567
4567
  if (!cacheEntry) {
4568
4568
  cacheEntry = LIVE_CACHE[key] = doc.getElementsByTagName(tagName);
4569
4569
  }
4570
-
4570
+
4571
4571
  return cacheEntry.length > 0;
4572
4572
  };
4573
4573
  })();/**
@@ -4587,7 +4587,7 @@ wysihtml5.dom.hasElementWithTagName = (function() {
4587
4587
  function _getDocumentIdentifier(doc) {
4588
4588
  return doc._wysihtml5_identifier || (doc._wysihtml5_identifier = DOCUMENT_IDENTIFIER++);
4589
4589
  }
4590
-
4590
+
4591
4591
  wysihtml5.dom.hasElementWithClassName = function(doc, className) {
4592
4592
  // getElementsByClassName is not supported by IE<9
4593
4593
  // but is sometimes mocked via library code (which then doesn't return live node lists)
@@ -4609,18 +4609,18 @@ wysihtml5.dom.insert = function(elementToInsert) {
4609
4609
  after: function(element) {
4610
4610
  element.parentNode.insertBefore(elementToInsert, element.nextSibling);
4611
4611
  },
4612
-
4612
+
4613
4613
  before: function(element) {
4614
4614
  element.parentNode.insertBefore(elementToInsert, element);
4615
4615
  },
4616
-
4616
+
4617
4617
  into: function(element) {
4618
4618
  element.appendChild(elementToInsert);
4619
4619
  }
4620
4620
  };
4621
4621
  };wysihtml5.dom.insertCSS = function(rules) {
4622
4622
  rules = rules.join("\n");
4623
-
4623
+
4624
4624
  return {
4625
4625
  into: function(doc) {
4626
4626
  var head = doc.head || doc.getElementsByTagName("head")[0],
@@ -4647,12 +4647,12 @@ wysihtml5.dom.insert = function(elementToInsert) {
4647
4647
  */
4648
4648
  wysihtml5.dom.observe = function(element, eventNames, handler) {
4649
4649
  eventNames = typeof(eventNames) === "string" ? [eventNames] : eventNames;
4650
-
4650
+
4651
4651
  var handlerWrapper,
4652
4652
  eventName,
4653
4653
  i = 0,
4654
4654
  length = eventNames.length;
4655
-
4655
+
4656
4656
  for (; i<length; i++) {
4657
4657
  eventName = eventNames[i];
4658
4658
  if (element.addEventListener) {
@@ -4673,7 +4673,7 @@ wysihtml5.dom.observe = function(element, eventNames, handler) {
4673
4673
  element.attachEvent("on" + eventName, handlerWrapper);
4674
4674
  }
4675
4675
  }
4676
-
4676
+
4677
4677
  return {
4678
4678
  stop: function() {
4679
4679
  var eventName,
@@ -4742,7 +4742,7 @@ wysihtml5.dom.observe = function(element, eventNames, handler) {
4742
4742
  * // => '<p class="red">foo</p><p>bar</p>'
4743
4743
  */
4744
4744
  wysihtml5.dom.parse = (function() {
4745
-
4745
+
4746
4746
  /**
4747
4747
  * It's not possible to use a XMLParser/DOMParser as HTML5 is not always well-formed XML
4748
4748
  * new DOMParser().parseFromString('<img src="foo.gif">') will cause a parseError since the
@@ -4759,27 +4759,27 @@ wysihtml5.dom.parse = (function() {
4759
4759
  WHITE_SPACE_REG_EXP = /\s+/,
4760
4760
  defaultRules = { tags: {}, classes: {} },
4761
4761
  currentRules = {};
4762
-
4762
+
4763
4763
  /**
4764
4764
  * Iterates over all childs of the element, recreates them, appends them into a document fragment
4765
4765
  * which later replaces the entire body content
4766
4766
  */
4767
4767
  function parse(elementOrHtml, rules, context, cleanUp) {
4768
4768
  wysihtml5.lang.object(currentRules).merge(defaultRules).merge(rules).get();
4769
-
4769
+
4770
4770
  context = context || elementOrHtml.ownerDocument || document;
4771
4771
  var fragment = context.createDocumentFragment(),
4772
4772
  isString = typeof(elementOrHtml) === "string",
4773
4773
  element,
4774
4774
  newNode,
4775
4775
  firstChild;
4776
-
4776
+
4777
4777
  if (isString) {
4778
4778
  element = wysihtml5.dom.getAsDom(elementOrHtml, context);
4779
4779
  } else {
4780
4780
  element = elementOrHtml;
4781
4781
  }
4782
-
4782
+
4783
4783
  while (element.firstChild) {
4784
4784
  firstChild = element.firstChild;
4785
4785
  element.removeChild(firstChild);
@@ -4788,16 +4788,16 @@ wysihtml5.dom.parse = (function() {
4788
4788
  fragment.appendChild(newNode);
4789
4789
  }
4790
4790
  }
4791
-
4791
+
4792
4792
  // Clear element contents
4793
4793
  element.innerHTML = "";
4794
-
4794
+
4795
4795
  // Insert new DOM tree
4796
4796
  element.appendChild(fragment);
4797
-
4797
+
4798
4798
  return isString ? wysihtml5.quirks.getCorrectInnerHTML(element) : element;
4799
4799
  }
4800
-
4800
+
4801
4801
  function _convert(oldNode, cleanUp) {
4802
4802
  var oldNodeType = oldNode.nodeType,
4803
4803
  oldChilds = oldNode.childNodes,
@@ -4805,20 +4805,20 @@ wysihtml5.dom.parse = (function() {
4805
4805
  newNode,
4806
4806
  method = NODE_TYPE_MAPPING[oldNodeType],
4807
4807
  i = 0;
4808
-
4808
+
4809
4809
  newNode = method && method(oldNode);
4810
-
4810
+
4811
4811
  if (!newNode) {
4812
4812
  return null;
4813
4813
  }
4814
-
4814
+
4815
4815
  for (i=0; i<oldChildsLength; i++) {
4816
4816
  newChild = _convert(oldChilds[i], cleanUp);
4817
4817
  if (newChild) {
4818
4818
  newNode.appendChild(newChild);
4819
4819
  }
4820
4820
  }
4821
-
4821
+
4822
4822
  // Cleanup senseless <span> elements
4823
4823
  if (cleanUp &&
4824
4824
  newNode.childNodes.length <= 1 &&
@@ -4826,10 +4826,10 @@ wysihtml5.dom.parse = (function() {
4826
4826
  !newNode.attributes.length) {
4827
4827
  return newNode.firstChild;
4828
4828
  }
4829
-
4829
+
4830
4830
  return newNode;
4831
4831
  }
4832
-
4832
+
4833
4833
  function _handleElement(oldNode) {
4834
4834
  var rule,
4835
4835
  newNode,
@@ -4837,7 +4837,7 @@ wysihtml5.dom.parse = (function() {
4837
4837
  tagRules = currentRules.tags,
4838
4838
  nodeName = oldNode.nodeName.toLowerCase(),
4839
4839
  scopeName = oldNode.scopeName;
4840
-
4840
+
4841
4841
  /**
4842
4842
  * We already parsed that element
4843
4843
  * ignore it! (yes, this sometimes happens in IE8 when the html is invalid)
@@ -4846,11 +4846,11 @@ wysihtml5.dom.parse = (function() {
4846
4846
  return null;
4847
4847
  }
4848
4848
  oldNode._wysihtml5 = 1;
4849
-
4849
+
4850
4850
  if (oldNode.className === "wysihtml5-temp") {
4851
4851
  return null;
4852
4852
  }
4853
-
4853
+
4854
4854
  /**
4855
4855
  * IE is the only browser who doesn't include the namespace in the
4856
4856
  * nodeName, that's why we have to prepend it by ourselves
@@ -4860,7 +4860,7 @@ wysihtml5.dom.parse = (function() {
4860
4860
  if (scopeName && scopeName != "HTML") {
4861
4861
  nodeName = scopeName + ":" + nodeName;
4862
4862
  }
4863
-
4863
+
4864
4864
  /**
4865
4865
  * Repair node
4866
4866
  * IE is a bit bitchy when it comes to invalid nested markup which includes unclosed tags
@@ -4873,13 +4873,13 @@ wysihtml5.dom.parse = (function() {
4873
4873
  nodeName = "div";
4874
4874
  }
4875
4875
  }
4876
-
4876
+
4877
4877
  if (nodeName in tagRules) {
4878
4878
  rule = tagRules[nodeName];
4879
4879
  if (!rule || rule.remove) {
4880
4880
  return null;
4881
4881
  }
4882
-
4882
+
4883
4883
  rule = typeof(rule) === "string" ? { rename_tag: rule } : rule;
4884
4884
  } else if (oldNode.firstChild) {
4885
4885
  rule = { rename_tag: DEFAULT_NODE_NAME };
@@ -4887,14 +4887,14 @@ wysihtml5.dom.parse = (function() {
4887
4887
  // Remove empty unknown elements
4888
4888
  return null;
4889
4889
  }
4890
-
4890
+
4891
4891
  newNode = oldNode.ownerDocument.createElement(rule.rename_tag || nodeName);
4892
4892
  _handleAttributes(oldNode, newNode, rule);
4893
-
4893
+
4894
4894
  oldNode = null;
4895
4895
  return newNode;
4896
4896
  }
4897
-
4897
+
4898
4898
  function _handleAttributes(oldNode, newNode, rule) {
4899
4899
  var attributes = {}, // fresh new set of attributes to set on newNode
4900
4900
  setClass = rule.set_class, // classes to set
@@ -4914,11 +4914,11 @@ wysihtml5.dom.parse = (function() {
4914
4914
  attributeName,
4915
4915
  newAttributeValue,
4916
4916
  method;
4917
-
4917
+
4918
4918
  if (setAttributes) {
4919
4919
  attributes = wysihtml5.lang.object(setAttributes).clone();
4920
4920
  }
4921
-
4921
+
4922
4922
  if (checkAttributes) {
4923
4923
  for (attributeName in checkAttributes) {
4924
4924
  method = attributeCheckMethods[checkAttributes[attributeName]];
@@ -4931,11 +4931,11 @@ wysihtml5.dom.parse = (function() {
4931
4931
  }
4932
4932
  }
4933
4933
  }
4934
-
4934
+
4935
4935
  if (setClass) {
4936
4936
  classes.push(setClass);
4937
4937
  }
4938
-
4938
+
4939
4939
  if (addClass) {
4940
4940
  for (attributeName in addClass) {
4941
4941
  method = addClassMethods[addClass[attributeName]];
@@ -4948,10 +4948,10 @@ wysihtml5.dom.parse = (function() {
4948
4948
  }
4949
4949
  }
4950
4950
  }
4951
-
4951
+
4952
4952
  // make sure that wysihtml5 temp class doesn't get stripped out
4953
4953
  allowedClasses["_wysihtml5-temp-placeholder"] = 1;
4954
-
4954
+
4955
4955
  // add old classes last
4956
4956
  oldClasses = oldNode.getAttribute("class");
4957
4957
  if (oldClasses) {
@@ -4964,7 +4964,7 @@ wysihtml5.dom.parse = (function() {
4964
4964
  newClasses.push(currentClass);
4965
4965
  }
4966
4966
  }
4967
-
4967
+
4968
4968
  // remove duplicate entries and preserve class specificity
4969
4969
  newClassesLength = newClasses.length;
4970
4970
  while (newClassesLength--) {
@@ -4973,11 +4973,11 @@ wysihtml5.dom.parse = (function() {
4973
4973
  newUniqueClasses.unshift(currentClass);
4974
4974
  }
4975
4975
  }
4976
-
4976
+
4977
4977
  if (newUniqueClasses.length) {
4978
4978
  attributes["class"] = newUniqueClasses.join(" ");
4979
4979
  }
4980
-
4980
+
4981
4981
  // set attributes on newNode
4982
4982
  for (attributeName in attributes) {
4983
4983
  // Setting attributes can cause a js error in IE under certain circumstances
@@ -4987,7 +4987,7 @@ wysihtml5.dom.parse = (function() {
4987
4987
  newNode.setAttribute(attributeName, attributes[attributeName]);
4988
4988
  } catch(e) {}
4989
4989
  }
4990
-
4990
+
4991
4991
  // IE8 sometimes loses the width/height attributes when those are set before the "src"
4992
4992
  // so we make sure to set them again
4993
4993
  if (attributes.src) {
@@ -4999,7 +4999,7 @@ wysihtml5.dom.parse = (function() {
4999
4999
  }
5000
5000
  }
5001
5001
  }
5002
-
5002
+
5003
5003
  /**
5004
5004
  * IE gives wrong results for hasAttribute/getAttribute, for example:
5005
5005
  * var td = document.createElement("td");
@@ -5022,13 +5022,13 @@ wysihtml5.dom.parse = (function() {
5022
5022
  var outerHTML = node.outerHTML.toLowerCase(),
5023
5023
  // TODO: This might not work for attributes without value: <input disabled>
5024
5024
  hasAttribute = outerHTML.indexOf(" " + attributeName + "=") != -1;
5025
-
5025
+
5026
5026
  return hasAttribute ? node.getAttribute(attributeName) : null;
5027
5027
  } else{
5028
5028
  return node.getAttribute(attributeName);
5029
5029
  }
5030
5030
  }
5031
-
5031
+
5032
5032
  /**
5033
5033
  * Check whether the given node is a proper loaded image
5034
5034
  * FIXME: Returns undefined when unknown (Chrome, Safari)
@@ -5042,12 +5042,12 @@ wysihtml5.dom.parse = (function() {
5042
5042
  }
5043
5043
  }
5044
5044
  }
5045
-
5045
+
5046
5046
  function _handleText(oldNode) {
5047
5047
  return oldNode.ownerDocument.createTextNode(oldNode.data);
5048
5048
  }
5049
-
5050
-
5049
+
5050
+
5051
5051
  // ------------ attribute checks ------------ \\
5052
5052
  var attributeCheckMethods = {
5053
5053
  url: (function() {
@@ -5061,7 +5061,7 @@ wysihtml5.dom.parse = (function() {
5061
5061
  });
5062
5062
  };
5063
5063
  })(),
5064
-
5064
+
5065
5065
  alt: (function() {
5066
5066
  var REG_EXP = /[^ a-z0-9_\-]/gi;
5067
5067
  return function(attributeValue) {
@@ -5071,7 +5071,7 @@ wysihtml5.dom.parse = (function() {
5071
5071
  return attributeValue.replace(REG_EXP, "");
5072
5072
  };
5073
5073
  })(),
5074
-
5074
+
5075
5075
  numbers: (function() {
5076
5076
  var REG_EXP = /\D/g;
5077
5077
  return function(attributeValue) {
@@ -5080,7 +5080,7 @@ wysihtml5.dom.parse = (function() {
5080
5080
  };
5081
5081
  })()
5082
5082
  };
5083
-
5083
+
5084
5084
  // ------------ class converter (converts an html attribute to a class name) ------------ \\
5085
5085
  var addClassMethods = {
5086
5086
  align_img: (function() {
@@ -5092,7 +5092,7 @@ wysihtml5.dom.parse = (function() {
5092
5092
  return mapping[String(attributeValue).toLowerCase()];
5093
5093
  };
5094
5094
  })(),
5095
-
5095
+
5096
5096
  align_text: (function() {
5097
5097
  var mapping = {
5098
5098
  left: "wysiwyg-text-align-left",
@@ -5104,7 +5104,7 @@ wysihtml5.dom.parse = (function() {
5104
5104
  return mapping[String(attributeValue).toLowerCase()];
5105
5105
  };
5106
5106
  })(),
5107
-
5107
+
5108
5108
  clear_br: (function() {
5109
5109
  var mapping = {
5110
5110
  left: "wysiwyg-clear-left",
@@ -5116,7 +5116,7 @@ wysihtml5.dom.parse = (function() {
5116
5116
  return mapping[String(attributeValue).toLowerCase()];
5117
5117
  };
5118
5118
  })(),
5119
-
5119
+
5120
5120
  size_font: (function() {
5121
5121
  var mapping = {
5122
5122
  "1": "wysiwyg-font-size-xx-small",
@@ -5134,7 +5134,7 @@ wysihtml5.dom.parse = (function() {
5134
5134
  };
5135
5135
  })()
5136
5136
  };
5137
-
5137
+
5138
5138
  return parse;
5139
5139
  })();/**
5140
5140
  * Checks for empty text node childs and removes them
@@ -5191,7 +5191,7 @@ wysihtml5.dom.renameElement = function(element, newNodeName) {
5191
5191
  return newElement;
5192
5192
  };/**
5193
5193
  * Takes an element, removes it and replaces it with it's childs
5194
- *
5194
+ *
5195
5195
  * @param {Object} node The node which to replace with it's child nodes
5196
5196
  * @example
5197
5197
  * <div id="foo">
@@ -5206,12 +5206,12 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
5206
5206
  if (!node.parentNode) {
5207
5207
  return;
5208
5208
  }
5209
-
5209
+
5210
5210
  if (!node.firstChild) {
5211
5211
  node.parentNode.removeChild(node);
5212
5212
  return;
5213
5213
  }
5214
-
5214
+
5215
5215
  var fragment = node.ownerDocument.createDocumentFragment();
5216
5216
  while (node.firstChild) {
5217
5217
  fragment.appendChild(node.firstChild);
@@ -5245,21 +5245,21 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
5245
5245
  function _isBlockElement(node) {
5246
5246
  return dom.getStyle("display").from(node) === "block";
5247
5247
  }
5248
-
5248
+
5249
5249
  function _isLineBreak(node) {
5250
5250
  return node.nodeName === "BR";
5251
5251
  }
5252
-
5252
+
5253
5253
  function _appendLineBreak(element) {
5254
5254
  var lineBreak = element.ownerDocument.createElement("br");
5255
5255
  element.appendChild(lineBreak);
5256
5256
  }
5257
-
5257
+
5258
5258
  function resolveList(list) {
5259
5259
  if (list.nodeName !== "MENU" && list.nodeName !== "UL" && list.nodeName !== "OL") {
5260
5260
  return;
5261
5261
  }
5262
-
5262
+
5263
5263
  var doc = list.ownerDocument,
5264
5264
  fragment = doc.createDocumentFragment(),
5265
5265
  previousSibling = list.previousElementSibling || list.previousSibling,
@@ -5268,11 +5268,11 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
5268
5268
  isLastChild,
5269
5269
  shouldAppendLineBreak,
5270
5270
  listItem;
5271
-
5271
+
5272
5272
  if (previousSibling && !_isBlockElement(previousSibling)) {
5273
5273
  _appendLineBreak(fragment);
5274
5274
  }
5275
-
5275
+
5276
5276
  while (listItem = list.firstChild) {
5277
5277
  lastChild = listItem.lastChild;
5278
5278
  while (firstChild = listItem.firstChild) {
@@ -5284,12 +5284,12 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
5284
5284
  _appendLineBreak(fragment);
5285
5285
  }
5286
5286
  }
5287
-
5287
+
5288
5288
  listItem.parentNode.removeChild(listItem);
5289
5289
  }
5290
5290
  list.parentNode.replaceChild(fragment, list);
5291
5291
  }
5292
-
5292
+
5293
5293
  dom.resolveList = resolveList;
5294
5294
  })(wysihtml5.dom);/**
5295
5295
  * Sandbox for executing javascript, parsing css styles and doing dom operations in a secure way
@@ -5341,7 +5341,7 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
5341
5341
  "referrer",
5342
5342
  "write", "open", "close"
5343
5343
  ];
5344
-
5344
+
5345
5345
  wysihtml5.dom.Sandbox = Base.extend(
5346
5346
  /** @scope wysihtml5.dom.Sandbox.prototype */ {
5347
5347
 
@@ -5350,12 +5350,12 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
5350
5350
  this.config = wysihtml5.lang.object({}).merge(config).get();
5351
5351
  this.iframe = this._createIframe();
5352
5352
  },
5353
-
5353
+
5354
5354
  insertInto: function(element) {
5355
5355
  if (typeof(element) === "string") {
5356
5356
  element = doc.getElementById(element);
5357
5357
  }
5358
-
5358
+
5359
5359
  element.appendChild(this.iframe);
5360
5360
  },
5361
5361
 
@@ -5391,7 +5391,7 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
5391
5391
  * In order to make this happen we need to set the "allow-scripts" flag.
5392
5392
  * A combination of allow-scripts and allow-same-origin is almost the same as setting no sandbox attribute at all.
5393
5393
  * - Chrome & Safari, doesn't seem to support sandboxing correctly when the iframe's html is inlined (no physical document)
5394
- * - IE needs to have the security="restricted" attribute set before the iframe is
5394
+ * - IE needs to have the security="restricted" attribute set before the iframe is
5395
5395
  * inserted into the dom tree
5396
5396
  * - Believe it or not but in IE "security" in document.createElement("iframe") is false, even
5397
5397
  * though it supports it
@@ -5468,7 +5468,7 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
5468
5468
 
5469
5469
  if (!wysihtml5.browser.supportsSandboxedIframes()) {
5470
5470
  // Unset a bunch of sensitive variables
5471
- // Please note: This isn't hack safe!
5471
+ // Please note: This isn't hack safe!
5472
5472
  // It more or less just takes care of basic attacks and prevents accidental theft of sensitive information
5473
5473
  // IE is secure though, which is the most important thing, since IE is the only browser, who
5474
5474
  // takes over scripts & styles into contentEditable elements when copied from external websites
@@ -5483,7 +5483,7 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
5483
5483
  for (i=0, length=documentProperties.length; i<length; i++) {
5484
5484
  this._unset(iframeDocument, documentProperties[i]);
5485
5485
  }
5486
- // This doesn't work in Safari 5
5486
+ // This doesn't work in Safari 5
5487
5487
  // See http://stackoverflow.com/questions/992461/is-it-possible-to-override-document-cookie-in-webkit
5488
5488
  this._unset(iframeDocument, "cookie", "", true);
5489
5489
  }
@@ -5655,11 +5655,11 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
5655
5655
  // When pasting underlined links <a> into a contentEditable, IE thinks, it has to insert <u> to keep the styling
5656
5656
  "a u": wysihtml5.dom.replaceWithChildNodes
5657
5657
  };
5658
-
5658
+
5659
5659
  function cleanPastedHTML(elementOrHtml, rules, context) {
5660
5660
  rules = rules || defaultRules;
5661
5661
  context = context || elementOrHtml.ownerDocument || document;
5662
-
5662
+
5663
5663
  var element,
5664
5664
  isString = typeof(elementOrHtml) === "string",
5665
5665
  method,
@@ -5672,7 +5672,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
5672
5672
  } else {
5673
5673
  element = elementOrHtml;
5674
5674
  }
5675
-
5675
+
5676
5676
  for (i in rules) {
5677
5677
  matches = element.querySelectorAll(i);
5678
5678
  method = rules[i];
@@ -5681,12 +5681,12 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
5681
5681
  method(matches[j]);
5682
5682
  }
5683
5683
  }
5684
-
5684
+
5685
5685
  matches = elementOrHtml = rules = null;
5686
-
5686
+
5687
5687
  return isString ? element.innerHTML : element;
5688
5688
  }
5689
-
5689
+
5690
5690
  return cleanPastedHTML;
5691
5691
  })();/**
5692
5692
  * IE and Opera leave an empty paragraph in the contentEditable element after clearing it
@@ -5697,7 +5697,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
5697
5697
  */
5698
5698
  (function(wysihtml5) {
5699
5699
  var dom = wysihtml5.dom;
5700
-
5700
+
5701
5701
  wysihtml5.quirks.ensureProperClearing = (function() {
5702
5702
  var clearIfNecessary = function(event) {
5703
5703
  var element = this;
@@ -5784,7 +5784,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
5784
5784
  if (innerHTML.indexOf(TILDE_ESCAPED) === -1) {
5785
5785
  return innerHTML;
5786
5786
  }
5787
-
5787
+
5788
5788
  var elementsWithTilde = element.querySelectorAll("[href*='~'], [src*='~']"),
5789
5789
  url,
5790
5790
  urlToSearch,
@@ -5812,7 +5812,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
5812
5812
  var dom = wysihtml5.dom,
5813
5813
  USE_NATIVE_LINE_BREAK_WHEN_CARET_INSIDE_TAGS = ["LI", "P", "H1", "H2", "H3", "H4", "H5", "H6"],
5814
5814
  LIST_TAGS = ["UL", "OL", "MENU"];
5815
-
5815
+
5816
5816
  wysihtml5.quirks.insertLineBreakOnReturn = function(composer) {
5817
5817
  function unwrap(selectedNode) {
5818
5818
  var parentElement = dom.getParentElement(selectedNode, { nodeName: ["P", "DIV"] }, 2);
@@ -5861,7 +5861,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
5861
5861
  setTimeout(function() {
5862
5862
  unwrap(composer.selection.getSelectedNode());
5863
5863
  }, 0);
5864
- }
5864
+ }
5865
5865
  return;
5866
5866
  }
5867
5867
 
@@ -5870,7 +5870,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
5870
5870
  event.preventDefault();
5871
5871
  }
5872
5872
  }
5873
-
5873
+
5874
5874
  // keypress doesn't fire when you hit backspace
5875
5875
  dom.observe(composer.element.ownerDocument, "keydown", keyDown);
5876
5876
  };
@@ -5884,11 +5884,11 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
5884
5884
  */
5885
5885
  (function(wysihtml5) {
5886
5886
  var CLASS_NAME = "wysihtml5-quirks-redraw";
5887
-
5887
+
5888
5888
  wysihtml5.quirks.redraw = function(element) {
5889
5889
  wysihtml5.dom.addClass(element, CLASS_NAME);
5890
5890
  wysihtml5.dom.removeClass(element, CLASS_NAME);
5891
-
5891
+
5892
5892
  // Following hack is needed for firefox to make sure that image resize handles are properly removed
5893
5893
  try {
5894
5894
  var doc = element.ownerDocument;
@@ -5904,7 +5904,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
5904
5904
  */
5905
5905
  (function(wysihtml5) {
5906
5906
  var dom = wysihtml5.dom;
5907
-
5907
+
5908
5908
  function _getCumulativeOffsetTop(element) {
5909
5909
  var top = 0;
5910
5910
  if (element.parentNode) {
@@ -5915,18 +5915,18 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
5915
5915
  }
5916
5916
  return top;
5917
5917
  }
5918
-
5918
+
5919
5919
  wysihtml5.Selection = Base.extend(
5920
5920
  /** @scope wysihtml5.Selection.prototype */ {
5921
5921
  constructor: function(editor) {
5922
5922
  // Make sure that our external range library is initialized
5923
5923
  window.rangy.init();
5924
-
5924
+
5925
5925
  this.editor = editor;
5926
5926
  this.composer = editor.composer;
5927
5927
  this.doc = this.composer.doc;
5928
5928
  },
5929
-
5929
+
5930
5930
  /**
5931
5931
  * Get the current selection as a bookmark to be able to later restore it
5932
5932
  *
@@ -6051,23 +6051,23 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6051
6051
  placeholderHTML = '<span class="' + className + '">' + wysihtml5.INVISIBLE_SPACE + '</span>',
6052
6052
  range = this.getRange(this.doc),
6053
6053
  newRange;
6054
-
6054
+
6055
6055
  // Nothing selected, execute and say goodbye
6056
6056
  if (!range) {
6057
6057
  method(body, body);
6058
6058
  return;
6059
6059
  }
6060
-
6060
+
6061
6061
  var node = range.createContextualFragment(placeholderHTML);
6062
6062
  range.insertNode(node);
6063
-
6063
+
6064
6064
  // Make sure that a potential error doesn't cause our placeholder element to be left as a placeholder
6065
6065
  try {
6066
6066
  method(range.startContainer, range.endContainer);
6067
6067
  } catch(e3) {
6068
6068
  setTimeout(function() { throw e3; }, 0);
6069
6069
  }
6070
-
6070
+
6071
6071
  caretPlaceholder = this.doc.querySelector("." + className);
6072
6072
  if (caretPlaceholder) {
6073
6073
  newRange = rangy.createRange(this.doc);
@@ -6296,7 +6296,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6296
6296
  return [];
6297
6297
  }
6298
6298
  },
6299
-
6299
+
6300
6300
  getRange: function() {
6301
6301
  var selection = this.getSelection();
6302
6302
  return selection && selection.rangeCount && selection.getRangeAt(0);
@@ -6312,7 +6312,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6312
6312
  return selection.setSingleRange(range);
6313
6313
  }
6314
6314
  });
6315
-
6315
+
6316
6316
  })(wysihtml5);
6317
6317
  /**
6318
6318
  * Inspired by the rangy CSS Applier module written by Tim Down and licensed under the MIT license.
@@ -6324,14 +6324,14 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6324
6324
  */
6325
6325
  (function(wysihtml5, rangy) {
6326
6326
  var defaultTagName = "span";
6327
-
6327
+
6328
6328
  var REG_EXP_WHITE_SPACE = /\s+/g;
6329
-
6329
+
6330
6330
  function hasClass(el, cssClass, regExp) {
6331
6331
  if (!el.className) {
6332
6332
  return false;
6333
6333
  }
6334
-
6334
+
6335
6335
  var matchingClassNames = el.className.match(regExp) || [];
6336
6336
  return matchingClassNames[matchingClassNames.length - 1] === cssClass;
6337
6337
  }
@@ -6350,7 +6350,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6350
6350
  el.className = el.className.replace(regExp, "");
6351
6351
  }
6352
6352
  }
6353
-
6353
+
6354
6354
  function hasSameClasses(el1, el2) {
6355
6355
  return el1.className.replace(REG_EXP_WHITE_SPACE, " ") == el2.className.replace(REG_EXP_WHITE_SPACE, " ");
6356
6356
  }
@@ -6423,7 +6423,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6423
6423
  }
6424
6424
  return (descendantNode == node) ? newNode : splitNodeAt(node, newNode.parentNode, rangy.dom.getNodeIndex(newNode));
6425
6425
  }
6426
-
6426
+
6427
6427
  function Merge(firstNode) {
6428
6428
  this.isElementMerge = (firstNode.nodeType == wysihtml5.ELEMENT_NODE);
6429
6429
  this.firstTextNode = this.isElementMerge ? firstNode.lastChild : firstNode;
@@ -6539,7 +6539,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6539
6539
  range.setEnd(rangeEndNode, rangeEndOffset);
6540
6540
  }
6541
6541
  },
6542
-
6542
+
6543
6543
  getAdjacentMergeableTextNode: function(node, forward) {
6544
6544
  var isTextNode = (node.nodeType == wysihtml5.TEXT_NODE);
6545
6545
  var el = isTextNode ? node.parentNode : node;
@@ -6560,7 +6560,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6560
6560
  }
6561
6561
  return null;
6562
6562
  },
6563
-
6563
+
6564
6564
  areElementsMergeable: function(el1, el2) {
6565
6565
  return rangy.dom.arrayContains(this.tagNames, (el1.tagName || "").toLowerCase())
6566
6566
  && rangy.dom.arrayContains(this.tagNames, (el2.tagName || "").toLowerCase())
@@ -6607,7 +6607,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6607
6607
  ancestorWithClass = splitNodeAt(ancestorWithClass, range.startContainer, range.startOffset);
6608
6608
  }
6609
6609
  }
6610
-
6610
+
6611
6611
  if (this.similarClassRegExp) {
6612
6612
  removeClass(ancestorWithClass, this.similarClassRegExp);
6613
6613
  }
@@ -6626,10 +6626,10 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6626
6626
  return;
6627
6627
  } catch(e) {}
6628
6628
  }
6629
-
6629
+
6630
6630
  range.splitBoundaries();
6631
6631
  textNodes = range.getNodes([wysihtml5.TEXT_NODE]);
6632
-
6632
+
6633
6633
  if (textNodes.length) {
6634
6634
  var textNode;
6635
6635
 
@@ -6639,11 +6639,11 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6639
6639
  this.applyToTextNode(textNode);
6640
6640
  }
6641
6641
  }
6642
-
6642
+
6643
6643
  range.setStart(textNodes[0], 0);
6644
6644
  textNode = textNodes[textNodes.length - 1];
6645
6645
  range.setEnd(textNode, textNode.length);
6646
-
6646
+
6647
6647
  if (this.normalize) {
6648
6648
  this.postApply(textNodes, range);
6649
6649
  }
@@ -6662,7 +6662,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6662
6662
  range.selectNode(node);
6663
6663
  textNodes = [node];
6664
6664
  }
6665
-
6665
+
6666
6666
  for (var i = 0, len = textNodes.length; i < len; ++i) {
6667
6667
  textNode = textNodes[i];
6668
6668
  ancestorWithClass = this.getAncestorWithClass(textNode);
@@ -6670,7 +6670,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6670
6670
  this.undoToTextNode(textNode, range, ancestorWithClass);
6671
6671
  }
6672
6672
  }
6673
-
6673
+
6674
6674
  if (len == 1) {
6675
6675
  this.selectNode(range, textNodes[0]);
6676
6676
  } else {
@@ -6683,7 +6683,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6683
6683
  }
6684
6684
  }
6685
6685
  },
6686
-
6686
+
6687
6687
  selectNode: function(range, node) {
6688
6688
  var isElement = node.nodeType === wysihtml5.ELEMENT_NODE,
6689
6689
  canHaveHTML = "canHaveHTML" in node ? node.canHaveHTML : true,
@@ -6702,7 +6702,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6702
6702
  range.setEndAfter(node);
6703
6703
  }
6704
6704
  },
6705
-
6705
+
6706
6706
  getTextSelectedByRange: function(textNode, range) {
6707
6707
  var textRange = range.cloneRange();
6708
6708
  textRange.selectNodeContents(textNode);
@@ -6722,7 +6722,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6722
6722
  ancestor = this.getAncestorWithClass(range.startContainer);
6723
6723
  return ancestor ? [ancestor] : false;
6724
6724
  }
6725
-
6725
+
6726
6726
  for (var i = 0, len = textNodes.length, selectedText; i < len; ++i) {
6727
6727
  selectedText = this.getTextSelectedByRange(textNodes[i], range);
6728
6728
  ancestor = this.getAncestorWithClass(textNodes[i]);
@@ -6745,10 +6745,10 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6745
6745
  };
6746
6746
 
6747
6747
  wysihtml5.selection.HTMLApplier = HTMLApplier;
6748
-
6748
+
6749
6749
  })(wysihtml5, rangy);/**
6750
6750
  * Rich Text Query/Formatting Commands
6751
- *
6751
+ *
6752
6752
  * @example
6753
6753
  * var commands = new wysihtml5.Commands(editor);
6754
6754
  */
@@ -6759,7 +6759,7 @@ wysihtml5.Commands = Base.extend(
6759
6759
  this.composer = editor.composer;
6760
6760
  this.doc = this.composer.doc;
6761
6761
  },
6762
-
6762
+
6763
6763
  /**
6764
6764
  * Check whether the browser supports the given command
6765
6765
  *
@@ -6770,7 +6770,7 @@ wysihtml5.Commands = Base.extend(
6770
6770
  support: function(command) {
6771
6771
  return wysihtml5.browser.supportsCommand(this.doc, command);
6772
6772
  },
6773
-
6773
+
6774
6774
  /**
6775
6775
  * Check whether the browser supports the given command
6776
6776
  *
@@ -6784,9 +6784,9 @@ wysihtml5.Commands = Base.extend(
6784
6784
  args = wysihtml5.lang.array(arguments).get(),
6785
6785
  method = obj && obj.exec,
6786
6786
  result = null;
6787
-
6787
+
6788
6788
  this.editor.fire("beforecommand:composer");
6789
-
6789
+
6790
6790
  if (method) {
6791
6791
  args.unshift(this.composer);
6792
6792
  result = method.apply(obj, args);
@@ -6796,11 +6796,11 @@ wysihtml5.Commands = Base.extend(
6796
6796
  result = this.doc.execCommand(command, false, value);
6797
6797
  } catch(e) {}
6798
6798
  }
6799
-
6799
+
6800
6800
  this.editor.fire("aftercommand:composer");
6801
6801
  return result;
6802
6802
  },
6803
-
6803
+
6804
6804
  /**
6805
6805
  * Check whether the current command is active
6806
6806
  * If the caret is within a bold text, then calling this with command "bold" should return true
@@ -6827,7 +6827,7 @@ wysihtml5.Commands = Base.extend(
6827
6827
  }
6828
6828
  }
6829
6829
  },
6830
-
6830
+
6831
6831
  /**
6832
6832
  * Get the current command's value
6833
6833
  *
@@ -6853,7 +6853,7 @@ wysihtml5.Commands = Base.extend(
6853
6853
  });
6854
6854
  (function(wysihtml5) {
6855
6855
  var undef;
6856
-
6856
+
6857
6857
  wysihtml5.commands.bold = {
6858
6858
  exec: function(composer, command) {
6859
6859
  return wysihtml5.commands.formatInline.exec(composer, command, "b");
@@ -6878,7 +6878,7 @@ wysihtml5.Commands = Base.extend(
6878
6878
  var undef,
6879
6879
  NODE_NAME = "A",
6880
6880
  dom = wysihtml5.dom;
6881
-
6881
+
6882
6882
  function _removeFormat(composer, anchors) {
6883
6883
  var length = anchors.length,
6884
6884
  i = 0,
@@ -6941,7 +6941,7 @@ wysihtml5.Commands = Base.extend(
6941
6941
  }
6942
6942
  composer.selection.setAfter(elementToSetCaretAfter);
6943
6943
  }
6944
-
6944
+
6945
6945
  wysihtml5.commands.createLink = {
6946
6946
  /**
6947
6947
  * TODO: Use HTMLApplier or formatInline here
@@ -6949,7 +6949,7 @@ wysihtml5.Commands = Base.extend(
6949
6949
  * Turns selection into a link
6950
6950
  * If selection is already a link, it removes the link and wraps it with a <code> element
6951
6951
  * The <code> element is needed to avoid auto linking
6952
- *
6952
+ *
6953
6953
  * @example
6954
6954
  * // either ...
6955
6955
  * wysihtml5.commands.createLink.exec(composer, "createLink", "http://www.google.de");
@@ -6986,7 +6986,7 @@ wysihtml5.Commands = Base.extend(
6986
6986
  (function(wysihtml5) {
6987
6987
  var undef,
6988
6988
  REG_EXP = /wysiwyg-font-size-[a-z\-]+/g;
6989
-
6989
+
6990
6990
  wysihtml5.commands.fontSize = {
6991
6991
  exec: function(composer, command, size) {
6992
6992
  return wysihtml5.commands.formatInline.exec(composer, command, "span", "wysiwyg-font-size-" + size, REG_EXP);
@@ -7009,7 +7009,7 @@ wysihtml5.Commands = Base.extend(
7009
7009
  (function(wysihtml5) {
7010
7010
  var undef,
7011
7011
  REG_EXP = /wysiwyg-color-[a-z]+/g;
7012
-
7012
+
7013
7013
  wysihtml5.commands.foreColor = {
7014
7014
  exec: function(composer, command, color) {
7015
7015
  return wysihtml5.commands.formatInline.exec(composer, command, "span", "wysiwyg-color-" + color, REG_EXP);
@@ -7031,7 +7031,7 @@ wysihtml5.Commands = Base.extend(
7031
7031
  // when the caret is within a H1 and the H4 is invoked, the H1 should turn into H4
7032
7032
  // instead of creating a H4 within a H1 which would result in semantically invalid html
7033
7033
  BLOCK_ELEMENTS_GROUP = ["H1", "H2", "H3", "H4", "H5", "H6", "P", "BLOCKQUOTE", DEFAULT_NODE_NAME];
7034
-
7034
+
7035
7035
  /**
7036
7036
  * Remove similiar classes (based on classRegExp)
7037
7037
  * and add the desired class name
@@ -7173,7 +7173,7 @@ wysihtml5.Commands = Base.extend(
7173
7173
  function _hasClasses(element) {
7174
7174
  return !!wysihtml5.lang.string(element.className).trim();
7175
7175
  }
7176
-
7176
+
7177
7177
  wysihtml5.commands.formatBlock = {
7178
7178
  exec: function(composer, command, nodeName, className, classRegExp) {
7179
7179
  var doc = composer.doc,
@@ -7255,12 +7255,12 @@ wysihtml5.Commands = Base.extend(
7255
7255
  * abcdefg|
7256
7256
  * output:
7257
7257
  * abcdefg<b>|</b>
7258
- *
7258
+ *
7259
7259
  * #2 unformatted text selected:
7260
7260
  * abc|deg|h
7261
7261
  * output:
7262
7262
  * abc<b>|deg|</b>h
7263
- *
7263
+ *
7264
7264
  * #3 unformatted text selected across boundaries:
7265
7265
  * ab|c <span>defg|h</span>
7266
7266
  * output:
@@ -7291,12 +7291,12 @@ wysihtml5.Commands = Base.extend(
7291
7291
  "i": "em"
7292
7292
  },
7293
7293
  htmlApplier = {};
7294
-
7294
+
7295
7295
  function _getTagNames(tagName) {
7296
7296
  var alias = ALIAS_MAPPING[tagName];
7297
7297
  return alias ? [tagName.toLowerCase(), alias.toLowerCase()] : [tagName.toLowerCase()];
7298
7298
  }
7299
-
7299
+
7300
7300
  function _getApplier(tagName, className, classRegExp) {
7301
7301
  var identifier = tagName + ":" + className;
7302
7302
  if (!htmlApplier[identifier]) {
@@ -7304,7 +7304,7 @@ wysihtml5.Commands = Base.extend(
7304
7304
  }
7305
7305
  return htmlApplier[identifier];
7306
7306
  }
7307
-
7307
+
7308
7308
  wysihtml5.commands.formatInline = {
7309
7309
  exec: function(composer, command, tagName, className, classRegExp) {
7310
7310
  var range = composer.selection.getRange();
@@ -7345,7 +7345,7 @@ wysihtml5.Commands = Base.extend(
7345
7345
  };
7346
7346
  })(wysihtml5);(function(wysihtml5) {
7347
7347
  var undef;
7348
-
7348
+
7349
7349
  wysihtml5.commands.insertHTML = {
7350
7350
  exec: function(composer, command, html) {
7351
7351
  if (composer.commands.support(command)) {
@@ -7365,12 +7365,12 @@ wysihtml5.Commands = Base.extend(
7365
7365
  };
7366
7366
  })(wysihtml5);(function(wysihtml5) {
7367
7367
  var NODE_NAME = "IMG";
7368
-
7368
+
7369
7369
  wysihtml5.commands.insertImage = {
7370
7370
  /**
7371
7371
  * Inserts an <img>
7372
7372
  * If selection is already an image link, it removes it
7373
- *
7373
+ *
7374
7374
  * @example
7375
7375
  * // either ...
7376
7376
  * wysihtml5.commands.insertImage.exec(composer, "insertImage", "http://www.google.de/logo.jpg");
@@ -7469,7 +7469,7 @@ wysihtml5.Commands = Base.extend(
7469
7469
  })(wysihtml5);(function(wysihtml5) {
7470
7470
  var undef,
7471
7471
  LINE_BREAK = "<br>" + (wysihtml5.browser.needsSpaceAfterLineBreak() ? " " : "");
7472
-
7472
+
7473
7473
  wysihtml5.commands.insertLineBreak = {
7474
7474
  exec: function(composer, command) {
7475
7475
  if (composer.commands.support(command)) {
@@ -7492,7 +7492,7 @@ wysihtml5.Commands = Base.extend(
7492
7492
  };
7493
7493
  })(wysihtml5);(function(wysihtml5) {
7494
7494
  var undef;
7495
-
7495
+
7496
7496
  wysihtml5.commands.insertOrderedList = {
7497
7497
  exec: function(composer, command) {
7498
7498
  var doc = composer.doc,
@@ -7502,12 +7502,12 @@ wysihtml5.Commands = Base.extend(
7502
7502
  tempClassName = "_wysihtml5-temp-" + new Date().getTime(),
7503
7503
  isEmpty,
7504
7504
  tempElement;
7505
-
7505
+
7506
7506
  if (composer.commands.support(command)) {
7507
7507
  doc.execCommand(command, false, null);
7508
7508
  return;
7509
7509
  }
7510
-
7510
+
7511
7511
  if (list) {
7512
7512
  // Unwrap list
7513
7513
  // <ol><li>foo</li><li>bar</li></ol>
@@ -7537,7 +7537,7 @@ wysihtml5.Commands = Base.extend(
7537
7537
  }
7538
7538
  }
7539
7539
  },
7540
-
7540
+
7541
7541
  state: function(composer) {
7542
7542
  var selectedNode = composer.selection.getSelectedNode();
7543
7543
  return wysihtml5.dom.getParentElement(selectedNode, { nodeName: "OL" });
@@ -7549,7 +7549,7 @@ wysihtml5.Commands = Base.extend(
7549
7549
  };
7550
7550
  })(wysihtml5);(function(wysihtml5) {
7551
7551
  var undef;
7552
-
7552
+
7553
7553
  wysihtml5.commands.insertUnorderedList = {
7554
7554
  exec: function(composer, command) {
7555
7555
  var doc = composer.doc,
@@ -7559,12 +7559,12 @@ wysihtml5.Commands = Base.extend(
7559
7559
  tempClassName = "_wysihtml5-temp-" + new Date().getTime(),
7560
7560
  isEmpty,
7561
7561
  tempElement;
7562
-
7562
+
7563
7563
  if (composer.commands.support(command)) {
7564
7564
  doc.execCommand(command, false, null);
7565
7565
  return;
7566
7566
  }
7567
-
7567
+
7568
7568
  if (list) {
7569
7569
  // Unwrap list
7570
7570
  // <ul><li>foo</li><li>bar</li></ul>
@@ -7594,7 +7594,7 @@ wysihtml5.Commands = Base.extend(
7594
7594
  }
7595
7595
  }
7596
7596
  },
7597
-
7597
+
7598
7598
  state: function(composer) {
7599
7599
  var selectedNode = composer.selection.getSelectedNode();
7600
7600
  return wysihtml5.dom.getParentElement(selectedNode, { nodeName: "UL" });
@@ -7606,7 +7606,7 @@ wysihtml5.Commands = Base.extend(
7606
7606
  };
7607
7607
  })(wysihtml5);(function(wysihtml5) {
7608
7608
  var undef;
7609
-
7609
+
7610
7610
  wysihtml5.commands.italic = {
7611
7611
  exec: function(composer, command) {
7612
7612
  return wysihtml5.commands.formatInline.exec(composer, command, "i");
@@ -7629,7 +7629,7 @@ wysihtml5.Commands = Base.extend(
7629
7629
  var undef,
7630
7630
  CLASS_NAME = "wysiwyg-text-align-center",
7631
7631
  REG_EXP = /wysiwyg-text-align-[a-z]+/g;
7632
-
7632
+
7633
7633
  wysihtml5.commands.justifyCenter = {
7634
7634
  exec: function(composer, command) {
7635
7635
  return wysihtml5.commands.formatBlock.exec(composer, "formatBlock", null, CLASS_NAME, REG_EXP);
@@ -7647,7 +7647,7 @@ wysihtml5.Commands = Base.extend(
7647
7647
  var undef,
7648
7648
  CLASS_NAME = "wysiwyg-text-align-left",
7649
7649
  REG_EXP = /wysiwyg-text-align-[a-z]+/g;
7650
-
7650
+
7651
7651
  wysihtml5.commands.justifyLeft = {
7652
7652
  exec: function(composer, command) {
7653
7653
  return wysihtml5.commands.formatBlock.exec(composer, "formatBlock", null, CLASS_NAME, REG_EXP);
@@ -7665,7 +7665,7 @@ wysihtml5.Commands = Base.extend(
7665
7665
  var undef,
7666
7666
  CLASS_NAME = "wysiwyg-text-align-right",
7667
7667
  REG_EXP = /wysiwyg-text-align-[a-z]+/g;
7668
-
7668
+
7669
7669
  wysihtml5.commands.justifyRight = {
7670
7670
  exec: function(composer, command) {
7671
7671
  return wysihtml5.commands.formatBlock.exec(composer, "formatBlock", null, CLASS_NAME, REG_EXP);
@@ -7707,14 +7707,14 @@ wysihtml5.Commands = Base.extend(
7707
7707
  UNDO_HTML = '<span id="_wysihtml5-undo" class="_wysihtml5-temp">' + wysihtml5.INVISIBLE_SPACE + '</span>',
7708
7708
  REDO_HTML = '<span id="_wysihtml5-redo" class="_wysihtml5-temp">' + wysihtml5.INVISIBLE_SPACE + '</span>',
7709
7709
  dom = wysihtml5.dom;
7710
-
7710
+
7711
7711
  function cleanTempElements(doc) {
7712
7712
  var tempElement;
7713
7713
  while (tempElement = doc.querySelector("._wysihtml5-temp")) {
7714
7714
  tempElement.parentNode.removeChild(tempElement);
7715
7715
  }
7716
7716
  }
7717
-
7717
+
7718
7718
  wysihtml5.UndoManager = wysihtml5.lang.Dispatcher.extend(
7719
7719
  /** @scope wysihtml5.UndoManager.prototype */ {
7720
7720
  constructor: function(editor) {
@@ -7723,28 +7723,28 @@ wysihtml5.Commands = Base.extend(
7723
7723
  this.element = this.composer.element;
7724
7724
  this.history = [this.composer.getValue()];
7725
7725
  this.position = 1;
7726
-
7726
+
7727
7727
  // Undo manager currently only supported in browsers who have the insertHTML command (not IE)
7728
7728
  if (this.composer.commands.support("insertHTML")) {
7729
7729
  this._observe();
7730
7730
  }
7731
7731
  },
7732
-
7732
+
7733
7733
  _observe: function() {
7734
7734
  var that = this,
7735
7735
  doc = this.composer.sandbox.getDocument(),
7736
7736
  lastKey;
7737
-
7737
+
7738
7738
  // Catch CTRL+Z and CTRL+Y
7739
7739
  dom.observe(this.element, "keydown", function(event) {
7740
7740
  if (event.altKey || (!event.ctrlKey && !event.metaKey)) {
7741
7741
  return;
7742
7742
  }
7743
-
7743
+
7744
7744
  var keyCode = event.keyCode,
7745
7745
  isUndo = keyCode === Z_KEY && !event.shiftKey,
7746
7746
  isRedo = (keyCode === Z_KEY && event.shiftKey) || (keyCode === Y_KEY);
7747
-
7747
+
7748
7748
  if (isUndo) {
7749
7749
  that.undo();
7750
7750
  event.preventDefault();
@@ -7753,21 +7753,21 @@ wysihtml5.Commands = Base.extend(
7753
7753
  event.preventDefault();
7754
7754
  }
7755
7755
  });
7756
-
7756
+
7757
7757
  // Catch delete and backspace
7758
7758
  dom.observe(this.element, "keydown", function(event) {
7759
7759
  var keyCode = event.keyCode;
7760
7760
  if (keyCode === lastKey) {
7761
7761
  return;
7762
7762
  }
7763
-
7763
+
7764
7764
  lastKey = keyCode;
7765
-
7765
+
7766
7766
  if (keyCode === BACKSPACE_KEY || keyCode === DELETE_KEY) {
7767
7767
  that.transact();
7768
7768
  }
7769
7769
  });
7770
-
7770
+
7771
7771
  // Now this is very hacky:
7772
7772
  // These days browsers don't offer a undo/redo event which we could hook into
7773
7773
  // to be notified when the user hits undo/redo in the contextmenu.
@@ -7780,7 +7780,7 @@ wysihtml5.Commands = Base.extend(
7780
7780
  cleanTempElements(doc);
7781
7781
  clearInterval(interval);
7782
7782
  };
7783
-
7783
+
7784
7784
  dom.observe(this.element, "contextmenu", function() {
7785
7785
  cleanUp();
7786
7786
  that.composer.selection.executeAndRestoreSimple(function() {
@@ -7812,55 +7812,55 @@ wysihtml5.Commands = Base.extend(
7812
7812
  }
7813
7813
  });
7814
7814
  }
7815
-
7815
+
7816
7816
  this.editor
7817
7817
  .observe("newword:composer", function() {
7818
7818
  that.transact();
7819
7819
  })
7820
-
7820
+
7821
7821
  .observe("beforecommand:composer", function() {
7822
7822
  that.transact();
7823
7823
  });
7824
7824
  },
7825
-
7825
+
7826
7826
  transact: function() {
7827
7827
  var previousHtml = this.history[this.position - 1],
7828
7828
  currentHtml = this.composer.getValue();
7829
-
7829
+
7830
7830
  if (currentHtml == previousHtml) {
7831
7831
  return;
7832
7832
  }
7833
-
7833
+
7834
7834
  var length = this.history.length = this.position;
7835
7835
  if (length > MAX_HISTORY_ENTRIES) {
7836
7836
  this.history.shift();
7837
7837
  this.position--;
7838
7838
  }
7839
-
7839
+
7840
7840
  this.position++;
7841
7841
  this.history.push(currentHtml);
7842
7842
  },
7843
-
7843
+
7844
7844
  undo: function() {
7845
7845
  this.transact();
7846
-
7846
+
7847
7847
  if (this.position <= 1) {
7848
7848
  return;
7849
7849
  }
7850
-
7850
+
7851
7851
  this.set(this.history[--this.position - 1]);
7852
7852
  this.editor.fire("undo:composer");
7853
7853
  },
7854
-
7854
+
7855
7855
  redo: function() {
7856
7856
  if (this.position >= this.history.length) {
7857
7857
  return;
7858
7858
  }
7859
-
7859
+
7860
7860
  this.set(this.history[++this.position - 1]);
7861
7861
  this.editor.fire("redo:composer");
7862
7862
  },
7863
-
7863
+
7864
7864
  set: function(html) {
7865
7865
  this.composer.setValue(html);
7866
7866
  this.editor.focus(true);
@@ -7876,10 +7876,10 @@ wysihtml5.views.View = Base.extend(
7876
7876
  this.parent = parent;
7877
7877
  this.element = textareaElement;
7878
7878
  this.config = config;
7879
-
7879
+
7880
7880
  this._observeViewChange();
7881
7881
  },
7882
-
7882
+
7883
7883
  _observeViewChange: function() {
7884
7884
  var that = this;
7885
7885
  this.parent.observe("beforeload", function() {
@@ -7895,34 +7895,34 @@ wysihtml5.views.View = Base.extend(
7895
7895
  });
7896
7896
  });
7897
7897
  },
7898
-
7898
+
7899
7899
  focus: function() {
7900
7900
  if (this.element.ownerDocument.querySelector(":focus") === this.element) {
7901
7901
  return;
7902
7902
  }
7903
-
7903
+
7904
7904
  try { this.element.focus(); } catch(e) {}
7905
7905
  },
7906
-
7906
+
7907
7907
  hide: function() {
7908
7908
  this.element.style.display = "none";
7909
7909
  },
7910
-
7910
+
7911
7911
  show: function() {
7912
7912
  this.element.style.display = "";
7913
7913
  },
7914
-
7914
+
7915
7915
  disable: function() {
7916
7916
  this.element.setAttribute("disabled", "disabled");
7917
7917
  },
7918
-
7918
+
7919
7919
  enable: function() {
7920
7920
  this.element.removeAttribute("disabled");
7921
7921
  }
7922
7922
  });(function(wysihtml5) {
7923
7923
  var dom = wysihtml5.dom,
7924
7924
  browser = wysihtml5.browser;
7925
-
7925
+
7926
7926
  wysihtml5.views.Composer = wysihtml5.views.View.extend(
7927
7927
  /** @scope wysihtml5.views.Composer.prototype */ {
7928
7928
  name: "composer",
@@ -7942,7 +7942,7 @@ wysihtml5.views.View = Base.extend(
7942
7942
 
7943
7943
  getValue: function(parse) {
7944
7944
  var value = this.isEmpty() ? "" : wysihtml5.quirks.getCorrectInnerHTML(this.element);
7945
-
7945
+
7946
7946
  if (parse) {
7947
7947
  value = this.parent.parse(value);
7948
7948
  }
@@ -7995,9 +7995,9 @@ wysihtml5.views.View = Base.extend(
7995
7995
  if (wysihtml5.browser.doesAsyncFocus() && this.hasPlaceholderSet()) {
7996
7996
  this.clear();
7997
7997
  }
7998
-
7998
+
7999
7999
  this.base();
8000
-
8000
+
8001
8001
  var lastChild = this.element.lastChild;
8002
8002
  if (setToEnd && lastChild) {
8003
8003
  if (lastChild.nodeName === "BR") {
@@ -8019,7 +8019,7 @@ wysihtml5.views.View = Base.extend(
8019
8019
  isEmpty: function() {
8020
8020
  var innerHTML = this.element.innerHTML,
8021
8021
  elementsWithVisualValue = "blockquote, ul, ol, img, embed, object, table, iframe, svg, video, audio, button, input, select, textarea";
8022
- return innerHTML === "" ||
8022
+ return innerHTML === "" ||
8023
8023
  innerHTML === this.CARET_HACK ||
8024
8024
  this.hasPlaceholderSet() ||
8025
8025
  (this.getTextContent() === "" && !this.element.querySelector(elementsWithVisualValue));
@@ -8027,7 +8027,7 @@ wysihtml5.views.View = Base.extend(
8027
8027
 
8028
8028
  _initSandbox: function() {
8029
8029
  var that = this;
8030
-
8030
+
8031
8031
  this.sandbox = new dom.Sandbox(function() {
8032
8032
  that._create();
8033
8033
  }, {
@@ -8049,23 +8049,23 @@ wysihtml5.views.View = Base.extend(
8049
8049
 
8050
8050
  _create: function() {
8051
8051
  var that = this;
8052
-
8052
+
8053
8053
  this.doc = this.sandbox.getDocument();
8054
8054
  this.element = this.doc.body;
8055
8055
  this.textarea = this.parent.textarea;
8056
8056
  this.element.innerHTML = this.textarea.getValue(true);
8057
8057
  this.enable();
8058
-
8058
+
8059
8059
  // Make sure our selection handler is ready
8060
8060
  this.selection = new wysihtml5.Selection(this.parent);
8061
-
8061
+
8062
8062
  // Make sure commands dispatcher is ready
8063
8063
  this.commands = new wysihtml5.Commands(this.parent);
8064
8064
 
8065
8065
  dom.copyAttributes([
8066
8066
  "className", "spellcheck", "title", "lang", "dir", "accessKey"
8067
8067
  ]).from(this.textarea.element).to(this.element);
8068
-
8068
+
8069
8069
  dom.addClass(this.element, this.config.composerClassName);
8070
8070
 
8071
8071
  // Make the editor look like the original textarea, by syncing styles
@@ -8088,7 +8088,7 @@ wysihtml5.views.View = Base.extend(
8088
8088
  if (placeholderText) {
8089
8089
  dom.simulatePlaceholder(this.parent, this, placeholderText);
8090
8090
  }
8091
-
8091
+
8092
8092
  // Make sure that the browser avoids using inline styles whenever possible
8093
8093
  this.commands.exec("styleWithCSS", false);
8094
8094
 
@@ -8196,9 +8196,9 @@ wysihtml5.views.View = Base.extend(
8196
8196
  var properties = ["width", "height"],
8197
8197
  propertiesLength = properties.length,
8198
8198
  element = this.element;
8199
-
8199
+
8200
8200
  this.commands.exec("enableObjectResizing", this.config.allowObjectResizing);
8201
-
8201
+
8202
8202
  if (this.config.allowObjectResizing) {
8203
8203
  // IE sets inline styles after resizing objects
8204
8204
  // The following lines make sure that the width/height css properties
@@ -8226,7 +8226,7 @@ wysihtml5.views.View = Base.extend(
8226
8226
  }
8227
8227
  }
8228
8228
  },
8229
-
8229
+
8230
8230
  _initUndoManager: function() {
8231
8231
  new wysihtml5.UndoManager(this.parent);
8232
8232
  }
@@ -8283,13 +8283,13 @@ wysihtml5.views.View = Base.extend(
8283
8283
  "body { min-height: 100%; padding: 0; margin: 0; margin-top: -1px; padding-top: 1px; }",
8284
8284
  "._wysihtml5-temp { display: none; }",
8285
8285
  wysihtml5.browser.isGecko ?
8286
- "body.placeholder { color: graytext !important; }" :
8286
+ "body.placeholder { color: graytext !important; }" :
8287
8287
  "body.placeholder { color: #a9a9a9 !important; }",
8288
8288
  "body[disabled] { background-color: #eee !important; color: #999 !important; cursor: default !important; }",
8289
8289
  // Ensure that user see's broken images and can delete them
8290
8290
  "img:-moz-broken { -moz-force-broken-image-icon: 1; height: 24px; width: 24px; }"
8291
8291
  ];
8292
-
8292
+
8293
8293
  /**
8294
8294
  * With "setActive" IE offers a smart way of focusing elements without scrolling them into view:
8295
8295
  * http://msdn.microsoft.com/en-us/library/ms536738(v=vs.85).aspx
@@ -8313,7 +8313,7 @@ wysihtml5.views.View = Base.extend(
8313
8313
  left: elementStyle.left,
8314
8314
  WebkitUserSelect: elementStyle.WebkitUserSelect
8315
8315
  };
8316
-
8316
+
8317
8317
  dom.setStyles({
8318
8318
  position: "absolute",
8319
8319
  top: "-99999px",
@@ -8321,11 +8321,11 @@ wysihtml5.views.View = Base.extend(
8321
8321
  // Don't ask why but temporarily setting -webkit-user-select to none makes the whole thing performing smoother
8322
8322
  WebkitUserSelect: "none"
8323
8323
  }).on(element);
8324
-
8324
+
8325
8325
  element.focus();
8326
-
8326
+
8327
8327
  dom.setStyles(originalStyles).on(element);
8328
-
8328
+
8329
8329
  if (win.scrollTo) {
8330
8330
  // Some browser extensions unset this method to prevent annoyances
8331
8331
  // "Better PopUp Blocker" for Chrome http://code.google.com/p/betterpopupblocker/source/browse/trunk/blockStart.js#100
@@ -8334,8 +8334,8 @@ wysihtml5.views.View = Base.extend(
8334
8334
  }
8335
8335
  }
8336
8336
  };
8337
-
8338
-
8337
+
8338
+
8339
8339
  wysihtml5.views.Composer.prototype.style = function() {
8340
8340
  var that = this,
8341
8341
  originalActiveElement = doc.querySelector(":focus"),
@@ -8344,47 +8344,47 @@ wysihtml5.views.View = Base.extend(
8344
8344
  originalPlaceholder = hasPlaceholder && textareaElement.getAttribute("placeholder");
8345
8345
  this.focusStylesHost = this.focusStylesHost || HOST_TEMPLATE.cloneNode(false);
8346
8346
  this.blurStylesHost = this.blurStylesHost || HOST_TEMPLATE.cloneNode(false);
8347
-
8347
+
8348
8348
  // Remove placeholder before copying (as the placeholder has an affect on the computed style)
8349
8349
  if (hasPlaceholder) {
8350
8350
  textareaElement.removeAttribute("placeholder");
8351
8351
  }
8352
-
8352
+
8353
8353
  if (textareaElement === originalActiveElement) {
8354
8354
  textareaElement.blur();
8355
8355
  }
8356
-
8356
+
8357
8357
  // --------- iframe styles (has to be set before editor styles, otherwise IE9 sets wrong fontFamily on blurStylesHost) ---------
8358
8358
  dom.copyStyles(BOX_FORMATTING).from(textareaElement).to(this.iframe).andTo(this.blurStylesHost);
8359
-
8359
+
8360
8360
  // --------- editor styles ---------
8361
8361
  dom.copyStyles(TEXT_FORMATTING).from(textareaElement).to(this.element).andTo(this.blurStylesHost);
8362
-
8362
+
8363
8363
  // --------- apply standard rules ---------
8364
8364
  dom.insertCSS(ADDITIONAL_CSS_RULES).into(this.element.ownerDocument);
8365
-
8365
+
8366
8366
  // --------- :focus styles ---------
8367
8367
  focusWithoutScrolling(textareaElement);
8368
8368
  dom.copyStyles(BOX_FORMATTING).from(textareaElement).to(this.focusStylesHost);
8369
8369
  dom.copyStyles(TEXT_FORMATTING).from(textareaElement).to(this.focusStylesHost);
8370
-
8370
+
8371
8371
  // Make sure that we don't change the display style of the iframe when copying styles oblur/onfocus
8372
8372
  // this is needed for when the change_view event is fired where the iframe is hidden and then
8373
8373
  // the blur event fires and re-displays it
8374
8374
  var boxFormattingStyles = wysihtml5.lang.array(BOX_FORMATTING).without(["display"]);
8375
-
8375
+
8376
8376
  // --------- restore focus ---------
8377
8377
  if (originalActiveElement) {
8378
8378
  originalActiveElement.focus();
8379
8379
  } else {
8380
8380
  textareaElement.blur();
8381
8381
  }
8382
-
8382
+
8383
8383
  // --------- restore placeholder ---------
8384
8384
  if (hasPlaceholder) {
8385
8385
  textareaElement.setAttribute("placeholder", originalPlaceholder);
8386
8386
  }
8387
-
8387
+
8388
8388
  // When copying styles, we only get the computed style which is never returned in percent unit
8389
8389
  // Therefore we've to recalculate style onresize
8390
8390
  if (!wysihtml5.browser.hasCurrentStyleProperty()) {
@@ -8407,7 +8407,7 @@ wysihtml5.views.View = Base.extend(
8407
8407
  textareaElement.style.display = originalTextareaDisplayStyle;
8408
8408
  });
8409
8409
  }
8410
-
8410
+
8411
8411
  // --------- Sync focus/blur styles ---------
8412
8412
  this.parent.observe("focus:composer", function() {
8413
8413
  dom.copyStyles(boxFormattingStyles) .from(that.focusStylesHost).to(that.iframe);
@@ -8418,7 +8418,7 @@ wysihtml5.views.View = Base.extend(
8418
8418
  dom.copyStyles(boxFormattingStyles) .from(that.blurStylesHost).to(that.iframe);
8419
8419
  dom.copyStyles(TEXT_FORMATTING) .from(that.blurStylesHost).to(that.element);
8420
8420
  });
8421
-
8421
+
8422
8422
  return this;
8423
8423
  };
8424
8424
  })(wysihtml5);/**
@@ -8440,7 +8440,7 @@ wysihtml5.views.View = Base.extend(
8440
8440
  "73": "italic", // I
8441
8441
  "85": "underline" // U
8442
8442
  };
8443
-
8443
+
8444
8444
  wysihtml5.views.Composer.prototype.observe = function() {
8445
8445
  var that = this,
8446
8446
  state = this.getValue(),
@@ -8480,7 +8480,7 @@ wysihtml5.views.View = Base.extend(
8480
8480
  }
8481
8481
  that.parent.fire("blur").fire("blur:composer");
8482
8482
  });
8483
-
8483
+
8484
8484
  if (wysihtml5.browser.isIos()) {
8485
8485
  // When on iPad/iPhone/IPod after clicking outside of editor, the editor loses focus
8486
8486
  // but the UI still acts as if the editor has focus (blinking caret and onscreen keyboard visible)
@@ -8496,7 +8496,7 @@ wysihtml5.views.View = Base.extend(
8496
8496
  }
8497
8497
  input.focus();
8498
8498
  input.parentNode.removeChild(input);
8499
-
8499
+
8500
8500
  window.scrollTo(originalScrollLeft, originalScrollTop);
8501
8501
  });
8502
8502
  }
@@ -8554,7 +8554,7 @@ wysihtml5.views.View = Base.extend(
8554
8554
  }
8555
8555
  });
8556
8556
  }
8557
-
8557
+
8558
8558
  // --------- Shortcut logic ---------
8559
8559
  dom.observe(element, "keydown", function(event) {
8560
8560
  var keyCode = event.keyCode,
@@ -8589,7 +8589,7 @@ wysihtml5.views.View = Base.extend(
8589
8589
  IMG: "Image: ",
8590
8590
  A: "Link: "
8591
8591
  };
8592
-
8592
+
8593
8593
  dom.observe(element, "mouseover", function(event) {
8594
8594
  var target = event.target,
8595
8595
  nodeName = target.nodeName,
@@ -8609,7 +8609,7 @@ wysihtml5.views.View = Base.extend(
8609
8609
  */
8610
8610
  (function(wysihtml5) {
8611
8611
  var INTERVAL = 400;
8612
-
8612
+
8613
8613
  wysihtml5.views.Synchronizer = Base.extend(
8614
8614
  /** @scope wysihtml5.views.Synchronizer.prototype */ {
8615
8615
 
@@ -8704,17 +8704,17 @@ wysihtml5.views.View = Base.extend(
8704
8704
  wysihtml5.views.Textarea = wysihtml5.views.View.extend(
8705
8705
  /** @scope wysihtml5.views.Textarea.prototype */ {
8706
8706
  name: "textarea",
8707
-
8707
+
8708
8708
  constructor: function(parent, textareaElement, config) {
8709
8709
  this.base(parent, textareaElement, config);
8710
-
8710
+
8711
8711
  this._observe();
8712
8712
  },
8713
-
8713
+
8714
8714
  clear: function() {
8715
8715
  this.element.value = "";
8716
8716
  },
8717
-
8717
+
8718
8718
  getValue: function(parse) {
8719
8719
  var value = this.isEmpty() ? "" : this.element.value;
8720
8720
  if (parse) {
@@ -8722,14 +8722,14 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
8722
8722
  }
8723
8723
  return value;
8724
8724
  },
8725
-
8725
+
8726
8726
  setValue: function(html, parse) {
8727
8727
  if (parse) {
8728
8728
  html = this.parent.parse(html);
8729
8729
  }
8730
8730
  this.element.value = html;
8731
8731
  },
8732
-
8732
+
8733
8733
  hasPlaceholderSet: function() {
8734
8734
  var supportsPlaceholder = wysihtml5.browser.supportsPlaceholderAttributeOn(this.element),
8735
8735
  placeholderText = this.element.getAttribute("placeholder") || null,
@@ -8737,11 +8737,11 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
8737
8737
  isEmpty = !value;
8738
8738
  return (supportsPlaceholder && isEmpty) || (value === placeholderText);
8739
8739
  },
8740
-
8740
+
8741
8741
  isEmpty: function() {
8742
8742
  return !wysihtml5.lang.string(this.element.value).trim() || this.hasPlaceholderSet();
8743
8743
  },
8744
-
8744
+
8745
8745
  _observe: function() {
8746
8746
  var element = this.element,
8747
8747
  parent = this.parent,
@@ -8754,13 +8754,13 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
8754
8754
  * This is the case for focusin and focusout, so let's use them whenever possible, kkthxbai
8755
8755
  */
8756
8756
  events = wysihtml5.browser.supportsEvent("focusin") ? ["focusin", "focusout", "change"] : ["focus", "blur", "change"];
8757
-
8757
+
8758
8758
  parent.observe("beforeload", function() {
8759
8759
  wysihtml5.dom.observe(element, events, function(event) {
8760
8760
  var eventName = eventMapping[event.type] || event.type;
8761
8761
  parent.fire(eventName).fire(eventName + ":textarea");
8762
8762
  });
8763
-
8763
+
8764
8764
  wysihtml5.dom.observe(element, ["paste", "drop"], function() {
8765
8765
  setTimeout(function() { parent.fire("paste").fire("paste:textarea"); }, 0);
8766
8766
  });
@@ -8802,8 +8802,8 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
8802
8802
  SELECTOR_FORM_ELEMENTS = "input, select, textarea",
8803
8803
  SELECTOR_FIELDS = "[data-wysihtml5-dialog-field]",
8804
8804
  ATTRIBUTE_FIELDS = "data-wysihtml5-dialog-field";
8805
-
8806
-
8805
+
8806
+
8807
8807
  wysihtml5.toolbar.Dialog = wysihtml5.lang.Dispatcher.extend(
8808
8808
  /** @scope wysihtml5.toolbar.Dialog.prototype */ {
8809
8809
  constructor: function(link, container) {
@@ -8815,7 +8815,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
8815
8815
  if (this._observed) {
8816
8816
  return;
8817
8817
  }
8818
-
8818
+
8819
8819
  var that = this,
8820
8820
  callbackWrapper = function(event) {
8821
8821
  var attributes = that._serialize();
@@ -8883,14 +8883,14 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
8883
8883
  /**
8884
8884
  * Takes the attributes of the "elementToChange"
8885
8885
  * and inserts them in their corresponding dialog input fields
8886
- *
8886
+ *
8887
8887
  * Assume the "elementToChange" looks like this:
8888
8888
  * <a href="http://www.google.com" target="_blank">foo</a>
8889
8889
  *
8890
8890
  * and we have the following dialog:
8891
8891
  * <input type="text" data-wysihtml5-dialog-field="href" value="">
8892
8892
  * <input type="text" data-wysihtml5-dialog-field="target" value="">
8893
- *
8893
+ *
8894
8894
  * after calling _interpolate() the dialog will look like this
8895
8895
  * <input type="text" data-wysihtml5-dialog-field="href" value="http://www.google.com">
8896
8896
  * <input type="text" data-wysihtml5-dialog-field="target" value="_blank">
@@ -8908,18 +8908,18 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
8908
8908
  i = 0;
8909
8909
  for (; i<length; i++) {
8910
8910
  field = fields[i];
8911
-
8911
+
8912
8912
  // Never change elements where the user is currently typing in
8913
8913
  if (field === focusedElement) {
8914
8914
  continue;
8915
8915
  }
8916
-
8916
+
8917
8917
  // Don't update hidden fields
8918
8918
  // See https://github.com/xing/wysihtml5/pull/14
8919
8919
  if (avoidHiddenFields && field.type === "hidden") {
8920
8920
  continue;
8921
8921
  }
8922
-
8922
+
8923
8923
  fieldName = field.getAttribute(ATTRIBUTE_FIELDS);
8924
8924
  newValue = this.elementToChange ? (this.elementToChange[fieldName] || "") : field.defaultValue;
8925
8925
  field.value = newValue;
@@ -8969,17 +8969,17 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
8969
8969
  *
8970
8970
  * Current HTML5 draft can be found here
8971
8971
  * http://lists.w3.org/Archives/Public/public-xg-htmlspeech/2011Feb/att-0020/api-draft.html
8972
- *
8972
+ *
8973
8973
  * "Accessing Google Speech API Chrome 11"
8974
8974
  * http://mikepultz.com/2011/03/accessing-google-speech-api-chrome-11/
8975
8975
  */
8976
8976
  (function(wysihtml5) {
8977
8977
  var dom = wysihtml5.dom;
8978
-
8978
+
8979
8979
  var linkStyles = {
8980
8980
  position: "relative"
8981
8981
  };
8982
-
8982
+
8983
8983
  var wrapperStyles = {
8984
8984
  left: 0,
8985
8985
  margin: 0,
@@ -8990,7 +8990,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
8990
8990
  top: 0,
8991
8991
  zIndex: 1
8992
8992
  };
8993
-
8993
+
8994
8994
  var inputStyles = {
8995
8995
  cursor: "inherit",
8996
8996
  fontSize: "50px",
@@ -9002,46 +9002,46 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9002
9002
  right: "-4px",
9003
9003
  top: "50%"
9004
9004
  };
9005
-
9005
+
9006
9006
  var inputAttributes = {
9007
9007
  "x-webkit-speech": "",
9008
9008
  "speech": ""
9009
9009
  };
9010
-
9010
+
9011
9011
  wysihtml5.toolbar.Speech = function(parent, link) {
9012
9012
  var input = document.createElement("input");
9013
9013
  if (!wysihtml5.browser.supportsSpeechApiOn(input)) {
9014
9014
  link.style.display = "none";
9015
9015
  return;
9016
9016
  }
9017
-
9017
+
9018
9018
  var wrapper = document.createElement("div");
9019
-
9019
+
9020
9020
  wysihtml5.lang.object(wrapperStyles).merge({
9021
9021
  width: link.offsetWidth + "px",
9022
9022
  height: link.offsetHeight + "px"
9023
9023
  });
9024
-
9024
+
9025
9025
  dom.insert(input).into(wrapper);
9026
9026
  dom.insert(wrapper).into(link);
9027
-
9027
+
9028
9028
  dom.setStyles(inputStyles).on(input);
9029
9029
  dom.setAttributes(inputAttributes).on(input)
9030
-
9030
+
9031
9031
  dom.setStyles(wrapperStyles).on(wrapper);
9032
9032
  dom.setStyles(linkStyles).on(link);
9033
-
9033
+
9034
9034
  var eventName = "onwebkitspeechchange" in input ? "webkitspeechchange" : "speechchange";
9035
9035
  dom.observe(input, eventName, function() {
9036
9036
  parent.execCommand("insertText", input.value);
9037
9037
  input.value = "";
9038
9038
  });
9039
-
9039
+
9040
9040
  dom.observe(input, "click", function(event) {
9041
9041
  if (dom.hasClass(link, "wysihtml5-command-disabled")) {
9042
9042
  event.preventDefault();
9043
9043
  }
9044
-
9044
+
9045
9045
  event.stopPropagation();
9046
9046
  });
9047
9047
  };
@@ -9067,7 +9067,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9067
9067
  CLASS_NAME_COMMAND_ACTIVE = "wysihtml5-command-active",
9068
9068
  CLASS_NAME_ACTION_ACTIVE = "wysihtml5-action-active",
9069
9069
  dom = wysihtml5.dom;
9070
-
9070
+
9071
9071
  wysihtml5.toolbar.Toolbar = Base.extend(
9072
9072
  /** @scope wysihtml5.toolbar.Toolbar.prototype */ {
9073
9073
  constructor: function(editor, container) {
@@ -9080,7 +9080,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9080
9080
 
9081
9081
  this._observe();
9082
9082
  this.show();
9083
-
9083
+
9084
9084
  var speechInputLinks = this.container.querySelectorAll("[data-wysihtml5-command=insertSpeech]"),
9085
9085
  length = speechInputLinks.length,
9086
9086
  i = 0;
@@ -9105,7 +9105,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9105
9105
  value = link.getAttribute("data-wysihtml5-" + type + "-value");
9106
9106
  group = this.container.querySelector("[data-wysihtml5-" + type + "-group='" + name + "']");
9107
9107
  dialog = this._getDialog(link, name);
9108
-
9108
+
9109
9109
  mapping[name + ":" + value] = {
9110
9110
  link: link,
9111
9111
  group: group,
@@ -9122,7 +9122,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9122
9122
  dialogElement = this.container.querySelector("[data-wysihtml5-dialog='" + command + "']"),
9123
9123
  dialog,
9124
9124
  caretBookmark;
9125
-
9125
+
9126
9126
  if (dialogElement) {
9127
9127
  dialog = new wysihtml5.toolbar.Dialog(link, dialogElement);
9128
9128
 
@@ -9137,7 +9137,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9137
9137
  that.composer.selection.setBookmark(caretBookmark);
9138
9138
  }
9139
9139
  that._execCommand(command, attributes);
9140
-
9140
+
9141
9141
  that.editor.fire("save:dialog", { command: command, dialogContainer: dialogElement, commandLink: link });
9142
9142
  });
9143
9143
 
@@ -9198,7 +9198,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9198
9198
  links = this.commandLinks.concat(this.actionLinks),
9199
9199
  length = links.length,
9200
9200
  i = 0;
9201
-
9201
+
9202
9202
  for (; i<length; i++) {
9203
9203
  // 'javascript:;' and unselectable=on Needed for IE, but done in all browsers to make sure that all get the same css applied
9204
9204
  // (you know, a:link { ... } doesn't match anchors with missing href attribute)
@@ -9210,7 +9210,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9210
9210
 
9211
9211
  // Needed for opera
9212
9212
  dom.delegate(container, "[data-wysihtml5-command]", "mousedown", function(event) { event.preventDefault(); });
9213
-
9213
+
9214
9214
  dom.delegate(container, "[data-wysihtml5-command]", "click", function(event) {
9215
9215
  var link = this,
9216
9216
  command = link.getAttribute("data-wysihtml5-command"),
@@ -9315,10 +9315,10 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9315
9315
  }
9316
9316
  }
9317
9317
  }
9318
-
9318
+
9319
9319
  for (i in actionMapping) {
9320
9320
  action = actionMapping[i];
9321
-
9321
+
9322
9322
  if (action.name === "change_view") {
9323
9323
  action.state = this.editor.currentView === this.editor.textarea;
9324
9324
  if (action.state) {
@@ -9338,7 +9338,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9338
9338
  this.container.style.display = "none";
9339
9339
  }
9340
9340
  });
9341
-
9341
+
9342
9342
  })(wysihtml5);
9343
9343
  /**
9344
9344
  * WYSIHTML5 Editor
@@ -9371,9 +9371,9 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9371
9371
  */
9372
9372
  (function(wysihtml5) {
9373
9373
  var undef;
9374
-
9374
+
9375
9375
  var defaultConfig = {
9376
- // Give the editor a name, the name will also be set as class name on the iframe and on the iframe's body
9376
+ // Give the editor a name, the name will also be set as class name on the iframe and on the iframe's body
9377
9377
  name: undef,
9378
9378
  // Whether the editor should look like the textarea (by adopting styles)
9379
9379
  style: true,
@@ -9399,7 +9399,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9399
9399
  // Whether the rich text editor should be rendered on touch devices (wysihtml5 >= 0.3.0 comes with basic support for iOS 5)
9400
9400
  supportTouchDevices: true
9401
9401
  };
9402
-
9402
+
9403
9403
  wysihtml5.Editor = wysihtml5.lang.Dispatcher.extend(
9404
9404
  /** @scope wysihtml5.Editor.prototype */ {
9405
9405
  constructor: function(textareaElement, config) {
@@ -9408,36 +9408,36 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9408
9408
  this.textarea = new wysihtml5.views.Textarea(this, this.textareaElement, this.config);
9409
9409
  this.currentView = this.textarea;
9410
9410
  this._isCompatible = wysihtml5.browser.supported();
9411
-
9411
+
9412
9412
  // Sort out unsupported/unwanted browsers here
9413
9413
  if (!this._isCompatible || (!this.config.supportTouchDevices && wysihtml5.browser.isTouchDevice())) {
9414
9414
  var that = this;
9415
9415
  setTimeout(function() { that.fire("beforeload").fire("load"); }, 0);
9416
9416
  return;
9417
9417
  }
9418
-
9418
+
9419
9419
  // Add class name to body, to indicate that the editor is supported
9420
9420
  wysihtml5.dom.addClass(document.body, this.config.bodyClassName);
9421
-
9421
+
9422
9422
  this.composer = new wysihtml5.views.Composer(this, this.textareaElement, this.config);
9423
9423
  this.currentView = this.composer;
9424
-
9424
+
9425
9425
  if (typeof(this.config.parser) === "function") {
9426
9426
  this._initParser();
9427
9427
  }
9428
-
9428
+
9429
9429
  this.observe("beforeload", function() {
9430
9430
  this.synchronizer = new wysihtml5.views.Synchronizer(this, this.textarea, this.composer);
9431
9431
  if (this.config.toolbar) {
9432
9432
  this.toolbar = new wysihtml5.toolbar.Toolbar(this, this.config.toolbar);
9433
9433
  }
9434
9434
  });
9435
-
9435
+
9436
9436
  try {
9437
9437
  console.log("Heya! This page is using wysihtml5 for rich text editing. Check out https://github.com/xing/wysihtml5");
9438
9438
  } catch(e) {}
9439
9439
  },
9440
-
9440
+
9441
9441
  isCompatible: function() {
9442
9442
  return this._isCompatible;
9443
9443
  },
@@ -9471,7 +9471,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9471
9471
  this.currentView.disable();
9472
9472
  return this;
9473
9473
  },
9474
-
9474
+
9475
9475
  /**
9476
9476
  * Activate editor
9477
9477
  */
@@ -9479,15 +9479,15 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9479
9479
  this.currentView.enable();
9480
9480
  return this;
9481
9481
  },
9482
-
9482
+
9483
9483
  isEmpty: function() {
9484
9484
  return this.currentView.isEmpty();
9485
9485
  },
9486
-
9486
+
9487
9487
  hasPlaceholderSet: function() {
9488
9488
  return this.currentView.hasPlaceholderSet();
9489
9489
  },
9490
-
9490
+
9491
9491
  parse: function(htmlOrElement) {
9492
9492
  var returnValue = this.config.parser(htmlOrElement, this.config.parserRules, this.composer.sandbox.getDocument(), true);
9493
9493
  if (typeof(htmlOrElement) === "object") {
@@ -9495,7 +9495,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9495
9495
  }
9496
9496
  return returnValue;
9497
9497
  },
9498
-
9498
+
9499
9499
  /**
9500
9500
  * Prepare html parser logic
9501
9501
  * - Observes for paste and drop
@@ -9509,7 +9509,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9509
9509
  that.parse(that.composer.element);
9510
9510
  }, keepScrollPosition);
9511
9511
  });
9512
-
9512
+
9513
9513
  this.observe("paste:textarea", function() {
9514
9514
  var value = this.textarea.getValue(),
9515
9515
  newValue;
@@ -9518,4 +9518,4 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9518
9518
  });
9519
9519
  }
9520
9520
  });
9521
- })(wysihtml5);
9521
+ })(wysihtml5);