bootsy 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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