wysihtml-rails 0.5.0.beta6 → 0.5.0.beta7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 169166e826e5cf81830b93add509b5443904cdbb
4
- data.tar.gz: b3576b0d1ad6ac31988caa0e25e41e6920fb9e02
3
+ metadata.gz: 64f3d46ae259b28d6540ada222ddc2254e450305
4
+ data.tar.gz: b6124307107e3a712ad473e5461da9ca128c1e8d
5
5
  SHA512:
6
- metadata.gz: 56d0909357b5235b426c651ce8119d86f4a50d431e5e3b9725f511d1afe6663d310f01407f61da69beb4196d0bf196cd82a235ce510ebf7d12826d349fa7f025
7
- data.tar.gz: 21b029d33b26b2ea0b43078dae432823a3eff5937526f648e430d611dbc389ce3af640573d4dd4d798e7d06e834877d8405997853cea7192c0a9be9725b5345f
6
+ metadata.gz: d741717b1e1b496c1f3073f6b7a1ed16bd891ef69d5712342a860befc67880cef51e5e630dbd7cea70f48d7517404d065ceabb4671b0863e9a3e8088c44d8890
7
+ data.tar.gz: 1eca60fa61f5ef49a5e21873ff6a5610622b059a1e06687c0776215e489d62344fc9c43d716ff1d1343ce8bdbeca8ae880aaebeb4683948031587f8da3732dcd
@@ -1,5 +1,5 @@
1
1
  module Wysihtml
2
2
  module Rails
3
- VERSION = "0.5.0.beta6"
3
+ VERSION = "0.5.0.beta7"
4
4
  end
5
5
  end
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @license wysihtml5x v0.5.0-beta6
3
- * https://github.com/Edicy/wysihtml5
2
+ * @license wysihtml v0.5.0-beta7
3
+ * https://github.com/Voog/wysihtml
4
4
  *
5
5
  * Author: Christopher Blum (https://github.com/tiff)
6
6
  * Secondary author of extended features: Oliver Pulges (https://github.com/pulges)
@@ -10,7 +10,7 @@
10
10
  *
11
11
  */
12
12
  var wysihtml5 = {
13
- version: "0.5.0-beta6",
13
+ version: "0.5.0-beta7",
14
14
 
15
15
  // namespaces
16
16
  commands: {},
@@ -5081,9 +5081,17 @@ wysihtml5.browser = (function() {
5081
5081
  * wysihtml5.lang.object({ foo: 1, bar: 1 }).merge({ bar: 2, baz: 3 }).get();
5082
5082
  * // => { foo: 1, bar: 2, baz: 3 }
5083
5083
  */
5084
- merge: function(otherObj) {
5084
+ merge: function(otherObj, deep) {
5085
5085
  for (var i in otherObj) {
5086
- obj[i] = otherObj[i];
5086
+ if (deep && wysihtml5.lang.object(otherObj[i]).isPlainObject() && (typeof obj[i] === "undefined" || wysihtml5.lang.object(obj[i]).isPlainObject())) {
5087
+ if (typeof obj[i] === "undefined") {
5088
+ obj[i] = wysihtml5.lang.object(otherObj[i]).clone(true);
5089
+ } else {
5090
+ wysihtml5.lang.object(obj[i]).merge(wysihtml5.lang.object(otherObj[i]).clone(true));
5091
+ }
5092
+ } else {
5093
+ obj[i] = wysihtml5.lang.object(otherObj[i]).isPlainObject() ? wysihtml5.lang.object(otherObj[i]).clone(true) : otherObj[i];
5094
+ }
5087
5095
  }
5088
5096
  return this;
5089
5097
  },
@@ -5138,7 +5146,7 @@ wysihtml5.browser = (function() {
5138
5146
  },
5139
5147
 
5140
5148
  isPlainObject: function () {
5141
- return Object.prototype.toString.call(obj) === '[object Object]';
5149
+ return obj && Object.prototype.toString.call(obj) === '[object Object]';
5142
5150
  }
5143
5151
  };
5144
5152
  };
@@ -6696,11 +6704,9 @@ wysihtml5.dom.parse = function(elementOrHtml_current, config_current) {
6696
6704
  newAttributeValue;
6697
6705
 
6698
6706
  if (method) {
6699
- if (attributeValue || (attributeName === "alt" && nodeName == "IMG")) {
6700
- newAttributeValue = method(attributeValue);
6701
- if (typeof(newAttributeValue) === "string") {
6702
- return newAttributeValue;
6703
- }
6707
+ newAttributeValue = method(attributeValue, nodeName);
6708
+ if (typeof(newAttributeValue) === "string") {
6709
+ return newAttributeValue;
6704
6710
  }
6705
6711
  }
6706
6712
 
@@ -6935,9 +6941,13 @@ wysihtml5.dom.parse = function(elementOrHtml_current, config_current) {
6935
6941
 
6936
6942
  alt: (function() {
6937
6943
  var REG_EXP = /[^ a-z0-9_\-]/gi;
6938
- return function(attributeValue) {
6944
+ return function(attributeValue, nodeName) {
6939
6945
  if (!attributeValue) {
6940
- return "";
6946
+ if (nodeName === "IMG") {
6947
+ return "";
6948
+ } else {
6949
+ return null;
6950
+ }
6941
6951
  }
6942
6952
  return attributeValue.replace(REG_EXP, "");
6943
6953
  };
@@ -6963,6 +6973,9 @@ wysihtml5.dom.parse = function(elementOrHtml_current, config_current) {
6963
6973
 
6964
6974
  any: (function() {
6965
6975
  return function(attributeValue) {
6976
+ if (!attributeValue) {
6977
+ return null;
6978
+ }
6966
6979
  return attributeValue;
6967
6980
  };
6968
6981
  })()
@@ -7320,6 +7333,9 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
7320
7333
  constructor: function(readyCallback, config) {
7321
7334
  this.callback = readyCallback || wysihtml5.EMPTY_FUNCTION;
7322
7335
  this.config = wysihtml5.lang.object({}).merge(config).get();
7336
+ if (!this.config.className) {
7337
+ this.config.className = "wysihtml5-sandbox";
7338
+ }
7323
7339
  this.editableArea = this._createIframe();
7324
7340
  },
7325
7341
 
@@ -7374,7 +7390,7 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
7374
7390
  _createIframe: function() {
7375
7391
  var that = this,
7376
7392
  iframe = doc.createElement("iframe");
7377
- iframe.className = "wysihtml5-sandbox";
7393
+ iframe.className = this.config.className;
7378
7394
  wysihtml5.dom.setAttributes({
7379
7395
  "security": "restricted",
7380
7396
  "allowtransparency": "true",
@@ -7537,6 +7553,9 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
7537
7553
  constructor: function(readyCallback, config, contentEditable) {
7538
7554
  this.callback = readyCallback || wysihtml5.EMPTY_FUNCTION;
7539
7555
  this.config = wysihtml5.lang.object({}).merge(config).get();
7556
+ if (!this.config.className) {
7557
+ this.config.className = "wysihtml5-sandbox";
7558
+ }
7540
7559
  if (contentEditable) {
7541
7560
  this.element = this._bindElement(contentEditable);
7542
7561
  } else {
@@ -7547,7 +7566,7 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
7547
7566
  // creates a new contenteditable and initiates it
7548
7567
  _createElement: function() {
7549
7568
  var element = doc.createElement("div");
7550
- element.className = "wysihtml5-sandbox";
7569
+ element.className = this.config.className;
7551
7570
  this._loadElement(element);
7552
7571
  return element;
7553
7572
  },
@@ -7626,8 +7645,8 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
7626
7645
  * wysihtml.dom.simulatePlaceholder(this, composer, "Foobar");
7627
7646
  */
7628
7647
  (function(dom) {
7629
- dom.simulatePlaceholder = function(editor, view, placeholderText) {
7630
- var CLASS_NAME = "placeholder",
7648
+ dom.simulatePlaceholder = function(editor, view, placeholderText, placeholderClassName) {
7649
+ var CLASS_NAME = placeholderClassName || "wysihtml5-placeholder",
7631
7650
  unset = function() {
7632
7651
  var composerIsVisible = view.element.offsetWidth > 0 && view.element.offsetHeight > 0;
7633
7652
  if (view.hasPlaceholderSet()) {
@@ -11355,7 +11374,7 @@ wysihtml5.Commands = Base.extend(
11355
11374
  function cleanup(composer) {
11356
11375
  var container = composer.element,
11357
11376
  allElements = container.querySelectorAll(BLOCK_ELEMENTS),
11358
- uneditables = container.querySelectorAll(composer.config.uneditableContainerClassname),
11377
+ uneditables = container.querySelectorAll(composer.config.classNames.uneditableContainer),
11359
11378
  elements = wysihtml5.lang.array(allElements).without(uneditables);
11360
11379
 
11361
11380
  for (var i = elements.length; i--;) {
@@ -11627,7 +11646,7 @@ wysihtml5.Commands = Base.extend(
11627
11646
  state = this.state(composer, command, options);
11628
11647
  if (state) {
11629
11648
  bookmark = rangy.saveSelection(composer.win);
11630
- for (var j in state) {
11649
+ for (var j = 0, jmax = state.length; j < jmax; j++) {
11631
11650
  removeOptionsFromElement(state[j], options, composer);
11632
11651
  }
11633
11652
  }
@@ -11650,7 +11669,7 @@ wysihtml5.Commands = Base.extend(
11650
11669
  composer.selection.selectLine();
11651
11670
  }
11652
11671
  }
11653
-
11672
+
11654
11673
  // And get all selection ranges of current composer and iterat
11655
11674
  ranges = composer.selection.getOwnRanges();
11656
11675
  for (var i = ranges.length; i--;) {
@@ -12212,7 +12231,7 @@ wysihtml5.Commands = Base.extend(
12212
12231
 
12213
12232
  if (tempElement) {
12214
12233
  isEmpty = wysihtml5.lang.array(["", "<br>", wysihtml5.INVISIBLE_SPACE]).contains(tempElement.innerHTML);
12215
- list = wysihtml5.dom.convertToList(tempElement, nodeName.toLowerCase(), composer.parent.config.uneditableContainerClassname);
12234
+ list = wysihtml5.dom.convertToList(tempElement, nodeName.toLowerCase(), composer.parent.config.classNames.uneditableContainer);
12216
12235
  if (isEmpty) {
12217
12236
  composer.selection.selectNode(list.querySelector("li"), true);
12218
12237
  }
@@ -12441,7 +12460,7 @@ wysihtml5.Commands = Base.extend(
12441
12460
  for (row = 0; row < value.rows; row ++) {
12442
12461
  html += '<tr>';
12443
12462
  for (col = 0; col < value.cols; col ++) {
12444
- html += "<td></td>";
12463
+ html += "<td><br></td>";
12445
12464
  }
12446
12465
  html += '</tr>';
12447
12466
  }
@@ -13123,14 +13142,17 @@ wysihtml5.views.View = Base.extend(
13123
13142
 
13124
13143
  _initContentEditableArea: function() {
13125
13144
  var that = this;
13126
-
13127
13145
  if (this.config.noTextarea) {
13128
13146
  this.sandbox = new dom.ContentEditableArea(function() {
13129
13147
  that._create();
13130
- }, {}, this.editableArea);
13148
+ }, {
13149
+ className: this.config.classNames.sandbox
13150
+ }, this.editableArea);
13131
13151
  } else {
13132
13152
  this.sandbox = new dom.ContentEditableArea(function() {
13133
13153
  that._create();
13154
+ }, {
13155
+ className: this.config.classNames.sandbox
13134
13156
  });
13135
13157
  this.editableArea = this.sandbox.getContentEditable();
13136
13158
  dom.insert(this.editableArea).after(this.textarea.element);
@@ -13140,11 +13162,11 @@ wysihtml5.views.View = Base.extend(
13140
13162
 
13141
13163
  _initSandbox: function() {
13142
13164
  var that = this;
13143
-
13144
13165
  this.sandbox = new dom.Sandbox(function() {
13145
13166
  that._create();
13146
13167
  }, {
13147
- stylesheets: this.config.stylesheets
13168
+ stylesheets: this.config.stylesheets,
13169
+ className: this.config.classNames.sandbox
13148
13170
  });
13149
13171
  this.editableArea = this.sandbox.getIframe();
13150
13172
 
@@ -13178,7 +13200,7 @@ wysihtml5.views.View = Base.extend(
13178
13200
  }
13179
13201
 
13180
13202
  // Make sure our selection handler is ready
13181
- this.selection = new wysihtml5.Selection(this.parent, this.element, this.config.uneditableContainerClassname);
13203
+ this.selection = new wysihtml5.Selection(this.parent, this.element, this.config.classNames.uneditableContainer);
13182
13204
 
13183
13205
  // Make sure commands dispatcher is ready
13184
13206
  this.commands = new wysihtml5.Commands(this.parent);
@@ -13189,7 +13211,7 @@ wysihtml5.views.View = Base.extend(
13189
13211
  ]).from(this.textarea.element).to(this.element);
13190
13212
  }
13191
13213
 
13192
- dom.addClass(this.element, this.config.composerClassName);
13214
+ dom.addClass(this.element, this.config.classNames.composer);
13193
13215
  //
13194
13216
  // Make the editor look like the original textarea, by syncing styles
13195
13217
  if (this.config.style && !this.config.contentEditableMode) {
@@ -13215,7 +13237,7 @@ wysihtml5.views.View = Base.extend(
13215
13237
  ? this.config.placeholder
13216
13238
  : ((this.config.noTextarea) ? this.editableArea.getAttribute("data-placeholder") : this.textarea.element.getAttribute("placeholder"));
13217
13239
  if (placeholderText) {
13218
- dom.simulatePlaceholder(this.parent, this, placeholderText);
13240
+ dom.simulatePlaceholder(this.parent, this, placeholderText, this.config.classNames.placeholder);
13219
13241
  }
13220
13242
 
13221
13243
  // Make sure that the browser avoids using inline styles whenever possible
@@ -13267,7 +13289,7 @@ wysihtml5.views.View = Base.extend(
13267
13289
  this.parent.on("newword:composer", function() {
13268
13290
  if (dom.getTextContent(that.element).match(dom.autoLink.URL_REG_EXP)) {
13269
13291
  var nodeWithSelection = that.selection.getSelectedNode(),
13270
- uneditables = that.element.querySelectorAll("." + that.config.uneditableContainerClassname),
13292
+ uneditables = that.element.querySelectorAll("." + that.config.classNames.uneditableContainer),
13271
13293
  isInUneditable = false;
13272
13294
 
13273
13295
  for (var i = uneditables.length; i--;) {
@@ -13276,12 +13298,12 @@ wysihtml5.views.View = Base.extend(
13276
13298
  }
13277
13299
  }
13278
13300
 
13279
- if (!isInUneditable) dom.autoLink(nodeWithSelection, [that.config.uneditableContainerClassname]);
13301
+ if (!isInUneditable) dom.autoLink(nodeWithSelection, [that.config.classNames.uneditableContainer]);
13280
13302
  }
13281
13303
  });
13282
13304
 
13283
13305
  dom.observe(this.element, "blur", function() {
13284
- dom.autoLink(that.element, [that.config.uneditableContainerClassname]);
13306
+ dom.autoLink(that.element, [that.config.classNames.uneditableContainer]);
13285
13307
  });
13286
13308
  }
13287
13309
 
@@ -13716,7 +13738,7 @@ wysihtml5.views.View = Base.extend(
13716
13738
  // If found an uneditable before caret then notify it before deletion
13717
13739
  var handleUneditableDeletion = function(composer) {
13718
13740
  var before = composer.selection.getBeforeSelection(true);
13719
- if (before && (before.type === "element" || before.type === "leafnode") && before.node.nodeType === 1 && before.node.classList.contains(composer.config.uneditableContainerClassname)) {
13741
+ if (before && (before.type === "element" || before.type === "leafnode") && before.node.nodeType === 1 && before.node.classList.contains(composer.config.classNames.uneditableContainer)) {
13720
13742
  if (fixLastBrDeletionInTable(composer, true)) {
13721
13743
  return true;
13722
13744
  }
@@ -13881,7 +13903,7 @@ wysihtml5.views.View = Base.extend(
13881
13903
  // Make sure that images are selected when clicking on them
13882
13904
  var target = event.target,
13883
13905
  allImages = this.element.querySelectorAll('img'),
13884
- notMyImages = this.element.querySelectorAll('.' + this.config.uneditableContainerClassname + ' img'),
13906
+ notMyImages = this.element.querySelectorAll('.' + this.config.classNames.uneditableContainer + ' img'),
13885
13907
  myImages = wysihtml5.lang.array(allImages).without(notMyImages);
13886
13908
 
13887
13909
  if (target.nodeName === "IMG" && wysihtml5.lang.array(myImages).contains(target)) {
@@ -13911,10 +13933,10 @@ wysihtml5.views.View = Base.extend(
13911
13933
  };
13912
13934
 
13913
13935
  var handleClick = function(event) {
13914
- if (this.config.uneditableContainerClassname) {
13936
+ if (this.config.classNames.uneditableContainer) {
13915
13937
  // If uneditables is configured, makes clicking on uneditable move caret after clicked element (so it can be deleted like text)
13916
13938
  // If uneditable needs text selection itself event.stopPropagation can be used to prevent this behaviour
13917
- var uneditable = wysihtml5.dom.getParentElement(event.target, { query: "." + this.config.uneditableContainerClassname }, false, this.element);
13939
+ var uneditable = wysihtml5.dom.getParentElement(event.target, { query: "." + this.config.classNames.uneditableContainer }, false, this.element);
13918
13940
  if (uneditable) {
13919
13941
  this.selection.setAfter(uneditable);
13920
13942
  }
@@ -14338,10 +14360,6 @@ wysihtml5.views.View = Base.extend(
14338
14360
  pasteParserRulesets: null,
14339
14361
  // Parser method to use when the user inserts content
14340
14362
  parser: wysihtml5.dom.parse,
14341
- // Class name which should be set on the contentEditable element in the created sandbox iframe, can be styled via the 'stylesheets' option
14342
- composerClassName: "wysihtml5-editor",
14343
- // Class name to add to the body when the wysihtml5 editor is supported
14344
- bodyClassName: "wysihtml5-supported",
14345
14363
  // By default wysihtml5 will insert a <br> for line breaks, set this to false to use <p>
14346
14364
  useLineBreaks: true,
14347
14365
  // Array (or single string) of stylesheet urls to be loaded in the editor's iframe
@@ -14354,9 +14372,18 @@ wysihtml5.views.View = Base.extend(
14354
14372
  cleanUp: true,
14355
14373
  // Whether to use div instead of secure iframe
14356
14374
  contentEditableMode: false,
14357
- // Classname of container that editor should not touch and pass through
14358
- // Pass false to disable
14359
- uneditableContainerClassname: "wysihtml5-uneditable-container",
14375
+ classNames: {
14376
+ // Class name which should be set on the contentEditable element in the created sandbox iframe, can be styled via the 'stylesheets' option
14377
+ composer: "wysihtml5-editor",
14378
+ // Class name to add to the body when the wysihtml5 editor is supported
14379
+ body: "wysihtml5-supported",
14380
+ // classname added to editable area element (iframe/div) on creation
14381
+ sandbox: "wysihtml5-sandbox",
14382
+ // class on editable area with placeholder
14383
+ placeholder: "wysihtml5-placeholder",
14384
+ // Classname of container that editor should not touch and pass through
14385
+ uneditableContainer: "wysihtml5-uneditable-container"
14386
+ },
14360
14387
  // Browsers that support copied source handling will get a marking of the origin of the copied source (for determinig code cleanup rules on paste)
14361
14388
  // Also copied source is based directly on selection -
14362
14389
  // (very useful for webkit based browsers where copy will otherwise contain a lot of code and styles based on whatever and not actually in selection).
@@ -14368,9 +14395,14 @@ wysihtml5.views.View = Base.extend(
14368
14395
  /** @scope wysihtml5.Editor.prototype */ {
14369
14396
  constructor: function(editableElement, config) {
14370
14397
  this.editableElement = typeof(editableElement) === "string" ? document.getElementById(editableElement) : editableElement;
14371
- this.config = wysihtml5.lang.object({}).merge(defaultConfig).merge(config).get();
14398
+ this.config = wysihtml5.lang.object({}).merge(defaultConfig).merge(config, true).get();
14372
14399
  this._isCompatible = wysihtml5.browser.supported();
14373
14400
 
14401
+ // make sure that rules override instead of extend
14402
+ if (config && config.parserRules) {
14403
+ this.config.parserRules = wysihtml5.lang.object(config.parserRules).clone(true);
14404
+ }
14405
+
14374
14406
  if (this.editableElement.nodeName.toLowerCase() != "textarea") {
14375
14407
  this.config.contentEditableMode = true;
14376
14408
  this.config.noTextarea = true;
@@ -14388,7 +14420,7 @@ wysihtml5.views.View = Base.extend(
14388
14420
  }
14389
14421
 
14390
14422
  // Add class name to body, to indicate that the editor is supported
14391
- wysihtml5.dom.addClass(document.body, this.config.bodyClassName);
14423
+ wysihtml5.dom.addClass(document.body, this.config.classNames.body);
14392
14424
 
14393
14425
  this.composer = new wysihtml5.views.Composer(this, this.editableElement, this.config);
14394
14426
  this.currentView = this.composer;
@@ -14474,7 +14506,7 @@ wysihtml5.views.View = Base.extend(
14474
14506
  "rules": this.config.parserRules,
14475
14507
  "cleanUp": this.config.cleanUp,
14476
14508
  "context": parseContext,
14477
- "uneditableClass": this.config.uneditableContainerClassname,
14509
+ "uneditableClass": this.config.classNames.uneditableContainer,
14478
14510
  "clearInternals" : clearInternals
14479
14511
  });
14480
14512
  if (typeof(htmlOrElement) === "object") {
@@ -14520,7 +14552,7 @@ wysihtml5.views.View = Base.extend(
14520
14552
  var cleanHtml = wysihtml5.quirks.cleanPastedHTML(oldHtml, {
14521
14553
  "referenceNode": this.composer.element,
14522
14554
  "rules": this.config.pasteParserRulesets || [{"set": this.config.parserRules}],
14523
- "uneditableClass": this.config.uneditableContainerClassname
14555
+ "uneditableClass": this.config.classNames.uneditableContainer
14524
14556
  });
14525
14557
  this.composer.selection.deleteContents();
14526
14558
  this.composer.selection.insertHTML(cleanHtml);
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @license wysihtml5x v0.5.0-beta6
3
- * https://github.com/Edicy/wysihtml5
2
+ * @license wysihtml v0.5.0-beta7
3
+ * https://github.com/Voog/wysihtml
4
4
  *
5
5
  * Author: Christopher Blum (https://github.com/tiff)
6
6
  * Secondary author of extended features: Oliver Pulges (https://github.com/pulges)
@@ -10,7 +10,7 @@
10
10
  *
11
11
  */
12
12
  var wysihtml5 = {
13
- version: "0.5.0-beta6",
13
+ version: "0.5.0-beta7",
14
14
 
15
15
  // namespaces
16
16
  commands: {},
@@ -5081,9 +5081,17 @@ wysihtml5.browser = (function() {
5081
5081
  * wysihtml5.lang.object({ foo: 1, bar: 1 }).merge({ bar: 2, baz: 3 }).get();
5082
5082
  * // => { foo: 1, bar: 2, baz: 3 }
5083
5083
  */
5084
- merge: function(otherObj) {
5084
+ merge: function(otherObj, deep) {
5085
5085
  for (var i in otherObj) {
5086
- obj[i] = otherObj[i];
5086
+ if (deep && wysihtml5.lang.object(otherObj[i]).isPlainObject() && (typeof obj[i] === "undefined" || wysihtml5.lang.object(obj[i]).isPlainObject())) {
5087
+ if (typeof obj[i] === "undefined") {
5088
+ obj[i] = wysihtml5.lang.object(otherObj[i]).clone(true);
5089
+ } else {
5090
+ wysihtml5.lang.object(obj[i]).merge(wysihtml5.lang.object(otherObj[i]).clone(true));
5091
+ }
5092
+ } else {
5093
+ obj[i] = wysihtml5.lang.object(otherObj[i]).isPlainObject() ? wysihtml5.lang.object(otherObj[i]).clone(true) : otherObj[i];
5094
+ }
5087
5095
  }
5088
5096
  return this;
5089
5097
  },
@@ -5138,7 +5146,7 @@ wysihtml5.browser = (function() {
5138
5146
  },
5139
5147
 
5140
5148
  isPlainObject: function () {
5141
- return Object.prototype.toString.call(obj) === '[object Object]';
5149
+ return obj && Object.prototype.toString.call(obj) === '[object Object]';
5142
5150
  }
5143
5151
  };
5144
5152
  };
@@ -6696,11 +6704,9 @@ wysihtml5.dom.parse = function(elementOrHtml_current, config_current) {
6696
6704
  newAttributeValue;
6697
6705
 
6698
6706
  if (method) {
6699
- if (attributeValue || (attributeName === "alt" && nodeName == "IMG")) {
6700
- newAttributeValue = method(attributeValue);
6701
- if (typeof(newAttributeValue) === "string") {
6702
- return newAttributeValue;
6703
- }
6707
+ newAttributeValue = method(attributeValue, nodeName);
6708
+ if (typeof(newAttributeValue) === "string") {
6709
+ return newAttributeValue;
6704
6710
  }
6705
6711
  }
6706
6712
 
@@ -6935,9 +6941,13 @@ wysihtml5.dom.parse = function(elementOrHtml_current, config_current) {
6935
6941
 
6936
6942
  alt: (function() {
6937
6943
  var REG_EXP = /[^ a-z0-9_\-]/gi;
6938
- return function(attributeValue) {
6944
+ return function(attributeValue, nodeName) {
6939
6945
  if (!attributeValue) {
6940
- return "";
6946
+ if (nodeName === "IMG") {
6947
+ return "";
6948
+ } else {
6949
+ return null;
6950
+ }
6941
6951
  }
6942
6952
  return attributeValue.replace(REG_EXP, "");
6943
6953
  };
@@ -6963,6 +6973,9 @@ wysihtml5.dom.parse = function(elementOrHtml_current, config_current) {
6963
6973
 
6964
6974
  any: (function() {
6965
6975
  return function(attributeValue) {
6976
+ if (!attributeValue) {
6977
+ return null;
6978
+ }
6966
6979
  return attributeValue;
6967
6980
  };
6968
6981
  })()
@@ -7320,6 +7333,9 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
7320
7333
  constructor: function(readyCallback, config) {
7321
7334
  this.callback = readyCallback || wysihtml5.EMPTY_FUNCTION;
7322
7335
  this.config = wysihtml5.lang.object({}).merge(config).get();
7336
+ if (!this.config.className) {
7337
+ this.config.className = "wysihtml5-sandbox";
7338
+ }
7323
7339
  this.editableArea = this._createIframe();
7324
7340
  },
7325
7341
 
@@ -7374,7 +7390,7 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
7374
7390
  _createIframe: function() {
7375
7391
  var that = this,
7376
7392
  iframe = doc.createElement("iframe");
7377
- iframe.className = "wysihtml5-sandbox";
7393
+ iframe.className = this.config.className;
7378
7394
  wysihtml5.dom.setAttributes({
7379
7395
  "security": "restricted",
7380
7396
  "allowtransparency": "true",
@@ -7537,6 +7553,9 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
7537
7553
  constructor: function(readyCallback, config, contentEditable) {
7538
7554
  this.callback = readyCallback || wysihtml5.EMPTY_FUNCTION;
7539
7555
  this.config = wysihtml5.lang.object({}).merge(config).get();
7556
+ if (!this.config.className) {
7557
+ this.config.className = "wysihtml5-sandbox";
7558
+ }
7540
7559
  if (contentEditable) {
7541
7560
  this.element = this._bindElement(contentEditable);
7542
7561
  } else {
@@ -7547,7 +7566,7 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
7547
7566
  // creates a new contenteditable and initiates it
7548
7567
  _createElement: function() {
7549
7568
  var element = doc.createElement("div");
7550
- element.className = "wysihtml5-sandbox";
7569
+ element.className = this.config.className;
7551
7570
  this._loadElement(element);
7552
7571
  return element;
7553
7572
  },
@@ -7626,8 +7645,8 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
7626
7645
  * wysihtml.dom.simulatePlaceholder(this, composer, "Foobar");
7627
7646
  */
7628
7647
  (function(dom) {
7629
- dom.simulatePlaceholder = function(editor, view, placeholderText) {
7630
- var CLASS_NAME = "placeholder",
7648
+ dom.simulatePlaceholder = function(editor, view, placeholderText, placeholderClassName) {
7649
+ var CLASS_NAME = placeholderClassName || "wysihtml5-placeholder",
7631
7650
  unset = function() {
7632
7651
  var composerIsVisible = view.element.offsetWidth > 0 && view.element.offsetHeight > 0;
7633
7652
  if (view.hasPlaceholderSet()) {
@@ -11355,7 +11374,7 @@ wysihtml5.Commands = Base.extend(
11355
11374
  function cleanup(composer) {
11356
11375
  var container = composer.element,
11357
11376
  allElements = container.querySelectorAll(BLOCK_ELEMENTS),
11358
- uneditables = container.querySelectorAll(composer.config.uneditableContainerClassname),
11377
+ uneditables = container.querySelectorAll(composer.config.classNames.uneditableContainer),
11359
11378
  elements = wysihtml5.lang.array(allElements).without(uneditables);
11360
11379
 
11361
11380
  for (var i = elements.length; i--;) {
@@ -11627,7 +11646,7 @@ wysihtml5.Commands = Base.extend(
11627
11646
  state = this.state(composer, command, options);
11628
11647
  if (state) {
11629
11648
  bookmark = rangy.saveSelection(composer.win);
11630
- for (var j in state) {
11649
+ for (var j = 0, jmax = state.length; j < jmax; j++) {
11631
11650
  removeOptionsFromElement(state[j], options, composer);
11632
11651
  }
11633
11652
  }
@@ -11650,7 +11669,7 @@ wysihtml5.Commands = Base.extend(
11650
11669
  composer.selection.selectLine();
11651
11670
  }
11652
11671
  }
11653
-
11672
+
11654
11673
  // And get all selection ranges of current composer and iterat
11655
11674
  ranges = composer.selection.getOwnRanges();
11656
11675
  for (var i = ranges.length; i--;) {
@@ -12212,7 +12231,7 @@ wysihtml5.Commands = Base.extend(
12212
12231
 
12213
12232
  if (tempElement) {
12214
12233
  isEmpty = wysihtml5.lang.array(["", "<br>", wysihtml5.INVISIBLE_SPACE]).contains(tempElement.innerHTML);
12215
- list = wysihtml5.dom.convertToList(tempElement, nodeName.toLowerCase(), composer.parent.config.uneditableContainerClassname);
12234
+ list = wysihtml5.dom.convertToList(tempElement, nodeName.toLowerCase(), composer.parent.config.classNames.uneditableContainer);
12216
12235
  if (isEmpty) {
12217
12236
  composer.selection.selectNode(list.querySelector("li"), true);
12218
12237
  }
@@ -12441,7 +12460,7 @@ wysihtml5.Commands = Base.extend(
12441
12460
  for (row = 0; row < value.rows; row ++) {
12442
12461
  html += '<tr>';
12443
12462
  for (col = 0; col < value.cols; col ++) {
12444
- html += "<td></td>";
12463
+ html += "<td><br></td>";
12445
12464
  }
12446
12465
  html += '</tr>';
12447
12466
  }
@@ -13123,14 +13142,17 @@ wysihtml5.views.View = Base.extend(
13123
13142
 
13124
13143
  _initContentEditableArea: function() {
13125
13144
  var that = this;
13126
-
13127
13145
  if (this.config.noTextarea) {
13128
13146
  this.sandbox = new dom.ContentEditableArea(function() {
13129
13147
  that._create();
13130
- }, {}, this.editableArea);
13148
+ }, {
13149
+ className: this.config.classNames.sandbox
13150
+ }, this.editableArea);
13131
13151
  } else {
13132
13152
  this.sandbox = new dom.ContentEditableArea(function() {
13133
13153
  that._create();
13154
+ }, {
13155
+ className: this.config.classNames.sandbox
13134
13156
  });
13135
13157
  this.editableArea = this.sandbox.getContentEditable();
13136
13158
  dom.insert(this.editableArea).after(this.textarea.element);
@@ -13140,11 +13162,11 @@ wysihtml5.views.View = Base.extend(
13140
13162
 
13141
13163
  _initSandbox: function() {
13142
13164
  var that = this;
13143
-
13144
13165
  this.sandbox = new dom.Sandbox(function() {
13145
13166
  that._create();
13146
13167
  }, {
13147
- stylesheets: this.config.stylesheets
13168
+ stylesheets: this.config.stylesheets,
13169
+ className: this.config.classNames.sandbox
13148
13170
  });
13149
13171
  this.editableArea = this.sandbox.getIframe();
13150
13172
 
@@ -13178,7 +13200,7 @@ wysihtml5.views.View = Base.extend(
13178
13200
  }
13179
13201
 
13180
13202
  // Make sure our selection handler is ready
13181
- this.selection = new wysihtml5.Selection(this.parent, this.element, this.config.uneditableContainerClassname);
13203
+ this.selection = new wysihtml5.Selection(this.parent, this.element, this.config.classNames.uneditableContainer);
13182
13204
 
13183
13205
  // Make sure commands dispatcher is ready
13184
13206
  this.commands = new wysihtml5.Commands(this.parent);
@@ -13189,7 +13211,7 @@ wysihtml5.views.View = Base.extend(
13189
13211
  ]).from(this.textarea.element).to(this.element);
13190
13212
  }
13191
13213
 
13192
- dom.addClass(this.element, this.config.composerClassName);
13214
+ dom.addClass(this.element, this.config.classNames.composer);
13193
13215
  //
13194
13216
  // Make the editor look like the original textarea, by syncing styles
13195
13217
  if (this.config.style && !this.config.contentEditableMode) {
@@ -13215,7 +13237,7 @@ wysihtml5.views.View = Base.extend(
13215
13237
  ? this.config.placeholder
13216
13238
  : ((this.config.noTextarea) ? this.editableArea.getAttribute("data-placeholder") : this.textarea.element.getAttribute("placeholder"));
13217
13239
  if (placeholderText) {
13218
- dom.simulatePlaceholder(this.parent, this, placeholderText);
13240
+ dom.simulatePlaceholder(this.parent, this, placeholderText, this.config.classNames.placeholder);
13219
13241
  }
13220
13242
 
13221
13243
  // Make sure that the browser avoids using inline styles whenever possible
@@ -13267,7 +13289,7 @@ wysihtml5.views.View = Base.extend(
13267
13289
  this.parent.on("newword:composer", function() {
13268
13290
  if (dom.getTextContent(that.element).match(dom.autoLink.URL_REG_EXP)) {
13269
13291
  var nodeWithSelection = that.selection.getSelectedNode(),
13270
- uneditables = that.element.querySelectorAll("." + that.config.uneditableContainerClassname),
13292
+ uneditables = that.element.querySelectorAll("." + that.config.classNames.uneditableContainer),
13271
13293
  isInUneditable = false;
13272
13294
 
13273
13295
  for (var i = uneditables.length; i--;) {
@@ -13276,12 +13298,12 @@ wysihtml5.views.View = Base.extend(
13276
13298
  }
13277
13299
  }
13278
13300
 
13279
- if (!isInUneditable) dom.autoLink(nodeWithSelection, [that.config.uneditableContainerClassname]);
13301
+ if (!isInUneditable) dom.autoLink(nodeWithSelection, [that.config.classNames.uneditableContainer]);
13280
13302
  }
13281
13303
  });
13282
13304
 
13283
13305
  dom.observe(this.element, "blur", function() {
13284
- dom.autoLink(that.element, [that.config.uneditableContainerClassname]);
13306
+ dom.autoLink(that.element, [that.config.classNames.uneditableContainer]);
13285
13307
  });
13286
13308
  }
13287
13309
 
@@ -13716,7 +13738,7 @@ wysihtml5.views.View = Base.extend(
13716
13738
  // If found an uneditable before caret then notify it before deletion
13717
13739
  var handleUneditableDeletion = function(composer) {
13718
13740
  var before = composer.selection.getBeforeSelection(true);
13719
- if (before && (before.type === "element" || before.type === "leafnode") && before.node.nodeType === 1 && before.node.classList.contains(composer.config.uneditableContainerClassname)) {
13741
+ if (before && (before.type === "element" || before.type === "leafnode") && before.node.nodeType === 1 && before.node.classList.contains(composer.config.classNames.uneditableContainer)) {
13720
13742
  if (fixLastBrDeletionInTable(composer, true)) {
13721
13743
  return true;
13722
13744
  }
@@ -13881,7 +13903,7 @@ wysihtml5.views.View = Base.extend(
13881
13903
  // Make sure that images are selected when clicking on them
13882
13904
  var target = event.target,
13883
13905
  allImages = this.element.querySelectorAll('img'),
13884
- notMyImages = this.element.querySelectorAll('.' + this.config.uneditableContainerClassname + ' img'),
13906
+ notMyImages = this.element.querySelectorAll('.' + this.config.classNames.uneditableContainer + ' img'),
13885
13907
  myImages = wysihtml5.lang.array(allImages).without(notMyImages);
13886
13908
 
13887
13909
  if (target.nodeName === "IMG" && wysihtml5.lang.array(myImages).contains(target)) {
@@ -13911,10 +13933,10 @@ wysihtml5.views.View = Base.extend(
13911
13933
  };
13912
13934
 
13913
13935
  var handleClick = function(event) {
13914
- if (this.config.uneditableContainerClassname) {
13936
+ if (this.config.classNames.uneditableContainer) {
13915
13937
  // If uneditables is configured, makes clicking on uneditable move caret after clicked element (so it can be deleted like text)
13916
13938
  // If uneditable needs text selection itself event.stopPropagation can be used to prevent this behaviour
13917
- var uneditable = wysihtml5.dom.getParentElement(event.target, { query: "." + this.config.uneditableContainerClassname }, false, this.element);
13939
+ var uneditable = wysihtml5.dom.getParentElement(event.target, { query: "." + this.config.classNames.uneditableContainer }, false, this.element);
13918
13940
  if (uneditable) {
13919
13941
  this.selection.setAfter(uneditable);
13920
13942
  }
@@ -14338,10 +14360,6 @@ wysihtml5.views.View = Base.extend(
14338
14360
  pasteParserRulesets: null,
14339
14361
  // Parser method to use when the user inserts content
14340
14362
  parser: wysihtml5.dom.parse,
14341
- // Class name which should be set on the contentEditable element in the created sandbox iframe, can be styled via the 'stylesheets' option
14342
- composerClassName: "wysihtml5-editor",
14343
- // Class name to add to the body when the wysihtml5 editor is supported
14344
- bodyClassName: "wysihtml5-supported",
14345
14363
  // By default wysihtml5 will insert a <br> for line breaks, set this to false to use <p>
14346
14364
  useLineBreaks: true,
14347
14365
  // Array (or single string) of stylesheet urls to be loaded in the editor's iframe
@@ -14354,9 +14372,18 @@ wysihtml5.views.View = Base.extend(
14354
14372
  cleanUp: true,
14355
14373
  // Whether to use div instead of secure iframe
14356
14374
  contentEditableMode: false,
14357
- // Classname of container that editor should not touch and pass through
14358
- // Pass false to disable
14359
- uneditableContainerClassname: "wysihtml5-uneditable-container",
14375
+ classNames: {
14376
+ // Class name which should be set on the contentEditable element in the created sandbox iframe, can be styled via the 'stylesheets' option
14377
+ composer: "wysihtml5-editor",
14378
+ // Class name to add to the body when the wysihtml5 editor is supported
14379
+ body: "wysihtml5-supported",
14380
+ // classname added to editable area element (iframe/div) on creation
14381
+ sandbox: "wysihtml5-sandbox",
14382
+ // class on editable area with placeholder
14383
+ placeholder: "wysihtml5-placeholder",
14384
+ // Classname of container that editor should not touch and pass through
14385
+ uneditableContainer: "wysihtml5-uneditable-container"
14386
+ },
14360
14387
  // Browsers that support copied source handling will get a marking of the origin of the copied source (for determinig code cleanup rules on paste)
14361
14388
  // Also copied source is based directly on selection -
14362
14389
  // (very useful for webkit based browsers where copy will otherwise contain a lot of code and styles based on whatever and not actually in selection).
@@ -14368,9 +14395,14 @@ wysihtml5.views.View = Base.extend(
14368
14395
  /** @scope wysihtml5.Editor.prototype */ {
14369
14396
  constructor: function(editableElement, config) {
14370
14397
  this.editableElement = typeof(editableElement) === "string" ? document.getElementById(editableElement) : editableElement;
14371
- this.config = wysihtml5.lang.object({}).merge(defaultConfig).merge(config).get();
14398
+ this.config = wysihtml5.lang.object({}).merge(defaultConfig).merge(config, true).get();
14372
14399
  this._isCompatible = wysihtml5.browser.supported();
14373
14400
 
14401
+ // make sure that rules override instead of extend
14402
+ if (config && config.parserRules) {
14403
+ this.config.parserRules = wysihtml5.lang.object(config.parserRules).clone(true);
14404
+ }
14405
+
14374
14406
  if (this.editableElement.nodeName.toLowerCase() != "textarea") {
14375
14407
  this.config.contentEditableMode = true;
14376
14408
  this.config.noTextarea = true;
@@ -14388,7 +14420,7 @@ wysihtml5.views.View = Base.extend(
14388
14420
  }
14389
14421
 
14390
14422
  // Add class name to body, to indicate that the editor is supported
14391
- wysihtml5.dom.addClass(document.body, this.config.bodyClassName);
14423
+ wysihtml5.dom.addClass(document.body, this.config.classNames.body);
14392
14424
 
14393
14425
  this.composer = new wysihtml5.views.Composer(this, this.editableElement, this.config);
14394
14426
  this.currentView = this.composer;
@@ -14474,7 +14506,7 @@ wysihtml5.views.View = Base.extend(
14474
14506
  "rules": this.config.parserRules,
14475
14507
  "cleanUp": this.config.cleanUp,
14476
14508
  "context": parseContext,
14477
- "uneditableClass": this.config.uneditableContainerClassname,
14509
+ "uneditableClass": this.config.classNames.uneditableContainer,
14478
14510
  "clearInternals" : clearInternals
14479
14511
  });
14480
14512
  if (typeof(htmlOrElement) === "object") {
@@ -14520,7 +14552,7 @@ wysihtml5.views.View = Base.extend(
14520
14552
  var cleanHtml = wysihtml5.quirks.cleanPastedHTML(oldHtml, {
14521
14553
  "referenceNode": this.composer.element,
14522
14554
  "rules": this.config.pasteParserRulesets || [{"set": this.config.parserRules}],
14523
- "uneditableClass": this.config.uneditableContainerClassname
14555
+ "uneditableClass": this.config.classNames.uneditableContainer
14524
14556
  });
14525
14557
  this.composer.selection.deleteContents();
14526
14558
  this.composer.selection.insertHTML(cleanHtml);
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wysihtml-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0.beta6
4
+ version: 0.5.0.beta7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tanel Jakobsoo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-03 00:00:00.000000000 Z
11
+ date: 2015-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties