comfortable_mexican_sofa 1.12.7 → 1.12.8

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/app/assets/javascripts/comfy/admin/cms/application.js.coffee +1 -1
  4. data/app/assets/javascripts/comfy/admin/cms/base.js.coffee +4 -2
  5. data/app/assets/javascripts/comfy/admin/cms/lib/redactor.js +309 -218
  6. data/app/assets/javascripts/comfy/admin/cms/lib/redactor/definedlinks.js +53 -0
  7. data/app/controllers/comfy/admin/cms/pages_controller.rb +21 -0
  8. data/app/helpers/comfy/cms_helper.rb +1 -1
  9. data/app/models/comfy/cms/site.rb +1 -1
  10. data/app/views/comfy/admin/cms/pages/_form.html.haml +2 -4
  11. data/app/views/layouts/comfy/admin/cms/_head.html.haml +1 -0
  12. data/config/environments/test.rb +4 -0
  13. data/config/locales/cs.yml +28 -23
  14. data/config/locales/da.yml +36 -31
  15. data/config/locales/de.yml +32 -27
  16. data/config/locales/en.yml +10 -7
  17. data/config/locales/es.yml +21 -16
  18. data/config/locales/fr.yml +28 -23
  19. data/config/locales/it.yml +12 -7
  20. data/config/locales/ja.yml +28 -23
  21. data/config/locales/nb.yml +12 -7
  22. data/config/locales/nl.yml +21 -16
  23. data/config/locales/pl.yml +28 -23
  24. data/config/locales/pt-BR.yml +27 -22
  25. data/config/locales/ru.yml +19 -16
  26. data/config/locales/sv.yml +28 -23
  27. data/config/locales/uk.yml +10 -7
  28. data/config/locales/zh-CN.yml +22 -17
  29. data/config/locales/zh-TW.yml +22 -17
  30. data/lib/comfortable_mexican_sofa/render_methods.rb +1 -1
  31. data/lib/comfortable_mexican_sofa/version.rb +1 -1
  32. data/test/controllers/comfy/admin/cms/pages_controller_test.rb +59 -46
  33. data/test/gemfiles/Gemfile.rails.4.0 +2 -2
  34. data/test/gemfiles/Gemfile.rails.4.1 +1 -1
  35. data/test/gemfiles/Gemfile.rails.4.2 +1 -1
  36. data/test/gemfiles/Gemfile.rails.master +1 -1
  37. data/test/integration/i18n_test.rb +37 -0
  38. data/test/integration/js_variables_test.rb +1 -0
  39. data/test/lib/mirrors_test.rb +35 -35
  40. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c52b1a77e4bfaf2d30972cfab68c402313e1b890
4
- data.tar.gz: 75b8d1e27e366945246919e3ede5fe5298cd7bb4
3
+ metadata.gz: f933c8018264bf9d49d604db850abedcde229e03
4
+ data.tar.gz: 28b5de9bdd3d6db7accafdba10d4a1408ef6bb90
5
5
  SHA512:
6
- metadata.gz: 660c8208447330360005e76d8cdabd153244ca26df3f39e7072991838e67251efda5f6c203af3bc5cda973fe57d432c9d180ae16b5e55defe39731c3ca989569
7
- data.tar.gz: 43cf5358ca68f84839f7da76e917f5b8d0e7ab10603fdb3bd440cd6d19359998b84e7c6ebc2e11f7e1438033d92e2e11806a1cd79d82cb2adb77d9d18bca5890
6
+ metadata.gz: b421cc43496c817bc03c01729b3f45147665420343ab92cfcf82166e66e8ebf86976e87f783e4de58797896a2eda17d6dc4c86e95fed30917c3e76e5ed8c1baf
7
+ data.tar.gz: 2d31bfe29ac5c3bc8e61ef0794e9c3121440dce69ee5a1b0f71ad1c125889471479fed9057cbd5dbf4f51ebf110ac9d1667494a921f8ebf7b71f90c547b738d2
@@ -9,7 +9,7 @@ rvm:
9
9
  - 1.9.3
10
10
  - 2.0.0
11
11
  - 2.1.5
12
- - 2.2.0
12
+ - 2.2.1
13
13
  gemfile:
14
14
  - test/gemfiles/Gemfile.rails.4.0
15
15
  - test/gemfiles/Gemfile.rails.4.1
@@ -9,12 +9,12 @@
9
9
  #= require codemirror/modes/xml
10
10
  #= require codemirror/addons/edit/closetag
11
11
  #= require bootstrap-sprockets
12
- #= require bootstrap
13
12
  #= require comfy/admin/cms/lib/bootstrap-datetimepicker
14
13
  #= require comfy/admin/cms/lib/diff
15
14
  #= require comfy/admin/cms/lib/redactor
16
15
  #= require comfy/admin/cms/lib/redactor/filemanager
17
16
  #= require comfy/admin/cms/lib/redactor/imagemanager
17
+ #= require comfy/admin/cms/lib/redactor/definedlinks
18
18
  #= require comfy/admin/cms/lib/redactor/table
19
19
  #= require comfy/admin/cms/lib/redactor/video
20
20
  #= require_directory ./lib/redactor/i18n/
@@ -51,10 +51,12 @@ window.CMS.wysiwyg = ->
51
51
  imageManagerJson: "#{CMS.file_upload_path}?source=redactor&type=image"
52
52
  fileUpload: "#{CMS.file_upload_path}?source=redactor&type=file&#{params}"
53
53
  fileManagerJson: "#{CMS.file_upload_path}?source=redactor&type=file"
54
+ definedLinks: "#{CMS.pages_path}?source=redactor"
54
55
  buttonSource: true
55
- formattingTags: ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']
56
- plugins: ['imagemanager', 'filemanager', 'table', 'video']
56
+ formatting: ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']
57
+ plugins: ['imagemanager', 'filemanager', 'table', 'video', 'definedlinks']
57
58
  lang: CMS.locale
59
+ convertDivs: false
58
60
 
59
61
 
60
62
  window.CMS.codemirror = ->
@@ -1,6 +1,6 @@
1
1
  /*
2
- Redactor v10.0.6
3
- Updated: January 7, 2015
2
+ Redactor v10.0.7
3
+ Updated: January 31, 2015
4
4
 
5
5
  http://imperavi.com/redactor/
6
6
 
@@ -94,7 +94,7 @@
94
94
 
95
95
  // Functionality
96
96
  $.Redactor = Redactor;
97
- $.Redactor.VERSION = '10.0.6';
97
+ $.Redactor.VERSION = '10.0.7';
98
98
  $.Redactor.modules = ['alignment', 'autosave', 'block', 'buffer', 'build', 'button',
99
99
  'caret', 'clean', 'code', 'core', 'dropdown', 'file', 'focus',
100
100
  'image', 'indent', 'inline', 'insert', 'keydown', 'keyup',
@@ -147,14 +147,14 @@
147
147
  imageFloatMargin: '10px',
148
148
  imageResizable: true,
149
149
 
150
- imageUpload: false,
150
+ imageUpload: null,
151
151
  imageUploadParam: 'file',
152
152
 
153
153
  uploadImageField: false,
154
154
 
155
155
  dragImageUpload: true,
156
156
 
157
- fileUpload: false,
157
+ fileUpload: null,
158
158
  fileUploadParam: 'file',
159
159
 
160
160
  dragFileUpload: true,
@@ -179,7 +179,7 @@
179
179
  toolbarExternal: false, // ID selector
180
180
  toolbarOverflow: false,
181
181
 
182
- buttonSource: false,
182
+ source: true,
183
183
  buttons: ['html', 'formatting', 'bold', 'italic', 'deleted', 'unorderedlist', 'orderedlist',
184
184
  'outdent', 'indent', 'image', 'file', 'link', 'alignment', 'horizontalrule'], // + 'underline'
185
185
 
@@ -447,50 +447,69 @@
447
447
  },
448
448
  set: function(type)
449
449
  {
450
+ // focus
450
451
  if (!this.utils.browser('msie')) this.$editor.focus();
451
452
 
452
453
  this.buffer.set();
453
454
  this.selection.save();
454
455
 
456
+ // get blocks
455
457
  this.alignment.blocks = this.selection.getBlocks();
456
- if (this.opts.linebreaks && this.alignment.blocks[0] === false)
458
+ this.alignment.type = type;
459
+
460
+ // set alignment
461
+ if (this.alignment.isLinebreaksOrNoBlocks())
457
462
  {
458
- this.alignment.setText(type);
463
+ this.alignment.setText();
459
464
  }
460
465
  else
461
466
  {
462
- this.alignment.setBlocks(type);
467
+ this.alignment.setBlocks();
463
468
  }
464
469
 
470
+ // sync
465
471
  this.selection.restore();
466
472
  this.code.sync();
467
473
  },
468
- setText: function(type)
474
+ setText: function()
469
475
  {
470
476
  var wrapper = this.selection.wrap('div');
471
- $(wrapper).attr('data-tagblock', 'redactor');
472
- $(wrapper).css('text-align', type);
477
+ $(wrapper).attr('data-tagblock', 'redactor').css('text-align', this.alignment.type);
473
478
  },
474
- setBlocks: function(type)
479
+ setBlocks: function()
475
480
  {
476
481
  $.each(this.alignment.blocks, $.proxy(function(i, el)
477
482
  {
478
483
  var $el = this.utils.getAlignmentElement(el);
479
-
480
484
  if (!$el) return;
481
485
 
482
- if (type === '' && typeof($el.data('tagblock')) !== 'undefined')
486
+ if (this.alignment.isNeedReplaceElement($el))
483
487
  {
484
- $el.replaceWith($el.html());
488
+ this.alignment.replaceElement($el);
485
489
  }
486
490
  else
487
491
  {
488
- $el.css('text-align', type);
489
- this.utils.removeEmptyAttr($el, 'style');
492
+ this.alignment.alignElement($el);
490
493
  }
491
494
 
492
-
493
495
  }, this));
496
+ },
497
+ isLinebreaksOrNoBlocks: function()
498
+ {
499
+ return (this.opts.linebreaks && this.alignment.blocks[0] === false);
500
+ },
501
+ isNeedReplaceElement: function($el)
502
+ {
503
+ return (this.alignment.type === '' && typeof($el.data('tagblock')) !== 'undefined');
504
+ },
505
+ replaceElement: function($el)
506
+ {
507
+ $el.replaceWith($el.html());
508
+ },
509
+ alignElement: function($el)
510
+ {
511
+ $el.css('text-align', this.alignment.type);
512
+ this.utils.removeEmptyAttr($el, 'style');
494
513
  }
495
514
  };
496
515
  },
@@ -504,35 +523,36 @@
504
523
  this.autosave.html = false;
505
524
  this.autosave.name = (this.opts.autosaveName) ? this.opts.autosaveName : this.$textarea.attr('name');
506
525
 
507
- if (!this.opts.autosaveOnChange)
508
- {
509
- this.autosaveInterval = setInterval($.proxy(this.autosave.load, this), this.opts.autosaveInterval * 1000);
510
- }
526
+ if (this.opts.autosaveOnChange) return;
527
+ this.autosaveInterval = setInterval(this.autosave.load, this.opts.autosaveInterval * 1000);
511
528
  },
512
529
  onChange: function()
513
530
  {
514
531
  if (!this.opts.autosaveOnChange) return;
515
-
516
532
  this.autosave.load();
517
533
  },
518
534
  load: function()
519
535
  {
520
- var html = this.code.get();
521
- if (this.autosave.html === html) return;
522
- if (this.utils.isEmpty(html)) return;
536
+ this.autosave.source = this.code.get();
523
537
 
524
- $.ajax({
538
+ if (this.autosave.html === this.autosave.source) return;
539
+ if (this.utils.isEmpty(this.autosave.source)) return;
540
+
541
+ // data
542
+ var data = {};
543
+ data['name'] = this.autosave.name;
544
+ data[this.autosave.name] = escape(encodeURIComponent(this.autosave.source));
545
+
546
+ // ajax
547
+ var jsxhr = $.ajax({
525
548
  url: this.opts.autosave,
526
549
  type: 'post',
527
- data: 'name=' + this.autosave.name + '&' + this.autosave.name + '=' + escape(encodeURIComponent(html)),
528
- success: $.proxy(function(data)
529
- {
530
- this.autosave.success(data, html);
531
-
532
- }, this)
550
+ data: data
533
551
  });
552
+
553
+ jsxhr.done(this.autosave.success);
534
554
  },
535
- success: function(data, html)
555
+ success: function(data)
536
556
  {
537
557
  var json;
538
558
  try
@@ -548,7 +568,7 @@
548
568
  var callbackName = (typeof json.error == 'undefined') ? 'autosave' : 'autosaveError';
549
569
 
550
570
  this.core.setCallback(callbackName, this.autosave.name, json);
551
- this.autosave.html = html;
571
+ this.autosave.html = this.autosave.source;
552
572
  },
553
573
  disable: function()
554
574
  {
@@ -741,6 +761,7 @@
741
761
  }
742
762
  else
743
763
  {
764
+
744
765
  if (this.opts.linebreaks || tag != 'p')
745
766
  {
746
767
  if (tag == 'blockquote')
@@ -773,6 +794,7 @@
773
794
 
774
795
  }
775
796
 
797
+
776
798
  this.block.formatWrap(tag);
777
799
  }
778
800
  else
@@ -782,7 +804,7 @@
782
804
  if (this.block.type == 'class')
783
805
  {
784
806
  toggleType = 'toggle';
785
- classSize = $(this.block.blocks).filter('.' + this.block.value).size();
807
+ classSize = $(this.block.blocks).filter('.' + this.block.value).length;
786
808
 
787
809
  if (this.block.blocksSize == classSize) toggleType = 'toggle';
788
810
  else if (this.block.blocksSize > classSize) toggleType = 'set';
@@ -964,10 +986,10 @@
964
986
  },
965
987
  formatTableWrapping: function($formatted)
966
988
  {
967
- if ($formatted.closest('table').size() === 0) return;
989
+ if ($formatted.closest('table').length === 0) return;
968
990
 
969
- if ($formatted.closest('tr').size() === 0) $formatted.wrap('<tr>');
970
- if ($formatted.closest('td').size() === 0 && $formatted.closest('th').size() === 0)
991
+ if ($formatted.closest('tr').length === 0) $formatted.wrap('<tr>');
992
+ if ($formatted.closest('td').length === 0 && $formatted.closest('th').length === 0)
971
993
  {
972
994
  $formatted.wrap('<td>');
973
995
  }
@@ -1122,13 +1144,11 @@
1122
1144
  return {
1123
1145
  run: function()
1124
1146
  {
1125
-
1126
1147
  this.build.createContainerBox();
1127
1148
  this.build.loadContent();
1128
1149
  this.build.loadEditor();
1129
1150
  this.build.enableEditor();
1130
1151
  this.build.setCodeAndCall();
1131
-
1132
1152
  },
1133
1153
  isTextarea: function()
1134
1154
  {
@@ -1144,13 +1164,7 @@
1144
1164
  },
1145
1165
  getTextareaName: function()
1146
1166
  {
1147
- var name = this.$element.attr('id');
1148
- if (typeof(name) == 'undefined')
1149
- {
1150
- name = 'content-' + this.uuid;
1151
- }
1152
-
1153
- return name;
1167
+ return ((typeof(name) == 'undefined')) ? 'content-' + this.uuid : this.$element.attr('id');
1154
1168
  },
1155
1169
  loadContent: function()
1156
1170
  {
@@ -1193,10 +1207,8 @@
1193
1207
  this.build.callEditor();
1194
1208
 
1195
1209
  // code mode
1196
- if (!this.opts.visual)
1197
- {
1198
- setTimeout($.proxy(this.code.showCode, this), 200);
1199
- }
1210
+ if (this.opts.visual) return;
1211
+ setTimeout($.proxy(this.code.showCode, this), 200);
1200
1212
  },
1201
1213
  callEditor: function()
1202
1214
  {
@@ -1236,6 +1248,21 @@
1236
1248
  if (this.opts.maxHeight) this.$editor.css('maxHeight', this.opts.maxHeight);
1237
1249
 
1238
1250
  },
1251
+ setEventDropUpload: function(e)
1252
+ {
1253
+ e.preventDefault();
1254
+
1255
+ if (!this.opts.dragImageUpload || !this.opts.dragFileUpload) return;
1256
+
1257
+ var files = e.dataTransfer.files;
1258
+ this.upload.directUpload(files[0], e);
1259
+ },
1260
+ setEventDrop: function(e)
1261
+ {
1262
+ this.code.sync();
1263
+ setTimeout(this.clean.clearUnverified, 1);
1264
+ this.core.setCallback('drop', e);
1265
+ },
1239
1266
  setEvents: function()
1240
1267
  {
1241
1268
  // drop
@@ -1245,28 +1272,16 @@
1245
1272
 
1246
1273
  if (window.FormData === undefined || !e.dataTransfer) return true;
1247
1274
 
1248
- var length = e.dataTransfer.files.length;
1249
- if (length === 0)
1275
+ if (e.dataTransfer.files.length === 0)
1250
1276
  {
1251
- this.code.sync();
1252
- setTimeout($.proxy(this.clean.clearUnverified, this), 1);
1253
- this.core.setCallback('drop', e);
1254
-
1255
- return true;
1277
+ return this.build.setEventDrop(e);
1256
1278
  }
1257
1279
  else
1258
1280
  {
1259
- e.preventDefault();
1260
-
1261
- if (this.opts.dragImageUpload || this.opts.dragFileUpload)
1262
- {
1263
- var files = e.dataTransfer.files;
1264
- this.upload.directUpload(files[0], e);
1265
- }
1281
+ this.build.setEventDropUpload(e);
1266
1282
  }
1267
1283
 
1268
- setTimeout($.proxy(this.clean.clearUnverified, this), 1);
1269
-
1284
+ setTimeout(this.clean.clearUnverified, 1);
1270
1285
  this.core.setCallback('drop', e);
1271
1286
 
1272
1287
  }, this));
@@ -1275,11 +1290,8 @@
1275
1290
  // click
1276
1291
  this.$editor.on('click.redactor', $.proxy(function(e)
1277
1292
  {
1278
- var type = 'click';
1279
- if ((this.core.getEvent() == 'click' || this.core.getEvent() == 'arrow'))
1280
- {
1281
- type = false;
1282
- }
1293
+ var event = this.core.getEvent();
1294
+ var type = (event == 'click' || event == 'arrow') ? false : 'click';
1283
1295
 
1284
1296
  this.core.addEvent(type);
1285
1297
  this.utils.disableSelectAll();
@@ -1315,23 +1327,25 @@
1315
1327
  }
1316
1328
 
1317
1329
  var clickedElement;
1318
- $(document).on('mousedown', function(e) {
1319
- clickedElement = $(e.target);
1320
- });
1330
+ $(document).on('mousedown', function(e) { clickedElement = e.target; });
1321
1331
 
1322
1332
  // blur
1323
1333
  this.$editor.on('blur.redactor', $.proxy(function(e)
1324
1334
  {
1325
1335
  if (this.rtePaste) return;
1336
+ if (!this.build.isBlured(clickedElement)) return;
1337
+
1338
+ this.utils.disableSelectAll();
1339
+ if ($.isFunction(this.opts.blurCallback)) this.core.setCallback('blur', e);
1326
1340
 
1327
- var $el = $(clickedElement);
1328
- if (!$el.hasClass('redactor-toolbar, redactor-dropdown') && !$el.is('#redactor-modal') && $el.parents('.redactor-toolbar, .redactor-dropdown, #redactor-modal').size() === 0)
1329
- {
1330
- this.utils.disableSelectAll();
1331
- if ($.isFunction(this.opts.blurCallback)) this.core.setCallback('blur', e);
1332
- }
1333
1341
  }, this));
1334
1342
  },
1343
+ isBlured: function(clickedElement)
1344
+ {
1345
+ var $el = $(clickedElement);
1346
+
1347
+ return (!$el.hasClass('redactor-toolbar, redactor-dropdown') && !$el.is('#redactor-modal') && $el.parents('.redactor-toolbar, .redactor-dropdown, #redactor-modal').length === 0);
1348
+ },
1335
1349
  setHelpers: function()
1336
1350
  {
1337
1351
  // autosave
@@ -1341,8 +1355,8 @@
1341
1355
  this.placeholder.enable();
1342
1356
 
1343
1357
  // focus
1344
- if (this.opts.focus) setTimeout($.proxy(this.focus.setStart, this), 100);
1345
- if (this.opts.focusEnd) setTimeout($.proxy(this.focus.setEnd, this), 100);
1358
+ if (this.opts.focus) setTimeout(this.focus.setStart, 100);
1359
+ if (this.opts.focusEnd) setTimeout(this.focus.setEnd, 100);
1346
1360
 
1347
1361
  },
1348
1362
  plugins: function()
@@ -1364,6 +1378,7 @@
1364
1378
 
1365
1379
  this[s] = RedactorPlugins[s]();
1366
1380
 
1381
+ // get methods
1367
1382
  var methods = this.getModuleMethods(this[s]);
1368
1383
  var len = methods.length;
1369
1384
 
@@ -1378,7 +1393,6 @@
1378
1393
 
1379
1394
  }, this));
1380
1395
 
1381
-
1382
1396
  },
1383
1397
  disableMozillaEditing: function()
1384
1398
  {
@@ -1399,28 +1413,10 @@
1399
1413
  {
1400
1414
  var $button = $('<a href="#" class="re-icon re-' + btnName + '" rel="' + btnName + '" />').attr('tabindex', '-1');
1401
1415
 
1416
+ // click
1402
1417
  if (btnObject.func || btnObject.command || btnObject.dropdown)
1403
1418
  {
1404
- $button.on('touchstart click', $.proxy(function(e)
1405
- {
1406
- if ($button.hasClass('redactor-button-disabled')) return false;
1407
-
1408
- var type = 'func';
1409
- var callback = btnObject.func;
1410
- if (btnObject.command)
1411
- {
1412
- type = 'command';
1413
- callback = btnObject.command;
1414
- }
1415
- else if (btnObject.dropdown)
1416
- {
1417
- type = 'dropdown';
1418
- callback = false;
1419
- }
1420
-
1421
- this.button.onClick(e, btnName, type, callback);
1422
-
1423
- }, this));
1419
+ this.button.setEvent($button, btnName, btnObject);
1424
1420
  }
1425
1421
 
1426
1422
  // dropdown
@@ -1439,6 +1435,30 @@
1439
1435
 
1440
1436
  return $button;
1441
1437
  },
1438
+ setEvent: function($button, btnName, btnObject)
1439
+ {
1440
+ $button.on('touchstart click', $.proxy(function(e)
1441
+ {
1442
+ if ($button.hasClass('redactor-button-disabled')) return false;
1443
+
1444
+ var type = 'func';
1445
+ var callback = btnObject.func;
1446
+
1447
+ if (btnObject.command)
1448
+ {
1449
+ type = 'command';
1450
+ callback = btnObject.command;
1451
+ }
1452
+ else if (btnObject.dropdown)
1453
+ {
1454
+ type = 'dropdown';
1455
+ callback = false;
1456
+ }
1457
+
1458
+ this.button.onClick(e, btnName, type, callback);
1459
+
1460
+ }, this));
1461
+ },
1442
1462
  createTooltip: function($button, name, title)
1443
1463
  {
1444
1464
  var $tooltip = $('<span>').addClass('redactor-toolbar-tooltip redactor-toolbar-tooltip-' + name).hide().html(title);
@@ -1449,13 +1469,11 @@
1449
1469
  if ($(this).hasClass('redactor-button-disabled')) return;
1450
1470
 
1451
1471
  var pos = $button.offset();
1452
- var height = $button.innerHeight();
1453
- var width = $button.innerWidth();
1454
1472
 
1455
1473
  $tooltip.show();
1456
1474
  $tooltip.css({
1457
- top: (pos.top + height) + 'px',
1458
- left: (pos.left + width/2 - $tooltip.innerWidth()/2) + 'px'
1475
+ top: (pos.top + $button.innerHeight()) + 'px',
1476
+ left: (pos.left + $button.innerWidth()/2 - $tooltip.innerWidth()/2) + 'px'
1459
1477
  });
1460
1478
  });
1461
1479
 
@@ -1473,38 +1491,25 @@
1473
1491
 
1474
1492
  if (this.utils.browser('msie')) e.returnValue = false;
1475
1493
 
1476
- if (type == 'command')
1477
- {
1478
- this.inline.format(callback);
1479
- }
1480
- else if (type == 'dropdown')
1481
- {
1482
- this.dropdown.show(e, btnName);
1483
- }
1484
- else
1494
+ if (type == 'command') this.inline.format(callback);
1495
+ else if (type == 'dropdown') this.dropdown.show(e, btnName);
1496
+ else this.button.onClickCallback(e, callback, btnName);
1497
+ },
1498
+ onClickCallback: function(e, callback, btnName)
1499
+ {
1500
+ var func;
1501
+
1502
+ if ($.isFunction(callback)) callback.call(this, btnName);
1503
+ else if (callback.search(/\./) != '-1')
1485
1504
  {
1486
- var func;
1505
+ func = callback.split('.');
1506
+ if (typeof this[func[0]] == 'undefined') return;
1487
1507
 
1488
- if ($.isFunction(callback))
1489
- {
1490
- callback.call(this, btnName);
1491
- this.observe.buttons(e, btnName);
1492
- }
1493
- else if (callback.search(/\./) != '-1')
1494
- {
1495
- func = callback.split('.');
1496
- if (typeof this[func[0]] != 'undefined')
1497
- {
1498
- this[func[0]][func[1]](btnName);
1499
- this.observe.buttons(e, btnName);
1500
- }
1501
- }
1502
- else
1503
- {
1504
- this[callback](btnName);
1505
- this.observe.buttons(e, btnName);
1506
- }
1508
+ this[func[0]][func[1]](btnName);
1507
1509
  }
1510
+ else this[callback](btnName);
1511
+
1512
+ this.observe.buttons(e, btnName);
1508
1513
  },
1509
1514
  get: function(key)
1510
1515
  {
@@ -1570,10 +1575,8 @@
1570
1575
  var $dropdown = $('<div class="redactor-dropdown redactor-dropdown-box-' + key + '" style="display: none;">');
1571
1576
  $btn.data('dropdown', $dropdown);
1572
1577
 
1573
- if (dropdown)
1574
- {
1575
- this.dropdown.build(key, $dropdown, dropdown);
1576
- }
1578
+ // build dropdown
1579
+ if (dropdown) this.dropdown.build(key, $dropdown, dropdown);
1577
1580
 
1578
1581
  return $dropdown;
1579
1582
  },
@@ -1604,7 +1607,7 @@
1604
1607
  var btn = this.button.build(key, { title: title });
1605
1608
  var $btn = this.button.get(afterkey);
1606
1609
 
1607
- if ($btn.size() !== 0) $btn.parent().after($('<li>').append(btn));
1610
+ if ($btn.length !== 0) $btn.parent().after($('<li>').append(btn));
1608
1611
  else this.$toolbar.append($('<li>').append(btn));
1609
1612
 
1610
1613
  return btn;
@@ -1616,7 +1619,7 @@
1616
1619
  var btn = this.button.build(key, { title: title });
1617
1620
  var $btn = this.button.get(beforekey);
1618
1621
 
1619
- if ($btn.size() !== 0) $btn.parent().before($('<li>').append(btn));
1622
+ if ($btn.length !== 0) $btn.parent().before($('<li>').append(btn));
1620
1623
  else this.$toolbar.append($('<li>').append(btn));
1621
1624
 
1622
1625
  return btn;
@@ -1652,7 +1655,8 @@
1652
1655
  set: function(orgn, orgo, focn, foco)
1653
1656
  {
1654
1657
  // focus
1655
- if (!this.utils.browser('msie')) this.$editor.focus();
1658
+ // disabled in 10.0.7
1659
+ // if (!this.utils.browser('msie')) this.$editor.focus();
1656
1660
 
1657
1661
  orgn = orgn[0] || orgn;
1658
1662
  focn = focn[0] || focn;
@@ -1664,15 +1668,16 @@
1664
1668
 
1665
1669
  if (orgn.tagName == 'BR' && this.opts.linebreaks === false)
1666
1670
  {
1667
- var par = $(this.opts.emptyHtml)[0];
1668
- $(orgn).replaceWith(par);
1669
- orgn = par;
1671
+ var parent = $(this.opts.emptyHtml)[0];
1672
+ $(orgn).replaceWith(parent);
1673
+ orgn = parent;
1670
1674
  focn = orgn;
1671
1675
  }
1672
1676
 
1673
1677
  this.selection.get();
1674
1678
 
1675
- try {
1679
+ try
1680
+ {
1676
1681
  this.range.setStart(orgn, orgo);
1677
1682
  this.range.setEnd(focn, foco);
1678
1683
  }
@@ -1682,7 +1687,8 @@
1682
1687
  },
1683
1688
  setAfter: function(node)
1684
1689
  {
1685
- try {
1690
+ try
1691
+ {
1686
1692
  var tag = $(node)[0].tagName;
1687
1693
 
1688
1694
  // inline tag
@@ -1705,7 +1711,8 @@
1705
1711
  }
1706
1712
  }
1707
1713
  }
1708
- catch (e) {
1714
+ catch (e)
1715
+ {
1709
1716
  var space = this.utils.createSpaceElement();
1710
1717
  $(node).after(space);
1711
1718
  this.caret.setEnd(space);
@@ -1810,6 +1817,7 @@
1810
1817
  this.range.collapse(false);
1811
1818
  this.selection.addRange();
1812
1819
  },
1820
+ // deprecated
1813
1821
  setToPoint: function(start, end)
1814
1822
  {
1815
1823
  this.caret.setOffset(start, end);
@@ -1945,9 +1953,7 @@
1945
1953
  }
1946
1954
 
1947
1955
  // reconvert inline
1948
- html = html.replace(/<(.*?) data-redactor-tag="(.*?)"(.*?[^>])>/gi, '<$1$3>');
1949
- html = html.replace(/<(.*?) data-redactor-class="(.*?)"(.*?[^>])>/gi, '<$1$3>');
1950
- html = html.replace(/<(.*?) data-redactor-style="(.*?)"(.*?[^>])>/gi, '<$1$3>');
1956
+ html = html.replace(/\sdata-redactor-(tag|class|style)="(.*?[^>])"/gi, '');
1951
1957
  html = html.replace(new RegExp('<(.*?) data-verified="redactor"(.*?[^>])>', 'gi'), '<$1$2>');
1952
1958
  html = html.replace(new RegExp('<(.*?) data-verified="redactor">', 'gi'), '<$1>');
1953
1959
 
@@ -1958,12 +1964,11 @@
1958
1964
  html = $.trim(html);
1959
1965
 
1960
1966
  html = html.replace(/\$/g, '&#36;');
1961
- html = html.replace(/”/g, '"');
1962
- html = html.replace(/“/g, '"');
1963
1967
  html = html.replace(/‘/g, '\'');
1964
1968
  html = html.replace(/’/g, '\'');
1965
1969
 
1966
1970
  // convert dirty spaces
1971
+ html = html.replace(/<span class="s1">/gi, '<span>');
1967
1972
  html = html.replace(/<span class="Apple-converted-space">&nbsp;<\/span>/gi, ' ');
1968
1973
  html = html.replace(/<span class="Apple-tab-span"[^>]*>\t<\/span>/gi, '\t');
1969
1974
  html = html.replace(/<span[^>]*>(\s|&nbsp;)<\/span>/gi, ' ');
@@ -1982,6 +1987,9 @@
1982
1987
 
1983
1988
  if (this.utils.isCurrentOrParent('PRE'))
1984
1989
  {
1990
+ html = html.replace(/”/g, '"');
1991
+ html = html.replace(/“/g, '"');
1992
+
1985
1993
  return this.clean.getPreCode(html);
1986
1994
  }
1987
1995
 
@@ -2200,6 +2208,11 @@
2200
2208
  removeEmpty: tagsEmpty
2201
2209
  };
2202
2210
 
2211
+ // denied tags
2212
+ if (this.opts.deniedTags)
2213
+ {
2214
+ options.deniedTags = this.opts.deniedTags;
2215
+ }
2203
2216
 
2204
2217
  return this.tidy.load(html, options);
2205
2218
 
@@ -2800,6 +2813,8 @@
2800
2813
 
2801
2814
  $item.on('click', $.proxy(function(e)
2802
2815
  {
2816
+ e.preventDefault();
2817
+
2803
2818
  var type = 'func';
2804
2819
  var callback = btnObject.func;
2805
2820
  if (btnObject.command)
@@ -2814,6 +2829,7 @@
2814
2829
  }
2815
2830
 
2816
2831
  this.button.onClick(e, btnName, type, callback);
2832
+ this.dropdown.hideAll();
2817
2833
 
2818
2834
  }, this));
2819
2835
 
@@ -2859,7 +2875,7 @@
2859
2875
  var dropdownWidth = $dropdown.width();
2860
2876
  if ((keyPosition.left + dropdownWidth) > $(document).width())
2861
2877
  {
2862
- keyPosition.left -= dropdownWidth;
2878
+ keyPosition.left = Math.max(0, keyPosition.left - dropdownWidth);
2863
2879
  }
2864
2880
 
2865
2881
  var left = keyPosition.left + 'px';
@@ -2988,7 +3004,7 @@
2988
3004
  if (typeof json == 'string') return;
2989
3005
 
2990
3006
  var linkmarker = $(this.$editor.find('a#filelink-marker'));
2991
- if (linkmarker.size() !== 0)
3007
+ if (linkmarker.length !== 0)
2992
3008
  {
2993
3009
  linkmarker.removeAttr('id').removeAttr('style');
2994
3010
  }
@@ -3008,7 +3024,7 @@
3008
3024
 
3009
3025
  var first = this.$editor.children().first();
3010
3026
 
3011
- if (first.size() === 0) return;
3027
+ if (first.length === 0) return;
3012
3028
  if (first[0].length === 0 || first[0].tagName == 'BR' || first[0].nodeType == 3)
3013
3029
  {
3014
3030
  return;
@@ -3106,7 +3122,6 @@
3106
3122
 
3107
3123
  }, this));
3108
3124
 
3109
-
3110
3125
  $('#redactor-image-title').val($image.attr('alt'));
3111
3126
 
3112
3127
  if (!this.opts.imageLink) $('.redactor-image-link-option').hide();
@@ -3115,7 +3130,7 @@
3115
3130
  var $redactorImageLink = $('#redactor-image-link');
3116
3131
 
3117
3132
  $redactorImageLink.attr('href', $image.attr('src'));
3118
- if ($link.size() !== 0)
3133
+ if ($link.length !== 0)
3119
3134
  {
3120
3135
  $redactorImageLink.val($link.attr('href'));
3121
3136
  if ($link.attr('target') == '_blank') $('#redactor-image-link-blank').prop('checked', true);
@@ -3174,9 +3189,19 @@
3174
3189
  var link = $.trim($('#redactor-image-link').val());
3175
3190
  if (link !== '')
3176
3191
  {
3192
+ // test url (add protocol)
3193
+ var pattern = '((xn--)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,}';
3194
+ var re = new RegExp('^(http|ftp|https)://' + pattern, 'i');
3195
+ var re2 = new RegExp('^' + pattern, 'i');
3196
+
3197
+ if (link.search(re) == -1 && link.search(re2) === 0 && this.opts.linkProtocol)
3198
+ {
3199
+ link = this.opts.linkProtocol + '://' + link;
3200
+ }
3201
+
3177
3202
  var target = ($('#redactor-image-link-blank').prop('checked')) ? true : false;
3178
3203
 
3179
- if ($link.size() === 0)
3204
+ if ($link.length === 0)
3180
3205
  {
3181
3206
  var a = $('<a href="' + link + '">' + this.utils.getOuterHtml($image) + '</a>');
3182
3207
  if (target) a.attr('target', '_blank');
@@ -3196,7 +3221,7 @@
3196
3221
  }
3197
3222
  }
3198
3223
  }
3199
- else if ($link.size() !== 0)
3224
+ else if ($link.length !== 0)
3200
3225
  {
3201
3226
  $link.replaceWith(this.utils.getOuterHtml($image));
3202
3227
 
@@ -3220,7 +3245,7 @@
3220
3245
  {
3221
3246
  this.observe.image = $image;
3222
3247
 
3223
- if (this.$editor.find('#redactor-image-box').size() !== 0) return false;
3248
+ if (this.$editor.find('#redactor-image-box').length !== 0) return false;
3224
3249
 
3225
3250
  this.image.resizer = this.image.loadEditableControls($image);
3226
3251
 
@@ -3296,7 +3321,7 @@
3296
3321
  },
3297
3322
  onDrag: function(e)
3298
3323
  {
3299
- if (this.$editor.find('#redactor-image-box').size() !== 0)
3324
+ if (this.$editor.find('#redactor-image-box').length !== 0)
3300
3325
  {
3301
3326
  e.preventDefault();
3302
3327
  return false;
@@ -3335,7 +3360,7 @@
3335
3360
  }
3336
3361
 
3337
3362
  var imageBox = this.$editor.find('#redactor-image-box');
3338
- if (imageBox.size() === 0) return;
3363
+ if (imageBox.length === 0) return;
3339
3364
 
3340
3365
  if (this.opts.imageEditable)
3341
3366
  {
@@ -3442,18 +3467,18 @@
3442
3467
  var $link = $image.closest('a');
3443
3468
  var $figure = $image.closest('figure');
3444
3469
  var $parent = $image.parent();
3445
- if ($('#redactor-image-box').size() !== 0)
3470
+ if ($('#redactor-image-box').length !== 0)
3446
3471
  {
3447
3472
  $parent = $('#redactor-image-box').parent();
3448
3473
  }
3449
3474
 
3450
3475
  var $next;
3451
- if ($figure.size() !== 0)
3476
+ if ($figure.length !== 0)
3452
3477
  {
3453
3478
  $next = $figure.next();
3454
3479
  $figure.remove();
3455
3480
  }
3456
- else if ($link.size() !== 0)
3481
+ else if ($link.length !== 0)
3457
3482
  {
3458
3483
  $parent = $link.parent();
3459
3484
  $link.remove();
@@ -3465,7 +3490,7 @@
3465
3490
 
3466
3491
  $('#redactor-image-box').remove();
3467
3492
 
3468
- if ($figure.size() !== 0)
3493
+ if ($figure.length !== 0)
3469
3494
  {
3470
3495
  this.caret.setStart($next);
3471
3496
  }
@@ -3525,7 +3550,6 @@
3525
3550
  this.selection.restore();
3526
3551
  this.buffer.set();
3527
3552
 
3528
-
3529
3553
  this.insert.html(this.utils.getOuterHtml(node), false);
3530
3554
 
3531
3555
  var $image = this.$editor.find('img[data-redactor-inserted-image=true]').removeAttr('data-redactor-inserted-image');
@@ -3628,14 +3652,14 @@
3628
3652
 
3629
3653
  var $item = $(current).closest('li');
3630
3654
  var $parent = $item.parent();
3631
- if ($item.size() !== 0 && $parent.size() !== 0 && $parent[0].tagName == 'LI')
3655
+ if ($item.length !== 0 && $parent.length !== 0 && $parent[0].tagName == 'LI')
3632
3656
  {
3633
3657
  $parent.after($item);
3634
3658
  }
3635
3659
 
3636
3660
  this.indent.fixEmptyIndent();
3637
3661
 
3638
- if (!this.opts.linebreaks && $item.size() === 0)
3662
+ if (!this.opts.linebreaks && $item.length === 0)
3639
3663
  {
3640
3664
  document.execCommand('formatblock', false, 'p');
3641
3665
  this.$editor.find('ul, ol, blockquote, p').each($.proxy(this.utils.removeEmpty, this));
@@ -3733,14 +3757,16 @@
3733
3757
  var $parent = $(current).closest(tag + '[data-redactor-tag=' + tag + ']');
3734
3758
 
3735
3759
  // inline there is
3736
- if ($parent.size() !== 0)
3760
+ if ($parent.length !== 0 && (this.inline.type != 'style' && $parent[0].tagName != 'SPAN'))
3737
3761
  {
3738
3762
  this.caret.setAfter($parent[0]);
3739
3763
 
3740
3764
  // remove empty
3741
- if (this.utils.isEmpty($parent.text())) $parent.remove();
3742
-
3743
- this.code.sync();
3765
+ if ( this.utils.isEmpty($parent.text()))
3766
+ {
3767
+ $parent.remove();
3768
+ this.code.sync();
3769
+ }
3744
3770
 
3745
3771
  return;
3746
3772
  }
@@ -3763,7 +3789,6 @@
3763
3789
  this.selection.save();
3764
3790
  document.execCommand('strikethrough');
3765
3791
 
3766
-
3767
3792
  this.$editor.find('strike').each($.proxy(function(i,s)
3768
3793
  {
3769
3794
  var $el = $(s);
@@ -3838,13 +3863,37 @@
3838
3863
  },
3839
3864
  formatRemoveSameChildren: function($el, tag)
3840
3865
  {
3866
+ var self = this;
3841
3867
  $el.children(tag).each(function()
3842
3868
  {
3843
3869
  var $child = $(this);
3870
+
3844
3871
  if (!$child.hasClass('redactor-selection-marker'))
3845
3872
  {
3846
- $child.contents().unwrap();
3873
+ if (self.inline.type == 'style')
3874
+ {
3875
+ var arr = self.inline.value.split(';');
3876
+
3877
+ for (var z = 0; z < arr.length; z++)
3878
+ {
3879
+ if (arr[z] === '') return;
3880
+
3881
+ var style = arr[z].split(':');
3882
+ $child.css(style[0], '');
3883
+
3884
+ if (self.utils.removeEmptyAttr($child , 'style'))
3885
+ {
3886
+ $child.replaceWith($child.contents());
3887
+ }
3888
+
3889
+ }
3890
+ }
3891
+ else
3892
+ {
3893
+ $child.contents().unwrap();
3894
+ }
3847
3895
  }
3896
+
3848
3897
  });
3849
3898
  },
3850
3899
  formatConvert: function(tag)
@@ -3858,15 +3907,25 @@
3858
3907
  find = '[data-redactor-style="' + this.inline.value + '"]';
3859
3908
  }
3860
3909
 
3910
+ var self = this;
3861
3911
  if (tag != 'del')
3862
3912
  {
3863
- var self = this;
3864
3913
  this.$editor.find('del').each(function(i,s)
3865
3914
  {
3866
3915
  self.utils.replaceToTag(s, 'inline');
3867
3916
  });
3868
3917
  }
3869
3918
 
3919
+ if (tag != 'span')
3920
+ {
3921
+ this.$editor.find(tag).each(function()
3922
+ {
3923
+ var $el = $(this);
3924
+ $el.replaceWith($('<strike />').html($el.contents()));
3925
+
3926
+ });
3927
+ }
3928
+
3870
3929
  this.$editor.find('[data-redactor-tag="' + tag + '"]' + find).each(function()
3871
3930
  {
3872
3931
  if (find === '' && tag == 'span' && this.tagName.toLowerCase() == tag) return;
@@ -4194,7 +4253,10 @@
4194
4253
  var html = this.utils.getOuterHtml(node);
4195
4254
  html = this.clean.setVerified(html);
4196
4255
 
4197
- node = $(html)[0];
4256
+ if (html.match(/</g) !== null)
4257
+ {
4258
+ node = $(html)[0];
4259
+ }
4198
4260
 
4199
4261
  this.selection.get();
4200
4262
 
@@ -4398,7 +4460,7 @@
4398
4460
  current = this.selection.getCurrent();
4399
4461
  $next = $(current).next();
4400
4462
 
4401
- if ($next.size() !== 0 && $next[0].tagName == 'BR')
4463
+ if ($next.length !== 0 && $next[0].tagName == 'BR')
4402
4464
  {
4403
4465
  return this.keydown.insertBreakLine(e);
4404
4466
  }
@@ -4418,7 +4480,8 @@
4418
4480
 
4419
4481
  if (current !== false && $(current).hasClass('redactor-invisible-space'))
4420
4482
  {
4421
- $(current).remove();
4483
+ this.caret.setAfter(current);
4484
+ $(current).contents().unwrap();
4422
4485
  return this.keydown.insertDblBreakLine(e);
4423
4486
  }
4424
4487
  else
@@ -4427,6 +4490,10 @@
4427
4490
  {
4428
4491
  return this.keydown.insertDblBreakLine(e);
4429
4492
  }
4493
+ else if (this.utils.isEndOfEditor())
4494
+ {
4495
+ return this.keydown.insertDblBreakLine(e);
4496
+ }
4430
4497
 
4431
4498
  return this.keydown.insertBreakLine(e);
4432
4499
  }
@@ -4448,7 +4515,6 @@
4448
4515
 
4449
4516
  }
4450
4517
 
4451
-
4452
4518
  // Shift+Enter or Ctrl+Enter
4453
4519
  if (key === this.keyCode.ENTER && (e.ctrlKey || e.shiftKey))
4454
4520
  {
@@ -4462,7 +4528,6 @@
4462
4528
  return this.keydown.onTab(e, key);
4463
4529
  }
4464
4530
 
4465
-
4466
4531
  // image delete and backspace
4467
4532
  if (key === this.keyCode.BACKSPACE || key === this.keyCode.DELETE)
4468
4533
  {
@@ -4474,7 +4539,7 @@
4474
4539
  for (var i = 0; i < len; i++)
4475
4540
  {
4476
4541
  var children = $(nodes[i]).children('img');
4477
- if (children.size() !== 0)
4542
+ if (children.length !== 0)
4478
4543
  {
4479
4544
  var self = this;
4480
4545
  $.each(children, function(z,s)
@@ -4810,7 +4875,7 @@
4810
4875
  var $parent = $(this.keydown.parent);
4811
4876
  var td = $current.closest('td');
4812
4877
 
4813
- if (td.size() !== 0 && $current.closest('li') && $parent.children('li').size() === 1)
4878
+ if (td.length !== 0 && $current.closest('li') && $parent.children('li').length === 1)
4814
4879
  {
4815
4880
  if (!this.utils.isEmpty($current.text())) return;
4816
4881
 
@@ -4896,14 +4961,11 @@
4896
4961
  this.$editor.find('p').each($.proxy(this.utils.removeEmpty, this));
4897
4962
 
4898
4963
  // remove invisible space
4899
- if (this.keyup.current && this.keyup.current.tagName == 'DIV' && this.utils.isEmpty(this.keyup.current.innerHTML))
4964
+ if (this.opts.linebreaks && this.keyup.current && this.keyup.current.tagName == 'DIV' && this.utils.isEmpty(this.keyup.current.innerHTML))
4900
4965
  {
4901
- if (this.opts.linebreaks)
4902
- {
4903
- $(this.keyup.current).after(this.selection.getMarkerAsHtml());
4904
- this.selection.restore();
4905
- $(this.keyup.current).remove();
4906
- }
4966
+ $(this.keyup.current).after(this.selection.getMarkerAsHtml());
4967
+ this.selection.restore();
4968
+ $(this.keyup.current).remove();
4907
4969
  }
4908
4970
 
4909
4971
  // if empty
@@ -5111,7 +5173,7 @@
5111
5173
  this.link.$node = false;
5112
5174
 
5113
5175
  var $el = $(this.selection.getCurrent()).closest('a');
5114
- if ($el.size() !== 0 && $el[0].tagName === 'A')
5176
+ if ($el.length !== 0 && $el[0].tagName === 'A')
5115
5177
  {
5116
5178
  this.link.$node = $el;
5117
5179
 
@@ -5162,8 +5224,8 @@
5162
5224
  var pattern = '((xn--)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,}';
5163
5225
  var re = new RegExp('^(http|ftp|https)://' + pattern, 'i');
5164
5226
  var re2 = new RegExp('^' + pattern, 'i');
5165
-
5166
- if (link.search(re) == -1 && link.search(re2) === 0 && this.opts.linkProtocol)
5227
+ var re3 = new RegExp('\.(html|php)$', 'i');
5228
+ if (link.search(re) == -1 && link.search(re3) == -1 && link.search(re2) === 0 && this.opts.linkProtocol)
5167
5229
  {
5168
5230
  link = this.opts.linkProtocol + '://' + link;
5169
5231
  }
@@ -5227,7 +5289,7 @@
5227
5289
  if (target !== '') $a.attr('target', target);
5228
5290
  $a.removeAttr('style');
5229
5291
 
5230
- if (this.link.text === '')
5292
+ if (this.link.text === '' || this.link.text != text)
5231
5293
  {
5232
5294
  $a.text(text);
5233
5295
  this.selection.selectElement($a);
@@ -5288,7 +5350,7 @@
5288
5350
  var parent = this.selection.getParent();
5289
5351
  var $list = $(parent).closest('ol, ul');
5290
5352
 
5291
- if (!this.utils.isRedactorParent($list) && $list.size() !== 0)
5353
+ if (!this.utils.isRedactorParent($list) && $list.length !== 0)
5292
5354
  {
5293
5355
  $list = false;
5294
5356
  }
@@ -5345,7 +5407,7 @@
5345
5407
 
5346
5408
  var $list = $(this.selection.getParent()).closest('ol, ul');
5347
5409
 
5348
- if ($td.size() !== 0)
5410
+ if ($td.length !== 0)
5349
5411
  {
5350
5412
  var prev = $td.prev();
5351
5413
  var html = $td.html();
@@ -5430,7 +5492,7 @@
5430
5492
 
5431
5493
  this.indent.fixEmptyIndent();
5432
5494
 
5433
- if (!this.opts.linebreaks && $current.closest('li, th, td').size() === 0)
5495
+ if (!this.opts.linebreaks && $current.closest('li, th, td').length === 0)
5434
5496
  {
5435
5497
  document.execCommand('formatblock', false, 'p');
5436
5498
  this.$editor.find('ul, ol, blockquote').each($.proxy(this.utils.removeEmpty, this));
@@ -5438,7 +5500,7 @@
5438
5500
 
5439
5501
  var $table = $(this.selection.getCurrent()).closest('table');
5440
5502
  var $prev = $table.prev();
5441
- if (!this.opts.linebreaks && $table.size() !== 0 && $prev.size() !== 0 && $prev[0].tagName == 'BR')
5503
+ if (!this.opts.linebreaks && $table.length !== 0 && $prev.length !== 0 && $prev[0].tagName == 'BR')
5442
5504
  {
5443
5505
  $prev.remove();
5444
5506
  }
@@ -5603,8 +5665,7 @@
5603
5665
  $(document).off('focusin.modal');
5604
5666
 
5605
5667
  // enter
5606
- this.$modal.find('input[type=text]').on('keydown.redactor-modal', $.proxy(this.modal.setEnter, this));
5607
-
5668
+ this.$modal.find('input[type=text],input[type=url],input[type=email]').on('keydown.redactor-modal', $.proxy(this.modal.setEnter, this));
5608
5669
  },
5609
5670
  showOnDesktop: function()
5610
5671
  {
@@ -5702,7 +5763,7 @@
5702
5763
  setButtonsWidth: function()
5703
5764
  {
5704
5765
  var buttons = this.$modalFooter.find('button');
5705
- var buttonsSize = buttons.size();
5766
+ var buttonsSize = buttons.length;
5706
5767
  if (buttonsSize === 0) return;
5707
5768
 
5708
5769
  buttons.css('width', (100/buttonsSize) + '%');
@@ -5877,7 +5938,7 @@
5877
5938
  {
5878
5939
  var $link = $(e.target);
5879
5940
  var $parent = $link.closest('a');
5880
- var tag = ($link.size() !== 0) ? $link[0].tagName : false;
5941
+ var tag = ($link.length !== 0) ? $link[0].tagName : false;
5881
5942
 
5882
5943
  if ($parent[0].tagName === 'A')
5883
5944
  {
@@ -5907,7 +5968,7 @@
5907
5968
 
5908
5969
  tooltip.append(aLink).append(' | ').append(aEdit).append(' | ').append(aUnlink);
5909
5970
  tooltip.css({
5910
- top: (pos.top + 20) + 'px',
5971
+ top: (pos.top + parseInt($link.css('line-height'), 10)) + 'px',
5911
5972
  left: pos.left + 'px'
5912
5973
  });
5913
5974
 
@@ -5920,7 +5981,7 @@
5920
5981
 
5921
5982
  var target = e.target;
5922
5983
  var $parent = $(target).closest('a');
5923
- if ($parent.size() !== 0 && $parent[0].tagName === 'A' && target.tagName !== 'A')
5984
+ if ($parent.length !== 0 && $parent[0].tagName === 'A' && target.tagName !== 'A')
5924
5985
  {
5925
5986
  return;
5926
5987
  }
@@ -6323,15 +6384,23 @@
6323
6384
 
6324
6385
  var startNode = this.selection.getNodesMarker(1);
6325
6386
  var endNode = this.selection.getNodesMarker(2);
6326
-
6327
- this.selection.setNodesMarker(this.range, startNode, true);
6387
+ var range = this.range.cloneRange();
6328
6388
 
6329
6389
  if (this.range.collapsed === false)
6330
6390
  {
6331
- this.selection.setNodesMarker(this.range, endNode, false);
6391
+ var startContainer = range.startContainer;
6392
+ var startOffset = range.startOffset;
6393
+
6394
+ // end marker
6395
+ this.selection.setNodesMarker(range, endNode, false);
6396
+
6397
+ // start marker
6398
+ range.setStart(startContainer, startOffset);
6399
+ this.selection.setNodesMarker(range, startNode, true);
6332
6400
  }
6333
6401
  else
6334
6402
  {
6403
+ this.selection.setNodesMarker(range, startNode, true);
6335
6404
  endNode = startNode;
6336
6405
  }
6337
6406
 
@@ -6389,8 +6458,6 @@
6389
6458
  },
6390
6459
  setNodesMarker: function(range, node, type)
6391
6460
  {
6392
- range = range.cloneRange();
6393
-
6394
6461
  try {
6395
6462
  range.collapse(type);
6396
6463
  range.insertNode(node);
@@ -7334,8 +7401,17 @@
7334
7401
  {
7335
7402
  if (!this.opts.toolbar[btnName]) return;
7336
7403
 
7337
- if (this.opts.fileUpload === false && btnName === 'file') return true;
7338
- if ((this.opts.imageUpload === false && this.opts.s3 === false) && btnName === 'image') return true;
7404
+ if (btnName === 'file')
7405
+ {
7406
+ if (this.opts.fileUpload === false) return;
7407
+ else if (!this.opts.fileUpload && this.opts.s3 === false) return;
7408
+ }
7409
+
7410
+ if (btnName === 'image')
7411
+ {
7412
+ if (this.opts.imageUpload === false) return;
7413
+ else if (!this.opts.imageUpload && this.opts.s3 === false) return;
7414
+ }
7339
7415
 
7340
7416
  var btnObject = this.opts.toolbar[btnName];
7341
7417
  this.$toolbar.append($('<li>').append(this.button.build(btnName, btnObject)));
@@ -7373,7 +7449,7 @@
7373
7449
  },
7374
7450
  isButtonSourceNeeded: function()
7375
7451
  {
7376
- if (this.opts.buttonSource) return;
7452
+ if (this.opts.source) return;
7377
7453
 
7378
7454
  var index = this.opts.buttons.indexOf('html');
7379
7455
  if (index !== -1)
@@ -8005,6 +8081,15 @@
8005
8081
 
8006
8082
  return (offset == text.length) ? true : false;
8007
8083
  },
8084
+ isEndOfEditor: function()
8085
+ {
8086
+ var block = this.$editor[0];
8087
+
8088
+ var offset = this.caret.getOffsetOfElement(block);
8089
+ var text = $.trim($(block).text()).replace(/\n\r\n/g, '');
8090
+
8091
+ return (offset == text.length) ? true : false;
8092
+ },
8008
8093
 
8009
8094
  // test blocks
8010
8095
  isBlock: function(block)
@@ -8024,7 +8109,7 @@
8024
8109
  isTag: function(current, tag)
8025
8110
  {
8026
8111
  var element = $(current).closest(tag);
8027
- if (element.size() == 1)
8112
+ if (element.length == 1)
8028
8113
  {
8029
8114
  return element[0];
8030
8115
  }
@@ -8122,6 +8207,7 @@
8122
8207
  ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
8123
8208
  [];
8124
8209
 
8210
+ if (browser == 'safari') return (typeof match[3] != 'undefined') ? match[3] == 'safari' : false;
8125
8211
  if (browser == 'version') return match[2];
8126
8212
  if (browser == 'webkit') return (match[1] == 'chrome' || match[1] == 'webkit');
8127
8213
  if (match[1] == 'rv') return browser == 'msie';
@@ -8133,6 +8219,11 @@
8133
8219
  }
8134
8220
  };
8135
8221
 
8222
+ $(window).on('load.tools.redactor', function()
8223
+ {
8224
+ $('[data-tools="redactor"]').redactor();
8225
+ });
8226
+
8136
8227
  // constructor
8137
8228
  Redactor.prototype.init.prototype = Redactor.prototype;
8138
8229