tinymce-rails 4.0.19 → 4.0.26

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +62 -36
  3. data/app/assets/source/tinymce/tinymce.jquery.js +1344 -760
  4. data/app/assets/source/tinymce/tinymce.js +1284 -700
  5. data/lib/tinymce/rails/engine.rb +4 -1
  6. data/lib/tinymce/rails/version.rb +2 -2
  7. data/vendor/assets/javascripts/tinymce/jquery.tinymce.js +1 -1
  8. data/vendor/assets/javascripts/tinymce/plugins/advlist/plugin.js +1 -1
  9. data/vendor/assets/javascripts/tinymce/plugins/anchor/plugin.js +1 -1
  10. data/vendor/assets/javascripts/tinymce/plugins/autolink/plugin.js +1 -1
  11. data/vendor/assets/javascripts/tinymce/plugins/autoresize/plugin.js +1 -1
  12. data/vendor/assets/javascripts/tinymce/plugins/charmap/plugin.js +1 -1
  13. data/vendor/assets/javascripts/tinymce/plugins/directionality/plugin.js +1 -1
  14. data/vendor/assets/javascripts/tinymce/plugins/emoticons/plugin.js +1 -1
  15. data/vendor/assets/javascripts/tinymce/plugins/example/dialog.html +8 -0
  16. data/vendor/assets/javascripts/tinymce/plugins/example/plugin.js +1 -1
  17. data/vendor/assets/javascripts/tinymce/plugins/fullpage/plugin.js +1 -1
  18. data/vendor/assets/javascripts/tinymce/plugins/image/plugin.js +1 -1
  19. data/vendor/assets/javascripts/tinymce/plugins/importcss/plugin.js +1 -1
  20. data/vendor/assets/javascripts/tinymce/plugins/insertdatetime/plugin.js +1 -1
  21. data/vendor/assets/javascripts/tinymce/plugins/layer/plugin.js +1 -1
  22. data/vendor/assets/javascripts/tinymce/plugins/legacyoutput/plugin.js +1 -1
  23. data/vendor/assets/javascripts/tinymce/plugins/link/plugin.js +1 -1
  24. data/vendor/assets/javascripts/tinymce/plugins/lists/plugin.js +1 -1
  25. data/vendor/assets/javascripts/tinymce/plugins/media/plugin.js +1 -1
  26. data/vendor/assets/javascripts/tinymce/plugins/noneditable/plugin.js +1 -1
  27. data/vendor/assets/javascripts/tinymce/plugins/pagebreak/plugin.js +1 -1
  28. data/vendor/assets/javascripts/tinymce/plugins/paste/plugin.js +1 -1
  29. data/vendor/assets/javascripts/tinymce/plugins/preview/plugin.js +1 -1
  30. data/vendor/assets/javascripts/tinymce/plugins/print/plugin.js +1 -1
  31. data/vendor/assets/javascripts/tinymce/plugins/save/plugin.js +1 -1
  32. data/vendor/assets/javascripts/tinymce/plugins/searchreplace/plugin.js +1 -1
  33. data/vendor/assets/javascripts/tinymce/plugins/spellchecker/plugin.js +1 -1
  34. data/vendor/assets/javascripts/tinymce/plugins/table/plugin.js +1 -1
  35. data/vendor/assets/javascripts/tinymce/plugins/template/plugin.js +1 -1
  36. data/vendor/assets/javascripts/tinymce/plugins/textcolor/plugin.js +1 -1
  37. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce-small.dev.svg +175 -0
  38. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce-small.eot +0 -0
  39. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce-small.svg +55 -168
  40. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce-small.ttf +0 -0
  41. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce-small.woff +0 -0
  42. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce.dev.svg +153 -0
  43. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce.eot +0 -0
  44. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce.svg +56 -146
  45. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce.ttf +0 -0
  46. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce.woff +0 -0
  47. data/vendor/assets/javascripts/tinymce/skins/lightgray/skin.ie7.min.css +1 -1
  48. data/vendor/assets/javascripts/tinymce/skins/lightgray/skin.min.css +1 -1
  49. data/vendor/assets/javascripts/tinymce/themes/modern/theme.js +1 -1
  50. data/vendor/assets/javascripts/tinymce/tinymce.jquery.js +10 -10
  51. data/vendor/assets/javascripts/tinymce/tinymce.js +10 -10
  52. metadata +5 -2
@@ -1,4 +1,4 @@
1
- // 4.0.19 (2014-03-11)
1
+ // 4.0.26 (2014-05-06)
2
2
 
3
3
  /**
4
4
  * Compiled inline version. (Library mode)
@@ -487,10 +487,13 @@ define("tinymce/dom/EventUtils", [], function() {
487
487
  while (ci--) {
488
488
  if (callbackList[ci].func === callback) {
489
489
  var nativeHandler = callbackList.nativeHandler;
490
+ var fakeName = callbackList.fakeName, capture = callbackList.capture;
490
491
 
491
492
  // Clone callbackList since unbind inside a callback would otherwise break the handlers loop
492
493
  callbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1));
493
494
  callbackList.nativeHandler = nativeHandler;
495
+ callbackList.fakeName = fakeName;
496
+ callbackList.capture = capture;
494
497
 
495
498
  eventMap[name] = callbackList;
496
499
  }
@@ -3509,8 +3512,16 @@ define("tinymce/html/Styles", [], function() {
3509
3512
 
3510
3513
  url = decode(url || url2 || url3);
3511
3514
 
3512
- if (!settings.allow_script_urls && /(java|vb)script:/i.test(url.replace(/[\s\r\n]+/, ''))) {
3513
- return "";
3515
+ if (!settings.allow_script_urls) {
3516
+ var scriptUrl = url.replace(/[\s\r\n]+/, '');
3517
+
3518
+ if (/(java|vb)script:/i.test(scriptUrl)) {
3519
+ return "";
3520
+ }
3521
+
3522
+ if (!settings.allow_svg_data_urls && /^data:image\/svg/i.test(scriptUrl)) {
3523
+ return "";
3524
+ }
3514
3525
  }
3515
3526
 
3516
3527
  // Convert the URL to relative/absolute depending on config
@@ -3535,8 +3546,16 @@ define("tinymce/html/Styles", [], function() {
3535
3546
  name = matches[1].replace(trimRightRegExp, '').toLowerCase();
3536
3547
  value = matches[2].replace(trimRightRegExp, '');
3537
3548
 
3549
+ // Decode escaped sequences like \65 -> e
3550
+ /*jshint loopfunc:true*/
3551
+ /*eslint no-loop-func:0 */
3552
+ value = value.replace(/\\[0-9a-f]+/g, function(e) {
3553
+ return String.fromCharCode(parseInt(e.substr(1), 16));
3554
+ });
3555
+
3538
3556
  if (name && value.length > 0) {
3539
- if (!settings.allow_script_urls && (name == "behavior" || /expression\s*\(/.test(value))) {
3557
+ // Don't allow behavior name or expression/comments within the values
3558
+ if (!settings.allow_script_urls && (name == "behavior" || /expression\s*\(|\/\*|\*\//.test(value))) {
3540
3559
  continue;
3541
3560
  }
3542
3561
 
@@ -5026,7 +5045,7 @@ define("tinymce/html/Entities", [
5026
5045
  var makeMap = Tools.makeMap;
5027
5046
 
5028
5047
  var namedEntities, baseEntities, reverseEntities,
5029
- attrsCharsRegExp = /[&<>\"\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
5048
+ attrsCharsRegExp = /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
5030
5049
  textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
5031
5050
  rawCharsRegExp = /[<>&\"\']/g,
5032
5051
  entityRegExp = /&(#x|#)?([\w]+);/g,
@@ -5044,7 +5063,8 @@ define("tinymce/html/Entities", [
5044
5063
  "'": '&#39;',
5045
5064
  '<': '&lt;',
5046
5065
  '>': '&gt;',
5047
- '&': '&amp;'
5066
+ '&': '&amp;',
5067
+ '\u0060': '&#96;'
5048
5068
  };
5049
5069
 
5050
5070
  // Reverse lookup table for raw entities
@@ -6028,7 +6048,8 @@ define("tinymce/dom/DOMUtils", [
6028
6048
  return false;
6029
6049
  }
6030
6050
 
6031
- return Sizzle.matches(selector, elm.nodeType ? [elm] : elm).length > 0;
6051
+ var elms = elm.nodeType ? [elm] : elm;
6052
+ return Sizzle(selector, elms[0].ownerDocument || elms[0], null, elms).length > 0;
6032
6053
  },
6033
6054
 
6034
6055
  // #endif
@@ -7316,9 +7337,9 @@ define("tinymce/dom/DOMUtils", [
7316
7337
 
7317
7338
  // Keep elements with data-bookmark attributes or name attribute like <a name="1"></a>
7318
7339
  attributes = self.getAttribs(node);
7319
- i = node.attributes.length;
7340
+ i = attributes.length;
7320
7341
  while (i--) {
7321
- name = node.attributes[i].nodeName;
7342
+ name = attributes[i].nodeName;
7322
7343
  if (name === "name" || name === 'data-mce-bookmark') {
7323
7344
  return false;
7324
7345
  }
@@ -7576,7 +7597,7 @@ define("tinymce/dom/DOMUtils", [
7576
7597
  var contentEditable;
7577
7598
 
7578
7599
  // Check type
7579
- if (node.nodeType != 1) {
7600
+ if (!node || node.nodeType != 1) {
7580
7601
  return null;
7581
7602
  }
7582
7603
 
@@ -7590,6 +7611,20 @@ define("tinymce/dom/DOMUtils", [
7590
7611
  return node.contentEditable !== "inherit" ? node.contentEditable : null;
7591
7612
  },
7592
7613
 
7614
+ getContentEditableParent: function(node) {
7615
+ var root = this.getRoot(), state = null;
7616
+
7617
+ for (; node && node !== root; node = node.parentNode) {
7618
+ state = this.getContentEditable(node);
7619
+
7620
+ if (state !== null) {
7621
+ break;
7622
+ }
7623
+ }
7624
+
7625
+ return state;
7626
+ },
7627
+
7593
7628
  /**
7594
7629
  * Destroys all internal references to the DOM to solve IE leak issues.
7595
7630
  *
@@ -7619,6 +7654,18 @@ define("tinymce/dom/DOMUtils", [
7619
7654
  self.win = self.doc = self.root = self.events = self.frag = null;
7620
7655
  },
7621
7656
 
7657
+ isChildOf: function(node, parent) {
7658
+ while (node) {
7659
+ if (parent === node) {
7660
+ return true;
7661
+ }
7662
+
7663
+ node = node.parentNode;
7664
+ }
7665
+
7666
+ return false;
7667
+ },
7668
+
7622
7669
  // #ifdef debug
7623
7670
 
7624
7671
  dumpRng: function(r) {
@@ -7993,12 +8040,21 @@ define("tinymce/AddOnManager", [
7993
8040
  * @param {String} languages Optional comma or space separated list of languages to check if it matches the name.
7994
8041
  */
7995
8042
  requireLangPack: function(name, languages) {
7996
- if (AddOnManager.language && AddOnManager.languageLoad !== false) {
7997
- if (languages && new RegExp('([, ]|\\b)' + AddOnManager.language + '([, ]|\\b)').test(languages) === false) {
7998
- return;
8043
+ var language = AddOnManager.language;
8044
+
8045
+ if (language && AddOnManager.languageLoad !== false) {
8046
+ if (languages) {
8047
+ languages = ',' + languages + ',';
8048
+
8049
+ // Load short form sv.js or long form sv_SE.js
8050
+ if (languages.indexOf(',' + language.substr(0, 2) + ',') != -1) {
8051
+ language = language.substr(0, 2);
8052
+ } else if (languages.indexOf(',' + language + ',') == -1) {
8053
+ return;
8054
+ }
7999
8055
  }
8000
8056
 
8001
- ScriptLoader.ScriptLoader.add(this.urls[name] + '/langs/' + AddOnManager.language + '.js');
8057
+ ScriptLoader.ScriptLoader.add(this.urls[name] + '/langs/' + language + '.js');
8002
8058
  }
8003
8059
  },
8004
8060
 
@@ -8912,8 +8968,8 @@ define("tinymce/html/Schema", [
8912
8968
  add("mark rt rp summary bdi", "", phrasingContent);
8913
8969
  add("canvas", "width height", flowContent);
8914
8970
  add("video", "src crossorigin poster preload autoplay mediagroup loop " +
8915
- "muted controls width height", flowContent, "track source");
8916
- add("audio", "src crossorigin preload autoplay mediagroup loop muted controls", flowContent, "track source");
8971
+ "muted controls width height buffered", flowContent, "track source");
8972
+ add("audio", "src crossorigin preload autoplay mediagroup loop muted controls buffered volume", flowContent, "track source");
8917
8973
  add("source", "src type media");
8918
8974
  add("track", "kind src srclang label default");
8919
8975
  add("datalist", "", phrasingContent, "option");
@@ -8972,7 +9028,7 @@ define("tinymce/html/Schema", [
8972
9028
  addAttrs("input textarea", "placeholder");
8973
9029
  addAttrs("a", "download");
8974
9030
  addAttrs("link script img", "crossorigin");
8975
- addAttrs("iframe", "srcdoc sandbox seamless allowfullscreen");
9031
+ addAttrs("iframe", "sandbox seamless allowfullscreen"); // Excluded: srcdoc
8976
9032
  }
8977
9033
 
8978
9034
  // Special: iframe, ruby, video, audio, label
@@ -9031,7 +9087,7 @@ define("tinymce/html/Schema", [
9031
9087
  }
9032
9088
  } else {
9033
9089
  // Create custom map
9034
- value = makeMap(value, ',', makeMap(value.toUpperCase(), ' '));
9090
+ value = makeMap(value, /[, ]/, makeMap(value.toUpperCase(), /[, ]/));
9035
9091
  }
9036
9092
 
9037
9093
  return value;
@@ -9245,6 +9301,9 @@ define("tinymce/html/Schema", [
9245
9301
  var customElementRegExp = /^(~)?(.+)$/;
9246
9302
 
9247
9303
  if (custom_elements) {
9304
+ // Flush cached items since we are altering the default maps
9305
+ mapCache.text_block_elements = mapCache.block_elements = null;
9306
+
9248
9307
  each(split(custom_elements, ','), function(rule) {
9249
9308
  var matches = customElementRegExp.exec(rule),
9250
9309
  inline = matches[1] === '~',
@@ -9272,8 +9331,9 @@ define("tinymce/html/Schema", [
9272
9331
  }
9273
9332
 
9274
9333
  // Add custom elements at span/div positions
9275
- each(children, function(element) {
9334
+ each(children, function(element, elmName) {
9276
9335
  if (element[cloneName]) {
9336
+ children[elmName] = element = extend({}, children[elmName]);
9277
9337
  element[name] = element[cloneName];
9278
9338
  }
9279
9339
  });
@@ -9303,6 +9363,10 @@ define("tinymce/html/Schema", [
9303
9363
 
9304
9364
  each(split(matches[3], '|'), function(child) {
9305
9365
  if (prefix === '-') {
9366
+ // Clone the element before we delete
9367
+ // things in it to not mess up default schemas
9368
+ children[matches[2]] = parent = extend({}, children[matches[2]]);
9369
+
9306
9370
  delete parent[child];
9307
9371
  } else {
9308
9372
  parent[child] = {};
@@ -9721,8 +9785,8 @@ define("tinymce/html/SaxParser", [
9721
9785
  var validate, elementRule, isValidElement, attr, attribsValue, validAttributesMap, validAttributePatterns;
9722
9786
  var attributesRequired, attributesDefault, attributesForced;
9723
9787
  var anyAttributesRequired, selfClosing, tokenRegExp, attrRegExp, specialElements, attrValue, idCount = 0;
9724
- var decode = Entities.decode, fixSelfClosing, filteredUrlAttrs = Tools.makeMap('src,href');
9725
- var scriptUriRegExp = /(java|vb)script:/i;
9788
+ var decode = Entities.decode, fixSelfClosing, filteredUrlAttrs = Tools.makeMap('src,href,data,background,formaction,poster');
9789
+ var scriptUriRegExp = /((java|vb)script|mhtml):/i, dataUriRegExp = /^data:/i;
9726
9790
 
9727
9791
  function processEndTag(name) {
9728
9792
  var pos, i;
@@ -9788,22 +9852,24 @@ define("tinymce/html/SaxParser", [
9788
9852
  }
9789
9853
  }
9790
9854
 
9791
- // Block any javascript: urls
9855
+ // Block any javascript: urls or non image data uris
9792
9856
  if (filteredUrlAttrs[name] && !settings.allow_script_urls) {
9793
9857
  var uri = value.replace(trimRegExp, '');
9794
9858
 
9795
9859
  try {
9796
9860
  // Might throw malformed URI sequence
9797
9861
  uri = decodeURIComponent(uri);
9798
- if (scriptUriRegExp.test(uri)) {
9799
- return;
9800
- }
9801
9862
  } catch (ex) {
9802
9863
  // Fallback to non UTF-8 decoder
9803
9864
  uri = unescape(uri);
9804
- if (scriptUriRegExp.test(uri)) {
9805
- return;
9806
- }
9865
+ }
9866
+
9867
+ if (scriptUriRegExp.test(uri)) {
9868
+ return;
9869
+ }
9870
+
9871
+ if (!settings.allow_html_data_urls && dataUriRegExp.test(uri) && !/^data:image\//i.test(uri)) {
9872
+ return;
9807
9873
  }
9808
9874
  }
9809
9875
 
@@ -11220,6 +11286,17 @@ define("tinymce/dom/Serializer", [
11220
11286
 
11221
11287
  htmlParser = new DomParser(settings, schema);
11222
11288
 
11289
+ // Convert tabindex back to elements when serializing contents
11290
+ htmlParser.addAttributeFilter('data-mce-tabindex', function(nodes, name) {
11291
+ var i = nodes.length, node;
11292
+
11293
+ while (i--) {
11294
+ node = nodes[i];
11295
+ node.attr('tabindex', node.attributes.map['data-mce-tabindex']);
11296
+ node.attr(name, null);
11297
+ }
11298
+ });
11299
+
11223
11300
  // Convert move data-mce-src, data-mce-href and data-mce-style into nodes or process them if needed
11224
11301
  htmlParser.addAttributeFilter('src,href,style', function(nodes, name) {
11225
11302
  var i = nodes.length, node, value, internalName = 'data-mce-' + name;
@@ -12271,6 +12348,8 @@ define("tinymce/dom/ControlSelection", [
12271
12348
  function showResizeRect(targetElm, mouseDownHandleName, mouseDownEvent) {
12272
12349
  var position, targetWidth, targetHeight, e, rect, offsetParent = editor.getBody();
12273
12350
 
12351
+ unbindResizeHandleEvents();
12352
+
12274
12353
  // Get position and size of target
12275
12354
  position = dom.getPos(targetElm, offsetParent);
12276
12355
  selectedElmX = position.x;
@@ -12350,14 +12429,18 @@ define("tinymce/dom/ControlSelection", [
12350
12429
  if (Env.ie) {
12351
12430
  handleElm.contentEditable = false;
12352
12431
  }
12432
+ } else {
12433
+ dom.show(handleElm);
12434
+ }
12353
12435
 
12436
+ if (!handle.elm) {
12354
12437
  dom.bind(handleElm, 'mousedown', function(e) {
12355
12438
  e.stopImmediatePropagation();
12356
12439
  e.preventDefault();
12357
12440
  startDrag(e);
12358
12441
  });
12359
- } else {
12360
- dom.show(handleElm);
12442
+
12443
+ handle.elm = handleElm;
12361
12444
  }
12362
12445
 
12363
12446
  /*
@@ -12387,6 +12470,8 @@ define("tinymce/dom/ControlSelection", [
12387
12470
  function hideResizeRect() {
12388
12471
  var name, handleElm;
12389
12472
 
12473
+ unbindResizeHandleEvents();
12474
+
12390
12475
  if (selectedElm) {
12391
12476
  selectedElm.removeAttribute('data-mce-selected');
12392
12477
  }
@@ -12496,6 +12581,17 @@ define("tinymce/dom/ControlSelection", [
12496
12581
  detachEvent(selectedElm, 'resizestart', resizeNativeStart);
12497
12582
  }
12498
12583
 
12584
+ function unbindResizeHandleEvents() {
12585
+ for (var name in resizeHandles) {
12586
+ var handle = resizeHandles[name];
12587
+
12588
+ if (handle.elm) {
12589
+ dom.unbind(handle.elm);
12590
+ delete handle.elm;
12591
+ }
12592
+ }
12593
+ }
12594
+
12499
12595
  function disableGeckoResize() {
12500
12596
  try {
12501
12597
  // Disable object resizing on Gecko
@@ -12577,10 +12673,14 @@ define("tinymce/dom/ControlSelection", [
12577
12673
  }
12578
12674
  });
12579
12675
 
12676
+ editor.on('hide', hideResizeRect);
12677
+
12580
12678
  // Hide rect on focusout since it would float on top of windows otherwise
12581
12679
  //editor.on('focusout', hideResizeRect);
12582
12680
  });
12583
12681
 
12682
+ editor.on('remove', unbindResizeHandleEvents);
12683
+
12584
12684
  function destroy() {
12585
12685
  selectedElm = selectedElmGhost = null;
12586
12686
 
@@ -12857,7 +12957,7 @@ define("tinymce/dom/RangeUtils", [
12857
12957
  var normalized, collapsed;
12858
12958
 
12859
12959
  function normalizeEndPoint(start) {
12860
- var container, offset, walker, body = dom.getRoot(), node, nonEmptyElementsMap, nodeName;
12960
+ var container, offset, walker, body = dom.getRoot(), node, nonEmptyElementsMap;
12861
12961
  var directionLeft, isAfterNode;
12862
12962
 
12863
12963
  function hasBrBeforeAfter(node, left) {
@@ -12894,6 +12994,11 @@ define("tinymce/dom/RangeUtils", [
12894
12994
  // Walk left until we hit a text node we can move to or a block/br/img
12895
12995
  walker = new TreeWalker(startNode, parentBlockContainer);
12896
12996
  while ((node = walker[left ? 'prev' : 'next']())) {
12997
+ // Break if we hit a non content editable node
12998
+ if (dom.getContentEditableParent(node) === "false") {
12999
+ return;
13000
+ }
13001
+
12897
13002
  // Found text node that has a length
12898
13003
  if (node.nodeType === 3 && node.nodeValue.length > 0) {
12899
13004
  container = node;
@@ -12940,7 +13045,6 @@ define("tinymce/dom/RangeUtils", [
12940
13045
  if (directionLeft) {
12941
13046
  node = container.childNodes[offset > 0 ? offset - 1 : 0];
12942
13047
  if (node) {
12943
- nodeName = node.nodeName.toLowerCase();
12944
13048
  if (nonEmptyElementsMap[node.nodeName] || node.nodeName == "TABLE") {
12945
13049
  return;
12946
13050
  }
@@ -14342,6 +14446,160 @@ define("tinymce/dom/Selection", [
14342
14446
  return Selection;
14343
14447
  });
14344
14448
 
14449
+ // Included from: js/tinymce/classes/fmt/Preview.js
14450
+
14451
+ /**
14452
+ * Preview.js
14453
+ *
14454
+ * Copyright, Moxiecode Systems AB
14455
+ * Released under LGPL License.
14456
+ *
14457
+ * License: http://www.tinymce.com/license
14458
+ * Contributing: http://www.tinymce.com/contributing
14459
+ */
14460
+
14461
+ /**
14462
+ * Internal class for generating previews styles for formats.
14463
+ *
14464
+ * Example:
14465
+ * Preview.getCssText(editor, 'bold');
14466
+ *
14467
+ * @class tinymce.fmt.Preview
14468
+ * @private
14469
+ */
14470
+ define("tinymce/fmt/Preview", [
14471
+ "tinymce/util/Tools"
14472
+ ], function(Tools) {
14473
+ var each = Tools.each;
14474
+
14475
+ function getCssText(editor, format) {
14476
+ var name, previewElm, dom = editor.dom;
14477
+ var previewCss = '', parentFontSize, previewStyles;
14478
+
14479
+ previewStyles = editor.settings.preview_styles;
14480
+
14481
+ // No preview forced
14482
+ if (previewStyles === false) {
14483
+ return '';
14484
+ }
14485
+
14486
+ // Default preview
14487
+ if (!previewStyles) {
14488
+ previewStyles = 'font-family font-size font-weight font-style text-decoration ' +
14489
+ 'text-transform color background-color border border-radius outline text-shadow';
14490
+ }
14491
+
14492
+ // Removes any variables since these can't be previewed
14493
+ function removeVars(val) {
14494
+ return val.replace(/%(\w+)/g, '');
14495
+ }
14496
+
14497
+ // Create block/inline element to use for preview
14498
+ if (typeof(format) == "string") {
14499
+ format = editor.formatter.get(format);
14500
+ if (!format) {
14501
+ return;
14502
+ }
14503
+
14504
+ format = format[0];
14505
+ }
14506
+
14507
+ name = format.block || format.inline || 'span';
14508
+ previewElm = dom.create(name);
14509
+
14510
+ // Add format styles to preview element
14511
+ each(format.styles, function(value, name) {
14512
+ value = removeVars(value);
14513
+
14514
+ if (value) {
14515
+ dom.setStyle(previewElm, name, value);
14516
+ }
14517
+ });
14518
+
14519
+ // Add attributes to preview element
14520
+ each(format.attributes, function(value, name) {
14521
+ value = removeVars(value);
14522
+
14523
+ if (value) {
14524
+ dom.setAttrib(previewElm, name, value);
14525
+ }
14526
+ });
14527
+
14528
+ // Add classes to preview element
14529
+ each(format.classes, function(value) {
14530
+ value = removeVars(value);
14531
+
14532
+ if (!dom.hasClass(previewElm, value)) {
14533
+ dom.addClass(previewElm, value);
14534
+ }
14535
+ });
14536
+
14537
+ editor.fire('PreviewFormats');
14538
+
14539
+ // Add the previewElm outside the visual area
14540
+ dom.setStyles(previewElm, {position: 'absolute', left: -0xFFFF});
14541
+ editor.getBody().appendChild(previewElm);
14542
+
14543
+ // Get parent container font size so we can compute px values out of em/% for older IE:s
14544
+ parentFontSize = dom.getStyle(editor.getBody(), 'fontSize', true);
14545
+ parentFontSize = /px$/.test(parentFontSize) ? parseInt(parentFontSize, 10) : 0;
14546
+
14547
+ each(previewStyles.split(' '), function(name) {
14548
+ var value = dom.getStyle(previewElm, name, true);
14549
+
14550
+ // If background is transparent then check if the body has a background color we can use
14551
+ if (name == 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
14552
+ value = dom.getStyle(editor.getBody(), name, true);
14553
+
14554
+ // Ignore white since it's the default color, not the nicest fix
14555
+ // TODO: Fix this by detecting runtime style
14556
+ if (dom.toHex(value).toLowerCase() == '#ffffff') {
14557
+ return;
14558
+ }
14559
+ }
14560
+
14561
+ if (name == 'color') {
14562
+ // Ignore black since it's the default color, not the nicest fix
14563
+ // TODO: Fix this by detecting runtime style
14564
+ if (dom.toHex(value).toLowerCase() == '#000000') {
14565
+ return;
14566
+ }
14567
+ }
14568
+
14569
+ // Old IE won't calculate the font size so we need to do that manually
14570
+ if (name == 'font-size') {
14571
+ if (/em|%$/.test(value)) {
14572
+ if (parentFontSize === 0) {
14573
+ return;
14574
+ }
14575
+
14576
+ // Convert font size from em/% to px
14577
+ value = parseFloat(value, 10) / (/%$/.test(value) ? 100 : 1);
14578
+ value = (value * parentFontSize) + 'px';
14579
+ }
14580
+ }
14581
+
14582
+ if (name == "border" && value) {
14583
+ previewCss += 'padding:0 2px;';
14584
+ }
14585
+
14586
+ previewCss += name + ':' + value + ';';
14587
+ });
14588
+
14589
+ editor.fire('AfterPreviewFormats');
14590
+
14591
+ //previewCss += 'line-height:normal';
14592
+
14593
+ dom.remove(previewElm);
14594
+
14595
+ return previewCss;
14596
+ }
14597
+
14598
+ return {
14599
+ getCssText: getCssText
14600
+ };
14601
+ });
14602
+
14345
14603
  // Included from: js/tinymce/classes/Formatter.js
14346
14604
 
14347
14605
  /**
@@ -14371,8 +14629,9 @@ define("tinymce/dom/Selection", [
14371
14629
  define("tinymce/Formatter", [
14372
14630
  "tinymce/dom/TreeWalker",
14373
14631
  "tinymce/dom/RangeUtils",
14374
- "tinymce/util/Tools"
14375
- ], function(TreeWalker, RangeUtils, Tools) {
14632
+ "tinymce/util/Tools",
14633
+ "tinymce/fmt/Preview"
14634
+ ], function(TreeWalker, RangeUtils, Tools, Preview) {
14376
14635
  /**
14377
14636
  * Constructs a new formatter instance.
14378
14637
  *
@@ -14421,6 +14680,19 @@ define("tinymce/Formatter", [
14421
14680
 
14422
14681
  function defaultFormats() {
14423
14682
  register({
14683
+
14684
+ valigntop: [
14685
+ {selector: 'td,th', styles: {'verticalAlign': 'top'}}
14686
+ ],
14687
+
14688
+ valignmiddle: [
14689
+ {selector: 'td,th', styles: {'verticalAlign': 'middle'}}
14690
+ ],
14691
+
14692
+ valignbottom: [
14693
+ {selector: 'td,th', styles: {'verticalAlign': 'bottom'}}
14694
+ ],
14695
+
14424
14696
  alignleft: [
14425
14697
  {selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li', styles: {textAlign: 'left'}, defaultBlock: 'div'},
14426
14698
  {selector: 'img,table', collapsed: false, styles: {'float': 'left'}}
@@ -14635,6 +14907,16 @@ define("tinymce/Formatter", [
14635
14907
  dom.setStyle(elm, name, replaceVars(value, vars));
14636
14908
  });
14637
14909
 
14910
+ // Needed for the WebKit span spam bug
14911
+ // TODO: Remove this once WebKit/Blink fixes this
14912
+ if (fmt.styles) {
14913
+ var styleVal = dom.getAttrib(elm, 'style');
14914
+
14915
+ if (styleVal) {
14916
+ elm.setAttribute('data-mce-style', styleVal);
14917
+ }
14918
+ }
14919
+
14638
14920
  each(fmt.attributes, function(value, name) {
14639
14921
  dom.setAttrib(elm, name, replaceVars(value, vars));
14640
14922
  });
@@ -15537,6 +15819,20 @@ define("tinymce/Formatter", [
15537
15819
  return this;
15538
15820
  }
15539
15821
 
15822
+ /**
15823
+ * Returns a preview css text for the specified format.
15824
+ *
15825
+ * @method getCssText
15826
+ * @param {String/Object} format Format to generate preview css text for.
15827
+ * @return {String} Css text for the specified format.
15828
+ * @example
15829
+ * var cssText1 = editor.formatter.getCssText('bold');
15830
+ * var cssText2 = editor.formatter.getCssText({inline: 'b'});
15831
+ */
15832
+ function getCssText(format) {
15833
+ return Preview.getCssText(ed, format);
15834
+ }
15835
+
15540
15836
  // Expose to public
15541
15837
  extend(this, {
15542
15838
  get: get,
@@ -15548,7 +15844,8 @@ define("tinymce/Formatter", [
15548
15844
  matchAll: matchAll,
15549
15845
  matchNode: matchNode,
15550
15846
  canApply: canApply,
15551
- formatChanged: formatChanged
15847
+ formatChanged: formatChanged,
15848
+ getCssText: getCssText
15552
15849
  });
15553
15850
 
15554
15851
  // Initialize
@@ -16801,7 +17098,7 @@ define("tinymce/UndoManager", [
16801
17098
  ].join('|'), 'gi');
16802
17099
 
16803
17100
  return function(editor) {
16804
- var self = this, index = 0, data = [], beforeBookmark, isFirstTypedCharacter, lock;
17101
+ var self = this, index = 0, data = [], beforeBookmark, isFirstTypedCharacter, locks = 0;
16805
17102
 
16806
17103
  // Returns a trimmed version of the current editor contents
16807
17104
  function getContent() {
@@ -16841,7 +17138,7 @@ define("tinymce/UndoManager", [
16841
17138
  });
16842
17139
 
16843
17140
  editor.on('SaveContent ObjectResized blur', addNonTypingUndoLevel);
16844
- editor.dom.bind(editor.dom.getRoot(), 'dragend', addNonTypingUndoLevel);
17141
+ editor.on('DragEnd', addNonTypingUndoLevel);
16845
17142
 
16846
17143
  editor.on('KeyUp', function(e) {
16847
17144
  var keyCode = e.keyCode;
@@ -16929,7 +17226,7 @@ define("tinymce/UndoManager", [
16929
17226
  * @method beforeChange
16930
17227
  */
16931
17228
  beforeChange: function() {
16932
- if (!lock) {
17229
+ if (!locks) {
16933
17230
  beforeBookmark = editor.selection.getBookmark(2, true);
16934
17231
  }
16935
17232
  },
@@ -16948,16 +17245,16 @@ define("tinymce/UndoManager", [
16948
17245
  level = level || {};
16949
17246
  level.content = getContent();
16950
17247
 
16951
- if (lock || editor.removed) {
17248
+ if (locks || editor.removed) {
16952
17249
  return null;
16953
17250
  }
16954
17251
 
16955
- if (editor.fire('BeforeAddUndo', {level: level, originalEvent: event}).isDefaultPrevented()) {
17252
+ lastLevel = data[index];
17253
+ if (editor.fire('BeforeAddUndo', {level: level, lastLevel: lastLevel, originalEvent: event}).isDefaultPrevented()) {
16956
17254
  return null;
16957
17255
  }
16958
17256
 
16959
17257
  // Add undo level if needed
16960
- lastLevel = data[index];
16961
17258
  if (lastLevel && lastLevel.content == level.content) {
16962
17259
  return null;
16963
17260
  }
@@ -17099,9 +17396,12 @@ define("tinymce/UndoManager", [
17099
17396
  transact: function(callback) {
17100
17397
  self.beforeChange();
17101
17398
 
17102
- lock = true;
17103
- callback();
17104
- lock = false;
17399
+ try {
17400
+ locks++;
17401
+ callback();
17402
+ } finally {
17403
+ locks--;
17404
+ }
17105
17405
 
17106
17406
  self.add();
17107
17407
  }
@@ -18662,7 +18962,13 @@ define("tinymce/EditorCommands", [
18662
18962
  define("tinymce/util/URI", [
18663
18963
  "tinymce/util/Tools"
18664
18964
  ], function(Tools) {
18665
- var each = Tools.each, trim = Tools.trim;
18965
+ var each = Tools.each, trim = Tools.trim,
18966
+ DEFAULT_PORTS = {
18967
+ 'ftp': 21,
18968
+ 'http': 80,
18969
+ 'https': 443,
18970
+ 'mailto': 25
18971
+ };
18666
18972
 
18667
18973
  /**
18668
18974
  * Constructs a new URI instance.
@@ -18834,7 +19140,31 @@ define("tinymce/util/URI", [
18834
19140
  toAbsolute: function(uri, noHost) {
18835
19141
  uri = new URI(uri, {base_uri: this});
18836
19142
 
18837
- return uri.getURI(this.host == uri.host && this.protocol == uri.protocol ? noHost : 0);
19143
+ return uri.getURI(noHost && this.isSameOrigin(uri));
19144
+ },
19145
+
19146
+ /**
19147
+ * Determine whether the given URI has the same origin as this URI. Based on RFC-6454.
19148
+ * Supports default ports for protocols listed in DEFAULT_PORTS. Unsupported protocols will fail safe: they
19149
+ * won't match, if the port specifications differ.
19150
+ *
19151
+ * @method isSameOrigin
19152
+ * @param {tinymce.util.URI} uri Uri instance to compare.
19153
+ * @returns {Boolean} True if the origins are the same.
19154
+ */
19155
+ isSameOrigin: function(uri) {
19156
+ if (this.host == uri.host && this.protocol == uri.protocol){
19157
+ if (this.port == uri.port) {
19158
+ return true;
19159
+ }
19160
+
19161
+ var defaultPort = DEFAULT_PORTS[this.protocol];
19162
+ if (defaultPort && ((this.port || defaultPort) == (uri.port || defaultPort))) {
19163
+ return true;
19164
+ }
19165
+ }
19166
+
19167
+ return false;
18838
19168
  },
18839
19169
 
18840
19170
  /**
@@ -19092,6 +19422,8 @@ define("tinymce/util/Class", [
19092
19422
  // Instantiate a base class (but only create the instance,
19093
19423
  // don't run the init constructor)
19094
19424
  initializing = true;
19425
+
19426
+ /*eslint new-cap:0 */
19095
19427
  prototype = new self();
19096
19428
  initializing = false;
19097
19429
 
@@ -19178,6 +19510,269 @@ define("tinymce/util/Class", [
19178
19510
  return Class;
19179
19511
  });
19180
19512
 
19513
+ // Included from: js/tinymce/classes/util/EventDispatcher.js
19514
+
19515
+ /**
19516
+ * EventDispatcher.js
19517
+ *
19518
+ * Copyright, Moxiecode Systems AB
19519
+ * Released under LGPL License.
19520
+ *
19521
+ * License: http://www.tinymce.com/license
19522
+ * Contributing: http://www.tinymce.com/contributing
19523
+ */
19524
+
19525
+ /**
19526
+ * This class lets you add/remove and fire events by name on the specified scope. This makes
19527
+ * it easy to add event listener logic to any class.
19528
+ *
19529
+ * @class tinymce.util.EventDispatcher
19530
+ * @example
19531
+ * var eventDispatcher = new EventDispatcher();
19532
+ *
19533
+ * eventDispatcher.on('click', function() {console.log('data');});
19534
+ * eventDispatcher.fire('click', {data: 123});
19535
+ */
19536
+ define("tinymce/util/EventDispatcher", [
19537
+ "tinymce/util/Tools"
19538
+ ], function(Tools) {
19539
+ var nativeEvents = Tools.makeMap(
19540
+ "focus blur focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange " +
19541
+ "mouseout mouseenter mouseleave wheel keydown keypress keyup input contextmenu dragstart dragend dragover " +
19542
+ "draggesture dragdrop drop drag submit",
19543
+ ' '
19544
+ );
19545
+
19546
+ function Dispatcher(settings) {
19547
+ var self = this, scope, bindings = {}, toggleEvent;
19548
+
19549
+ function returnFalse() {
19550
+ return false;
19551
+ }
19552
+
19553
+ function returnTrue() {
19554
+ return true;
19555
+ }
19556
+
19557
+ settings = settings || {};
19558
+ scope = settings.scope || self;
19559
+ toggleEvent = settings.toggleEvent || returnFalse;
19560
+
19561
+ /**
19562
+ * Fires the specified event by name.
19563
+ *
19564
+ * @method fire
19565
+ * @param {String} name Name of the event to fire.
19566
+ * @param {Object?} args Event arguments.
19567
+ * @return {Object} Event args instance passed in.
19568
+ * @example
19569
+ * instance.fire('event', {...});
19570
+ */
19571
+ function fire(name, args) {
19572
+ var handlers, i, l, callback;
19573
+
19574
+ name = name.toLowerCase();
19575
+ args = args || {};
19576
+ args.type = name;
19577
+
19578
+ // Setup target is there isn't one
19579
+ if (!args.target) {
19580
+ args.target = scope;
19581
+ }
19582
+
19583
+ // Add event delegation methods if they are missing
19584
+ if (!args.preventDefault) {
19585
+ // Add preventDefault method
19586
+ args.preventDefault = function() {
19587
+ args.isDefaultPrevented = returnTrue;
19588
+ };
19589
+
19590
+ // Add stopPropagation
19591
+ args.stopPropagation = function() {
19592
+ args.isPropagationStopped = returnTrue;
19593
+ };
19594
+
19595
+ // Add stopImmediatePropagation
19596
+ args.stopImmediatePropagation = function() {
19597
+ args.isImmediatePropagationStopped = returnTrue;
19598
+ };
19599
+
19600
+ // Add event delegation states
19601
+ args.isDefaultPrevented = returnFalse;
19602
+ args.isPropagationStopped = returnFalse;
19603
+ args.isImmediatePropagationStopped = returnFalse;
19604
+ }
19605
+
19606
+ if (settings.beforeFire) {
19607
+ settings.beforeFire(args);
19608
+ }
19609
+
19610
+ handlers = bindings[name];
19611
+ if (handlers) {
19612
+ for (i = 0, l = handlers.length; i < l; i++) {
19613
+ handlers[i] = callback = handlers[i];
19614
+
19615
+ // Stop immediate propagation if needed
19616
+ if (args.isImmediatePropagationStopped()) {
19617
+ args.stopPropagation();
19618
+ return args;
19619
+ }
19620
+
19621
+ // If callback returns false then prevent default and stop all propagation
19622
+ if (callback.call(scope, args) === false) {
19623
+ args.preventDefault();
19624
+ return args;
19625
+ }
19626
+ }
19627
+ }
19628
+
19629
+ return args;
19630
+ }
19631
+
19632
+ /**
19633
+ * Binds an event listener to a specific event by name.
19634
+ *
19635
+ * @method on
19636
+ * @param {String} name Event name or space separated list of events to bind.
19637
+ * @param {callback} callback Callback to be executed when the event occurs.
19638
+ * @param {Boolean} first Optional flag if the event should be prepended. Use this with care.
19639
+ * @return {Object} Current class instance.
19640
+ * @example
19641
+ * instance.on('event', function(e) {
19642
+ * // Callback logic
19643
+ * });
19644
+ */
19645
+ function on(name, callback, prepend) {
19646
+ var handlers, names, i;
19647
+
19648
+ if (callback === false) {
19649
+ callback = returnFalse;
19650
+ }
19651
+
19652
+ if (callback) {
19653
+ names = name.toLowerCase().split(' ');
19654
+ i = names.length;
19655
+ while (i--) {
19656
+ name = names[i];
19657
+ handlers = bindings[name];
19658
+ if (!handlers) {
19659
+ handlers = bindings[name] = [];
19660
+ toggleEvent(name, true);
19661
+ }
19662
+
19663
+ if (prepend) {
19664
+ handlers.unshift(callback);
19665
+ } else {
19666
+ handlers.push(callback);
19667
+ }
19668
+ }
19669
+ }
19670
+
19671
+ return self;
19672
+ }
19673
+
19674
+ /**
19675
+ * Unbinds an event listener to a specific event by name.
19676
+ *
19677
+ * @method off
19678
+ * @param {String?} name Name of the event to unbind.
19679
+ * @param {callback?} callback Callback to unbind.
19680
+ * @return {Object} Current class instance.
19681
+ * @example
19682
+ * // Unbind specific callback
19683
+ * instance.off('event', handler);
19684
+ *
19685
+ * // Unbind all listeners by name
19686
+ * instance.off('event');
19687
+ *
19688
+ * // Unbind all events
19689
+ * instance.off();
19690
+ */
19691
+ function off(name, callback) {
19692
+ var i, handlers, bindingName, names, hi;
19693
+
19694
+ if (name) {
19695
+ names = name.toLowerCase().split(' ');
19696
+ i = names.length;
19697
+ while (i--) {
19698
+ name = names[i];
19699
+ handlers = bindings[name];
19700
+
19701
+ // Unbind all handlers
19702
+ if (!name) {
19703
+ for (bindingName in bindings) {
19704
+ toggleEvent(bindingName, false);
19705
+ delete bindings[bindingName];
19706
+ }
19707
+
19708
+ return self;
19709
+ }
19710
+
19711
+ if (handlers) {
19712
+ // Unbind all by name
19713
+ if (!callback) {
19714
+ handlers.length = 0;
19715
+ } else {
19716
+ // Unbind specific ones
19717
+ hi = handlers.length;
19718
+ while (hi--) {
19719
+ if (handlers[hi] === callback) {
19720
+ handlers.splice(hi, 1);
19721
+ }
19722
+ }
19723
+ }
19724
+
19725
+ if (!handlers.length) {
19726
+ toggleEvent(name, false);
19727
+ delete bindings[name];
19728
+ }
19729
+ }
19730
+ }
19731
+ } else {
19732
+ for (name in bindings) {
19733
+ toggleEvent(name, false);
19734
+ }
19735
+
19736
+ bindings = {};
19737
+ }
19738
+
19739
+ return self;
19740
+ }
19741
+
19742
+ /**
19743
+ * Returns true/false if the dispatcher has a event of the specified name.
19744
+ *
19745
+ * @method has
19746
+ * @param {String} name Name of the event to check for.
19747
+ * @return {Boolean} true/false if the event exists or not.
19748
+ */
19749
+ function has(name) {
19750
+ name = name.toLowerCase();
19751
+ return !(!bindings[name] || bindings[name].length === 0);
19752
+ }
19753
+
19754
+ // Expose
19755
+ self.fire = fire;
19756
+ self.on = on;
19757
+ self.off = off;
19758
+ self.has = has;
19759
+ }
19760
+
19761
+ /**
19762
+ * Returns true/false if the specified event name is a native browser event or not.
19763
+ *
19764
+ * @method isNative
19765
+ * @param {String} name Name to check if it's native.
19766
+ * @return {Boolean} true/false if the event is native or not.
19767
+ * @static
19768
+ */
19769
+ Dispatcher.isNative = function(name) {
19770
+ return !!nativeEvents[name.toLowerCase()];
19771
+ };
19772
+
19773
+ return Dispatcher;
19774
+ });
19775
+
19181
19776
  // Included from: js/tinymce/classes/ui/Selector.js
19182
19777
 
19183
19778
  /**
@@ -20104,21 +20699,44 @@ define("tinymce/ui/DomUtils", [
20104
20699
  define("tinymce/ui/Control", [
20105
20700
  "tinymce/util/Class",
20106
20701
  "tinymce/util/Tools",
20702
+ "tinymce/util/EventDispatcher",
20107
20703
  "tinymce/ui/Collection",
20108
20704
  "tinymce/ui/DomUtils"
20109
- ], function(Class, Tools, Collection, DomUtils) {
20705
+ ], function(Class, Tools, EventDispatcher, Collection, DomUtils) {
20110
20706
  "use strict";
20111
20707
 
20112
- var nativeEvents = Tools.makeMap("focusin focusout scroll click dblclick mousedown mouseup mousemove mouseover" +
20113
- " mouseout mouseenter mouseleave wheel keydown keypress keyup contextmenu", " ");
20114
-
20115
20708
  var elementIdCache = {};
20116
20709
  var hasMouseWheelEventSupport = "onmousewheel" in document;
20117
20710
  var hasWheelEventSupport = false;
20711
+ var classPrefix = "mce-";
20712
+
20713
+ function getEventDispatcher(obj) {
20714
+ if (!obj._eventDispatcher) {
20715
+ obj._eventDispatcher = new EventDispatcher({
20716
+ scope: obj,
20717
+ toggleEvent: function(name, state) {
20718
+ if (state && EventDispatcher.isNative(name)) {
20719
+ if (!obj._nativeEvents) {
20720
+ obj._nativeEvents = {};
20721
+ }
20722
+
20723
+ obj._nativeEvents[name] = true;
20724
+
20725
+ if (obj._rendered) {
20726
+ obj.bindPendingEvents();
20727
+ }
20728
+ }
20729
+ }
20730
+ });
20731
+ }
20732
+
20733
+ return obj._eventDispatcher;
20734
+ }
20118
20735
 
20119
20736
  var Control = Class.extend({
20120
20737
  Statics: {
20121
- elementIdCache: elementIdCache
20738
+ elementIdCache: elementIdCache,
20739
+ classPrefix: classPrefix
20122
20740
  },
20123
20741
 
20124
20742
  isRtl: function() {
@@ -20131,7 +20749,7 @@ define("tinymce/ui/Control", [
20131
20749
  * @final
20132
20750
  * @field {String} classPrefix
20133
20751
  */
20134
- classPrefix: "mce-",
20752
+ classPrefix: classPrefix,
20135
20753
 
20136
20754
  /**
20137
20755
  * Constructs a new control instance with the specified settings.
@@ -20588,14 +21206,18 @@ define("tinymce/ui/Control", [
20588
21206
  * @return {tinymce.ui.Control} Current control object.
20589
21207
  */
20590
21208
  on: function(name, callback) {
20591
- var self = this, bindings, handlers, names, i;
21209
+ var self = this;
20592
21210
 
20593
21211
  function resolveCallbackName(name) {
20594
21212
  var callback, scope;
20595
21213
 
21214
+ if (typeof(name) != 'string') {
21215
+ return name;
21216
+ }
21217
+
20596
21218
  return function(e) {
20597
21219
  if (!callback) {
20598
- self.parents().each(function(ctrl) {
21220
+ self.parentsAndSelf().each(function(ctrl) {
20599
21221
  var callbacks = ctrl.settings.callbacks;
20600
21222
 
20601
21223
  if (callbacks && (callback = callbacks[name])) {
@@ -20609,41 +21231,7 @@ define("tinymce/ui/Control", [
20609
21231
  };
20610
21232
  }
20611
21233
 
20612
- if (callback) {
20613
- if (typeof(callback) == 'string') {
20614
- callback = resolveCallbackName(callback);
20615
- }
20616
-
20617
- names = name.toLowerCase().split(' ');
20618
- i = names.length;
20619
- while (i--) {
20620
- name = names[i];
20621
-
20622
- bindings = self._bindings;
20623
- if (!bindings) {
20624
- bindings = self._bindings = {};
20625
- }
20626
-
20627
- handlers = bindings[name];
20628
- if (!handlers) {
20629
- handlers = bindings[name] = [];
20630
- }
20631
-
20632
- handlers.push(callback);
20633
-
20634
- if (nativeEvents[name]) {
20635
- if (!self._nativeEvents) {
20636
- self._nativeEvents = {name: true};
20637
- } else {
20638
- self._nativeEvents[name] = true;
20639
- }
20640
-
20641
- if (self._rendered) {
20642
- self.bindPendingEvents();
20643
- }
20644
- }
20645
- }
20646
- }
21234
+ getEventDispatcher(self).on(name, resolveCallbackName(callback));
20647
21235
 
20648
21236
  return self;
20649
21237
  },
@@ -20659,46 +21247,8 @@ define("tinymce/ui/Control", [
20659
21247
  * @return {mxex.ui.Control} Current control object.
20660
21248
  */
20661
21249
  off: function(name, callback) {
20662
- var self = this, i, bindings = self._bindings, handlers, bindingName, names, hi;
20663
-
20664
- if (bindings) {
20665
- if (name) {
20666
- names = name.toLowerCase().split(' ');
20667
- i = names.length;
20668
- while (i--) {
20669
- name = names[i];
20670
- handlers = bindings[name];
20671
-
20672
- // Unbind all handlers
20673
- if (!name) {
20674
- for (bindingName in bindings) {
20675
- bindings[bindingName].length = 0;
20676
- }
20677
-
20678
- return self;
20679
- }
20680
-
20681
- if (handlers) {
20682
- // Unbind all by name
20683
- if (!callback) {
20684
- handlers.length = 0;
20685
- } else {
20686
- // Unbind specific ones
20687
- hi = handlers.length;
20688
- while (hi--) {
20689
- if (handlers[hi] === callback) {
20690
- handlers.splice(hi, 1);
20691
- }
20692
- }
20693
- }
20694
- }
20695
- }
20696
- } else {
20697
- self._bindings = [];
20698
- }
20699
- }
20700
-
20701
- return self;
21250
+ getEventDispatcher(this).off(name, callback);
21251
+ return this;
20702
21252
  },
20703
21253
 
20704
21254
  /**
@@ -20712,75 +21262,22 @@ define("tinymce/ui/Control", [
20712
21262
  * @return {Object} Current arguments object.
20713
21263
  */
20714
21264
  fire: function(name, args, bubble) {
20715
- var self = this, i, l, handlers, parentCtrl;
20716
-
20717
- name = name.toLowerCase();
20718
-
20719
- // Dummy function that gets replaced on the delegation state functions
20720
- function returnFalse() {
20721
- return false;
20722
- }
20723
-
20724
- // Dummy function that gets replaced on the delegation state functions
20725
- function returnTrue() {
20726
- return true;
20727
- }
21265
+ var self = this;
20728
21266
 
20729
- // Setup empty object if args is omited
20730
21267
  args = args || {};
20731
21268
 
20732
- // Stick type into event object
20733
- if (!args.type) {
20734
- args.type = name;
20735
- }
20736
-
20737
- // Stick control into event
20738
21269
  if (!args.control) {
20739
21270
  args.control = self;
20740
21271
  }
20741
21272
 
20742
- // Add event delegation methods if they are missing
20743
- if (!args.preventDefault) {
20744
- // Add preventDefault method
20745
- args.preventDefault = function() {
20746
- args.isDefaultPrevented = returnTrue;
20747
- };
21273
+ args = getEventDispatcher(self).fire(name, args);
20748
21274
 
20749
- // Add stopPropagation
20750
- args.stopPropagation = function() {
20751
- args.isPropagationStopped = returnTrue;
20752
- };
20753
-
20754
- // Add stopImmediatePropagation
20755
- args.stopImmediatePropagation = function() {
20756
- args.isImmediatePropagationStopped = returnTrue;
20757
- };
20758
-
20759
- // Add event delegation states
20760
- args.isDefaultPrevented = returnFalse;
20761
- args.isPropagationStopped = returnFalse;
20762
- args.isImmediatePropagationStopped = returnFalse;
20763
- }
20764
-
20765
- if (self._bindings) {
20766
- handlers = self._bindings[name];
20767
-
20768
- if (handlers) {
20769
- for (i = 0, l = handlers.length; i < l; i++) {
20770
- // Execute callback and break if the callback returns a false
20771
- if (!args.isImmediatePropagationStopped() && handlers[i].call(self, args) === false) {
20772
- break;
20773
- }
20774
- }
20775
- }
20776
- }
20777
-
20778
- // Bubble event up to parent controls
20779
- if (bubble !== false) {
20780
- parentCtrl = self.parent();
20781
- while (parentCtrl && !args.isPropagationStopped()) {
20782
- parentCtrl.fire(name, args, false);
20783
- parentCtrl = parentCtrl.parent();
21275
+ // Bubble event up to parents
21276
+ if (bubble !== false && self.parent) {
21277
+ var parent = self.parent();
21278
+ while (parent && !args.isPropagationStopped()) {
21279
+ parent.fire(name, args, false);
21280
+ parent = parent.parent();
20784
21281
  }
20785
21282
  }
20786
21283
 
@@ -20795,7 +21292,7 @@ define("tinymce/ui/Control", [
20795
21292
  * @return {Boolean} True/false state if the event has listeners.
20796
21293
  */
20797
21294
  hasEventListeners: function(name) {
20798
- return name in this._bindings;
21295
+ return getEventDispatcher(this).has(name);
20799
21296
  },
20800
21297
 
20801
21298
  /**
@@ -20821,6 +21318,17 @@ define("tinymce/ui/Control", [
20821
21318
  return parents;
20822
21319
  },
20823
21320
 
21321
+ /**
21322
+ * Returns the current control and it's parents.
21323
+ *
21324
+ * @method parentsAndSelf
21325
+ * @param {String} selector Optional selector expression to find parents.
21326
+ * @return {tinymce.ui.Collection} Collection with all parent controls.
21327
+ */
21328
+ parentsAndSelf: function(selector) {
21329
+ return new Collection(this).add(this.parents(selector));
21330
+ },
21331
+
20824
21332
  /**
20825
21333
  * Returns the control next to the current control.
20826
21334
  *
@@ -21137,8 +21645,8 @@ define("tinymce/ui/Control", [
21137
21645
  * @return {String} Encoded and possible traslated string.
21138
21646
  */
21139
21647
  encode: function(text, translate) {
21140
- if (translate !== false && Control.translate) {
21141
- text = Control.translate(text);
21648
+ if (translate !== false) {
21649
+ text = this.translate(text);
21142
21650
  }
21143
21651
 
21144
21652
  return (text || '').replace(/[&<>"]/g, function(match) {
@@ -21146,6 +21654,17 @@ define("tinymce/ui/Control", [
21146
21654
  });
21147
21655
  },
21148
21656
 
21657
+ /**
21658
+ * Returns the translated string.
21659
+ *
21660
+ * @method translate
21661
+ * @param {String} text Text to translate.
21662
+ * @return {String} Translated string or the same as the input.
21663
+ */
21664
+ translate: function(text) {
21665
+ return Control.translate ? Control.translate(text) : text;
21666
+ },
21667
+
21149
21668
  /**
21150
21669
  * Adds items before the current control.
21151
21670
  *
@@ -21489,6 +22008,11 @@ define("tinymce/ui/Control", [
21489
22008
  parents[i]._eventsRoot = eventRootCtrl;
21490
22009
  }
21491
22010
 
22011
+ var eventRootDelegates = eventRootCtrl._delegates;
22012
+ if (!eventRootDelegates) {
22013
+ eventRootDelegates = eventRootCtrl._delegates = {};
22014
+ }
22015
+
21492
22016
  // Bind native event delegates
21493
22017
  for (name in nativeEvents) {
21494
22018
  if (!nativeEvents) {
@@ -21513,9 +22037,9 @@ define("tinymce/ui/Control", [
21513
22037
  DomUtils.on(eventRootCtrl.getEl(), "mouseover", mouseEnterHandler);
21514
22038
  eventRootCtrl._hasMouseEnter = 1;
21515
22039
  }
21516
- } else if (!eventRootCtrl[name]) {
22040
+ } else if (!eventRootDelegates[name]) {
21517
22041
  DomUtils.on(eventRootCtrl.getEl(), name, delegate);
21518
- eventRootCtrl[name] = true;
22042
+ eventRootDelegates[name] = true;
21519
22043
  }
21520
22044
 
21521
22045
  // Remove the event once it's bound
@@ -21839,9 +22363,11 @@ define("tinymce/ui/KeyboardNavigation", [
21839
22363
  * @return {Boolean} True/false if the element is a text element or not.
21840
22364
  */
21841
22365
  function isTextInputElement(elm) {
22366
+ var tagName = elm.tagName.toUpperCase();
22367
+
21842
22368
  // Notice: since type can be "email" etc we don't check the type
21843
22369
  // So all input elements gets treated as text input elements
21844
- return elm.tagName == "INPUT" || elm.tagName == "TEXTAREA";
22370
+ return tagName == "INPUT" || tagName == "TEXTAREA";
21845
22371
  }
21846
22372
 
21847
22373
  /**
@@ -22083,7 +22609,7 @@ define("tinymce/ui/KeyboardNavigation", [
22083
22609
  }
22084
22610
 
22085
22611
  root.on('keydown', function(e) {
22086
- function handleNonTabEvent(e, handler) {
22612
+ function handleNonTabOrEscEvent(e, handler) {
22087
22613
  // Ignore non tab keys for text elements
22088
22614
  if (isTextInputElement(focusedElement)) {
22089
22615
  return;
@@ -22100,29 +22626,29 @@ define("tinymce/ui/KeyboardNavigation", [
22100
22626
 
22101
22627
  switch (e.keyCode) {
22102
22628
  case 37: // DOM_VK_LEFT
22103
- handleNonTabEvent(e, left);
22629
+ handleNonTabOrEscEvent(e, left);
22104
22630
  break;
22105
22631
 
22106
22632
  case 39: // DOM_VK_RIGHT
22107
- handleNonTabEvent(e, right);
22633
+ handleNonTabOrEscEvent(e, right);
22108
22634
  break;
22109
22635
 
22110
22636
  case 38: // DOM_VK_UP
22111
- handleNonTabEvent(e, up);
22637
+ handleNonTabOrEscEvent(e, up);
22112
22638
  break;
22113
22639
 
22114
22640
  case 40: // DOM_VK_DOWN
22115
- handleNonTabEvent(e, down);
22641
+ handleNonTabOrEscEvent(e, down);
22116
22642
  break;
22117
22643
 
22118
22644
  case 27: // DOM_VK_ESCAPE
22119
- handleNonTabEvent(e, cancel);
22645
+ cancel();
22120
22646
  break;
22121
22647
 
22122
22648
  case 14: // DOM_VK_ENTER
22123
22649
  case 13: // DOM_VK_RETURN
22124
22650
  case 32: // DOM_VK_SPACE
22125
- handleNonTabEvent(e, enter);
22651
+ handleNonTabOrEscEvent(e, enter);
22126
22652
  break;
22127
22653
 
22128
22654
  case 9: // DOM_VK_TAB
@@ -22994,7 +23520,7 @@ define("tinymce/ui/Panel", [
22994
23520
  }
22995
23521
 
22996
23522
  return (
22997
- '<div id="' + self._id + '" class="' + self.classes() + '" hideFocus="1" tabIndex="-1" role="group">' +
23523
+ '<div id="' + self._id + '" class="' + self.classes() + '" hidefocus="1" tabindex="-1" role="group">' +
22998
23524
  (self._preBodyHtml || '') +
22999
23525
  innerHtml +
23000
23526
  '</div>'
@@ -23848,7 +24374,7 @@ define("tinymce/ui/Window", [
23848
24374
  headerHtml = (
23849
24375
  '<div id="' + id + '-head" class="' + prefix + 'window-head">' +
23850
24376
  '<div id="' + id + '-title" class="' + prefix + 'title">' + self.encode(settings.title) + '</div>' +
23851
- '<button type="button" class="' + prefix + 'close" aria-hidden="true">&times;</button>' +
24377
+ '<button type="button" class="' + prefix + 'close" aria-hidden="true">\u00d7</button>' +
23852
24378
  '<div id="' + id + '-dragh" class="' + prefix + 'dragh"></div>' +
23853
24379
  '</div>'
23854
24380
  );
@@ -23867,7 +24393,7 @@ define("tinymce/ui/Window", [
23867
24393
  }
23868
24394
 
23869
24395
  return (
23870
- '<div id="' + id + '" class="' + self.classes() + '" hideFocus="1">' +
24396
+ '<div id="' + id + '" class="' + self.classes() + '" hidefocus="1">' +
23871
24397
  '<div class="' + self.classPrefix + 'reset" role="application">' +
23872
24398
  headerHtml +
23873
24399
  '<div id="' + id + '-body" class="' + self.classes('body') + '">' +
@@ -24016,6 +24542,17 @@ define("tinymce/ui/Window", [
24016
24542
  DomUtils.removeClass(document.documentElement, prefix + 'fullscreen');
24017
24543
  DomUtils.removeClass(document.body, prefix + 'fullscreen');
24018
24544
  }
24545
+ },
24546
+
24547
+ /**
24548
+ * Returns the contentWindow object of the iframe if it exists.
24549
+ *
24550
+ * @method getContentWindow
24551
+ * @return {Window} window object or null.
24552
+ */
24553
+ getContentWindow: function() {
24554
+ var ifr = this.getEl().getElementsByTagName('iframe')[0];
24555
+ return ifr ? ifr.contentWindow : null;
24019
24556
  }
24020
24557
  });
24021
24558
 
@@ -24324,7 +24861,6 @@ define("tinymce/WindowManager", [
24324
24861
  args.buttons = [
24325
24862
  {text: 'Ok', subtype: 'primary', onclick: function() {
24326
24863
  win.find('form')[0].submit();
24327
- win.close();
24328
24864
  }},
24329
24865
 
24330
24866
  {text: 'Cancel', onclick: function() {
@@ -24368,7 +24904,7 @@ define("tinymce/WindowManager", [
24368
24904
  // Takes a snapshot in the FocusManager of the selection before focus is lost to dialog
24369
24905
  editor.nodeChanged();
24370
24906
 
24371
- return win.renderTo(document.body).reflow();
24907
+ return win.renderTo().reflow();
24372
24908
  };
24373
24909
 
24374
24910
  /**
@@ -24452,6 +24988,16 @@ define("tinymce/WindowManager", [
24452
24988
  getTopMostWindow().params = params;
24453
24989
  }
24454
24990
  };
24991
+
24992
+ /**
24993
+ * Returns the currently opened window objects.
24994
+ *
24995
+ * @method getWindows
24996
+ * @return {Array} Array of the currently opened windows.
24997
+ */
24998
+ self.getWindows = function() {
24999
+ return windows;
25000
+ };
24455
25001
  };
24456
25002
  });
24457
25003
 
@@ -24548,9 +25094,45 @@ define("tinymce/util/Quirks", [
24548
25094
  */
24549
25095
  function cleanupStylesWhenDeleting() {
24550
25096
  var doc = editor.getDoc(), urlPrefix = 'data:text/mce-internal,';
25097
+ var MutationObserver = window.MutationObserver, olderWebKit, dragStartRng;
24551
25098
 
24552
- if (!window.MutationObserver) {
24553
- return;
25099
+ // Add mini polyfill for older WebKits
25100
+ // TODO: Remove this when old Safari versions gets updated
25101
+ if (!MutationObserver) {
25102
+ olderWebKit = true;
25103
+
25104
+ MutationObserver = function() {
25105
+ var records = [], target;
25106
+
25107
+ function nodeInsert(e) {
25108
+ var target = e.relatedNode || e.target;
25109
+ records.push({target: target, addedNodes: [target]});
25110
+ }
25111
+
25112
+ function attrModified(e) {
25113
+ var target = e.relatedNode || e.target;
25114
+ records.push({target: target, attributeName: e.attrName});
25115
+ }
25116
+
25117
+ this.observe = function(node) {
25118
+ target = node;
25119
+ target.addEventListener('DOMSubtreeModified', nodeInsert, false);
25120
+ target.addEventListener('DOMNodeInsertedIntoDocument', nodeInsert, false);
25121
+ target.addEventListener('DOMNodeInserted', nodeInsert, false);
25122
+ target.addEventListener('DOMAttrModified', attrModified, false);
25123
+ };
25124
+
25125
+ this.disconnect = function() {
25126
+ target.removeEventListener('DOMSubtreeModified', nodeInsert, false);
25127
+ target.removeEventListener('DOMNodeInsertedIntoDocument', nodeInsert, false);
25128
+ target.removeEventListener('DOMNodeInserted', nodeInsert, false);
25129
+ target.removeEventListener('DOMAttrModified', attrModified, false);
25130
+ };
25131
+
25132
+ this.takeRecords = function() {
25133
+ return records;
25134
+ };
25135
+ };
24554
25136
  }
24555
25137
 
24556
25138
  function customDelete(isForward) {
@@ -24582,6 +25164,10 @@ define("tinymce/util/Quirks", [
24582
25164
  var caretElement = rng.startContainer.parentNode;
24583
25165
 
24584
25166
  Tools.each(mutationObserver.takeRecords(), function(record) {
25167
+ if (!dom.isChildOf(record.target, editor.getBody())) {
25168
+ return;
25169
+ }
25170
+
24585
25171
  // Restore style attribute to previous value
24586
25172
  if (record.attributeName == "style") {
24587
25173
  var oldValue = record.target.getAttribute('data-mce-style');
@@ -24661,9 +25247,25 @@ define("tinymce/util/Quirks", [
24661
25247
  customDelete(true);
24662
25248
  });
24663
25249
 
25250
+ // Older WebKits doesn't properly handle the clipboard so we can't add the rest
25251
+ if (olderWebKit) {
25252
+ return;
25253
+ }
25254
+
24664
25255
  editor.on('dragstart', function(e) {
25256
+ var selectionHtml;
25257
+
25258
+ if (editor.selection.isCollapsed() && e.target.tagName == 'IMG') {
25259
+ selection.select(e.target);
25260
+ }
25261
+
25262
+ dragStartRng = selection.getRng();
25263
+ selectionHtml = editor.selection.getContent();
25264
+
24665
25265
  // Safari doesn't support custom dataTransfer items so we can only use URL and Text
24666
- e.dataTransfer.setData('URL', 'data:text/mce-internal,' + escape(editor.selection.getContent()));
25266
+ if (selectionHtml.length > 0) {
25267
+ e.dataTransfer.setData('URL', 'data:text/mce-internal,' + escape(selectionHtml));
25268
+ }
24667
25269
  });
24668
25270
 
24669
25271
  editor.on('drop', function(e) {
@@ -24677,10 +25279,26 @@ define("tinymce/util/Quirks", [
24677
25279
  internalContent = unescape(internalContent.substr(urlPrefix.length));
24678
25280
  if (doc.caretRangeFromPoint) {
24679
25281
  e.preventDefault();
24680
- customDelete();
24681
- editor.selection.setRng(doc.caretRangeFromPoint(e.x, e.y));
24682
- editor.insertContent(internalContent);
25282
+
25283
+ // Safari has a weird issue where drag/dropping images sometimes
25284
+ // produces a green plus icon. When this happens the caretRangeFromPoint
25285
+ // will return "null" even though the x, y coordinate is correct.
25286
+ // But if we detach the insert from the drop event we will get a proper range
25287
+ window.setTimeout(function() {
25288
+ var pointRng = doc.caretRangeFromPoint(e.x, e.y);
25289
+
25290
+ if (dragStartRng) {
25291
+ selection.setRng(dragStartRng);
25292
+ dragStartRng = null;
25293
+ }
25294
+
25295
+ customDelete();
25296
+
25297
+ selection.setRng(pointRng);
25298
+ editor.insertContent(internalContent);
25299
+ }, 0);
24683
25300
  }
25301
+
24684
25302
  }
24685
25303
  });
24686
25304
 
@@ -24961,6 +25579,10 @@ define("tinymce/util/Quirks", [
24961
25579
  }
24962
25580
 
24963
25581
  selectionTimer = window.setTimeout(function() {
25582
+ if (editor.removed) {
25583
+ return;
25584
+ }
25585
+
24964
25586
  var rng = selection.getRng();
24965
25587
 
24966
25588
  // Compare the ranges to see if it was a real change or not
@@ -25373,16 +25995,16 @@ define("tinymce/util/Quirks", [
25373
25995
  }
25374
25996
 
25375
25997
  /**
25376
- * Fixes selection issues on Gecko where the caret can be placed between two inline elements like <b>a</b>|<b>b</b>
25998
+ * Fixes selection issues where the caret can be placed between two inline elements like <b>a</b>|<b>b</b>
25377
25999
  * this fix will lean the caret right into the closest inline element.
25378
26000
  */
25379
26001
  function normalizeSelection() {
25380
26002
  // Normalize selection for example <b>a</b><i>|a</i> becomes <b>a|</b><i>a</i> except for Ctrl+A since it selects everything
25381
- editor.on('keyup focusin', function(e) {
26003
+ editor.on('keyup focusin mouseup', function(e) {
25382
26004
  if (e.keyCode != 65 || !VK.metaKeyPressed(e)) {
25383
26005
  selection.normalize();
25384
26006
  }
25385
- });
26007
+ }, true);
25386
26008
  }
25387
26009
 
25388
26010
  /**
@@ -25470,7 +26092,7 @@ define("tinymce/util/Quirks", [
25470
26092
  */
25471
26093
  function doubleTrailingBrElements() {
25472
26094
  if (!editor.inline) {
25473
- editor.on('focus blur', function() {
26095
+ editor.on('focus blur beforegetcontent', function() {
25474
26096
  var br = editor.dom.create('br');
25475
26097
  editor.getBody().appendChild(br);
25476
26098
  br.parentNode.removeChild(br);
@@ -25478,6 +26100,38 @@ define("tinymce/util/Quirks", [
25478
26100
  }
25479
26101
  }
25480
26102
 
26103
+ /**
26104
+ * iOS 7.1 introduced two new bugs:
26105
+ * 1) It's possible to open links within a contentEditable area by clicking on them.
26106
+ * 2) If you hold down the finger it will display the link/image touch callout menu.
26107
+ */
26108
+ function tapLinksAndImages() {
26109
+ editor.on('click', function(e) {
26110
+ var elm = e.target;
26111
+
26112
+ do {
26113
+ if (elm.tagName === 'A') {
26114
+ e.preventDefault();
26115
+ return;
26116
+ }
26117
+ } while ((elm = elm.parentNode));
26118
+ });
26119
+
26120
+ editor.contentStyles.push('.mce-content-body {-webkit-touch-callout: none}');
26121
+ }
26122
+
26123
+ /**
26124
+ * WebKit has a bug where it will allow forms to be submitted if they are inside a contentEditable element.
26125
+ * For example this: <form><button></form>
26126
+ */
26127
+ function blockFormSubmitInsideEditor() {
26128
+ editor.on('init', function() {
26129
+ editor.dom.bind(editor.getBody(), 'submit', function(e) {
26130
+ e.preventDefault();
26131
+ });
26132
+ });
26133
+ }
26134
+
25481
26135
  // All browsers
25482
26136
  disableBackspaceIntoATable();
25483
26137
  removeBlockQuoteOnBackSpace();
@@ -25490,12 +26144,14 @@ define("tinymce/util/Quirks", [
25490
26144
  inputMethodFocus();
25491
26145
  selectControlElements();
25492
26146
  setDefaultBlockType();
26147
+ blockFormSubmitInsideEditor();
25493
26148
 
25494
26149
  // iOS
25495
26150
  if (Env.iOS) {
25496
26151
  selectionChangeNodeChanged();
25497
26152
  restoreFocusOnKeyDown();
25498
26153
  bodyHeight();
26154
+ tapLinksAndImages();
25499
26155
  } else {
25500
26156
  selectAll();
25501
26157
  }
@@ -25555,20 +26211,21 @@ define("tinymce/util/Quirks", [
25555
26211
  * @mixin tinymce.util.Observable
25556
26212
  */
25557
26213
  define("tinymce/util/Observable", [
25558
- "tinymce/util/Tools"
25559
- ], function(Tools) {
25560
- var bindingsName = "__bindings";
25561
- var nativeEvents = Tools.makeMap(
25562
- "focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange" +
25563
- " mouseout mouseenter mouseleave keydown keypress keyup contextmenu dragstart dragend dragover draggesture dragdrop drop drag", ' '
25564
- );
25565
-
25566
- function returnFalse() {
25567
- return false;
25568
- }
26214
+ "tinymce/util/EventDispatcher"
26215
+ ], function(EventDispatcher) {
26216
+ function getEventDispatcher(obj) {
26217
+ if (!obj._eventDispatcher) {
26218
+ obj._eventDispatcher = new EventDispatcher({
26219
+ scope: obj,
26220
+ toggleEvent: function(name, state) {
26221
+ if (EventDispatcher.isNative(name) && obj.toggleNativeEvent) {
26222
+ obj.toggleNativeEvent(name, state);
26223
+ }
26224
+ }
26225
+ });
26226
+ }
25569
26227
 
25570
- function returnTrue() {
25571
- return true;
26228
+ return obj._eventDispatcher;
25572
26229
  }
25573
26230
 
25574
26231
  return {
@@ -25577,77 +26234,25 @@ define("tinymce/util/Observable", [
25577
26234
  *
25578
26235
  * @method fire
25579
26236
  * @param {String} name Name of the event to fire.
25580
- * @param {tinymce.Event/Object?} args Event arguments.
26237
+ * @param {Object?} args Event arguments.
25581
26238
  * @param {Boolean?} bubble True/false if the event is to be bubbled.
25582
- * @return {tinymce.Event} Event instance passed in converted into tinymce.Event instance.
26239
+ * @return {Object} Event args instance passed in.
25583
26240
  * @example
25584
26241
  * instance.fire('event', {...});
25585
26242
  */
25586
26243
  fire: function(name, args, bubble) {
25587
- var self = this, handlers, i, l, callback, parent;
25588
-
25589
- if (self.removed) {
25590
- return;
25591
- }
25592
-
25593
- name = name.toLowerCase();
25594
- args = args || {};
25595
- args.type = name;
25596
-
25597
- // Setup target is there isn't one
25598
- if (!args.target) {
25599
- args.target = self;
25600
- }
25601
-
25602
- // Add event delegation methods if they are missing
25603
- if (!args.preventDefault) {
25604
- // Add preventDefault method
25605
- args.preventDefault = function() {
25606
- args.isDefaultPrevented = returnTrue;
25607
- };
25608
-
25609
- // Add stopPropagation
25610
- args.stopPropagation = function() {
25611
- args.isPropagationStopped = returnTrue;
25612
- };
25613
-
25614
- // Add stopImmediatePropagation
25615
- args.stopImmediatePropagation = function() {
25616
- args.isImmediatePropagationStopped = returnTrue;
25617
- };
26244
+ var self = this;
25618
26245
 
25619
- // Add event delegation states
25620
- args.isDefaultPrevented = returnFalse;
25621
- args.isPropagationStopped = returnFalse;
25622
- args.isImmediatePropagationStopped = returnFalse;
26246
+ // Prevent all events except the remove event after the instance has been removed
26247
+ if (self.removed && name !== "remove") {
26248
+ return args;
25623
26249
  }
25624
26250
 
25625
- //console.log(name, args);
25626
-
25627
- if (self[bindingsName]) {
25628
- handlers = self[bindingsName][name];
25629
-
25630
- if (handlers) {
25631
- for (i = 0, l = handlers.length; i < l; i++) {
25632
- handlers[i] = callback = handlers[i];
25633
-
25634
- // Stop immediate propagation if needed
25635
- if (args.isImmediatePropagationStopped()) {
25636
- break;
25637
- }
25638
-
25639
- // If callback returns false then prevent default and stop all propagation
25640
- if (callback.call(self, args) === false) {
25641
- args.preventDefault();
25642
- return args;
25643
- }
25644
- }
25645
- }
25646
- }
26251
+ args = getEventDispatcher(self).fire(name, args, bubble);
25647
26252
 
25648
26253
  // Bubble event up to parents
25649
26254
  if (bubble !== false && self.parent) {
25650
- parent = self.parent();
26255
+ var parent = self.parent();
25651
26256
  while (parent && !args.isPropagationStopped()) {
25652
26257
  parent.fire(name, args, false);
25653
26258
  parent = parent.parent();
@@ -25671,42 +26276,7 @@ define("tinymce/util/Observable", [
25671
26276
  * });
25672
26277
  */
25673
26278
  on: function(name, callback, prepend) {
25674
- var self = this, bindings, handlers, names, i;
25675
-
25676
- if (callback === false) {
25677
- callback = function() {
25678
- return false;
25679
- };
25680
- }
25681
-
25682
- if (callback) {
25683
- names = name.toLowerCase().split(' ');
25684
- i = names.length;
25685
- while (i--) {
25686
- name = names[i];
25687
-
25688
- bindings = self[bindingsName];
25689
- if (!bindings) {
25690
- bindings = self[bindingsName] = {};
25691
- }
25692
-
25693
- handlers = bindings[name];
25694
- if (!handlers) {
25695
- handlers = bindings[name] = [];
25696
- if (self.bindNative && nativeEvents[name]) {
25697
- self.bindNative(name);
25698
- }
25699
- }
25700
-
25701
- if (prepend) {
25702
- handlers.unshift(callback);
25703
- } else {
25704
- handlers.push(callback);
25705
- }
25706
- }
25707
- }
25708
-
25709
- return self;
26279
+ return getEventDispatcher(this).on(name, callback, prepend);
25710
26280
  },
25711
26281
 
25712
26282
  /**
@@ -25727,67 +26297,150 @@ define("tinymce/util/Observable", [
25727
26297
  * instance.off();
25728
26298
  */
25729
26299
  off: function(name, callback) {
25730
- var self = this, i, bindings = self[bindingsName], handlers, bindingName, names, hi;
26300
+ return getEventDispatcher(this).off(name, callback);
26301
+ },
25731
26302
 
25732
- if (bindings) {
25733
- if (name) {
25734
- names = name.toLowerCase().split(' ');
25735
- i = names.length;
25736
- while (i--) {
25737
- name = names[i];
25738
- handlers = bindings[name];
26303
+ /**
26304
+ * Returns true/false if the object has a event of the specified name.
26305
+ *
26306
+ * @method hasEventListeners
26307
+ * @param {String} name Name of the event to check for.
26308
+ * @return {Boolean} true/false if the event exists or not.
26309
+ */
26310
+ hasEventListeners: function(name) {
26311
+ return getEventDispatcher(this).has(name);
26312
+ }
26313
+ };
26314
+ });
25739
26315
 
25740
- // Unbind all handlers
25741
- if (!name) {
25742
- for (bindingName in bindings) {
25743
- bindings[name].length = 0;
25744
- }
26316
+ // Included from: js/tinymce/classes/EditorObservable.js
25745
26317
 
25746
- return self;
25747
- }
26318
+ /**
26319
+ * EditorObservable.js
26320
+ *
26321
+ * Copyright, Moxiecode Systems AB
26322
+ * Released under LGPL License.
26323
+ *
26324
+ * License: http://www.tinymce.com/license
26325
+ * Contributing: http://www.tinymce.com/contributing
26326
+ */
25748
26327
 
25749
- if (handlers) {
25750
- // Unbind all by name
25751
- if (!callback) {
25752
- handlers.length = 0;
25753
- } else {
25754
- // Unbind specific ones
25755
- hi = handlers.length;
25756
- while (hi--) {
25757
- if (handlers[hi] === callback) {
25758
- handlers.splice(hi, 1);
25759
- }
25760
- }
25761
- }
26328
+ /**
26329
+ * This mixin contains the event logic for the tinymce.Editor class.
26330
+ *
26331
+ * @mixin tinymce.EditorObservable
26332
+ * @extends tinymce.util.Observable
26333
+ */
26334
+ define("tinymce/EditorObservable", [
26335
+ "tinymce/util/Observable",
26336
+ "tinymce/dom/DOMUtils",
26337
+ "tinymce/util/Tools"
26338
+ ], function(Observable, DOMUtils, Tools) {
26339
+ var DOM = DOMUtils.DOM;
25762
26340
 
25763
- if (!handlers.length && self.unbindNative && nativeEvents[name]) {
25764
- self.unbindNative(name);
25765
- delete bindings[name];
25766
- }
25767
- }
26341
+ function getEventTarget(editor, eventName) {
26342
+ if (eventName == 'selectionchange') {
26343
+ return editor.getDoc();
26344
+ }
26345
+
26346
+ // Need to bind mousedown/mouseup etc to document not body in iframe mode
26347
+ // Since the user might click on the HTML element not the BODY
26348
+ if (!editor.inline && /^mouse|click|contextmenu|drop/.test(eventName)) {
26349
+ return editor.getDoc();
26350
+ }
26351
+
26352
+ return editor.getBody();
26353
+ }
26354
+
26355
+ function bindEventDelegate(editor, name) {
26356
+ var eventRootSelector = editor.settings.event_root, editorManager = editor.editorManager;
26357
+ var eventRootElm = editorManager.eventRootElm || getEventTarget(editor, name);
26358
+
26359
+ if (eventRootSelector) {
26360
+ if (!editorManager.rootEvents) {
26361
+ editorManager.rootEvents = {};
26362
+
26363
+ editorManager.on('RemoveEditor', function() {
26364
+ if (!editorManager.activeEditor) {
26365
+ DOM.unbind(eventRootElm);
26366
+ delete editorManager.rootEvents;
25768
26367
  }
25769
- } else {
25770
- if (self.unbindNative) {
25771
- for (name in bindings) {
25772
- self.unbindNative(name);
26368
+ });
26369
+ }
26370
+
26371
+ if (editorManager.rootEvents[name]) {
26372
+ return;
26373
+ }
26374
+
26375
+ if (eventRootElm == editor.getBody()) {
26376
+ eventRootElm = DOM.select(eventRootSelector)[0];
26377
+ editorManager.eventRootElm = eventRootElm;
26378
+ }
26379
+
26380
+ editorManager.rootEvents[name] = true;
26381
+
26382
+ DOM.bind(eventRootElm, name, function(e) {
26383
+ var target = e.target, editors = editorManager.editors, i = editors.length;
26384
+
26385
+ while (i--) {
26386
+ var body = editors[i].getBody();
26387
+
26388
+ if (body === target || DOM.isChildOf(target, body)) {
26389
+ if (!editors[i].hidden) {
26390
+ editors[i].fire(name, e);
25773
26391
  }
25774
26392
  }
25775
-
25776
- self[bindingsName] = [];
25777
26393
  }
25778
- }
26394
+ });
26395
+ } else {
26396
+ editor.dom.bind(eventRootElm, name, function(e) {
26397
+ if (!editor.hidden) {
26398
+ editor.fire(name, e);
26399
+ }
26400
+ });
26401
+ }
26402
+ }
25779
26403
 
25780
- return self;
26404
+ var EditorObservable = {
26405
+ bindPendingEventDelegates: function() {
26406
+ var self = this;
26407
+
26408
+ Tools.each(self._pendingNativeEvents, function(name) {
26409
+ bindEventDelegate(self, name);
26410
+ });
25781
26411
  },
25782
26412
 
25783
- hasEventListeners: function(name) {
25784
- var bindings = this[bindingsName];
26413
+ toggleNativeEvent: function(name, state) {
26414
+ var self = this;
25785
26415
 
25786
- name = name.toLowerCase();
26416
+ if (self.settings.readonly) {
26417
+ return;
26418
+ }
26419
+
26420
+ // Never bind focus/blur since the FocusManager fakes those
26421
+ if (name == "focus" || name == "blur") {
26422
+ return;
26423
+ }
25787
26424
 
25788
- return !(!bindings || !bindings[name] || bindings[name].length === 0);
26425
+ if (state) {
26426
+ if (self.initialized) {
26427
+ bindEventDelegate(self, name);
26428
+ } else {
26429
+ if (!self._pendingNativeEvents) {
26430
+ self._pendingNativeEvents = [name];
26431
+ } else {
26432
+ self._pendingNativeEvents.push(name);
26433
+ }
26434
+ }
26435
+ } else if (self.initialized) {
26436
+ self.dom.unbind(getEventTarget(self, name), name);
26437
+ }
25789
26438
  }
25790
26439
  };
26440
+
26441
+ EditorObservable = Tools.extend({}, Observable, EditorObservable);
26442
+
26443
+ return EditorObservable;
25791
26444
  });
25792
26445
 
25793
26446
  // Included from: js/tinymce/classes/Shortcuts.js
@@ -25969,13 +26622,13 @@ define("tinymce/Editor", [
25969
26622
  "tinymce/util/Quirks",
25970
26623
  "tinymce/Env",
25971
26624
  "tinymce/util/Tools",
25972
- "tinymce/util/Observable",
26625
+ "tinymce/EditorObservable",
25973
26626
  "tinymce/Shortcuts"
25974
26627
  ], function(
25975
26628
  DOMUtils, AddOnManager, Node, DomSerializer, Serializer,
25976
26629
  Selection, Formatter, UndoManager, EnterKey, ForceBlocks, EditorCommands,
25977
26630
  URI, ScriptLoader, EventUtils, WindowManager,
25978
- Schema, DomParser, Quirks, Env, Tools, Observable, Shortcuts
26631
+ Schema, DomParser, Quirks, Env, Tools, EditorObservable, Shortcuts
25979
26632
  ) {
25980
26633
  // Shorten these names
25981
26634
  var DOM = DOMUtils.DOM, ThemeManager = AddOnManager.ThemeManager, PluginManager = AddOnManager.PluginManager;
@@ -25984,20 +26637,6 @@ define("tinymce/Editor", [
25984
26637
  var Event = EventUtils.Event;
25985
26638
  var isGecko = Env.gecko, ie = Env.ie;
25986
26639
 
25987
- function getEventTarget(editor, eventName) {
25988
- if (eventName == 'selectionchange') {
25989
- return editor.getDoc();
25990
- }
25991
-
25992
- // Need to bind mousedown/mouseup etc to document not body in iframe mode
25993
- // Since the user might click on the HTML element not the BODY
25994
- if (!editor.inline && /^mouse|click|contextmenu|drop/.test(eventName)) {
25995
- return editor.getDoc();
25996
- }
25997
-
25998
- return editor.getBody();
25999
- }
26000
-
26001
26640
  /**
26002
26641
  * Include documentation for all the events.
26003
26642
  *
@@ -26627,12 +27266,10 @@ define("tinymce/Editor", [
26627
27266
 
26628
27267
  DOM.removeClass(bodyEl, 'mce-content-body');
26629
27268
  DOM.removeClass(bodyEl, 'mce-edit-focus');
26630
- DOM.setAttrib(bodyEl, 'tabIndex', null);
26631
27269
  DOM.setAttrib(bodyEl, 'contentEditable', null);
26632
27270
  });
26633
27271
 
26634
27272
  DOM.addClass(targetElm, 'mce-content-body');
26635
- targetElm.tabIndex = -1;
26636
27273
  self.contentDocument = doc = settings.content_document || document;
26637
27274
  self.contentWindow = settings.content_window || window;
26638
27275
  self.bodyElement = targetElm;
@@ -26699,7 +27336,7 @@ define("tinymce/Editor", [
26699
27336
  self.parser = new DomParser(settings, self.schema);
26700
27337
 
26701
27338
  // Convert src and href into data-mce-src, data-mce-href and data-mce-style
26702
- self.parser.addAttributeFilter('src,href,style', function(nodes, name) {
27339
+ self.parser.addAttributeFilter('src,href,style,tabindex', function(nodes, name) {
26703
27340
  var i = nodes.length, node, dom = self.dom, value, internalName;
26704
27341
 
26705
27342
  while (i--) {
@@ -26711,6 +27348,9 @@ define("tinymce/Editor", [
26711
27348
  if (!node.attributes.map[internalName]) {
26712
27349
  if (name === "style") {
26713
27350
  node.attr(internalName, dom.serializeStyle(dom.parseStyle(value), node.name));
27351
+ } else if (name === "tabindex") {
27352
+ node.attr(internalName, value);
27353
+ node.attr(name, null);
26714
27354
  } else {
26715
27355
  node.attr(internalName, self.convertURL(value, name, node.name));
26716
27356
  }
@@ -26856,12 +27496,7 @@ define("tinymce/Editor", [
26856
27496
  * }
26857
27497
  */
26858
27498
  self.initialized = true;
26859
-
26860
- each(self._pendingNativeEvents, function(name) {
26861
- self.dom.bind(getEventTarget(self, name), name, function(e) {
26862
- self.fire(e.type, e);
26863
- });
26864
- });
27499
+ self.bindPendingEventDelegates();
26865
27500
 
26866
27501
  self.fire('init');
26867
27502
  self.focus(true);
@@ -26939,8 +27574,13 @@ define("tinymce/Editor", [
26939
27574
  body = self.getBody();
26940
27575
 
26941
27576
  // Check for setActive since it doesn't scroll to the element
26942
- if (body.setActive && Env.ie < 11) {
26943
- body.setActive();
27577
+ if (body.setActive) {
27578
+ // IE 11 sometimes throws "Invalid function" then fallback to focus
27579
+ try {
27580
+ body.setActive();
27581
+ } catch (ex) {
27582
+ body.focus();
27583
+ }
26944
27584
  } else {
26945
27585
  body.focus();
26946
27586
  }
@@ -27114,9 +27754,7 @@ define("tinymce/Editor", [
27114
27754
  },
27115
27755
 
27116
27756
  /**
27117
- * Adds a button that later gets created by the ControlManager. This is a shorter and easier method
27118
- * of adding buttons without the need to deal with the ControlManager directly. But it's also less
27119
- * powerfull if you need more control use the ControlManagers factory methods instead.
27757
+ * Adds a button that later gets created by the theme in the editors toolbars.
27120
27758
  *
27121
27759
  * @method addButton
27122
27760
  * @param {String} name Button name to add.
@@ -27158,7 +27796,9 @@ define("tinymce/Editor", [
27158
27796
  },
27159
27797
 
27160
27798
  /**
27161
- * Adds a menu item to be used in the menus of the modern theme.
27799
+ * Adds a menu item to be used in the menus of the theme. There might be multiple instances
27800
+ * of this menu item for example it might be used in the main menus of the theme but also in
27801
+ * the context menu so make sure that it's self contained and supports multiple instances.
27162
27802
  *
27163
27803
  * @method addMenuItem
27164
27804
  * @param {String} name Menu item name to add.
@@ -27428,10 +28068,19 @@ define("tinymce/Editor", [
27428
28068
  show: function() {
27429
28069
  var self = this;
27430
28070
 
27431
- DOM.show(self.getContainer());
27432
- DOM.hide(self.id);
27433
- self.load();
27434
- self.fire('show');
28071
+ if (self.hidden) {
28072
+ self.hidden = false;
28073
+
28074
+ if (self.inline) {
28075
+ self.getBody().contentEditable = true;
28076
+ } else {
28077
+ DOM.show(self.getContainer());
28078
+ DOM.hide(self.id);
28079
+ }
28080
+
28081
+ self.load();
28082
+ self.fire('show');
28083
+ }
27435
28084
  },
27436
28085
 
27437
28086
  /**
@@ -27442,18 +28091,31 @@ define("tinymce/Editor", [
27442
28091
  hide: function() {
27443
28092
  var self = this, doc = self.getDoc();
27444
28093
 
27445
- // Fixed bug where IE has a blinking cursor left from the editor
27446
- if (ie && doc && !self.inline) {
27447
- doc.execCommand('SelectAll');
27448
- }
28094
+ if (!self.hidden) {
28095
+ self.hidden = true;
28096
+
28097
+ // Fixed bug where IE has a blinking cursor left from the editor
28098
+ if (ie && doc && !self.inline) {
28099
+ doc.execCommand('SelectAll');
28100
+ }
28101
+
28102
+ // We must save before we hide so Safari doesn't crash
28103
+ self.save();
27449
28104
 
27450
- // We must save before we hide so Safari doesn't crash
27451
- self.save();
28105
+ if (self.inline) {
28106
+ self.getBody().contentEditable = false;
27452
28107
 
27453
- // defer the call to hide to prevent an IE9 crash #4921
27454
- DOM.hide(self.getContainer());
27455
- DOM.setStyle(self.id, 'display', self.orgDisplay);
27456
- self.fire('hide');
28108
+ // Make sure the editor gets blurred
28109
+ if (self == self.editorManager.focusedEditor) {
28110
+ self.editorManager.focusedEditor = null;
28111
+ }
28112
+ } else {
28113
+ DOM.hide(self.getContainer());
28114
+ DOM.setStyle(self.id, 'display', self.orgDisplay);
28115
+ }
28116
+
28117
+ self.fire('hide');
28118
+ }
27457
28119
  },
27458
28120
 
27459
28121
  /**
@@ -27463,7 +28125,7 @@ define("tinymce/Editor", [
27463
28125
  * @return {Boolean} True/false if the editor is hidden or not.
27464
28126
  */
27465
28127
  isHidden: function() {
27466
- return !DOM.isHidden(this.id);
28128
+ return !!this.hidden;
27467
28129
  },
27468
28130
 
27469
28131
  /**
@@ -27919,23 +28581,26 @@ define("tinymce/Editor", [
27919
28581
  var self = this;
27920
28582
 
27921
28583
  if (!self.removed) {
27922
- self.fire('remove');
27923
- self.off();
27924
- self.removed = 1; // Cancels post remove event execution
28584
+ self.removed = 1;
28585
+ self.save();
27925
28586
 
27926
28587
  // Remove any hidden input
27927
28588
  if (self.hasHiddenInput) {
27928
28589
  DOM.remove(self.getElement().nextSibling);
27929
28590
  }
27930
28591
 
27931
- // We must save before we hide so Safari doesn't crash
27932
- self.save();
28592
+ if (!self.inline) {
28593
+ // IE 9 has a bug where the selection stops working if you place the
28594
+ // caret inside the editor then remove the iframe
28595
+ if (ie && ie < 10) {
28596
+ self.getDoc().execCommand('SelectAll', false, null);
28597
+ }
27933
28598
 
27934
- DOM.setStyle(self.id, 'display', self.orgDisplay);
28599
+ DOM.setStyle(self.id, 'display', self.orgDisplay);
28600
+ self.getBody().onload = null; // Prevent #6816
27935
28601
 
27936
- // Don't clear the window or document if content editable
27937
- // is enabled since other instances might still be present
27938
- if (!self.settings.content_editable) {
28602
+ // Don't clear the window or document if content editable
28603
+ // is enabled since other instances might still be present
27939
28604
  Event.unbind(self.getWin());
27940
28605
  Event.unbind(self.getDoc());
27941
28606
  }
@@ -27944,40 +28609,14 @@ define("tinymce/Editor", [
27944
28609
  Event.unbind(self.getBody());
27945
28610
  Event.unbind(elm);
27946
28611
 
28612
+ self.fire('remove');
28613
+
27947
28614
  self.editorManager.remove(self);
27948
28615
  DOM.remove(elm);
27949
28616
  self.destroy();
27950
28617
  }
27951
28618
  },
27952
28619
 
27953
- bindNative: function(name) {
27954
- var self = this;
27955
-
27956
- if (self.settings.readonly) {
27957
- return;
27958
- }
27959
-
27960
- if (self.initialized) {
27961
- self.dom.bind(getEventTarget(self, name), name, function(e) {
27962
- self.fire(name, e);
27963
- });
27964
- } else {
27965
- if (!self._pendingNativeEvents) {
27966
- self._pendingNativeEvents = [name];
27967
- } else {
27968
- self._pendingNativeEvents.push(name);
27969
- }
27970
- }
27971
- },
27972
-
27973
- unbindNative: function(name) {
27974
- var self = this;
27975
-
27976
- if (self.initialized) {
27977
- self.dom.unbind(name);
27978
- }
27979
- },
27980
-
27981
28620
  /**
27982
28621
  * Destroys the editor instance by removing all events, element references or other resources
27983
28622
  * that could leak memory. This method will be called automatically when the page is unloaded
@@ -28072,7 +28711,7 @@ define("tinymce/Editor", [
28072
28711
  }
28073
28712
  };
28074
28713
 
28075
- extend(Editor.prototype, Observable);
28714
+ extend(Editor.prototype, EditorObservable);
28076
28715
 
28077
28716
  return Editor;
28078
28717
  });
@@ -28185,7 +28824,7 @@ define("tinymce/FocusManager", [
28185
28824
  "tinymce/dom/DOMUtils",
28186
28825
  "tinymce/Env"
28187
28826
  ], function(DOMUtils, Env) {
28188
- var selectionChangeHandler, documentFocusInHandler, DOM = DOMUtils.DOM;
28827
+ var selectionChangeHandler, documentFocusInHandler, documentMouseUpHandler, DOM = DOMUtils.DOM;
28189
28828
 
28190
28829
  /**
28191
28830
  * Constructs a new focus manager instance.
@@ -28206,8 +28845,13 @@ define("tinymce/FocusManager", [
28206
28845
 
28207
28846
  // We can't store a real range on IE 11 since it gets mutated so we need to use a bookmark object
28208
28847
  // TODO: Move this to a separate range utils class since it's it's logic is present in Selection as well.
28209
- function createBookmark(rng) {
28848
+ function createBookmark(dom, rng) {
28210
28849
  if (rng && rng.startContainer) {
28850
+ // Verify that the range is within the root of the editor
28851
+ if (!dom.isChildOf(rng.startContainer, dom.getRoot()) || !dom.isChildOf(rng.endContainer, dom.getRoot())) {
28852
+ return;
28853
+ }
28854
+
28211
28855
  return {
28212
28856
  startContainer: rng.startContainer,
28213
28857
  startOffset: rng.startOffset,
@@ -28237,44 +28881,12 @@ define("tinymce/FocusManager", [
28237
28881
  return !!DOM.getParent(elm, FocusManager.isEditorUIElement);
28238
28882
  }
28239
28883
 
28240
- function isNodeInBodyOfEditor(node, editor) {
28241
- var body = editor.getBody();
28242
-
28243
- while (node) {
28244
- if (node == body) {
28245
- return true;
28246
- }
28247
-
28248
- node = node.parentNode;
28249
- }
28250
- }
28251
-
28252
28884
  function registerEvents(e) {
28253
28885
  var editor = e.editor;
28254
28886
 
28255
28887
  editor.on('init', function() {
28256
- // On IE take selection snapshot onbeforedeactivate
28257
- if ("onbeforedeactivate" in document && Env.ie < 11) {
28258
- // Gets fired when the editor is about to be blurred but also when the selection
28259
- // is moved into a table cell so we need to add the range as a pending range then
28260
- // use that pending range on the blur event of the editor body
28261
- editor.dom.bind(editor.getBody(), 'beforedeactivate', function() {
28262
- try {
28263
- editor.pendingRng = editor.selection.getRng();
28264
- } catch (ex) {
28265
- // IE throws "Unexcpected call to method or property access" some times so lets ignore it
28266
- }
28267
- });
28268
-
28269
- // Set the pending range as the current last range if the blur event occurs
28270
- editor.dom.bind(editor.getBody(), 'blur', function() {
28271
- if (editor.pendingRng) {
28272
- editor.lastRng = editor.pendingRng;
28273
- editor.selection.lastFocusBookmark = createBookmark(editor.lastRng);
28274
- editor.pendingRng = null;
28275
- }
28276
- });
28277
- } else if (editor.inline || Env.ie > 10) {
28888
+ // Gecko/WebKit has ghost selections in iframes and IE only has one selection per browser tab
28889
+ if (editor.inline || Env.ie) {
28278
28890
  // On other browsers take snapshot on nodechange in inline mode since they have Ghost selections for iframes
28279
28891
  editor.on('nodechange keyup', function() {
28280
28892
  var node = document.activeElement;
@@ -28284,7 +28896,7 @@ define("tinymce/FocusManager", [
28284
28896
  node = editor.getBody();
28285
28897
  }
28286
28898
 
28287
- if (isNodeInBodyOfEditor(node, editor)) {
28899
+ if (editor.dom.isChildOf(node, editor.getBody())) {
28288
28900
  editor.lastRng = editor.selection.getRng();
28289
28901
  }
28290
28902
  });
@@ -28358,6 +28970,8 @@ define("tinymce/FocusManager", [
28358
28970
  }, 0);
28359
28971
  });
28360
28972
 
28973
+ // Check if focus is moved to an element outside the active editor by checking if the target node
28974
+ // isn't within the body of the activeEditor nor a UI element such as a dialog child control
28361
28975
  if (!documentFocusInHandler) {
28362
28976
  documentFocusInHandler = function(e) {
28363
28977
  var activeEditor = editorManager.activeEditor;
@@ -28365,7 +28979,7 @@ define("tinymce/FocusManager", [
28365
28979
  if (activeEditor && e.target.ownerDocument == document) {
28366
28980
  // Check to make sure we have a valid selection
28367
28981
  if (activeEditor.selection) {
28368
- activeEditor.selection.lastFocusBookmark = createBookmark(activeEditor.lastRng);
28982
+ activeEditor.selection.lastFocusBookmark = createBookmark(activeEditor.dom, activeEditor.lastRng);
28369
28983
  }
28370
28984
 
28371
28985
  // Fire a blur event if the element isn't a UI element
@@ -28376,17 +28990,39 @@ define("tinymce/FocusManager", [
28376
28990
  }
28377
28991
  };
28378
28992
 
28379
- // Check if focus is moved to an element outside the active editor by checking if the target node
28380
- // isn't within the body of the activeEditor nor a UI element such as a dialog child control
28381
28993
  DOM.bind(document, 'focusin', documentFocusInHandler);
28382
28994
  }
28995
+
28996
+ // Handle edge case when user starts the selection inside the editor and releases
28997
+ // the mouse outside the editor producing a new selection. This weird workaround is needed since
28998
+ // Gecko doesn't have the "selectionchange" event we need to do this. Fixes: #6843
28999
+ if (editor.inline && !documentMouseUpHandler) {
29000
+ documentMouseUpHandler = function(e) {
29001
+ var activeEditor = editorManager.activeEditor;
29002
+
29003
+ if (activeEditor.inline && !activeEditor.dom.isChildOf(e.target, activeEditor.getBody())) {
29004
+ var rng = activeEditor.selection.getRng();
29005
+
29006
+ if (!rng.collapsed) {
29007
+ activeEditor.lastRng = rng;
29008
+ }
29009
+ }
29010
+ };
29011
+
29012
+ DOM.bind(document, 'mouseup', documentMouseUpHandler);
29013
+ }
28383
29014
  }
28384
29015
 
28385
- function unregisterDocumentEvents() {
29016
+ function unregisterDocumentEvents(e) {
29017
+ if (editorManager.focusedEditor == e.editor) {
29018
+ editorManager.focusedEditor = null;
29019
+ }
29020
+
28386
29021
  if (!editorManager.activeEditor) {
28387
29022
  DOM.unbind(document, 'selectionchange', selectionChangeHandler);
28388
29023
  DOM.unbind(document, 'focusin', documentFocusInHandler);
28389
- selectionChangeHandler = documentFocusInHandler = null;
29024
+ DOM.unbind(document, 'mouseup', documentMouseUpHandler);
29025
+ selectionChangeHandler = documentFocusInHandler = documentMouseUpHandler = null;
28390
29026
  }
28391
29027
  }
28392
29028
 
@@ -28402,7 +29038,8 @@ define("tinymce/FocusManager", [
28402
29038
  * @return {Boolean} True/false state if the element is part of the UI or not.
28403
29039
  */
28404
29040
  FocusManager.isEditorUIElement = function(elm) {
28405
- return elm.className.indexOf('mce-') !== -1;
29041
+ // Needs to be converted to string since svg can have focus: #6776
29042
+ return elm.className.toString().indexOf('mce-') !== -1;
28406
29043
  };
28407
29044
 
28408
29045
  return FocusManager;
@@ -28442,9 +29079,46 @@ define("tinymce/EditorManager", [
28442
29079
  ], function(Editor, DOMUtils, URI, Env, Tools, Observable, I18n, FocusManager) {
28443
29080
  var DOM = DOMUtils.DOM;
28444
29081
  var explode = Tools.explode, each = Tools.each, extend = Tools.extend;
28445
- var instanceCounter = 0, beforeUnloadDelegate;
29082
+ var instanceCounter = 0, beforeUnloadDelegate, EditorManager;
29083
+
29084
+ function removeEditorFromList(editor) {
29085
+ var editors = EditorManager.editors, removedFromList;
29086
+
29087
+ delete editors[editor.id];
29088
+
29089
+ for (var i = 0; i < editors.length; i++) {
29090
+ if (editors[i] == editor) {
29091
+ editors.splice(i, 1);
29092
+ removedFromList = true;
29093
+ break;
29094
+ }
29095
+ }
29096
+
29097
+ // Select another editor since the active one was removed
29098
+ if (EditorManager.activeEditor == editor) {
29099
+ EditorManager.activeEditor = editors[0];
29100
+ }
29101
+
29102
+ // Clear focusedEditor if necessary, so that we don't try to blur the destroyed editor
29103
+ if (EditorManager.focusedEditor == editor) {
29104
+ EditorManager.focusedEditor = null;
29105
+ }
29106
+
29107
+ return removedFromList;
29108
+ }
28446
29109
 
28447
- var EditorManager = {
29110
+ function purgeDestroyedEditor(editor) {
29111
+ // User has manually destroyed the editor lets clean up the mess
29112
+ if (editor && !(editor.getContainer() || editor.getBody()).parentNode) {
29113
+ removeEditorFromList(editor);
29114
+ editor.destroy(true);
29115
+ editor = null;
29116
+ }
29117
+
29118
+ return editor;
29119
+ }
29120
+
29121
+ EditorManager = {
28448
29122
  /**
28449
29123
  * Major version of TinyMCE build.
28450
29124
  *
@@ -28459,7 +29133,7 @@ define("tinymce/EditorManager", [
28459
29133
  * @property minorVersion
28460
29134
  * @type String
28461
29135
  */
28462
- minorVersion : '0.19',
29136
+ minorVersion : '0.26',
28463
29137
 
28464
29138
  /**
28465
29139
  * Release date of TinyMCE build.
@@ -28467,7 +29141,7 @@ define("tinymce/EditorManager", [
28467
29141
  * @property releaseDate
28468
29142
  * @type String
28469
29143
  */
28470
- releaseDate: '2014-03-11',
29144
+ releaseDate: '2014-05-06',
28471
29145
 
28472
29146
  /**
28473
29147
  * Collection of editor instances.
@@ -28500,7 +29174,7 @@ define("tinymce/EditorManager", [
28500
29174
  activeEditor: null,
28501
29175
 
28502
29176
  setup: function() {
28503
- var self = this, baseURL, documentBaseURL, suffix = "", preInit;
29177
+ var self = this, baseURL, documentBaseURL, suffix = "", preInit, src;
28504
29178
 
28505
29179
  // Get base URL for the current document
28506
29180
  documentBaseURL = document.location.href.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
@@ -28517,7 +29191,7 @@ define("tinymce/EditorManager", [
28517
29191
  // Get base where the tinymce script is located
28518
29192
  var scripts = document.getElementsByTagName('script');
28519
29193
  for (var i = 0; i < scripts.length; i++) {
28520
- var src = scripts[i].src;
29194
+ src = scripts[i].src;
28521
29195
 
28522
29196
  // Script types supported:
28523
29197
  // tinymce.js tinymce.min.js tinymce.dev.js
@@ -28532,6 +29206,18 @@ define("tinymce/EditorManager", [
28532
29206
  break;
28533
29207
  }
28534
29208
  }
29209
+
29210
+ // We didn't find any baseURL by looking at the script elements
29211
+ // Try to use the document.currentScript as a fallback
29212
+ if (!baseURL && document.currentScript) {
29213
+ src = document.currentScript.src;
29214
+
29215
+ if (src.indexOf('.min') != -1) {
29216
+ suffix = '.min';
29217
+ }
29218
+
29219
+ baseURL = src.substring(0, src.lastIndexOf('/'));
29220
+ }
28535
29221
  }
28536
29222
 
28537
29223
  /**
@@ -28608,6 +29294,14 @@ define("tinymce/EditorManager", [
28608
29294
  return id;
28609
29295
  }
28610
29296
 
29297
+ function createEditor(id, settings) {
29298
+ if (!purgeDestroyedEditor(self.get(id))) {
29299
+ var editor = new Editor(id, settings, self);
29300
+ editors.push(editor);
29301
+ editor.render();
29302
+ }
29303
+ }
29304
+
28611
29305
  function execCallback(se, n, s) {
28612
29306
  var f = se[n];
28613
29307
 
@@ -28633,9 +29327,7 @@ define("tinymce/EditorManager", [
28633
29327
  // Process type specific selector
28634
29328
  each(settings.types, function(type) {
28635
29329
  each(DOM.select(type.selector), function(elm) {
28636
- var editor = new Editor(createId(elm), extend({}, settings, type), self);
28637
- editors.push(editor);
28638
- editor.render(1);
29330
+ createEditor(createId(elm), extend({}, settings, type));
28639
29331
  });
28640
29332
  });
28641
29333
 
@@ -28643,9 +29335,7 @@ define("tinymce/EditorManager", [
28643
29335
  } else if (settings.selector) {
28644
29336
  // Process global selector
28645
29337
  each(DOM.select(settings.selector), function(elm) {
28646
- var editor = new Editor(createId(elm), settings, self);
28647
- editors.push(editor);
28648
- editor.render(1);
29338
+ createEditor(createId(elm), settings);
28649
29339
  });
28650
29340
 
28651
29341
  return;
@@ -28656,22 +29346,19 @@ define("tinymce/EditorManager", [
28656
29346
  case "exact":
28657
29347
  l = settings.elements || '';
28658
29348
 
28659
- if(l.length > 0) {
29349
+ if (l.length > 0) {
28660
29350
  each(explode(l), function(v) {
28661
29351
  if (DOM.get(v)) {
28662
29352
  editor = new Editor(v, settings, self);
28663
29353
  editors.push(editor);
28664
- editor.render(true);
29354
+ editor.render();
28665
29355
  } else {
28666
29356
  each(document.forms, function(f) {
28667
29357
  each(f.elements, function(e) {
28668
29358
  if (e.name === v) {
28669
29359
  v = 'mce_editor_' + instanceCounter++;
28670
29360
  DOM.setAttrib(e, 'id', v);
28671
-
28672
- editor = new Editor(v, settings, self);
28673
- editors.push(editor);
28674
- editor.render(1);
29361
+ createEditor(v, settings);
28675
29362
  }
28676
29363
  });
28677
29364
  });
@@ -28688,9 +29375,7 @@ define("tinymce/EditorManager", [
28688
29375
  }
28689
29376
 
28690
29377
  if (!settings.editor_selector || hasClass(elm, settings.editor_selector)) {
28691
- editor = new Editor(createId(elm), settings, self);
28692
- editors.push(editor);
28693
- editor.render(true);
29378
+ createEditor(createId(elm), settings);
28694
29379
  }
28695
29380
  });
28696
29381
  break;
@@ -28748,11 +29433,11 @@ define("tinymce/EditorManager", [
28748
29433
  * });
28749
29434
  */
28750
29435
  get: function(id) {
28751
- if (id === undefined) {
29436
+ if (!arguments.length) {
28752
29437
  return this.editors;
28753
29438
  }
28754
29439
 
28755
- return this.editors[id];
29440
+ return id in this.editors ? this.editors[id] : null;
28756
29441
  },
28757
29442
 
28758
29443
  /**
@@ -28823,7 +29508,7 @@ define("tinymce/EditorManager", [
28823
29508
  * @return {tinymce.Editor} The editor that got passed in will be return if it was found otherwise null.
28824
29509
  */
28825
29510
  remove: function(selector) {
28826
- var self = this, i, editors = self.editors, editor, removedFromList;
29511
+ var self = this, i, editors = self.editors, editor;
28827
29512
 
28828
29513
  // Remove all editors
28829
29514
  if (!selector) {
@@ -28853,28 +29538,13 @@ define("tinymce/EditorManager", [
28853
29538
  return null;
28854
29539
  }
28855
29540
 
28856
- delete editors[editor.id];
28857
-
28858
- for (i = 0; i < editors.length; i++) {
28859
- if (editors[i] == editor) {
28860
- editors.splice(i, 1);
28861
- removedFromList = true;
28862
- break;
28863
- }
28864
- }
28865
-
28866
- // Select another editor since the active one was removed
28867
- if (self.activeEditor == editor) {
28868
- self.activeEditor = editors[0];
28869
- }
28870
-
28871
29541
  /**
28872
29542
  * Fires when an editor is removed from EditorManager collection.
28873
29543
  *
28874
29544
  * @event RemoveEditor
28875
29545
  * @param {Object} e Event arguments.
28876
29546
  */
28877
- if (removedFromList) {
29547
+ if (removeEditorFromList(editor)) {
28878
29548
  self.fire('RemoveEditor', {editor: editor});
28879
29549
  }
28880
29550
 
@@ -30029,6 +30699,7 @@ define("tinymce/ui/Widget", [
30029
30699
  var self = this;
30030
30700
 
30031
30701
  self._super(settings);
30702
+ settings = self.settings;
30032
30703
  self.canFocus = true;
30033
30704
 
30034
30705
  if (settings.tooltip && Widget.tooltips !== false) {
@@ -30263,6 +30934,26 @@ define("tinymce/ui/Button", [
30263
30934
  this._super();
30264
30935
  },
30265
30936
 
30937
+ /**
30938
+ * Sets/gets the current button text.
30939
+ *
30940
+ * @method text
30941
+ * @param {String} [text] New button text.
30942
+ * @return {String|tinymce.ui.Button} Current text or current Button instance.
30943
+ */
30944
+ text: function(text) {
30945
+ var self = this;
30946
+
30947
+ if (self._rendered) {
30948
+ var textNode = self.getEl().lastChild.lastChild;
30949
+ if (textNode) {
30950
+ textNode.data = self.translate(text);
30951
+ }
30952
+ }
30953
+
30954
+ return self._super(text);
30955
+ },
30956
+
30266
30957
  /**
30267
30958
  * Renders the control as a HTML string.
30268
30959
  *
@@ -30271,11 +30962,20 @@ define("tinymce/ui/Button", [
30271
30962
  */
30272
30963
  renderHtml: function() {
30273
30964
  var self = this, id = self._id, prefix = self.classPrefix;
30274
- var icon = self.settings.icon, image = '';
30965
+ var icon = self.settings.icon, image;
30275
30966
 
30276
- if (self.settings.image) {
30967
+ image = self.settings.image;
30968
+ if (image) {
30277
30969
  icon = 'none';
30278
- image = ' style="background-image: url(\'' + self.settings.image + '\')"';
30970
+
30971
+ // Support for [high dpi, low dpi] image sources
30972
+ if (typeof image != "string") {
30973
+ image = window.getSelection ? image[0] : image[1];
30974
+ }
30975
+
30976
+ image = ' style="background-image: url(\'' + image + '\')"';
30977
+ } else {
30978
+ image = '';
30279
30979
  }
30280
30980
 
30281
30981
  icon = self.settings.icon ? prefix + 'ico ' + prefix + 'i-' + icon : '';
@@ -30658,12 +31358,12 @@ define("tinymce/ui/ColorButton", [
30658
31358
 
30659
31359
  return (
30660
31360
  '<div id="' + id + '" class="' + self.classes() + '" role="button" tabindex="-1" aria-haspopup="true">' +
30661
- '<button role="presentation" hidefocus type="button" tabindex="-1">' +
31361
+ '<button role="presentation" hidefocus="1" type="button" tabindex="-1">' +
30662
31362
  (icon ? '<i class="' + icon + '"' + image + '></i>' : '') +
30663
31363
  '<span id="' + id + '-preview" class="' + prefix + 'preview"></span>' +
30664
31364
  (self._text ? (icon ? ' ' : '') + (self._text) : '') +
30665
31365
  '</button>' +
30666
- '<button type="button" class="' + prefix + 'open" hidefocus tabindex="-1">' +
31366
+ '<button type="button" class="' + prefix + 'open" hidefocus="1" tabindex="-1">' +
30667
31367
  ' <i class="' + prefix + 'caret"></i>' +
30668
31368
  '</button>' +
30669
31369
  '</div>'
@@ -30845,7 +31545,7 @@ define("tinymce/ui/ComboBox", [
30845
31545
  });
30846
31546
 
30847
31547
  self.on('focusin', function(e) {
30848
- if (e.target.tagName == 'INPUT') {
31548
+ if (e.target.tagName.toUpperCase() == 'INPUT') {
30849
31549
  self.menu.hide();
30850
31550
  }
30851
31551
  });
@@ -31011,7 +31711,7 @@ define("tinymce/ui/ComboBox", [
31011
31711
  if (icon || text) {
31012
31712
  openBtnHtml = (
31013
31713
  '<div id="' + id + '-open" class="' + prefix + 'btn ' + prefix + 'open" tabIndex="-1" role="button">' +
31014
- '<button id="' + id + '-action" type="button" hidefocus tabindex="-1">' +
31714
+ '<button id="' + id + '-action" type="button" hidefocus="1" tabindex="-1">' +
31015
31715
  (icon != 'caret' ? '<i class="' + icon + '"></i>' : '<i class="' + prefix + 'caret"></i>') +
31016
31716
  (text ? (icon ? ' ' : '') + text : '') +
31017
31717
  '</button>' +
@@ -31024,7 +31724,7 @@ define("tinymce/ui/ComboBox", [
31024
31724
  return (
31025
31725
  '<div id="' + id + '" class="' + self.classes() + '">' +
31026
31726
  '<input id="' + id + '-inp" class="' + prefix + 'textbox ' + prefix + 'placeholder" value="' +
31027
- value + '" hidefocus="true"' + extraAttrs + '>' +
31727
+ value + '" hidefocus="1"' + extraAttrs + ' />' +
31028
31728
  openBtnHtml +
31029
31729
  '</div>'
31030
31730
  );
@@ -31167,7 +31867,7 @@ define("tinymce/ui/Path", [
31167
31867
  }
31168
31868
 
31169
31869
  if (!html) {
31170
- html = '<div class="' + prefix + 'path-item">&nbsp;</div>';
31870
+ html = '<div class="' + prefix + 'path-item">\u00a0</div>';
31171
31871
  }
31172
31872
 
31173
31873
  return html;
@@ -31308,7 +32008,7 @@ define("tinymce/ui/FormItem", [
31308
32008
  layout.preRender(self);
31309
32009
 
31310
32010
  return (
31311
- '<div id="' + self._id + '" class="' + self.classes() + '" hideFocus="1" tabIndex="-1">' +
32011
+ '<div id="' + self._id + '" class="' + self.classes() + '" hidefocus="1" tabindex="-1">' +
31312
32012
  (self.settings.title ? ('<div id="' + self._id + '-title" class="' + prefix + 'title">' +
31313
32013
  self.settings.title + '</div>') : '') +
31314
32014
  '<div id="' + self._id + '-body" class="' + self.classes('body') + '">' +
@@ -31527,7 +32227,7 @@ define("tinymce/ui/FieldSet", [
31527
32227
  layout.preRender(self);
31528
32228
 
31529
32229
  return (
31530
- '<fieldset id="' + self._id + '" class="' + self.classes() + '" hideFocus="1" tabIndex="-1">' +
32230
+ '<fieldset id="' + self._id + '" class="' + self.classes() + '" hidefocus="1" tabindex="-1">' +
31531
32231
  (self.settings.title ? ('<legend id="' + self._id + '-title" class="' + prefix + 'fieldset-title">' +
31532
32232
  self.settings.title + '</legend>') : '') +
31533
32233
  '<div id="' + self._id + '-body" class="' + self.classes('body') + '">' +
@@ -31985,127 +32685,6 @@ define("tinymce/ui/FormatControls", [
31985
32685
  function registerControls(editor) {
31986
32686
  var formatMenu;
31987
32687
 
31988
- // Generates a preview for a format
31989
- function getPreviewCss(format) {
31990
- var name, previewElm, dom = editor.dom;
31991
- var previewCss = '', parentFontSize, previewStyles;
31992
-
31993
- previewStyles = editor.settings.preview_styles;
31994
-
31995
- // No preview forced
31996
- if (previewStyles === false) {
31997
- return '';
31998
- }
31999
-
32000
- // Default preview
32001
- if (!previewStyles) {
32002
- previewStyles = 'font-family font-size font-weight font-style text-decoration ' +
32003
- 'text-transform color background-color border border-radius outline text-shadow';
32004
- }
32005
-
32006
- // Removes any variables since these can't be previewed
32007
- function removeVars(val) {
32008
- return val.replace(/%(\w+)/g, '');
32009
- }
32010
-
32011
- // Create block/inline element to use for preview
32012
- format = editor.formatter.get(format);
32013
- if (!format) {
32014
- return;
32015
- }
32016
-
32017
- format = format[0];
32018
- name = format.block || format.inline || 'span';
32019
- previewElm = dom.create(name);
32020
-
32021
- // Add format styles to preview element
32022
- each(format.styles, function(value, name) {
32023
- value = removeVars(value);
32024
-
32025
- if (value) {
32026
- dom.setStyle(previewElm, name, value);
32027
- }
32028
- });
32029
-
32030
- // Add attributes to preview element
32031
- each(format.attributes, function(value, name) {
32032
- value = removeVars(value);
32033
-
32034
- if (value) {
32035
- dom.setAttrib(previewElm, name, value);
32036
- }
32037
- });
32038
-
32039
- // Add classes to preview element
32040
- each(format.classes, function(value) {
32041
- value = removeVars(value);
32042
-
32043
- if (!dom.hasClass(previewElm, value)) {
32044
- dom.addClass(previewElm, value);
32045
- }
32046
- });
32047
-
32048
- editor.fire('PreviewFormats');
32049
-
32050
- // Add the previewElm outside the visual area
32051
- dom.setStyles(previewElm, {position: 'absolute', left: -0xFFFF});
32052
- editor.getBody().appendChild(previewElm);
32053
-
32054
- // Get parent container font size so we can compute px values out of em/% for older IE:s
32055
- parentFontSize = dom.getStyle(editor.getBody(), 'fontSize', true);
32056
- parentFontSize = /px$/.test(parentFontSize) ? parseInt(parentFontSize, 10) : 0;
32057
-
32058
- each(previewStyles.split(' '), function(name) {
32059
- var value = dom.getStyle(previewElm, name, true);
32060
-
32061
- // If background is transparent then check if the body has a background color we can use
32062
- if (name == 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
32063
- value = dom.getStyle(editor.getBody(), name, true);
32064
-
32065
- // Ignore white since it's the default color, not the nicest fix
32066
- // TODO: Fix this by detecting runtime style
32067
- if (dom.toHex(value).toLowerCase() == '#ffffff') {
32068
- return;
32069
- }
32070
- }
32071
-
32072
- if (name == 'color') {
32073
- // Ignore black since it's the default color, not the nicest fix
32074
- // TODO: Fix this by detecting runtime style
32075
- if (dom.toHex(value).toLowerCase() == '#000000') {
32076
- return;
32077
- }
32078
- }
32079
-
32080
- // Old IE won't calculate the font size so we need to do that manually
32081
- if (name == 'font-size') {
32082
- if (/em|%$/.test(value)) {
32083
- if (parentFontSize === 0) {
32084
- return;
32085
- }
32086
-
32087
- // Convert font size from em/% to px
32088
- value = parseFloat(value, 10) / (/%$/.test(value) ? 100 : 1);
32089
- value = (value * parentFontSize) + 'px';
32090
- }
32091
- }
32092
-
32093
- if (name == "border" && value) {
32094
- previewCss += 'padding:0 2px;';
32095
- }
32096
-
32097
- previewCss += name + ':' + value + ';';
32098
- });
32099
-
32100
- editor.fire('AfterPreviewFormats');
32101
-
32102
- //previewCss += 'line-height:normal';
32103
-
32104
- dom.remove(previewElm);
32105
-
32106
- return previewCss;
32107
- }
32108
-
32109
32688
  function createListBoxChangeHandler(items, formatName) {
32110
32689
  return function() {
32111
32690
  var self = this;
@@ -32142,7 +32721,7 @@ define("tinymce/ui/FormatControls", [
32142
32721
  }
32143
32722
 
32144
32723
  function createFormats(formats) {
32145
- formats = formats.split(';');
32724
+ formats = formats.replace(/;$/, '').split(';');
32146
32725
 
32147
32726
  var i = formats.length;
32148
32727
  while (i--) {
@@ -32156,13 +32735,13 @@ define("tinymce/ui/FormatControls", [
32156
32735
  var count = 0, newFormats = [];
32157
32736
 
32158
32737
  var defaultStyleFormats = [
32159
- {title: 'Headers', items: [
32160
- {title: 'Header 1', format: 'h1'},
32161
- {title: 'Header 2', format: 'h2'},
32162
- {title: 'Header 3', format: 'h3'},
32163
- {title: 'Header 4', format: 'h4'},
32164
- {title: 'Header 5', format: 'h5'},
32165
- {title: 'Header 6', format: 'h6'}
32738
+ {title: 'Headings', items: [
32739
+ {title: 'Heading 1', format: 'h1'},
32740
+ {title: 'Heading 2', format: 'h2'},
32741
+ {title: 'Heading 3', format: 'h3'},
32742
+ {title: 'Heading 4', format: 'h4'},
32743
+ {title: 'Heading 5', format: 'h5'},
32744
+ {title: 'Heading 6', format: 'h6'}
32166
32745
  ]},
32167
32746
 
32168
32747
  {title: 'Inline', items: [
@@ -32255,7 +32834,7 @@ define("tinymce/ui/FormatControls", [
32255
32834
 
32256
32835
  textStyle: function() {
32257
32836
  if (this.settings.format) {
32258
- return getPreviewCss(this.settings.format);
32837
+ return editor.formatter.getCssText(this.settings.format);
32259
32838
  }
32260
32839
  },
32261
32840
 
@@ -32492,12 +33071,12 @@ define("tinymce/ui/FormatControls", [
32492
33071
  'Paragraph=p;' +
32493
33072
  'Address=address;' +
32494
33073
  'Pre=pre;' +
32495
- 'Header 1=h1;' +
32496
- 'Header 2=h2;' +
32497
- 'Header 3=h3;' +
32498
- 'Header 4=h4;' +
32499
- 'Header 5=h5;' +
32500
- 'Header 6=h6'
33074
+ 'Heading 1=h1;' +
33075
+ 'Heading 2=h2;' +
33076
+ 'Heading 3=h3;' +
33077
+ 'Heading 4=h4;' +
33078
+ 'Heading 5=h5;' +
33079
+ 'Heading 6=h6'
32501
33080
  );
32502
33081
 
32503
33082
  each(blocks, function(block) {
@@ -32505,7 +33084,7 @@ define("tinymce/ui/FormatControls", [
32505
33084
  text: block[0],
32506
33085
  value: block[1],
32507
33086
  textStyle: function() {
32508
- return getPreviewCss(block[1]);
33087
+ return editor.formatter.getCssText(block[1]);
32509
33088
  }
32510
33089
  });
32511
33090
  });
@@ -32865,6 +33444,7 @@ define("tinymce/ui/Iframe", [
32865
33444
  self.addClass('iframe');
32866
33445
  self.canFocus = false;
32867
33446
 
33447
+ /*eslint no-script-url:0 */
32868
33448
  return (
32869
33449
  '<iframe id="' + self._id + '" class="' + self.classes() + '" tabindex="-1" src="' +
32870
33450
  (self.settings.url || "javascript:\'\'") + '" frameborder="0"></iframe>'
@@ -33586,7 +34166,7 @@ define("tinymce/ui/MenuItem", [
33586
34166
  e.preventDefault();
33587
34167
  });
33588
34168
 
33589
- if (settings.menu) {
34169
+ if (settings.menu && !settings.ariaHideMenu) {
33590
34170
  self.aria('haspopup', true);
33591
34171
  }
33592
34172
  },
@@ -33730,7 +34310,7 @@ define("tinymce/ui/MenuItem", [
33730
34310
 
33731
34311
  return (
33732
34312
  '<div id="' + id + '" class="' + self.classes() + '" tabindex="-1">' +
33733
- (text !== '-' ? '<i class="' + icon + '"' + image + '></i>&nbsp;' : '') +
34313
+ (text !== '-' ? '<i class="' + icon + '"' + image + '></i>\u00a0' : '') +
33734
34314
  (text !== '-' ? '<span id="' + id + '-text" class="' + prefix + 'text">' + text + '</span>' : '') +
33735
34315
  (shortcut ? '<div id="' + id + '-shortcut" class="' + prefix + 'menu-shortcut">' + shortcut + '</div>' : '') +
33736
34316
  (settings.menu ? '<div class="' + prefix + 'caret"></div>' : '') +
@@ -34184,11 +34764,11 @@ define("tinymce/ui/SplitButton", [
34184
34764
 
34185
34765
  return (
34186
34766
  '<div id="' + id + '" class="' + self.classes() + '" role="button" tabindex="-1">' +
34187
- '<button type="button" hidefocus tabindex="-1">' +
34767
+ '<button type="button" hidefocus="1" tabindex="-1">' +
34188
34768
  (icon ? '<i class="' + icon + '"></i>' : '') +
34189
34769
  (self._text ? (icon ? ' ' : '') + self._text : '') +
34190
34770
  '</button>' +
34191
- '<button type="button" class="' + prefix + 'open" hidefocus tabindex="-1">' +
34771
+ '<button type="button" class="' + prefix + 'open" hidefocus="1" tabindex="-1">' +
34192
34772
  //(icon ? '<i class="' + icon + '"></i>' : '') +
34193
34773
  (self._menuBtnText ? (icon ? '\u00a0' : '') + self._menuBtnText : '') +
34194
34774
  ' <i class="' + prefix + 'caret"></i>' +
@@ -34356,7 +34936,7 @@ define("tinymce/ui/TabPanel", [
34356
34936
  });
34357
34937
 
34358
34938
  return (
34359
- '<div id="' + self._id + '" class="' + self.classes() + '" hideFocus="1" tabIndex="-1">' +
34939
+ '<div id="' + self._id + '" class="' + self.classes() + '" hidefocus="1" tabindex="-1">' +
34360
34940
  '<div id="' + self._id + '-head" class="' + prefix + 'tabs" role="tablist">' +
34361
34941
  tabsHtml +
34362
34942
  '</div>' +
@@ -34632,12 +35212,12 @@ define("tinymce/ui/TextBox", [
34632
35212
  return (
34633
35213
  '<textarea id="' + id + '" class="' + self.classes() + '" ' +
34634
35214
  (settings.rows ? ' rows="' + settings.rows + '"' : '') +
34635
- ' hidefocus="true"' + extraAttrs + '>' + value +
35215
+ ' hidefocus="1"' + extraAttrs + '>' + value +
34636
35216
  '</textarea>'
34637
35217
  );
34638
35218
  }
34639
35219
 
34640
- return '<input id="' + id + '" class="' + self.classes() + '" value="' + value + '" hidefocus="true"' + extraAttrs + '>';
35220
+ return '<input id="' + id + '" class="' + self.classes() + '" value="' + value + '" hidefocus="1"' + extraAttrs + ' />';
34641
35221
  },
34642
35222
 
34643
35223
  /**
@@ -34681,8 +35261,9 @@ define("tinymce/ui/TextBox", [
34681
35261
  * @class tinymce.ui.Throbber
34682
35262
  */
34683
35263
  define("tinymce/ui/Throbber", [
34684
- "tinymce/ui/DomUtils"
34685
- ], function(DomUtils) {
35264
+ "tinymce/ui/DomUtils",
35265
+ "tinymce/ui/Control"
35266
+ ], function(DomUtils, Control) {
34686
35267
  "use strict";
34687
35268
 
34688
35269
  /**
@@ -34690,9 +35271,10 @@ define("tinymce/ui/Throbber", [
34690
35271
  *
34691
35272
  * @constructor
34692
35273
  * @param {Element} elm DOM Html element to display throbber in.
35274
+ * @param {Boolean} inline Optional true/false state if the throbber should be appended to end of element for infinite scroll.
34693
35275
  */
34694
- return function(elm) {
34695
- var self = this, state;
35276
+ return function(elm, inline) {
35277
+ var self = this, state, classPrefix = Control.classPrefix;
34696
35278
 
34697
35279
  /**
34698
35280
  * Shows the throbber.
@@ -34708,7 +35290,9 @@ define("tinymce/ui/Throbber", [
34708
35290
 
34709
35291
  window.setTimeout(function() {
34710
35292
  if (state) {
34711
- elm.appendChild(DomUtils.createFragment('<div class="mce-throbber"></div>'));
35293
+ elm.appendChild(DomUtils.createFragment(
35294
+ '<div class="' + classPrefix + 'throbber' + (inline ? ' ' + classPrefix + 'throbber-inline' : '') + '"></div>'
35295
+ ));
34712
35296
  }
34713
35297
  }, time || 0);
34714
35298
 
@@ -34735,5 +35319,5 @@ define("tinymce/ui/Throbber", [
34735
35319
  };
34736
35320
  });
34737
35321
 
34738
- expose(["tinymce/dom/EventUtils","tinymce/dom/Sizzle","tinymce/dom/DomQuery","tinymce/html/Styles","tinymce/dom/TreeWalker","tinymce/util/Tools","tinymce/dom/Range","tinymce/html/Entities","tinymce/Env","tinymce/dom/StyleSheetLoader","tinymce/dom/DOMUtils","tinymce/dom/ScriptLoader","tinymce/AddOnManager","tinymce/html/Node","tinymce/html/Schema","tinymce/html/SaxParser","tinymce/html/DomParser","tinymce/html/Writer","tinymce/html/Serializer","tinymce/dom/Serializer","tinymce/dom/TridentSelection","tinymce/util/VK","tinymce/dom/ControlSelection","tinymce/dom/RangeUtils","tinymce/dom/Selection","tinymce/Formatter","tinymce/UndoManager","tinymce/EnterKey","tinymce/ForceBlocks","tinymce/EditorCommands","tinymce/util/URI","tinymce/util/Class","tinymce/ui/Selector","tinymce/ui/Collection","tinymce/ui/DomUtils","tinymce/ui/Control","tinymce/ui/Factory","tinymce/ui/KeyboardNavigation","tinymce/ui/Container","tinymce/ui/DragHelper","tinymce/ui/Scrollable","tinymce/ui/Panel","tinymce/ui/Movable","tinymce/ui/Resizable","tinymce/ui/FloatPanel","tinymce/ui/Window","tinymce/ui/MessageBox","tinymce/WindowManager","tinymce/util/Quirks","tinymce/util/Observable","tinymce/Shortcuts","tinymce/Editor","tinymce/util/I18n","tinymce/FocusManager","tinymce/EditorManager","tinymce/LegacyInput","tinymce/util/XHR","tinymce/util/JSON","tinymce/util/JSONRequest","tinymce/util/JSONP","tinymce/util/LocalStorage","tinymce/Compat","tinymce/ui/Layout","tinymce/ui/AbsoluteLayout","tinymce/ui/Tooltip","tinymce/ui/Widget","tinymce/ui/Button","tinymce/ui/ButtonGroup","tinymce/ui/Checkbox","tinymce/ui/PanelButton","tinymce/ui/ColorButton","tinymce/ui/ComboBox","tinymce/ui/Path","tinymce/ui/ElementPath","tinymce/ui/FormItem","tinymce/ui/Form","tinymce/ui/FieldSet","tinymce/ui/FilePicker","tinymce/ui/FitLayout","tinymce/ui/FlexLayout","tinymce/ui/FlowLayout","tinymce/ui/FormatControls","tinymce/ui/GridLayout","tinymce/ui/Iframe","tinymce/ui/Label","tinymce/ui/Toolbar","tinymce/ui/MenuBar","tinymce/ui/MenuButton","tinymce/ui/ListBox","tinymce/ui/MenuItem","tinymce/ui/Menu","tinymce/ui/Radio","tinymce/ui/ResizeHandle","tinymce/ui/Spacer","tinymce/ui/SplitButton","tinymce/ui/StackLayout","tinymce/ui/TabPanel","tinymce/ui/TextBox","tinymce/ui/Throbber"]);
35322
+ expose(["tinymce/dom/EventUtils","tinymce/dom/Sizzle","tinymce/dom/DomQuery","tinymce/html/Styles","tinymce/dom/TreeWalker","tinymce/util/Tools","tinymce/dom/Range","tinymce/html/Entities","tinymce/Env","tinymce/dom/StyleSheetLoader","tinymce/dom/DOMUtils","tinymce/dom/ScriptLoader","tinymce/AddOnManager","tinymce/html/Node","tinymce/html/Schema","tinymce/html/SaxParser","tinymce/html/DomParser","tinymce/html/Writer","tinymce/html/Serializer","tinymce/dom/Serializer","tinymce/dom/TridentSelection","tinymce/util/VK","tinymce/dom/ControlSelection","tinymce/dom/RangeUtils","tinymce/dom/Selection","tinymce/fmt/Preview","tinymce/Formatter","tinymce/UndoManager","tinymce/EnterKey","tinymce/ForceBlocks","tinymce/EditorCommands","tinymce/util/URI","tinymce/util/Class","tinymce/util/EventDispatcher","tinymce/ui/Selector","tinymce/ui/Collection","tinymce/ui/DomUtils","tinymce/ui/Control","tinymce/ui/Factory","tinymce/ui/KeyboardNavigation","tinymce/ui/Container","tinymce/ui/DragHelper","tinymce/ui/Scrollable","tinymce/ui/Panel","tinymce/ui/Movable","tinymce/ui/Resizable","tinymce/ui/FloatPanel","tinymce/ui/Window","tinymce/ui/MessageBox","tinymce/WindowManager","tinymce/util/Quirks","tinymce/util/Observable","tinymce/EditorObservable","tinymce/Shortcuts","tinymce/Editor","tinymce/util/I18n","tinymce/FocusManager","tinymce/EditorManager","tinymce/LegacyInput","tinymce/util/XHR","tinymce/util/JSON","tinymce/util/JSONRequest","tinymce/util/JSONP","tinymce/util/LocalStorage","tinymce/Compat","tinymce/ui/Layout","tinymce/ui/AbsoluteLayout","tinymce/ui/Tooltip","tinymce/ui/Widget","tinymce/ui/Button","tinymce/ui/ButtonGroup","tinymce/ui/Checkbox","tinymce/ui/PanelButton","tinymce/ui/ColorButton","tinymce/ui/ComboBox","tinymce/ui/Path","tinymce/ui/ElementPath","tinymce/ui/FormItem","tinymce/ui/Form","tinymce/ui/FieldSet","tinymce/ui/FilePicker","tinymce/ui/FitLayout","tinymce/ui/FlexLayout","tinymce/ui/FlowLayout","tinymce/ui/FormatControls","tinymce/ui/GridLayout","tinymce/ui/Iframe","tinymce/ui/Label","tinymce/ui/Toolbar","tinymce/ui/MenuBar","tinymce/ui/MenuButton","tinymce/ui/ListBox","tinymce/ui/MenuItem","tinymce/ui/Menu","tinymce/ui/Radio","tinymce/ui/ResizeHandle","tinymce/ui/Spacer","tinymce/ui/SplitButton","tinymce/ui/StackLayout","tinymce/ui/TabPanel","tinymce/ui/TextBox","tinymce/ui/Throbber"]);
34739
35323
  })(this);