comfortable_mexican_sofa 1.12.7 → 1.12.8

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