tinymce-rails 4.0.19 → 4.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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);