bootsy 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.
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  Bootsy
2
- ==========
2
+ ======
3
3
  [![Build Status](https://secure.travis-ci.org/volmer/bootsy.png?branch=master)](http://travis-ci.org/volmer/bootsy)
4
4
 
5
5
  *Bootsy* is a WYSIWYG solution for Rails based on [Bootstrap-wysihtml5](https://github.com/jhollingworth/bootstrap-wysihtml5) which includes image uploads via [CarrierWave](https://github.com/jnicklas/carrierwave).
@@ -8,8 +8,9 @@ Bootsy
8
8
  ## Requirements
9
9
 
10
10
  * Ruby MRI >= 1.9.3;
11
+ * ImageMagick or GraphicsMagick (for MiniMagick);
11
12
  * Rails >= 3.2.6;
12
- * Twitter Bootstrap properly integrated in your project's assets pipeline.
13
+ * [Twitter Bootstrap](http://twitter.github.com/bootstrap/) assets added on your application.
13
14
 
14
15
 
15
16
  ## Installation
@@ -31,7 +32,7 @@ Bootsy
31
32
  rails g bootsy:install
32
33
  ```
33
34
 
34
- 4. Add and run migrations:
35
+ 4. Add and run migrations (if you are using ActiveRecord):
35
36
  ```console
36
37
  rake bootsy:install:migrations
37
38
  rake db:migrate
@@ -67,7 +68,7 @@ Bootsy will group the uploaded image files as galleries and associate them to on
67
68
 
68
69
  ## I18n
69
70
 
70
- Bootsy defines some i18n keys. The english translation is automatically added to your `config/locales` directory as `bootsy.en.yml`. You can follow that template in order to translate Bootsy for your language.
71
+ Bootsy defines some i18n keys. The english translation is automatically added to your `config/locales` directory as `bootsy.en.yml`. You can follow that template in order to translate Bootsy for your language. You can find some examples [here](https://github.com/volmer/bootsy/tree/master/config/locales).
71
72
 
72
73
 
73
74
  ## Mongoid support
@@ -100,7 +100,7 @@
100
100
  "check_attributes": {
101
101
  "width": "numbers",
102
102
  "alt": "alt",
103
- "src": "url",
103
+ "src": "src",
104
104
  "height": "numbers"
105
105
  }
106
106
  },
@@ -161,8 +161,6 @@
161
161
  'style': "display:none"
162
162
  });
163
163
 
164
- console.log(options.locale);
165
-
166
164
  for(var key in defaultOptions) {
167
165
  var value = false;
168
166
 
@@ -11,8 +11,6 @@ function bootsyOpenImageGallery(editor){
11
11
  }
12
12
 
13
13
  function bootsyInsertImage(image, editor){
14
- console.log(image);
15
-
16
14
  $('#bootsy_image_gallery').modal('hide');
17
15
  editor.composer.commands.exec("insertImage", image);
18
16
  }
@@ -52,7 +50,6 @@ $(document).ready(function(){
52
50
  imagePrefix = '/';
53
51
  }
54
52
  var img = $(this).parents('li.dropdown').find('img');
55
- console.log($(this).parents('li.dropdown'));
56
53
  var src = img.attr('src').replace("/thumb_", imagePrefix);
57
54
  var alt = img.attr('alt');
58
55
 
@@ -3474,6 +3474,13 @@ wysihtml5.browser = (function() {
3474
3474
  hasCurrentStyleProperty: function() {
3475
3475
  return "currentStyle" in testElement;
3476
3476
  },
3477
+
3478
+ /**
3479
+ * Firefox on OSX navigates through history when hitting CMD + Arrow right/left
3480
+ */
3481
+ hasHistoryIssue: function() {
3482
+ return isGecko;
3483
+ },
3477
3484
 
3478
3485
  /**
3479
3486
  * Whether the browser inserts a <br> when pressing enter in a contentEditable element
@@ -3499,29 +3506,7 @@ wysihtml5.browser = (function() {
3499
3506
  supportsEventsInIframeCorrectly: function() {
3500
3507
  return !isOpera;
3501
3508
  },
3502
-
3503
- /**
3504
- * Chrome & Safari only fire the ondrop/ondragend/... events when the ondragover event is cancelled
3505
- * with event.preventDefault
3506
- * Firefox 3.6 fires those events anyway, but the mozilla doc says that the dragover/dragenter event needs
3507
- * to be cancelled
3508
- */
3509
- firesOnDropOnlyWhenOnDragOverIsCancelled: function() {
3510
- return isWebKit || isGecko;
3511
- },
3512
3509
 
3513
- /**
3514
- * Whether the browser supports the event.dataTransfer property in a proper way
3515
- */
3516
- supportsDataTransfer: function() {
3517
- try {
3518
- // Firefox doesn't support dataTransfer in a safe way, it doesn't strip script code in the html payload (like Chrome does)
3519
- return isWebKit && (window.Clipboard || window.DataTransfer).prototype.getData;
3520
- } catch(e) {
3521
- return false;
3522
- }
3523
- },
3524
-
3525
3510
  /**
3526
3511
  * Everything below IE9 doesn't know how to treat HTML5 tags
3527
3512
  *
@@ -3678,14 +3663,6 @@ wysihtml5.browser = (function() {
3678
3663
  return "getSelection" in window && "modify" in window.getSelection();
3679
3664
  },
3680
3665
 
3681
- /**
3682
- * Whether the browser supports the classList object for fast className manipulation
3683
- * See https://developer.mozilla.org/en/DOM/element.classList
3684
- */
3685
- supportsClassList: function() {
3686
- return "classList" in testElement;
3687
- },
3688
-
3689
3666
  /**
3690
3667
  * Opera needs a white space after a <br> in order to position the caret correctly
3691
3668
  */
@@ -4058,12 +4035,12 @@ wysihtml5.browser = (function() {
4058
4035
  // Reveal url reg exp to the outside
4059
4036
  wysihtml5.dom.autoLink.URL_REG_EXP = URL_REG_EXP;
4060
4037
  })(wysihtml5);(function(wysihtml5) {
4061
- var supportsClassList = wysihtml5.browser.supportsClassList(),
4062
- api = wysihtml5.dom;
4038
+ var api = wysihtml5.dom;
4063
4039
 
4064
4040
  api.addClass = function(element, className) {
4065
- if (supportsClassList) {
4066
- return element.classList.add(className);
4041
+ var classList = element.classList;
4042
+ if (classList) {
4043
+ return classList.add(className);
4067
4044
  }
4068
4045
  if (api.hasClass(element, className)) {
4069
4046
  return;
@@ -4072,16 +4049,18 @@ wysihtml5.browser = (function() {
4072
4049
  };
4073
4050
 
4074
4051
  api.removeClass = function(element, className) {
4075
- if (supportsClassList) {
4076
- return element.classList.remove(className);
4052
+ var classList = element.classList;
4053
+ if (classList) {
4054
+ return classList.remove(className);
4077
4055
  }
4078
4056
 
4079
4057
  element.className = element.className.replace(new RegExp("(^|\\s+)" + className + "(\\s+|$)"), " ");
4080
4058
  };
4081
4059
 
4082
4060
  api.hasClass = function(element, className) {
4083
- if (supportsClassList) {
4084
- return element.classList.contains(className);
4061
+ var classList = element.classList;
4062
+ if (classList) {
4063
+ return classList.contains(className);
4085
4064
  }
4086
4065
 
4087
4066
  var elementClassName = element.className;
@@ -5061,6 +5040,30 @@ wysihtml5.dom.parse = (function() {
5061
5040
  });
5062
5041
  };
5063
5042
  })(),
5043
+
5044
+ src: (function() {
5045
+ var REG_EXP = /^(\/|https?:\/\/)/i;
5046
+ return function(attributeValue) {
5047
+ if (!attributeValue || !attributeValue.match(REG_EXP)) {
5048
+ return null;
5049
+ }
5050
+ return attributeValue.replace(REG_EXP, function(match) {
5051
+ return match.toLowerCase();
5052
+ });
5053
+ };
5054
+ })(),
5055
+
5056
+ href: (function() {
5057
+ var REG_EXP = /^(\/|https?:\/\/|mailto:)/i;
5058
+ return function(attributeValue) {
5059
+ if (!attributeValue || !attributeValue.match(REG_EXP)) {
5060
+ return null;
5061
+ }
5062
+ return attributeValue.replace(REG_EXP, function(match) {
5063
+ return match.toLowerCase();
5064
+ });
5065
+ };
5066
+ })(),
5064
5067
 
5065
5068
  alt: (function() {
5066
5069
  var REG_EXP = /[^ a-z0-9_\-]/gi;
@@ -5136,7 +5139,8 @@ wysihtml5.dom.parse = (function() {
5136
5139
  };
5137
5140
 
5138
5141
  return parse;
5139
- })();/**
5142
+ })();
5143
+ /**
5140
5144
  * Checks for empty text node childs and removes them
5141
5145
  *
5142
5146
  * @param {Element} node The element in which to cleanup
@@ -5595,10 +5599,12 @@ wysihtml5.dom.replaceWithChildNodes = function(node) {
5595
5599
  if (view.hasPlaceholderSet()) {
5596
5600
  view.clear();
5597
5601
  }
5602
+ view.placeholderSet = false;
5598
5603
  dom.removeClass(view.element, CLASS_NAME);
5599
5604
  },
5600
5605
  set = function() {
5601
5606
  if (view.isEmpty()) {
5607
+ view.placeholderSet = true;
5602
5608
  view.setValue(placeholderText);
5603
5609
  dom.addClass(view.element, CLASS_NAME);
5604
5610
  }
@@ -6132,7 +6138,13 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6132
6138
  try { newRange.setEnd(rangeBackup.endContainer, rangeBackup.endOffset); } catch(e2) {}
6133
6139
  try { this.setSelection(newRange); } catch(e3) {}
6134
6140
  },
6135
-
6141
+
6142
+ set: function(node, offset) {
6143
+ var newRange = rangy.createRange(this.doc);
6144
+ newRange.setStart(node, offset || 0);
6145
+ this.setSelection(newRange);
6146
+ },
6147
+
6136
6148
  /**
6137
6149
  * Insert html at the caret position and move the cursor after the inserted html
6138
6150
  *
@@ -6195,6 +6207,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6195
6207
  */
6196
6208
  scrollIntoView: function() {
6197
6209
  var doc = this.doc,
6210
+ tolerance = 5, // px
6198
6211
  hasScrollBars = doc.documentElement.scrollHeight > doc.documentElement.offsetHeight,
6199
6212
  tempElement = doc._wysihtml5ScrollIntoViewElement = doc._wysihtml5ScrollIntoViewElement || (function() {
6200
6213
  var element = doc.createElement("span");
@@ -6208,7 +6221,7 @@ wysihtml5.quirks.cleanPastedHTML = (function() {
6208
6221
  this.insertNode(tempElement);
6209
6222
  offsetTop = _getCumulativeOffsetTop(tempElement);
6210
6223
  tempElement.parentNode.removeChild(tempElement);
6211
- if (offsetTop > doc.body.scrollTop) {
6224
+ if (offsetTop >= (doc.body.scrollTop + doc.documentElement.offsetHeight - tolerance)) {
6212
6225
  doc.body.scrollTop = offsetTop;
6213
6226
  }
6214
6227
  }
@@ -6826,53 +6839,22 @@ wysihtml5.Commands = Base.extend(
6826
6839
  return false;
6827
6840
  }
6828
6841
  }
6829
- },
6830
-
6831
- /**
6832
- * Get the current command's value
6833
- *
6834
- * @param {String} command The command string which to check (eg. "formatBlock")
6835
- * @return {String} The command value
6836
- * @example
6837
- * var currentBlockElement = commands.value("formatBlock");
6838
- */
6839
- value: function(command) {
6840
- var obj = wysihtml5.commands[command],
6841
- method = obj && obj.value;
6842
- if (method) {
6843
- return method.call(obj, this.composer, command);
6844
- } else {
6845
- try {
6846
- // try/catch for buggy firefox
6847
- return this.doc.queryCommandValue(command);
6848
- } catch(e) {
6849
- return null;
6850
- }
6851
- }
6852
6842
  }
6853
6843
  });
6854
- (function(wysihtml5) {
6855
- var undef;
6856
-
6857
- wysihtml5.commands.bold = {
6858
- exec: function(composer, command) {
6859
- return wysihtml5.commands.formatInline.exec(composer, command, "b");
6860
- },
6861
-
6862
- state: function(composer, command, color) {
6863
- // element.ownerDocument.queryCommandState("bold") results:
6864
- // firefox: only <b>
6865
- // chrome: <b>, <strong>, <h1>, <h2>, ...
6866
- // ie: <b>, <strong>
6867
- // opera: <b>, <strong>
6868
- return wysihtml5.commands.formatInline.state(composer, command, "b");
6869
- },
6844
+ wysihtml5.commands.bold = {
6845
+ exec: function(composer, command) {
6846
+ return wysihtml5.commands.formatInline.exec(composer, command, "b");
6847
+ },
6870
6848
 
6871
- value: function() {
6872
- return undef;
6873
- }
6874
- };
6875
- })(wysihtml5);
6849
+ state: function(composer, command) {
6850
+ // element.ownerDocument.queryCommandState("bold") results:
6851
+ // firefox: only <b>
6852
+ // chrome: <b>, <strong>, <h1>, <h2>, ...
6853
+ // ie: <b>, <strong>
6854
+ // opera: <b>, <strong>
6855
+ return wysihtml5.commands.formatInline.state(composer, command, "b");
6856
+ }
6857
+ };
6876
6858
 
6877
6859
  (function(wysihtml5) {
6878
6860
  var undef,
@@ -6972,10 +6954,6 @@ wysihtml5.Commands = Base.extend(
6972
6954
 
6973
6955
  state: function(composer, command) {
6974
6956
  return wysihtml5.commands.formatInline.state(composer, command, "A");
6975
- },
6976
-
6977
- value: function() {
6978
- return undef;
6979
6957
  }
6980
6958
  };
6981
6959
  })(wysihtml5);/**
@@ -6985,7 +6963,7 @@ wysihtml5.Commands = Base.extend(
6985
6963
  */
6986
6964
  (function(wysihtml5) {
6987
6965
  var undef,
6988
- REG_EXP = /wysiwyg-font-size-[a-z\-]+/g;
6966
+ REG_EXP = /wysiwyg-font-size-[0-9a-z\-]+/g;
6989
6967
 
6990
6968
  wysihtml5.commands.fontSize = {
6991
6969
  exec: function(composer, command, size) {
@@ -7007,8 +6985,7 @@ wysihtml5.Commands = Base.extend(
7007
6985
  * Instead we set a css class
7008
6986
  */
7009
6987
  (function(wysihtml5) {
7010
- var undef,
7011
- REG_EXP = /wysiwyg-color-[a-z]+/g;
6988
+ var REG_EXP = /wysiwyg-color-[0-9a-z]+/g;
7012
6989
 
7013
6990
  wysihtml5.commands.foreColor = {
7014
6991
  exec: function(composer, command, color) {
@@ -7017,15 +6994,10 @@ wysihtml5.Commands = Base.extend(
7017
6994
 
7018
6995
  state: function(composer, command, color) {
7019
6996
  return wysihtml5.commands.formatInline.state(composer, command, "span", "wysiwyg-color-" + color, REG_EXP);
7020
- },
7021
-
7022
- value: function() {
7023
- return undef;
7024
6997
  }
7025
6998
  };
7026
6999
  })(wysihtml5);(function(wysihtml5) {
7027
- var undef,
7028
- dom = wysihtml5.dom,
7000
+ var dom = wysihtml5.dom,
7029
7001
  DEFAULT_NODE_NAME = "DIV",
7030
7002
  // Following elements are grouped
7031
7003
  // when the caret is within a H1 and the H4 is invoked, the H1 should turn into H4
@@ -7242,10 +7214,6 @@ wysihtml5.Commands = Base.extend(
7242
7214
  className: className,
7243
7215
  classRegExp: classRegExp
7244
7216
  });
7245
- },
7246
-
7247
- value: function() {
7248
- return undef;
7249
7217
  }
7250
7218
  };
7251
7219
  })(wysihtml5);/**
@@ -7282,8 +7250,7 @@ wysihtml5.Commands = Base.extend(
7282
7250
  * <span>ab|c</span> de|<b>fgh</b>
7283
7251
  */
7284
7252
  (function(wysihtml5) {
7285
- var undef,
7286
- // Treat <b> as <strong> and vice versa
7253
+ var // Treat <b> as <strong> and vice versa
7287
7254
  ALIAS_MAPPING = {
7288
7255
  "strong": "b",
7289
7256
  "em": "i",
@@ -7337,33 +7304,22 @@ wysihtml5.Commands = Base.extend(
7337
7304
  }
7338
7305
 
7339
7306
  return _getApplier(tagName, className, classRegExp).isAppliedToRange(range);
7340
- },
7341
-
7342
- value: function() {
7343
- return undef;
7344
7307
  }
7345
7308
  };
7346
- })(wysihtml5);(function(wysihtml5) {
7347
- var undef;
7348
-
7349
- wysihtml5.commands.insertHTML = {
7350
- exec: function(composer, command, html) {
7351
- if (composer.commands.support(command)) {
7352
- composer.doc.execCommand(command, false, html);
7353
- } else {
7354
- composer.selection.insertHTML(html);
7355
- }
7356
- },
7357
-
7358
- state: function() {
7359
- return false;
7360
- },
7361
-
7362
- value: function() {
7363
- return undef;
7309
+ })(wysihtml5);wysihtml5.commands.insertHTML = {
7310
+ exec: function(composer, command, html) {
7311
+ if (composer.commands.support(command)) {
7312
+ composer.doc.execCommand(command, false, html);
7313
+ } else {
7314
+ composer.selection.insertHTML(html);
7364
7315
  }
7365
- };
7366
- })(wysihtml5);(function(wysihtml5) {
7316
+ },
7317
+
7318
+ state: function() {
7319
+ return false;
7320
+ }
7321
+ };
7322
+ (function(wysihtml5) {
7367
7323
  var NODE_NAME = "IMG";
7368
7324
 
7369
7325
  wysihtml5.commands.insertImage = {
@@ -7405,9 +7361,12 @@ wysihtml5.Commands = Base.extend(
7405
7361
  }
7406
7362
 
7407
7363
  image = doc.createElement(NODE_NAME);
7408
-
7364
+
7409
7365
  for (i in value) {
7410
- image[i] = value[i];
7366
+ if (i === "className") {
7367
+ i = "class";
7368
+ }
7369
+ image.setAttribute(i, value[i]);
7411
7370
  }
7412
7371
 
7413
7372
  composer.selection.insertNode(image);
@@ -7459,16 +7418,10 @@ wysihtml5.Commands = Base.extend(
7459
7418
  }
7460
7419
 
7461
7420
  return imagesInSelection[0];
7462
- },
7463
-
7464
- value: function(composer) {
7465
- var image = this.state(composer);
7466
- return image && image.src;
7467
7421
  }
7468
7422
  };
7469
7423
  })(wysihtml5);(function(wysihtml5) {
7470
- var undef,
7471
- LINE_BREAK = "<br>" + (wysihtml5.browser.needsSpaceAfterLineBreak() ? " " : "");
7424
+ var LINE_BREAK = "<br>" + (wysihtml5.browser.needsSpaceAfterLineBreak() ? " " : "");
7472
7425
 
7473
7426
  wysihtml5.commands.insertLineBreak = {
7474
7427
  exec: function(composer, command) {
@@ -7484,151 +7437,122 @@ wysihtml5.Commands = Base.extend(
7484
7437
 
7485
7438
  state: function() {
7486
7439
  return false;
7487
- },
7488
-
7489
- value: function() {
7490
- return undef;
7491
7440
  }
7492
7441
  };
7493
- })(wysihtml5);(function(wysihtml5) {
7494
- var undef;
7495
-
7496
- wysihtml5.commands.insertOrderedList = {
7497
- exec: function(composer, command) {
7498
- var doc = composer.doc,
7499
- selectedNode = composer.selection.getSelectedNode(),
7500
- list = wysihtml5.dom.getParentElement(selectedNode, { nodeName: "OL" }),
7501
- otherList = wysihtml5.dom.getParentElement(selectedNode, { nodeName: "UL" }),
7502
- tempClassName = "_wysihtml5-temp-" + new Date().getTime(),
7503
- isEmpty,
7504
- tempElement;
7505
-
7506
- if (composer.commands.support(command)) {
7507
- doc.execCommand(command, false, null);
7508
- return;
7509
- }
7510
-
7511
- if (list) {
7512
- // Unwrap list
7513
- // <ol><li>foo</li><li>bar</li></ol>
7514
- // becomes:
7515
- // foo<br>bar<br>
7516
- composer.selection.executeAndRestoreSimple(function() {
7517
- wysihtml5.dom.resolveList(list);
7518
- });
7519
- } else if (otherList) {
7520
- // Turn an unordered list into an ordered list
7521
- // <ul><li>foo</li><li>bar</li></ul>
7522
- // becomes:
7523
- // <ol><li>foo</li><li>bar</li></ol>
7524
- composer.selection.executeAndRestoreSimple(function() {
7525
- wysihtml5.dom.renameElement(otherList, "ol");
7526
- });
7527
- } else {
7528
- // Create list
7529
- composer.commands.exec("formatBlock", "div", tempClassName);
7530
- tempElement = doc.querySelector("." + tempClassName);
7531
- isEmpty = tempElement.innerHTML === "" || tempElement.innerHTML === wysihtml5.INVISIBLE_SPACE;
7532
- composer.selection.executeAndRestoreSimple(function() {
7533
- list = wysihtml5.dom.convertToList(tempElement, "ol");
7534
- });
7535
- if (isEmpty) {
7536
- composer.selection.selectNode(list.querySelector("li"));
7537
- }
7538
- }
7539
- },
7442
+ })(wysihtml5);wysihtml5.commands.insertOrderedList = {
7443
+ exec: function(composer, command) {
7444
+ var doc = composer.doc,
7445
+ selectedNode = composer.selection.getSelectedNode(),
7446
+ list = wysihtml5.dom.getParentElement(selectedNode, { nodeName: "OL" }),
7447
+ otherList = wysihtml5.dom.getParentElement(selectedNode, { nodeName: "UL" }),
7448
+ tempClassName = "_wysihtml5-temp-" + new Date().getTime(),
7449
+ isEmpty,
7450
+ tempElement;
7540
7451
 
7541
- state: function(composer) {
7542
- var selectedNode = composer.selection.getSelectedNode();
7543
- return wysihtml5.dom.getParentElement(selectedNode, { nodeName: "OL" });
7544
- },
7545
-
7546
- value: function() {
7547
- return undef;
7452
+ if (composer.commands.support(command)) {
7453
+ doc.execCommand(command, false, null);
7454
+ return;
7548
7455
  }
7549
- };
7550
- })(wysihtml5);(function(wysihtml5) {
7551
- var undef;
7552
-
7553
- wysihtml5.commands.insertUnorderedList = {
7554
- exec: function(composer, command) {
7555
- var doc = composer.doc,
7556
- selectedNode = composer.selection.getSelectedNode(),
7557
- list = wysihtml5.dom.getParentElement(selectedNode, { nodeName: "UL" }),
7558
- otherList = wysihtml5.dom.getParentElement(selectedNode, { nodeName: "OL" }),
7559
- tempClassName = "_wysihtml5-temp-" + new Date().getTime(),
7560
- isEmpty,
7561
- tempElement;
7562
-
7563
- if (composer.commands.support(command)) {
7564
- doc.execCommand(command, false, null);
7565
- return;
7566
- }
7567
-
7568
- if (list) {
7569
- // Unwrap list
7570
- // <ul><li>foo</li><li>bar</li></ul>
7571
- // becomes:
7572
- // foo<br>bar<br>
7573
- composer.selection.executeAndRestoreSimple(function() {
7574
- wysihtml5.dom.resolveList(list);
7575
- });
7576
- } else if (otherList) {
7577
- // Turn an ordered list into an unordered list
7578
- // <ol><li>foo</li><li>bar</li></ol>
7579
- // becomes:
7580
- // <ul><li>foo</li><li>bar</li></ul>
7581
- composer.selection.executeAndRestoreSimple(function() {
7582
- wysihtml5.dom.renameElement(otherList, "ul");
7583
- });
7584
- } else {
7585
- // Create list
7586
- composer.commands.exec("formatBlock", "div", tempClassName);
7587
- tempElement = doc.querySelector("." + tempClassName);
7588
- isEmpty = tempElement.innerHTML === "" || tempElement.innerHTML === wysihtml5.INVISIBLE_SPACE;
7589
- composer.selection.executeAndRestoreSimple(function() {
7590
- list = wysihtml5.dom.convertToList(tempElement, "ul");
7591
- });
7592
- if (isEmpty) {
7593
- composer.selection.selectNode(list.querySelector("li"));
7594
- }
7456
+
7457
+ if (list) {
7458
+ // Unwrap list
7459
+ // <ol><li>foo</li><li>bar</li></ol>
7460
+ // becomes:
7461
+ // foo<br>bar<br>
7462
+ composer.selection.executeAndRestoreSimple(function() {
7463
+ wysihtml5.dom.resolveList(list);
7464
+ });
7465
+ } else if (otherList) {
7466
+ // Turn an unordered list into an ordered list
7467
+ // <ul><li>foo</li><li>bar</li></ul>
7468
+ // becomes:
7469
+ // <ol><li>foo</li><li>bar</li></ol>
7470
+ composer.selection.executeAndRestoreSimple(function() {
7471
+ wysihtml5.dom.renameElement(otherList, "ol");
7472
+ });
7473
+ } else {
7474
+ // Create list
7475
+ composer.commands.exec("formatBlock", "div", tempClassName);
7476
+ tempElement = doc.querySelector("." + tempClassName);
7477
+ isEmpty = tempElement.innerHTML === "" || tempElement.innerHTML === wysihtml5.INVISIBLE_SPACE;
7478
+ composer.selection.executeAndRestoreSimple(function() {
7479
+ list = wysihtml5.dom.convertToList(tempElement, "ol");
7480
+ });
7481
+ if (isEmpty) {
7482
+ composer.selection.selectNode(list.querySelector("li"));
7595
7483
  }
7596
- },
7484
+ }
7485
+ },
7486
+
7487
+ state: function(composer) {
7488
+ var selectedNode = composer.selection.getSelectedNode();
7489
+ return wysihtml5.dom.getParentElement(selectedNode, { nodeName: "OL" });
7490
+ }
7491
+ };wysihtml5.commands.insertUnorderedList = {
7492
+ exec: function(composer, command) {
7493
+ var doc = composer.doc,
7494
+ selectedNode = composer.selection.getSelectedNode(),
7495
+ list = wysihtml5.dom.getParentElement(selectedNode, { nodeName: "UL" }),
7496
+ otherList = wysihtml5.dom.getParentElement(selectedNode, { nodeName: "OL" }),
7497
+ tempClassName = "_wysihtml5-temp-" + new Date().getTime(),
7498
+ isEmpty,
7499
+ tempElement;
7597
7500
 
7598
- state: function(composer) {
7599
- var selectedNode = composer.selection.getSelectedNode();
7600
- return wysihtml5.dom.getParentElement(selectedNode, { nodeName: "UL" });
7601
- },
7602
-
7603
- value: function() {
7604
- return undef;
7501
+ if (composer.commands.support(command)) {
7502
+ doc.execCommand(command, false, null);
7503
+ return;
7605
7504
  }
7606
- };
7607
- })(wysihtml5);(function(wysihtml5) {
7608
- var undef;
7505
+
7506
+ if (list) {
7507
+ // Unwrap list
7508
+ // <ul><li>foo</li><li>bar</li></ul>
7509
+ // becomes:
7510
+ // foo<br>bar<br>
7511
+ composer.selection.executeAndRestoreSimple(function() {
7512
+ wysihtml5.dom.resolveList(list);
7513
+ });
7514
+ } else if (otherList) {
7515
+ // Turn an ordered list into an unordered list
7516
+ // <ol><li>foo</li><li>bar</li></ol>
7517
+ // becomes:
7518
+ // <ul><li>foo</li><li>bar</li></ul>
7519
+ composer.selection.executeAndRestoreSimple(function() {
7520
+ wysihtml5.dom.renameElement(otherList, "ul");
7521
+ });
7522
+ } else {
7523
+ // Create list
7524
+ composer.commands.exec("formatBlock", "div", tempClassName);
7525
+ tempElement = doc.querySelector("." + tempClassName);
7526
+ isEmpty = tempElement.innerHTML === "" || tempElement.innerHTML === wysihtml5.INVISIBLE_SPACE;
7527
+ composer.selection.executeAndRestoreSimple(function() {
7528
+ list = wysihtml5.dom.convertToList(tempElement, "ul");
7529
+ });
7530
+ if (isEmpty) {
7531
+ composer.selection.selectNode(list.querySelector("li"));
7532
+ }
7533
+ }
7534
+ },
7609
7535
 
7610
- wysihtml5.commands.italic = {
7611
- exec: function(composer, command) {
7612
- return wysihtml5.commands.formatInline.exec(composer, command, "i");
7613
- },
7614
-
7615
- state: function(composer, command, color) {
7616
- // element.ownerDocument.queryCommandState("italic") results:
7617
- // firefox: only <i>
7618
- // chrome: <i>, <em>, <blockquote>, ...
7619
- // ie: <i>, <em>
7620
- // opera: only <i>
7621
- return wysihtml5.commands.formatInline.state(composer, command, "i");
7622
- },
7536
+ state: function(composer) {
7537
+ var selectedNode = composer.selection.getSelectedNode();
7538
+ return wysihtml5.dom.getParentElement(selectedNode, { nodeName: "UL" });
7539
+ }
7540
+ };wysihtml5.commands.italic = {
7541
+ exec: function(composer, command) {
7542
+ return wysihtml5.commands.formatInline.exec(composer, command, "i");
7543
+ },
7623
7544
 
7624
- value: function() {
7625
- return undef;
7626
- }
7627
- };
7628
- })(wysihtml5);(function(wysihtml5) {
7629
- var undef,
7630
- CLASS_NAME = "wysiwyg-text-align-center",
7631
- REG_EXP = /wysiwyg-text-align-[a-z]+/g;
7545
+ state: function(composer, command) {
7546
+ // element.ownerDocument.queryCommandState("italic") results:
7547
+ // firefox: only <i>
7548
+ // chrome: <i>, <em>, <blockquote>, ...
7549
+ // ie: <i>, <em>
7550
+ // opera: only <i>
7551
+ return wysihtml5.commands.formatInline.state(composer, command, "i");
7552
+ }
7553
+ };(function(wysihtml5) {
7554
+ var CLASS_NAME = "wysiwyg-text-align-center",
7555
+ REG_EXP = /wysiwyg-text-align-[0-9a-z]+/g;
7632
7556
 
7633
7557
  wysihtml5.commands.justifyCenter = {
7634
7558
  exec: function(composer, command) {
@@ -7637,16 +7561,11 @@ wysihtml5.Commands = Base.extend(
7637
7561
 
7638
7562
  state: function(composer, command) {
7639
7563
  return wysihtml5.commands.formatBlock.state(composer, "formatBlock", null, CLASS_NAME, REG_EXP);
7640
- },
7641
-
7642
- value: function() {
7643
- return undef;
7644
7564
  }
7645
7565
  };
7646
7566
  })(wysihtml5);(function(wysihtml5) {
7647
- var undef,
7648
- CLASS_NAME = "wysiwyg-text-align-left",
7649
- REG_EXP = /wysiwyg-text-align-[a-z]+/g;
7567
+ var CLASS_NAME = "wysiwyg-text-align-left",
7568
+ REG_EXP = /wysiwyg-text-align-[0-9a-z]+/g;
7650
7569
 
7651
7570
  wysihtml5.commands.justifyLeft = {
7652
7571
  exec: function(composer, command) {
@@ -7655,16 +7574,11 @@ wysihtml5.Commands = Base.extend(
7655
7574
 
7656
7575
  state: function(composer, command) {
7657
7576
  return wysihtml5.commands.formatBlock.state(composer, "formatBlock", null, CLASS_NAME, REG_EXP);
7658
- },
7659
-
7660
- value: function() {
7661
- return undef;
7662
7577
  }
7663
7578
  };
7664
7579
  })(wysihtml5);(function(wysihtml5) {
7665
- var undef,
7666
- CLASS_NAME = "wysiwyg-text-align-right",
7667
- REG_EXP = /wysiwyg-text-align-[a-z]+/g;
7580
+ var CLASS_NAME = "wysiwyg-text-align-right",
7581
+ REG_EXP = /wysiwyg-text-align-[0-9a-z]+/g;
7668
7582
 
7669
7583
  wysihtml5.commands.justifyRight = {
7670
7584
  exec: function(composer, command) {
@@ -7673,28 +7587,47 @@ wysihtml5.Commands = Base.extend(
7673
7587
 
7674
7588
  state: function(composer, command) {
7675
7589
  return wysihtml5.commands.formatBlock.state(composer, "formatBlock", null, CLASS_NAME, REG_EXP);
7676
- },
7677
-
7678
- value: function() {
7679
- return undef;
7680
7590
  }
7681
7591
  };
7682
7592
  })(wysihtml5);(function(wysihtml5) {
7683
- var undef;
7684
- wysihtml5.commands.underline = {
7593
+ var CLASS_NAME = "wysiwyg-text-align-justify",
7594
+ REG_EXP = /wysiwyg-text-align-[0-9a-z]+/g;
7595
+
7596
+ wysihtml5.commands.justifyFull = {
7685
7597
  exec: function(composer, command) {
7686
- return wysihtml5.commands.formatInline.exec(composer, command, "u");
7598
+ return wysihtml5.commands.formatBlock.exec(composer, "formatBlock", null, CLASS_NAME, REG_EXP);
7687
7599
  },
7688
7600
 
7689
7601
  state: function(composer, command) {
7690
- return wysihtml5.commands.formatInline.state(composer, command, "u");
7691
- },
7692
-
7693
- value: function() {
7694
- return undef;
7602
+ return wysihtml5.commands.formatBlock.state(composer, "formatBlock", null, CLASS_NAME, REG_EXP);
7695
7603
  }
7696
7604
  };
7697
- })(wysihtml5);/**
7605
+ })(wysihtml5);
7606
+ wysihtml5.commands.redo = {
7607
+ exec: function(composer) {
7608
+ return composer.undoManager.redo();
7609
+ },
7610
+
7611
+ state: function(composer) {
7612
+ return false;
7613
+ }
7614
+ };wysihtml5.commands.underline = {
7615
+ exec: function(composer, command) {
7616
+ return wysihtml5.commands.formatInline.exec(composer, command, "u");
7617
+ },
7618
+
7619
+ state: function(composer, command) {
7620
+ return wysihtml5.commands.formatInline.state(composer, command, "u");
7621
+ }
7622
+ };wysihtml5.commands.undo = {
7623
+ exec: function(composer) {
7624
+ return composer.undoManager.undo();
7625
+ },
7626
+
7627
+ state: function(composer) {
7628
+ return false;
7629
+ }
7630
+ };/**
7698
7631
  * Undo Manager for wysihtml5
7699
7632
  * slightly inspired by http://rniwa.com/editing/undomanager.html#the-undomanager-interface
7700
7633
  */
@@ -7703,7 +7636,9 @@ wysihtml5.Commands = Base.extend(
7703
7636
  Y_KEY = 89,
7704
7637
  BACKSPACE_KEY = 8,
7705
7638
  DELETE_KEY = 46,
7706
- MAX_HISTORY_ENTRIES = 40,
7639
+ MAX_HISTORY_ENTRIES = 25,
7640
+ DATA_ATTR_NODE = "data-wysihtml5-selection-node",
7641
+ DATA_ATTR_OFFSET = "data-wysihtml5-selection-offset",
7707
7642
  UNDO_HTML = '<span id="_wysihtml5-undo" class="_wysihtml5-temp">' + wysihtml5.INVISIBLE_SPACE + '</span>',
7708
7643
  REDO_HTML = '<span id="_wysihtml5-redo" class="_wysihtml5-temp">' + wysihtml5.INVISIBLE_SPACE + '</span>',
7709
7644
  dom = wysihtml5.dom;
@@ -7721,13 +7656,14 @@ wysihtml5.Commands = Base.extend(
7721
7656
  this.editor = editor;
7722
7657
  this.composer = editor.composer;
7723
7658
  this.element = this.composer.element;
7724
- this.history = [this.composer.getValue()];
7725
- this.position = 1;
7726
7659
 
7727
- // Undo manager currently only supported in browsers who have the insertHTML command (not IE)
7728
- if (this.composer.commands.support("insertHTML")) {
7729
- this._observe();
7730
- }
7660
+ this.position = 0;
7661
+ this.historyStr = [];
7662
+ this.historyDom = [];
7663
+
7664
+ this.transact();
7665
+
7666
+ this._observe();
7731
7667
  },
7732
7668
 
7733
7669
  _observe: function() {
@@ -7824,46 +7760,124 @@ wysihtml5.Commands = Base.extend(
7824
7760
  },
7825
7761
 
7826
7762
  transact: function() {
7827
- var previousHtml = this.history[this.position - 1],
7828
- currentHtml = this.composer.getValue();
7763
+ var previousHtml = this.historyStr[this.position - 1],
7764
+ currentHtml = this.composer.getValue();
7829
7765
 
7830
- if (currentHtml == previousHtml) {
7766
+ if (currentHtml === previousHtml) {
7831
7767
  return;
7832
7768
  }
7833
7769
 
7834
- var length = this.history.length = this.position;
7770
+ var length = this.historyStr.length = this.historyDom.length = this.position;
7835
7771
  if (length > MAX_HISTORY_ENTRIES) {
7836
- this.history.shift();
7772
+ this.historyStr.shift();
7773
+ this.historyDom.shift();
7837
7774
  this.position--;
7838
7775
  }
7839
7776
 
7840
7777
  this.position++;
7841
- this.history.push(currentHtml);
7778
+
7779
+ var range = this.composer.selection.getRange(),
7780
+ node = range.startContainer || this.element,
7781
+ offset = range.startOffset || 0,
7782
+ element,
7783
+ position;
7784
+
7785
+ if (node.nodeType === wysihtml5.ELEMENT_NODE) {
7786
+ element = node;
7787
+ } else {
7788
+ element = node.parentNode;
7789
+ position = this.getChildNodeIndex(element, node);
7790
+ }
7791
+
7792
+ element.setAttribute(DATA_ATTR_OFFSET, offset);
7793
+ if (typeof(position) !== "undefined") {
7794
+ element.setAttribute(DATA_ATTR_NODE, position);
7795
+ }
7796
+
7797
+ var clone = this.element.cloneNode(!!currentHtml);
7798
+ this.historyDom.push(clone);
7799
+ this.historyStr.push(currentHtml);
7800
+
7801
+ element.removeAttribute(DATA_ATTR_OFFSET);
7802
+ element.removeAttribute(DATA_ATTR_NODE);
7842
7803
  },
7843
7804
 
7844
7805
  undo: function() {
7845
7806
  this.transact();
7846
7807
 
7847
- if (this.position <= 1) {
7808
+ if (!this.undoPossible()) {
7848
7809
  return;
7849
7810
  }
7850
7811
 
7851
- this.set(this.history[--this.position - 1]);
7812
+ this.set(this.historyDom[--this.position - 1]);
7852
7813
  this.editor.fire("undo:composer");
7853
7814
  },
7854
7815
 
7855
7816
  redo: function() {
7856
- if (this.position >= this.history.length) {
7817
+ if (!this.redoPossible()) {
7857
7818
  return;
7858
7819
  }
7859
7820
 
7860
- this.set(this.history[++this.position - 1]);
7821
+ this.set(this.historyDom[++this.position - 1]);
7861
7822
  this.editor.fire("redo:composer");
7862
7823
  },
7863
7824
 
7864
- set: function(html) {
7865
- this.composer.setValue(html);
7866
- this.editor.focus(true);
7825
+ undoPossible: function() {
7826
+ return this.position > 1;
7827
+ },
7828
+
7829
+ redoPossible: function() {
7830
+ return this.position < this.historyStr.length;
7831
+ },
7832
+
7833
+ set: function(historyEntry) {
7834
+ this.element.innerHTML = "";
7835
+
7836
+ var i = 0,
7837
+ childNodes = historyEntry.childNodes,
7838
+ length = historyEntry.childNodes.length;
7839
+
7840
+ for (; i<length; i++) {
7841
+ this.element.appendChild(childNodes[i].cloneNode(true));
7842
+ }
7843
+
7844
+ // Restore selection
7845
+ var offset,
7846
+ node,
7847
+ position;
7848
+
7849
+ if (historyEntry.hasAttribute(DATA_ATTR_OFFSET)) {
7850
+ offset = historyEntry.getAttribute(DATA_ATTR_OFFSET);
7851
+ position = historyEntry.getAttribute(DATA_ATTR_NODE);
7852
+ node = this.element;
7853
+ } else {
7854
+ node = this.element.querySelector("[" + DATA_ATTR_OFFSET + "]") || this.element;
7855
+ offset = node.getAttribute(DATA_ATTR_OFFSET);
7856
+ position = node.getAttribute(DATA_ATTR_NODE);
7857
+ node.removeAttribute(DATA_ATTR_OFFSET);
7858
+ node.removeAttribute(DATA_ATTR_NODE);
7859
+ }
7860
+
7861
+ if (position !== null) {
7862
+ node = this.getChildNodeByIndex(node, +position);
7863
+ }
7864
+
7865
+ this.composer.selection.set(node, offset);
7866
+ },
7867
+
7868
+ getChildNodeIndex: function(parent, child) {
7869
+ var i = 0,
7870
+ childNodes = parent.childNodes,
7871
+ length = childNodes.length;
7872
+ for (; i<length; i++) {
7873
+ if (childNodes[i] === child) {
7874
+ return i;
7875
+ }
7876
+ }
7877
+ },
7878
+
7879
+ getChildNodeByIndex: function(parent, index) {
7880
+ return parent.childNodes[index];
7867
7881
  }
7868
7882
  });
7869
7883
  })(wysihtml5);
@@ -7959,7 +7973,12 @@ wysihtml5.views.View = Base.extend(
7959
7973
  if (parse) {
7960
7974
  html = this.parent.parse(html);
7961
7975
  }
7962
- this.element.innerHTML = html;
7976
+
7977
+ try {
7978
+ this.element.innerHTML = html;
7979
+ } catch (e) {
7980
+ this.element.innerText = html;
7981
+ }
7963
7982
  },
7964
7983
 
7965
7984
  show: function() {
@@ -8013,7 +8032,7 @@ wysihtml5.views.View = Base.extend(
8013
8032
  },
8014
8033
 
8015
8034
  hasPlaceholderSet: function() {
8016
- return this.getTextContent() == this.textarea.element.getAttribute("placeholder");
8035
+ return this.getTextContent() == this.textarea.element.getAttribute("placeholder") && this.placeholderSet;
8017
8036
  },
8018
8037
 
8019
8038
  isEmpty: function() {
@@ -8034,17 +8053,18 @@ wysihtml5.views.View = Base.extend(
8034
8053
  stylesheets: this.config.stylesheets
8035
8054
  });
8036
8055
  this.iframe = this.sandbox.getIframe();
8037
-
8038
- // Create hidden field which tells the server after submit, that the user used an wysiwyg editor
8039
- var hiddenField = document.createElement("input");
8040
- hiddenField.type = "hidden";
8041
- hiddenField.name = "_wysihtml5_mode";
8042
- hiddenField.value = 1;
8043
-
8044
- // Store reference to current wysihtml5 instance on the textarea element
8056
+
8045
8057
  var textareaElement = this.textarea.element;
8046
8058
  dom.insert(this.iframe).after(textareaElement);
8047
- dom.insert(hiddenField).after(textareaElement);
8059
+
8060
+ // Create hidden field which tells the server after submit, that the user used an wysiwyg editor
8061
+ if (textareaElement.form) {
8062
+ var hiddenField = document.createElement("input");
8063
+ hiddenField.type = "hidden";
8064
+ hiddenField.name = "_wysihtml5_mode";
8065
+ hiddenField.value = 1;
8066
+ dom.insert(hiddenField).after(textareaElement);
8067
+ }
8048
8068
  },
8049
8069
 
8050
8070
  _create: function() {
@@ -8098,7 +8118,7 @@ wysihtml5.views.View = Base.extend(
8098
8118
 
8099
8119
  // Simulate html5 autofocus on contentEditable element
8100
8120
  if (this.textarea.element.hasAttribute("autofocus") || document.querySelector(":focus") == this.textarea.element) {
8101
- setTimeout(function() { that.focus(); }, 100);
8121
+ setTimeout(function() { that.focus(true); }, 100);
8102
8122
  }
8103
8123
 
8104
8124
  wysihtml5.quirks.insertLineBreakOnReturn(this);
@@ -8144,6 +8164,10 @@ wysihtml5.views.View = Base.extend(
8144
8164
  dom.autoLink(endContainer.parentNode);
8145
8165
  });
8146
8166
  });
8167
+
8168
+ dom.observe(this.element, "blur", function() {
8169
+ dom.autoLink(that.element);
8170
+ });
8147
8171
  }
8148
8172
 
8149
8173
  // Assuming we have the following:
@@ -8195,40 +8219,43 @@ wysihtml5.views.View = Base.extend(
8195
8219
  _initObjectResizing: function() {
8196
8220
  var properties = ["width", "height"],
8197
8221
  propertiesLength = properties.length,
8198
- element = this.element;
8199
-
8200
- this.commands.exec("enableObjectResizing", this.config.allowObjectResizing);
8201
-
8202
- if (this.config.allowObjectResizing) {
8203
- // IE sets inline styles after resizing objects
8204
- // The following lines make sure that the width/height css properties
8205
- // are copied over to the width/height attributes
8206
- if (browser.supportsEvent("resizeend")) {
8207
- dom.observe(element, "resizeend", function(event) {
8222
+ element = this.element,
8223
+ adoptStyles = function(event) {
8208
8224
  var target = event.target || event.srcElement,
8209
8225
  style = target.style,
8210
8226
  i = 0,
8211
8227
  property;
8212
- for(; i<propertiesLength; i++) {
8228
+
8229
+ if (target.nodeName !== "IMG") {
8230
+ return;
8231
+ }
8232
+
8233
+ for (; i<propertiesLength; i++) {
8213
8234
  property = properties[i];
8214
8235
  if (style[property]) {
8215
8236
  target.setAttribute(property, parseInt(style[property], 10));
8216
8237
  style[property] = "";
8217
8238
  }
8218
8239
  }
8240
+
8219
8241
  // After resizing IE sometimes forgets to remove the old resize handles
8220
8242
  wysihtml5.quirks.redraw(element);
8221
- });
8222
- }
8243
+ };
8244
+
8245
+ this.commands.exec("enableObjectResizing", true);
8246
+
8247
+ // IE sets inline styles after resizing objects
8248
+ // The following lines make sure that the width/height css properties
8249
+ // are copied over to the width/height attributes
8250
+ if (browser.supportsEvent("resizeend")) {
8251
+ dom.observe(element, "resizeend", adoptStyles);
8223
8252
  } else {
8224
- if (browser.supportsEvent("resizestart")) {
8225
- dom.observe(element, "resizestart", function(event) { event.preventDefault(); });
8226
- }
8253
+ dom.observe(element, "DOMAttrModified", adoptStyles);
8227
8254
  }
8228
8255
  },
8229
8256
 
8230
8257
  _initUndoManager: function() {
8231
- new wysihtml5.UndoManager(this.parent);
8258
+ this.undoManager = new wysihtml5.UndoManager(this.parent);
8232
8259
  }
8233
8260
  });
8234
8261
  })(wysihtml5);(function(wysihtml5) {
@@ -8447,8 +8474,7 @@ wysihtml5.views.View = Base.extend(
8447
8474
  iframe = this.sandbox.getIframe(),
8448
8475
  element = this.element,
8449
8476
  focusBlurElement = browser.supportsEventsInIframeCorrectly() ? element : this.sandbox.getWindow(),
8450
- // Firefox < 3.5 doesn't support the drop event, instead it supports a so called "dragdrop" event which behaves almost the same
8451
- pasteEvents = browser.supportsEvent("drop") ? ["drop", "paste"] : ["dragdrop", "paste"];
8477
+ pasteEvents = ["drop", "paste"];
8452
8478
 
8453
8479
  // --------- destroy:composer event ---------
8454
8480
  dom.observe(iframe, "DOMNodeRemoved", function() {
@@ -8481,7 +8507,7 @@ wysihtml5.views.View = Base.extend(
8481
8507
  that.parent.fire("blur").fire("blur:composer");
8482
8508
  });
8483
8509
 
8484
- if (wysihtml5.browser.isIos()) {
8510
+ if (browser.isIos()) {
8485
8511
  // When on iPad/iPhone/IPod after clicking outside of editor, the editor loses focus
8486
8512
  // but the UI still acts as if the editor has focus (blinking caret and onscreen keyboard visible)
8487
8513
  // We prevent that by focusing a temporary input element which immediately loses focus
@@ -8506,30 +8532,10 @@ wysihtml5.views.View = Base.extend(
8506
8532
  that.parent.fire("unset_placeholder");
8507
8533
  });
8508
8534
 
8509
- if (browser.firesOnDropOnlyWhenOnDragOverIsCancelled()) {
8510
- dom.observe(element, ["dragover", "dragenter"], function(event) {
8511
- event.preventDefault();
8512
- });
8513
- }
8514
-
8515
8535
  dom.observe(element, pasteEvents, function(event) {
8516
- var dataTransfer = event.dataTransfer,
8517
- data;
8518
-
8519
- if (dataTransfer && browser.supportsDataTransfer()) {
8520
- data = dataTransfer.getData("text/html") || dataTransfer.getData("text/plain");
8521
- }
8522
- if (data) {
8523
- element.focus();
8524
- that.commands.exec("insertHTML", data);
8536
+ setTimeout(function() {
8525
8537
  that.parent.fire("paste").fire("paste:composer");
8526
- event.stopPropagation();
8527
- event.preventDefault();
8528
- } else {
8529
- setTimeout(function() {
8530
- that.parent.fire("paste").fire("paste:composer");
8531
- }, 0);
8532
- }
8538
+ }, 0);
8533
8539
  });
8534
8540
 
8535
8541
  // --------- neword event ---------
@@ -8555,6 +8561,34 @@ wysihtml5.views.View = Base.extend(
8555
8561
  });
8556
8562
  }
8557
8563
 
8564
+ if (browser.hasHistoryIssue() && browser.supportsSelectionModify()) {
8565
+ dom.observe(element, "keydown", function(event) {
8566
+ if (!event.metaKey && !event.ctrlKey) {
8567
+ return;
8568
+ }
8569
+
8570
+ var keyCode = event.keyCode,
8571
+ win = element.ownerDocument.defaultView,
8572
+ selection = win.getSelection();
8573
+
8574
+ if (keyCode === 37 || keyCode === 39) {
8575
+ if (keyCode === 37) {
8576
+ selection.modify("extend", "left", "lineboundary");
8577
+ if (!event.shiftKey) {
8578
+ selection.collapseToStart();
8579
+ }
8580
+ }
8581
+ if (keyCode === 39) {
8582
+ selection.modify("extend", "right", "lineboundary");
8583
+ if (!event.shiftKey) {
8584
+ selection.collapseToEnd();
8585
+ }
8586
+ }
8587
+ event.preventDefault();
8588
+ }
8589
+ });
8590
+ }
8591
+
8558
8592
  // --------- Shortcut logic ---------
8559
8593
  dom.observe(element, "keydown", function(event) {
8560
8594
  var keyCode = event.keyCode,
@@ -8930,6 +8964,10 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
8930
8964
  * Show the dialog element
8931
8965
  */
8932
8966
  show: function(elementToChange) {
8967
+ if (dom.hasClass(this.link, CLASS_NAME_OPENED)) {
8968
+ return;
8969
+ }
8970
+
8933
8971
  var that = this,
8934
8972
  firstField = this.container.querySelector(SELECTOR_FORM_ELEMENTS);
8935
8973
  this.elementToChange = elementToChange;
@@ -9014,7 +9052,11 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9014
9052
  link.style.display = "none";
9015
9053
  return;
9016
9054
  }
9017
-
9055
+ var lang = parent.editor.textarea.element.getAttribute("lang");
9056
+ if (lang) {
9057
+ inputAttributes.lang = lang;
9058
+ }
9059
+
9018
9060
  var wrapper = document.createElement("div");
9019
9061
 
9020
9062
  wysihtml5.lang.object(wrapperStyles).merge({
@@ -9026,7 +9068,7 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9026
9068
  dom.insert(wrapper).into(link);
9027
9069
 
9028
9070
  dom.setStyles(inputStyles).on(input);
9029
- dom.setAttributes(inputAttributes).on(input)
9071
+ dom.setAttributes(inputAttributes).on(input);
9030
9072
 
9031
9073
  dom.setStyles(wrapperStyles).on(wrapper);
9032
9074
  dom.setStyles(linkStyles).on(link);
@@ -9208,8 +9250,8 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9208
9250
  }).on(links[i]);
9209
9251
  }
9210
9252
 
9211
- // Needed for opera
9212
- dom.delegate(container, "[data-wysihtml5-command]", "mousedown", function(event) { event.preventDefault(); });
9253
+ // Needed for opera and chrome
9254
+ dom.delegate(container, "[data-wysihtml5-command], [data-wysihtml5-action]", "mousedown", function(event) { event.preventDefault(); });
9213
9255
 
9214
9256
  dom.delegate(container, "[data-wysihtml5-command]", "click", function(event) {
9215
9257
  var link = this,
@@ -9394,8 +9436,6 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9394
9436
  stylesheets: [],
9395
9437
  // Placeholder text to use, defaults to the placeholder attribute on the textarea element
9396
9438
  placeholderText: undef,
9397
- // Whether the composer should allow the user to manually resize images, tables etc.
9398
- allowObjectResizing: true,
9399
9439
  // Whether the rich text editor should be rendered on touch devices (wysihtml5 >= 0.3.0 comes with basic support for iOS 5)
9400
9440
  supportTouchDevices: true
9401
9441
  };
@@ -9452,9 +9492,12 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9452
9492
  },
9453
9493
 
9454
9494
  setValue: function(html, parse) {
9495
+ this.fire("unset_placeholder");
9496
+
9455
9497
  if (!html) {
9456
9498
  return this.clear();
9457
9499
  }
9500
+
9458
9501
  this.currentView.setValue(html, parse);
9459
9502
  return this;
9460
9503
  },
@@ -9518,4 +9561,4 @@ wysihtml5.views.Textarea = wysihtml5.views.View.extend(
9518
9561
  });
9519
9562
  }
9520
9563
  });
9521
- })(wysihtml5);
9564
+ })(wysihtml5);
@@ -1,3 +1,3 @@
1
1
  module Bootsy
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bootsy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-26 00:00:00.000000000 Z
12
+ date: 2012-08-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mini_magick
@@ -218,7 +218,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
218
218
  version: '0'
219
219
  segments:
220
220
  - 0
221
- hash: -1387219841281359177
221
+ hash: 2854455113211705351
222
222
  required_rubygems_version: !ruby/object:Gem::Requirement
223
223
  none: false
224
224
  requirements:
@@ -227,7 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
227
  version: '0'
228
228
  segments:
229
229
  - 0
230
- hash: -1387219841281359177
230
+ hash: 2854455113211705351
231
231
  requirements: []
232
232
  rubyforge_project:
233
233
  rubygems_version: 1.8.24