tinymce-rails 8.2.2 → 8.3.0

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/source/tinymce/tinymce.js +496 -462
  3. data/lib/tinymce/rails/version.rb +2 -2
  4. data/vendor/assets/javascripts/tinymce/icons/default/icons.js +1 -1
  5. data/vendor/assets/javascripts/tinymce/plugins/accordion/plugin.js +1 -1
  6. data/vendor/assets/javascripts/tinymce/plugins/advlist/plugin.js +1 -1
  7. data/vendor/assets/javascripts/tinymce/plugins/link/plugin.js +1 -1
  8. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.css +1 -1
  9. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.inline.css +1 -1
  10. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.inline.js +1 -1
  11. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.inline.min.css +1 -1
  12. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.js +1 -1
  13. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.min.css +1 -1
  14. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/skin.css +1 -1
  15. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/skin.js +1 -1
  16. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/skin.min.css +1 -1
  17. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.css +1 -1
  18. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.inline.css +1 -1
  19. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.inline.js +1 -1
  20. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.inline.min.css +1 -1
  21. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.js +1 -1
  22. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.min.css +1 -1
  23. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/skin.css +1 -1
  24. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/skin.js +1 -1
  25. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/skin.min.css +1 -1
  26. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.css +1 -1
  27. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.inline.css +1 -1
  28. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.inline.js +1 -1
  29. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.inline.min.css +1 -1
  30. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.js +1 -1
  31. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.min.css +1 -1
  32. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/skin.css +1 -1
  33. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/skin.js +1 -1
  34. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/skin.min.css +1 -1
  35. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.css +1 -1
  36. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.inline.css +1 -1
  37. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.inline.js +1 -1
  38. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css +1 -1
  39. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.js +1 -1
  40. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.min.css +1 -1
  41. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/skin.css +1 -1
  42. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/skin.js +1 -1
  43. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/skin.min.css +1 -1
  44. data/vendor/assets/javascripts/tinymce/themes/silver/theme.js +1 -1
  45. data/vendor/assets/javascripts/tinymce/tinymce.d.ts +15 -1
  46. data/vendor/assets/javascripts/tinymce/tinymce.js +2 -2
  47. metadata +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * TinyMCE version 8.2.2 (2025-11-17)
2
+ * TinyMCE version 8.3.0 (2025-12-10)
3
3
  */
4
4
 
5
5
  (function () {
@@ -2866,7 +2866,7 @@
2866
2866
  }
2867
2867
  return Optional.none();
2868
2868
  };
2869
- const closest$4 = (scope, predicate, isRoot) => {
2869
+ const closest$5 = (scope, predicate, isRoot) => {
2870
2870
  // This is required to avoid ClosestOrAncestor passing the predicate to itself
2871
2871
  const is = (s, test) => test(s);
2872
2872
  return ClosestOrAncestor(is, ancestor$5, scope, predicate, isRoot);
@@ -2904,7 +2904,7 @@
2904
2904
  const ancestor$4 = (scope, selector, isRoot) => ancestor$5(scope, (e) => is$2(e, selector), isRoot);
2905
2905
  const descendant$1 = (scope, selector) => one(selector, scope);
2906
2906
  // Returns Some(closest ancestor element (sugared)) matching 'selector' up to isRoot, or None() otherwise
2907
- const closest$3 = (scope, selector, isRoot) => {
2907
+ const closest$4 = (scope, selector, isRoot) => {
2908
2908
  const is = (element, selector) => is$2(element, selector);
2909
2909
  return ClosestOrAncestor(is, ancestor$4, scope, selector, isRoot);
2910
2910
  };
@@ -2978,14 +2978,14 @@
2978
2978
  });
2979
2979
  };
2980
2980
 
2981
- const closest$2 = (target) => closest$3(target, '[contenteditable]');
2981
+ const closest$3 = (target) => closest$4(target, '[contenteditable]');
2982
2982
  const isEditable$2 = (element, assumeEditable = false) => {
2983
2983
  if (inBody(element)) {
2984
2984
  return element.dom.isContentEditable;
2985
2985
  }
2986
2986
  else {
2987
2987
  // Find the closest contenteditable element and check if it's editable
2988
- return closest$2(element).fold(constant(assumeEditable), (editable) => getRaw(editable) === 'true');
2988
+ return closest$3(element).fold(constant(assumeEditable), (editable) => getRaw(editable) === 'true');
2989
2989
  }
2990
2990
  };
2991
2991
  const getRaw = (element) => element.dom.contentEditable;
@@ -3025,6 +3025,7 @@
3025
3025
  const ancestor$2 = (element, target) => ancestor$3(element, curry(eq, target));
3026
3026
 
3027
3027
  const ancestor$1 = (scope, selector, isRoot) => ancestor$4(scope, selector, isRoot).isSome();
3028
+ const closest$2 = (scope, selector, isRoot) => closest$4(scope, selector, isRoot).isSome();
3028
3029
 
3029
3030
  const ensureIsRoot = (isRoot) => isFunction(isRoot) ? isRoot : never;
3030
3031
  const ancestor = (scope, transform, isRoot) => {
@@ -8142,7 +8143,7 @@
8142
8143
  const root = SugarElement.fromDom(editor.getBody());
8143
8144
  const selector = annotationName.fold(() => '.' + annotation(), (an) => `[${dataAnnotation()}="${an}"]`);
8144
8145
  const newStart = child$1(start, rng.startOffset).getOr(start);
8145
- const closest = closest$3(newStart, selector, isRoot$1(root));
8146
+ const closest = closest$4(newStart, selector, isRoot$1(root));
8146
8147
  return closest.bind((c) => getOpt(c, `${dataAnnotationId()}`).bind((uid) => getOpt(c, `${dataAnnotation()}`).map((name) => {
8147
8148
  const elements = findMarkers(editor, uid);
8148
8149
  return {
@@ -9503,6 +9504,251 @@
9503
9504
  */
9504
9505
  const isBackwards = (direction) => direction === -1 /* HDirection.Backwards */;
9505
9506
 
9507
+ var SimpleResultType;
9508
+ (function (SimpleResultType) {
9509
+ SimpleResultType[SimpleResultType["Error"] = 0] = "Error";
9510
+ SimpleResultType[SimpleResultType["Value"] = 1] = "Value";
9511
+ })(SimpleResultType || (SimpleResultType = {}));
9512
+ const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue);
9513
+ const partition = (results) => {
9514
+ const values = [];
9515
+ const errors = [];
9516
+ each$e(results, (obj) => {
9517
+ fold$1(obj, (err) => errors.push(err), (val) => values.push(val));
9518
+ });
9519
+ return { values, errors };
9520
+ };
9521
+ const mapError = (res, f) => {
9522
+ if (res.stype === SimpleResultType.Error) {
9523
+ return { stype: SimpleResultType.Error, serror: f(res.serror) };
9524
+ }
9525
+ else {
9526
+ return res;
9527
+ }
9528
+ };
9529
+ const map = (res, f) => {
9530
+ if (res.stype === SimpleResultType.Value) {
9531
+ return { stype: SimpleResultType.Value, svalue: f(res.svalue) };
9532
+ }
9533
+ else {
9534
+ return res;
9535
+ }
9536
+ };
9537
+ const bind = (res, f) => {
9538
+ if (res.stype === SimpleResultType.Value) {
9539
+ return f(res.svalue);
9540
+ }
9541
+ else {
9542
+ return res;
9543
+ }
9544
+ };
9545
+ const bindError = (res, f) => {
9546
+ if (res.stype === SimpleResultType.Error) {
9547
+ return f(res.serror);
9548
+ }
9549
+ else {
9550
+ return res;
9551
+ }
9552
+ };
9553
+ const svalue = (v) => ({ stype: SimpleResultType.Value, svalue: v });
9554
+ const serror = (e) => ({ stype: SimpleResultType.Error, serror: e });
9555
+ const toResult = (res) => fold$1(res, Result.error, Result.value);
9556
+ const fromResult = (res) => res.fold(serror, svalue);
9557
+ const SimpleResult = {
9558
+ fromResult,
9559
+ toResult,
9560
+ svalue,
9561
+ partition,
9562
+ serror,
9563
+ bind,
9564
+ bindError,
9565
+ map,
9566
+ mapError,
9567
+ fold: fold$1
9568
+ };
9569
+
9570
+ const formatObj = (input) => {
9571
+ return isObject(input) && keys(input).length > 100 ? ' removed due to size' : JSON.stringify(input, null, 2);
9572
+ };
9573
+ const formatErrors = (errors) => {
9574
+ const es = errors.length > 10 ? errors.slice(0, 10).concat([
9575
+ {
9576
+ path: [],
9577
+ getErrorInfo: constant('... (only showing first ten failures)')
9578
+ }
9579
+ ]) : errors;
9580
+ // TODO: Work out a better split between PrettyPrinter and SchemaError
9581
+ return map$3(es, (e) => {
9582
+ return 'Failed path: (' + e.path.join(' > ') + ')\n' + e.getErrorInfo();
9583
+ });
9584
+ };
9585
+
9586
+ const nu = (path, getErrorInfo) => {
9587
+ return SimpleResult.serror([{
9588
+ path,
9589
+ // This is lazy so that it isn't calculated unnecessarily
9590
+ getErrorInfo
9591
+ }]);
9592
+ };
9593
+ const missingRequired = (path, key, obj) => nu(path, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj));
9594
+ const custom = (path, err) => nu(path, constant(err));
9595
+
9596
+ const value = (validator) => {
9597
+ const extract = (path, val) => {
9598
+ return SimpleResult.bindError(validator(val), (err) => custom(path, err));
9599
+ };
9600
+ const toString = constant('val');
9601
+ return {
9602
+ extract,
9603
+ toString
9604
+ };
9605
+ };
9606
+ const anyValue$1 = value(SimpleResult.svalue);
9607
+
9608
+ const anyValue = constant(anyValue$1);
9609
+ const typedValue = (validator, expectedType) => value((a) => {
9610
+ const actualType = typeof a;
9611
+ return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${expectedType} but got: ${actualType}`);
9612
+ });
9613
+ const number = typedValue(isNumber, 'number');
9614
+ const string = typedValue(isString, 'string');
9615
+ const functionProcessor = typedValue(isFunction, 'function');
9616
+
9617
+ const required$1 = () => ({ tag: "required" /* FieldPresenceTag.Required */, process: {} });
9618
+ const defaultedThunk = (fallbackThunk) => ({ tag: "defaultedThunk" /* FieldPresenceTag.DefaultedThunk */, process: fallbackThunk });
9619
+ const defaulted$1 = (fallback) => defaultedThunk(constant(fallback));
9620
+ const asOption = () => ({ tag: "option" /* FieldPresenceTag.Option */, process: {} });
9621
+
9622
+ const field$1 = (key, newKey, presence, prop) => ({ tag: "field" /* FieldTag.Field */, key, newKey, presence, prop });
9623
+ const fold = (value, ifField, ifCustom) => {
9624
+ switch (value.tag) {
9625
+ case "field" /* FieldTag.Field */:
9626
+ return ifField(value.key, value.newKey, value.presence, value.prop);
9627
+ case "custom" /* FieldTag.CustomField */:
9628
+ return ifCustom(value.newKey, value.instantiator);
9629
+ }
9630
+ };
9631
+
9632
+ const mergeValues = (values, base) => {
9633
+ return SimpleResult.svalue(deepMerge(base, merge$1.apply(undefined, values)));
9634
+ };
9635
+ const mergeErrors = (errors) => compose(SimpleResult.serror, flatten$1)(errors);
9636
+ const consolidateObj = (objects, base) => {
9637
+ const partition = SimpleResult.partition(objects);
9638
+ return partition.errors.length > 0 ? mergeErrors(partition.errors) : mergeValues(partition.values, base);
9639
+ };
9640
+ const consolidateArr = (objects) => {
9641
+ const partitions = SimpleResult.partition(objects);
9642
+ return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : SimpleResult.svalue(partitions.values);
9643
+ };
9644
+ const ResultCombine = {
9645
+ consolidateObj,
9646
+ consolidateArr
9647
+ };
9648
+
9649
+ const requiredAccess = (path, obj, key, bundle) =>
9650
+ // In required mode, if it is undefined, it is an error.
9651
+ get$a(obj, key).fold(() => missingRequired(path, key, obj), bundle);
9652
+ const fallbackAccess = (obj, key, fallback, bundle) => {
9653
+ const v = get$a(obj, key).getOrThunk(() => fallback(obj));
9654
+ return bundle(v);
9655
+ };
9656
+ const optionAccess = (obj, key, bundle) => bundle(get$a(obj, key));
9657
+ const optionDefaultedAccess = (obj, key, fallback, bundle) => {
9658
+ const opt = get$a(obj, key).map((val) => val === true ? fallback(obj) : val);
9659
+ return bundle(opt);
9660
+ };
9661
+ const extractField = (field, path, obj, key, prop) => {
9662
+ const bundle = (av) => prop.extract(path.concat([key]), av);
9663
+ const bundleAsOption = (optValue) => optValue.fold(() => SimpleResult.svalue(Optional.none()), (ov) => {
9664
+ const result = prop.extract(path.concat([key]), ov);
9665
+ return SimpleResult.map(result, Optional.some);
9666
+ });
9667
+ switch (field.tag) {
9668
+ case "required" /* FieldPresenceTag.Required */:
9669
+ return requiredAccess(path, obj, key, bundle);
9670
+ case "defaultedThunk" /* FieldPresenceTag.DefaultedThunk */:
9671
+ return fallbackAccess(obj, key, field.process, bundle);
9672
+ case "option" /* FieldPresenceTag.Option */:
9673
+ return optionAccess(obj, key, bundleAsOption);
9674
+ case "defaultedOptionThunk" /* FieldPresenceTag.DefaultedOptionThunk */:
9675
+ return optionDefaultedAccess(obj, key, field.process, bundleAsOption);
9676
+ case "mergeWithThunk" /* FieldPresenceTag.MergeWithThunk */: {
9677
+ return fallbackAccess(obj, key, constant({}), (v) => {
9678
+ const result = deepMerge(field.process(obj), v);
9679
+ return bundle(result);
9680
+ });
9681
+ }
9682
+ }
9683
+ };
9684
+ const extractFields = (path, obj, fields) => {
9685
+ const success = {};
9686
+ const errors = [];
9687
+ // PERFORMANCE: We use a for loop here instead of Arr.each as this is a hot code path
9688
+ for (const field of fields) {
9689
+ fold(field, (key, newKey, presence, prop) => {
9690
+ const result = extractField(presence, path, obj, key, prop);
9691
+ SimpleResult.fold(result, (err) => {
9692
+ errors.push(...err);
9693
+ }, (res) => {
9694
+ success[newKey] = res;
9695
+ });
9696
+ }, (newKey, instantiator) => {
9697
+ success[newKey] = instantiator(obj);
9698
+ });
9699
+ }
9700
+ return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success);
9701
+ };
9702
+ const objOf = (values) => {
9703
+ const extract = (path, o) => extractFields(path, o, values);
9704
+ const toString = () => {
9705
+ const fieldStrings = map$3(values, (value) => fold(value, (key, _okey, _presence, prop) => key + ' -> ' + prop.toString(), (newKey, _instantiator) => 'state(' + newKey + ')'));
9706
+ return 'obj{\n' + fieldStrings.join('\n') + '}';
9707
+ };
9708
+ return {
9709
+ extract,
9710
+ toString
9711
+ };
9712
+ };
9713
+ const arrOf = (prop) => {
9714
+ const extract = (path, array) => {
9715
+ const results = map$3(array, (a, i) => prop.extract(path.concat(['[' + i + ']']), a));
9716
+ return ResultCombine.consolidateArr(results);
9717
+ };
9718
+ const toString = () => 'array(' + prop.toString() + ')';
9719
+ return {
9720
+ extract,
9721
+ toString
9722
+ };
9723
+ };
9724
+ const arrOfObj = compose(arrOf, objOf);
9725
+
9726
+ const valueOf = (validator) => value((v) => validator(v).fold(SimpleResult.serror, SimpleResult.svalue));
9727
+ const extractValue = (label, prop, obj) => {
9728
+ const res = prop.extract([label], obj);
9729
+ return SimpleResult.mapError(res, (errs) => ({ input: obj, errors: errs }));
9730
+ };
9731
+ const asRaw = (label, prop, obj) => SimpleResult.toResult(extractValue(label, prop, obj));
9732
+ const formatError = (errInfo) => {
9733
+ return 'Errors: \n' + formatErrors(errInfo.errors).join('\n') +
9734
+ '\n\nInput object: ' + formatObj(errInfo.input);
9735
+ };
9736
+
9737
+ const field = field$1;
9738
+ const required = (key) => field(key, key, required$1(), anyValue());
9739
+ const requiredOf = (key, schema) => field(key, key, required$1(), schema);
9740
+ const requiredString = (key) => requiredOf(key, string);
9741
+ const requiredFunction = (key) => requiredOf(key, functionProcessor);
9742
+ const requiredArrayOf = (key, schema) => field(key, key, required$1(), arrOf(schema));
9743
+ const option$1 = (key) => field(key, key, asOption(), anyValue());
9744
+ const optionOf = (key, schema) => field(key, key, asOption(), schema);
9745
+ const optionString = (key) => optionOf(key, string);
9746
+ const optionFunction = (key) => optionOf(key, functionProcessor);
9747
+ const defaulted = (key, fallback) => field(key, key, defaulted$1(fallback), anyValue());
9748
+ const defaultedOf = (key, fallback, schema) => field(key, key, defaulted$1(fallback), schema);
9749
+ const defaultedNumber = (key, fallback) => defaultedOf(key, fallback, number);
9750
+ const defaultedArrayOf = (key, fallback, schema) => defaultedOf(key, fallback, arrOf(schema));
9751
+
9506
9752
  const isInlinePattern = (pattern) => pattern.type === 'inline-command' || pattern.type === 'inline-format';
9507
9753
  const isBlockPattern = (pattern) => pattern.type === 'block-command' || pattern.type === 'block-format';
9508
9754
  const hasBlockTrigger = (pattern, trigger) => (pattern.type === 'block-command' || pattern.type === 'block-format') && pattern.trigger === trigger;
@@ -9695,7 +9941,7 @@
9695
9941
  }, {});
9696
9942
  };
9697
9943
  const isRegExp = (x) => is$5(x, RegExp);
9698
- const option$1 = (name) => (editor) => editor.options.get(name);
9944
+ const option = (name) => (editor) => editor.options.get(name);
9699
9945
  const stringOrObjectProcessor = (value) => isString(value) || isObject(value);
9700
9946
  const bodyOptionProcessor = (editor, defaultValue = '') => (value) => {
9701
9947
  const valid = isString(value);
@@ -10456,6 +10702,23 @@
10456
10702
  };
10457
10703
  }
10458
10704
  });
10705
+ const documentsFileTypesOptionsSchema = arrOfObj([
10706
+ requiredString('mimeType'),
10707
+ requiredArrayOf('extensions', valueOf((ext) => {
10708
+ if (isString(ext)) {
10709
+ return Result.value(ext);
10710
+ }
10711
+ else {
10712
+ return Result.error('Extensions must be an array of strings');
10713
+ }
10714
+ })),
10715
+ ]);
10716
+ registerOption('documents_file_types', {
10717
+ processor: (value) => asRaw('documents_file_types', documentsFileTypesOptionsSchema, value).fold((_err) => ({
10718
+ valid: false,
10719
+ message: 'Must be a non-empty array of objects matching the configuration schema: https://www.tiny.cloud/docs/tinymce/latest/uploadcare-documents/#documents-file-types'
10720
+ }), (val) => ({ valid: true, value: val }))
10721
+ });
10459
10722
  // These options must be registered later in the init sequence due to their default values
10460
10723
  editor.on('ScriptsLoaded', () => {
10461
10724
  registerOption('directionality', {
@@ -10487,117 +10750,117 @@
10487
10750
  },
10488
10751
  });
10489
10752
  };
10490
- const getIframeAttrs = option$1('iframe_attrs');
10491
- const getDocType = option$1('doctype');
10492
- const getDocumentBaseUrl = option$1('document_base_url');
10493
- const getBodyId = option$1('body_id');
10494
- const getBodyClass = option$1('body_class');
10495
- const getContentSecurityPolicy = option$1('content_security_policy');
10496
- const shouldPutBrInPre$1 = option$1('br_in_pre');
10497
- const getForcedRootBlock = option$1('forced_root_block');
10498
- const getForcedRootBlockAttrs = option$1('forced_root_block_attrs');
10499
- const getNewlineBehavior = option$1('newline_behavior');
10500
- const getBrNewLineSelector = option$1('br_newline_selector');
10501
- const getNoNewLineSelector = option$1('no_newline_selector');
10502
- const shouldKeepStyles = option$1('keep_styles');
10503
- const shouldEndContainerOnEmptyBlock = option$1('end_container_on_empty_block');
10504
- const isAutomaticUploadsEnabled = option$1('automatic_uploads');
10505
- const shouldReuseFileName = option$1('images_reuse_filename');
10506
- const shouldReplaceBlobUris = option$1('images_replace_blob_uris');
10507
- const getIconPackName = option$1('icons');
10508
- const getIconsUrl = option$1('icons_url');
10509
- const getImageUploadUrl = option$1('images_upload_url');
10510
- const getImageUploadBasePath = option$1('images_upload_base_path');
10511
- const getImagesUploadCredentials = option$1('images_upload_credentials');
10512
- const getImagesUploadHandler = option$1('images_upload_handler');
10513
- const shouldUseContentCssCors = option$1('content_css_cors');
10514
- const getReferrerPolicy = option$1('referrer_policy');
10515
- const getCrossOrigin = option$1('crossorigin');
10516
- const getLanguageCode = option$1('language');
10517
- const getLanguageUrl = option$1('language_url');
10518
- const shouldIndentUseMargin = option$1('indent_use_margin');
10519
- const getIndentation = option$1('indentation');
10520
- const getContentCss = option$1('content_css');
10521
- const getContentStyle = option$1('content_style');
10522
- const getFontCss = option$1('font_css');
10523
- const getDirectionality = option$1('directionality');
10524
- const getInlineBoundarySelector = option$1('inline_boundaries_selector');
10525
- const getObjectResizing = option$1('object_resizing');
10526
- const getResizeImgProportional = option$1('resize_img_proportional');
10527
- const getPlaceholder = option$1('placeholder');
10528
- const getEventRoot = option$1('event_root');
10529
- const getServiceMessage = option$1('service_message');
10530
- const getTheme = option$1('theme');
10531
- const getThemeUrl = option$1('theme_url');
10532
- const getModel = option$1('model');
10533
- const getModelUrl = option$1('model_url');
10534
- const isInlineBoundariesEnabled = option$1('inline_boundaries');
10535
- const getFormats = option$1('formats');
10536
- const getPreviewStyles = option$1('preview_styles');
10537
- const canFormatEmptyLines = option$1('format_empty_lines');
10538
- const getFormatNoneditableSelector = option$1('format_noneditable_selector');
10539
- const getCustomUiSelector = option$1('custom_ui_selector');
10540
- const isInline$2 = option$1('inline');
10541
- const hasHiddenInput = option$1('hidden_input');
10542
- const shouldPatchSubmit = option$1('submit_patch');
10543
- const shouldAddFormSubmitTrigger = option$1('add_form_submit_trigger');
10544
- const shouldAddUnloadTrigger = option$1('add_unload_trigger');
10545
- const getCustomUndoRedoLevels = option$1('custom_undo_redo_levels');
10546
- const shouldDisableNodeChange = option$1('disable_nodechange');
10547
- const isReadOnly$1 = option$1('readonly');
10548
- const hasEditableRoot$1 = option$1('editable_root');
10549
- const hasContentCssCors = option$1('content_css_cors');
10550
- const getPlugins = option$1('plugins');
10551
- const getExternalPlugins$1 = option$1('external_plugins');
10552
- const shouldBlockUnsupportedDrop = option$1('block_unsupported_drop');
10553
- const isVisualAidsEnabled = option$1('visual');
10554
- const getVisualAidsTableClass = option$1('visual_table_class');
10555
- const getVisualAidsAnchorClass = option$1('visual_anchor_class');
10556
- const getIframeAriaText = option$1('iframe_aria_text');
10557
- const getSetupCallback = option$1('setup');
10558
- const getInitInstanceCallback = option$1('init_instance_callback');
10559
- const getUrlConverterCallback = option$1('urlconverter_callback');
10560
- const getAutoFocus = option$1('auto_focus');
10561
- const shouldBrowserSpellcheck = option$1('browser_spellcheck');
10562
- const getProtect = option$1('protect');
10563
- const shouldPasteBlockDrop = option$1('paste_block_drop');
10564
- const shouldPasteDataImages = option$1('paste_data_images');
10565
- const getPastePreProcess = option$1('paste_preprocess');
10566
- const getPastePostProcess = option$1('paste_postprocess');
10567
- const getNewDocumentContent = option$1('newdocument_content');
10568
- const getPasteWebkitStyles = option$1('paste_webkit_styles');
10569
- const shouldPasteRemoveWebKitStyles = option$1('paste_remove_styles_if_webkit');
10570
- const shouldPasteMergeFormats = option$1('paste_merge_formats');
10571
- const isSmartPasteEnabled = option$1('smart_paste');
10572
- const isPasteAsTextEnabled = option$1('paste_as_text');
10573
- const getPasteTabSpaces = option$1('paste_tab_spaces');
10574
- const shouldAllowHtmlDataUrls = option$1('allow_html_data_urls');
10575
- const getTextPatterns = option$1('text_patterns');
10576
- const getTextPatternsLookup = option$1('text_patterns_lookup');
10577
- const getNonEditableClass = option$1('noneditable_class');
10578
- const getEditableClass = option$1('editable_class');
10579
- const getNonEditableRegExps = option$1('noneditable_regexp');
10580
- const shouldPreserveCData = option$1('preserve_cdata');
10581
- const shouldHighlightOnFocus = option$1('highlight_on_focus');
10582
- const shouldSanitizeXss = option$1('xss_sanitization');
10583
- const shouldUseDocumentWrite = option$1('init_content_sync');
10753
+ const getIframeAttrs = option('iframe_attrs');
10754
+ const getDocType = option('doctype');
10755
+ const getDocumentBaseUrl = option('document_base_url');
10756
+ const getBodyId = option('body_id');
10757
+ const getBodyClass = option('body_class');
10758
+ const getContentSecurityPolicy = option('content_security_policy');
10759
+ const shouldPutBrInPre$1 = option('br_in_pre');
10760
+ const getForcedRootBlock = option('forced_root_block');
10761
+ const getForcedRootBlockAttrs = option('forced_root_block_attrs');
10762
+ const getNewlineBehavior = option('newline_behavior');
10763
+ const getBrNewLineSelector = option('br_newline_selector');
10764
+ const getNoNewLineSelector = option('no_newline_selector');
10765
+ const shouldKeepStyles = option('keep_styles');
10766
+ const shouldEndContainerOnEmptyBlock = option('end_container_on_empty_block');
10767
+ const isAutomaticUploadsEnabled = option('automatic_uploads');
10768
+ const shouldReuseFileName = option('images_reuse_filename');
10769
+ const shouldReplaceBlobUris = option('images_replace_blob_uris');
10770
+ const getIconPackName = option('icons');
10771
+ const getIconsUrl = option('icons_url');
10772
+ const getImageUploadUrl = option('images_upload_url');
10773
+ const getImageUploadBasePath = option('images_upload_base_path');
10774
+ const getImagesUploadCredentials = option('images_upload_credentials');
10775
+ const getImagesUploadHandler = option('images_upload_handler');
10776
+ const shouldUseContentCssCors = option('content_css_cors');
10777
+ const getReferrerPolicy = option('referrer_policy');
10778
+ const getCrossOrigin = option('crossorigin');
10779
+ const getLanguageCode = option('language');
10780
+ const getLanguageUrl = option('language_url');
10781
+ const shouldIndentUseMargin = option('indent_use_margin');
10782
+ const getIndentation = option('indentation');
10783
+ const getContentCss = option('content_css');
10784
+ const getContentStyle = option('content_style');
10785
+ const getFontCss = option('font_css');
10786
+ const getDirectionality = option('directionality');
10787
+ const getInlineBoundarySelector = option('inline_boundaries_selector');
10788
+ const getObjectResizing = option('object_resizing');
10789
+ const getResizeImgProportional = option('resize_img_proportional');
10790
+ const getPlaceholder = option('placeholder');
10791
+ const getEventRoot = option('event_root');
10792
+ const getServiceMessage = option('service_message');
10793
+ const getTheme = option('theme');
10794
+ const getThemeUrl = option('theme_url');
10795
+ const getModel = option('model');
10796
+ const getModelUrl = option('model_url');
10797
+ const isInlineBoundariesEnabled = option('inline_boundaries');
10798
+ const getFormats = option('formats');
10799
+ const getPreviewStyles = option('preview_styles');
10800
+ const canFormatEmptyLines = option('format_empty_lines');
10801
+ const getFormatNoneditableSelector = option('format_noneditable_selector');
10802
+ const getCustomUiSelector = option('custom_ui_selector');
10803
+ const isInline$2 = option('inline');
10804
+ const hasHiddenInput = option('hidden_input');
10805
+ const shouldPatchSubmit = option('submit_patch');
10806
+ const shouldAddFormSubmitTrigger = option('add_form_submit_trigger');
10807
+ const shouldAddUnloadTrigger = option('add_unload_trigger');
10808
+ const getCustomUndoRedoLevels = option('custom_undo_redo_levels');
10809
+ const shouldDisableNodeChange = option('disable_nodechange');
10810
+ const isReadOnly$1 = option('readonly');
10811
+ const hasEditableRoot$1 = option('editable_root');
10812
+ const hasContentCssCors = option('content_css_cors');
10813
+ const getPlugins = option('plugins');
10814
+ const getExternalPlugins$1 = option('external_plugins');
10815
+ const shouldBlockUnsupportedDrop = option('block_unsupported_drop');
10816
+ const isVisualAidsEnabled = option('visual');
10817
+ const getVisualAidsTableClass = option('visual_table_class');
10818
+ const getVisualAidsAnchorClass = option('visual_anchor_class');
10819
+ const getIframeAriaText = option('iframe_aria_text');
10820
+ const getSetupCallback = option('setup');
10821
+ const getInitInstanceCallback = option('init_instance_callback');
10822
+ const getUrlConverterCallback = option('urlconverter_callback');
10823
+ const getAutoFocus = option('auto_focus');
10824
+ const shouldBrowserSpellcheck = option('browser_spellcheck');
10825
+ const getProtect = option('protect');
10826
+ const shouldPasteBlockDrop = option('paste_block_drop');
10827
+ const shouldPasteDataImages = option('paste_data_images');
10828
+ const getPastePreProcess = option('paste_preprocess');
10829
+ const getPastePostProcess = option('paste_postprocess');
10830
+ const getNewDocumentContent = option('newdocument_content');
10831
+ const getPasteWebkitStyles = option('paste_webkit_styles');
10832
+ const shouldPasteRemoveWebKitStyles = option('paste_remove_styles_if_webkit');
10833
+ const shouldPasteMergeFormats = option('paste_merge_formats');
10834
+ const isSmartPasteEnabled = option('smart_paste');
10835
+ const isPasteAsTextEnabled = option('paste_as_text');
10836
+ const getPasteTabSpaces = option('paste_tab_spaces');
10837
+ const shouldAllowHtmlDataUrls = option('allow_html_data_urls');
10838
+ const getTextPatterns = option('text_patterns');
10839
+ const getTextPatternsLookup = option('text_patterns_lookup');
10840
+ const getNonEditableClass = option('noneditable_class');
10841
+ const getEditableClass = option('editable_class');
10842
+ const getNonEditableRegExps = option('noneditable_regexp');
10843
+ const shouldPreserveCData = option('preserve_cdata');
10844
+ const shouldHighlightOnFocus = option('highlight_on_focus');
10845
+ const shouldSanitizeXss = option('xss_sanitization');
10846
+ const shouldUseDocumentWrite = option('init_content_sync');
10584
10847
  const hasTextPatternsLookup = (editor) => editor.options.isSet('text_patterns_lookup');
10585
10848
  const getFontStyleValues = (editor) => Tools.explode(editor.options.get('font_size_style_values'));
10586
10849
  const getFontSizeClasses = (editor) => Tools.explode(editor.options.get('font_size_classes'));
10587
10850
  const isEncodingXml = (editor) => editor.options.get('encoding') === 'xml';
10588
10851
  const getAllowedImageFileTypes = (editor) => Tools.explode(editor.options.get('images_file_types'));
10589
- const hasTableTabNavigation = option$1('table_tab_navigation');
10590
- const getDetailsInitialState = option$1('details_initial_state');
10591
- const getDetailsSerializedState = option$1('details_serialized_state');
10592
- const shouldSandboxIframes = option$1('sandbox_iframes');
10852
+ const hasTableTabNavigation = option('table_tab_navigation');
10853
+ const getDetailsInitialState = option('details_initial_state');
10854
+ const getDetailsSerializedState = option('details_serialized_state');
10855
+ const shouldSandboxIframes = option('sandbox_iframes');
10593
10856
  const getSandboxIframesExclusions = (editor) => editor.options.get('sandbox_iframes_exclusions');
10594
- const shouldConvertUnsafeEmbeds = option$1('convert_unsafe_embeds');
10595
- const getLicenseKey = option$1('license_key');
10596
- const getApiKey = option$1('api_key');
10597
- const isDisabled$1 = option$1('disabled');
10598
- const getUserId = option$1('user_id');
10599
- const getFetchUsers = option$1('fetch_users');
10600
- const shouldIndentOnTab = option$1('lists_indent_on_tab');
10857
+ const shouldConvertUnsafeEmbeds = option('convert_unsafe_embeds');
10858
+ const getLicenseKey = option('license_key');
10859
+ const getApiKey = option('api_key');
10860
+ const isDisabled$1 = option('disabled');
10861
+ const getUserId = option('user_id');
10862
+ const getFetchUsers = option('fetch_users');
10863
+ const shouldIndentOnTab = option('lists_indent_on_tab');
10601
10864
  const getListMaxDepth = (editor) => Optional.from(editor.options.get('list_max_depth'));
10602
10865
 
10603
10866
  const isElement$4 = isElement$7;
@@ -13191,28 +13454,31 @@
13191
13454
  return elm.cloneNode(true);
13192
13455
  }
13193
13456
  };
13457
+ const setUcVideoSizeProp = (element, name, value) => {
13458
+ // this is needed because otherwise the ghost for `uc-video` is not correctly rendered
13459
+ element[name] = value;
13460
+ const minimumWidth = 400;
13461
+ if (element.width > minimumWidth && !(name === 'width' && value < minimumWidth)) {
13462
+ element[name] = value;
13463
+ dom.setStyle(element, name, value);
13464
+ }
13465
+ else {
13466
+ const valueConsideringMinWidth = name === 'height' ? minimumWidth * (ratio ?? 1) : minimumWidth;
13467
+ element[name] = valueConsideringMinWidth;
13468
+ dom.setStyle(element, name, valueConsideringMinWidth);
13469
+ }
13470
+ };
13194
13471
  const setSizeProp = (element, name, value) => {
13195
13472
  if (isNonNullable(value)) {
13196
13473
  // Resize by using style or attribute
13197
13474
  const targets = getResizeTargets(element);
13198
13475
  each$e(targets, (target) => {
13199
- if (target.style[name] || !editor.schema.isValid(target.nodeName.toLowerCase(), name)) {
13200
- dom.setStyle(target, name, value);
13476
+ if (isUcVideo(target)) {
13477
+ setUcVideoSizeProp(target, name, value);
13201
13478
  }
13202
13479
  else {
13203
- if (isUcVideo(target)) {
13204
- // this is needed because otherwise the ghost for `uc-video` is not correctly rendered
13205
- target[name] = value;
13206
- const minimumWidth = 400;
13207
- if (target.width > minimumWidth && !(name === 'width' && value < minimumWidth)) {
13208
- target[name] = value;
13209
- dom.setAttrib(target, name, '' + value);
13210
- }
13211
- else {
13212
- const value = name === 'height' ? minimumWidth * ratio : minimumWidth;
13213
- target[name] = value;
13214
- dom.setAttrib(target, name, '' + value);
13215
- }
13480
+ if (target.style[name] || !editor.schema.isValid(target.nodeName.toLowerCase(), name)) {
13481
+ dom.setStyle(target, name, value);
13216
13482
  }
13217
13483
  else {
13218
13484
  dom.setAttrib(target, name, '' + value);
@@ -13439,7 +13705,7 @@
13439
13705
  return;
13440
13706
  }
13441
13707
  const targetElm = e.type === 'mousedown' ? e.target : selection.getNode();
13442
- const controlElm = closest$3(SugarElement.fromDom(targetElm), controlElmSelector)
13708
+ const controlElm = closest$4(SugarElement.fromDom(targetElm), controlElmSelector)
13443
13709
  .map((e) => e.dom)
13444
13710
  .filter((e) => dom.isEditable(e.parentElement) || (e.nodeName === 'IMG' && dom.isEditable(e)))
13445
13711
  .getOrUndefined();
@@ -15222,7 +15488,7 @@
15222
15488
  };
15223
15489
  const isPreValue = (value) => contains$2(['pre', 'pre-wrap'], value);
15224
15490
  const isInPre = (pos) => getElementFromPosition(pos)
15225
- .bind((elm) => closest$4(elm, isElement$8))
15491
+ .bind((elm) => closest$5(elm, isElement$8))
15226
15492
  .exists((elm) => isPreValue(get$7(elm, 'white-space')));
15227
15493
  const isAtBeginningOfBody = (root, pos) => prevPosition(root.dom, pos).isNone();
15228
15494
  const isAtEndOfBody = (root, pos) => nextPosition(root.dom, pos).isNone();
@@ -15589,7 +15855,7 @@
15589
15855
  const isTextBlockOrListItem = (element) => isTextBlock$3(element) || isListItem$2(element);
15590
15856
  const getParentBlock$2 = (rootNode, elm) => {
15591
15857
  if (contains(rootNode, elm)) {
15592
- return closest$4(elm, isTextBlockOrListItem, isBeforeRoot(rootNode));
15858
+ return closest$5(elm, isTextBlockOrListItem, isBeforeRoot(rootNode));
15593
15859
  }
15594
15860
  else {
15595
15861
  return Optional.none();
@@ -15693,7 +15959,7 @@
15693
15959
  { partialTable: ['cells', 'outsideDetails'] },
15694
15960
  { multiTable: ['startTableCells', 'endTableCells', 'betweenRng'] },
15695
15961
  ]);
15696
- const getClosestCell$1 = (container, isRoot) => closest$3(SugarElement.fromDom(container), 'td,th', isRoot);
15962
+ const getClosestCell$1 = (container, isRoot) => closest$4(SugarElement.fromDom(container), 'td,th', isRoot);
15697
15963
  const isExpandedCellRng = (cellRng) => !eq(cellRng.start, cellRng.end);
15698
15964
  const getTableFromCellRng = (cellRng, isRoot) => getClosestTable(cellRng.start, isRoot)
15699
15965
  .bind((startParentTable) => getClosestTable(cellRng.end, isRoot)
@@ -16746,12 +17012,22 @@
16746
17012
  .exists((pos) => !isBr$7(pos.getNode()) || nextPosition(elm, pos).isSome()) === false;
16747
17013
  };
16748
17014
  const isEditableListItem = (dom) => (elm) => isListItem$3(elm) && dom.isEditable(elm);
17015
+ // TINY-13197: If the content is wrapped inside a block element, the first block returned by getSelectedBlocks() is not LI, even when the content is fully selected.
17016
+ // However, the second and subsequent do return LI as the selected block so only the first block needs to be adjusted
17017
+ const getAndOnlyNormalizeFirstBlockIf = (selection, pred) => map$3(selection.getSelectedBlocks(), (block, i) => {
17018
+ if (i === 0 && pred(block)) {
17019
+ return selection.dom.getParent(block, isListItem$3) ?? block;
17020
+ }
17021
+ else {
17022
+ return block;
17023
+ }
17024
+ });
16749
17025
  const getFullySelectedBlocks = (selection) => {
16750
- const blocks = selection.getSelectedBlocks();
16751
- const rng = selection.getRng();
16752
17026
  if (selection.isCollapsed()) {
16753
17027
  return [];
16754
17028
  }
17029
+ const rng = selection.getRng();
17030
+ const blocks = getAndOnlyNormalizeFirstBlockIf(selection, (el) => isRngStartAtStartOfElement(rng, el) && !isListItem$3(el));
16755
17031
  if (blocks.length === 1) {
16756
17032
  return isRngStartAtStartOfElement(rng, blocks[0]) && isRngEndAtEndOfElement(rng, blocks[0]) ? blocks : [];
16757
17033
  }
@@ -16763,7 +17039,7 @@
16763
17039
  }
16764
17040
  };
16765
17041
  const getFullySelectedListItems = (selection) => filter$5(getFullySelectedBlocks(selection), isEditableListItem(selection.dom));
16766
- const getPartiallySelectedListItems = (selection) => filter$5(selection.getSelectedBlocks(), isEditableListItem(selection.dom));
17042
+ const getPartiallySelectedListItems = (selection) => filter$5(getAndOnlyNormalizeFirstBlockIf(selection, (el) => !isListItem$3(el)), isEditableListItem(selection.dom));
16767
17043
 
16768
17044
  const each$8 = Tools.each;
16769
17045
  const isElementNode = (node) => isElement$7(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$1(node);
@@ -21842,7 +22118,8 @@
21842
22118
  applyCaretFormat(ed, name, vars);
21843
22119
  }
21844
22120
  getExpandedListItemFormat(ed.formatter, name).each((liFmt) => {
21845
- each$e(getFullySelectedListItems(ed.selection), (li) => applyStyles(dom, li, liFmt, vars));
22121
+ const list = getFullySelectedListItems(ed.selection);
22122
+ each$e(list, (li) => applyStyles(dom, li, liFmt, vars));
21846
22123
  });
21847
22124
  }
21848
22125
  postProcess$1(name, ed);
@@ -22483,16 +22760,19 @@
22483
22760
  const getLevelContent = (level) => {
22484
22761
  return level.type === 'fragmented' ? level.fragments.join('') : level.content;
22485
22762
  };
22486
- const getCleanLevelContent = (level) => {
22763
+ const getCleanLevelContent = (isReadonly, level) => {
22487
22764
  const elm = SugarElement.fromTag('body', lazyTempDocument());
22488
22765
  set$3(elm, getLevelContent(level));
22489
22766
  each$e(descendants(elm, '*[data-mce-bogus]'), unwrap);
22767
+ if (isReadonly) {
22768
+ each$e(descendants(elm, 'details[open]'), (element) => remove$9(element, 'open'));
22769
+ }
22490
22770
  return get$8(elm);
22491
22771
  };
22492
22772
  const hasEqualContent = (level1, level2) => getLevelContent(level1) === getLevelContent(level2);
22493
- const hasEqualCleanedContent = (level1, level2) => getCleanLevelContent(level1) === getCleanLevelContent(level2);
22773
+ const hasEqualCleanedContent = (isReadonly, level1, level2) => getCleanLevelContent(isReadonly, level1) === getCleanLevelContent(isReadonly, level2);
22494
22774
  // Most of the time the contents is equal so it's faster to first check that using strings then fallback to a cleaned dom comparison
22495
- const isEq$1 = (level1, level2) => {
22775
+ const isEq$1 = (isReadonly, level1, level2) => {
22496
22776
  if (!level1 || !level2) {
22497
22777
  return false;
22498
22778
  }
@@ -22500,7 +22780,7 @@
22500
22780
  return true;
22501
22781
  }
22502
22782
  else {
22503
- return hasEqualCleanedContent(level1, level2);
22783
+ return hasEqualCleanedContent(isReadonly, level1, level2);
22504
22784
  }
22505
22785
  };
22506
22786
 
@@ -22540,7 +22820,7 @@
22540
22820
  return null;
22541
22821
  }
22542
22822
  // Add undo level if needed
22543
- if (lastLevel && isEq$1(lastLevel, newLevel)) {
22823
+ if (lastLevel && isEq$1(editor.readonly, lastLevel, newLevel)) {
22544
22824
  return null;
22545
22825
  }
22546
22826
  // Set before bookmark on previous level
@@ -22628,7 +22908,7 @@
22628
22908
  };
22629
22909
  const hasUndo$1 = (editor, undoManager, index) =>
22630
22910
  // Has undo levels or typing and content isn't the same as the initial level
22631
- index.get() > 0 || (undoManager.typing && undoManager.data[0] && !isEq$1(createFromEditor(editor), undoManager.data[0]));
22911
+ index.get() > 0 || (undoManager.typing && undoManager.data[0] && !isEq$1(editor.readonly, createFromEditor(editor), undoManager.data[0]));
22632
22912
  const hasRedo$1 = (undoManager, index) => index.get() < undoManager.data.length - 1 && !undoManager.typing;
22633
22913
  const transact$1 = (undoManager, locks, callback) => {
22634
22914
  endTyping(undoManager, locks);
@@ -24610,7 +24890,7 @@
24610
24890
  }
24611
24891
  });
24612
24892
  };
24613
- const reportInvalidPlugin = (editor, pluginCode) => {
24893
+ const reportInvalidPlugin = (editor, pluginCode, hasShownPluginNotification) => {
24614
24894
  const baseMessage = `The "${pluginCode}" plugin requires a valid TinyMCE license key.`;
24615
24895
  reportMessage(editor, {
24616
24896
  console: {
@@ -24619,6 +24899,12 @@
24619
24899
  `${baseMessage}`,
24620
24900
  DOCS_URL_MESSAGE
24621
24901
  ].join(' ')
24902
+ },
24903
+ ...hasShownPluginNotification ? {} : {
24904
+ editor: {
24905
+ type: 'warning',
24906
+ message: `One or more premium plugins are disabled due to license key restrictions.`
24907
+ }
24622
24908
  }
24623
24909
  });
24624
24910
  };
@@ -24665,28 +24951,23 @@
24665
24951
  }
24666
24952
  };
24667
24953
 
24668
- const NoLicenseKeyManager = (editor) => ({
24669
- validate: (data) => {
24670
- const { plugin } = data;
24671
- const hasPlugin = isString(plugin);
24672
- // Premium plugins are not allowed
24673
- if (hasPlugin) {
24674
- reportInvalidPlugin(editor, plugin);
24675
- }
24676
- return Promise.resolve(false);
24677
- },
24678
- });
24679
- const GplLicenseKeyManager = (editor) => ({
24680
- validate: (data) => {
24681
- const { plugin } = data;
24682
- const hasPlugin = isString(plugin);
24683
- // Premium plugins are not allowed if 'gpl' is given as the license_key
24684
- if (hasPlugin) {
24685
- reportInvalidPlugin(editor, plugin);
24686
- }
24687
- return Promise.resolve(!hasPlugin);
24688
- },
24689
- });
24954
+ const createFallbackLicenseKeyManager = (canValidate) => (editor) => {
24955
+ let hasShownPluginNotification = false;
24956
+ return {
24957
+ validate: (data) => {
24958
+ const { plugin } = data;
24959
+ const hasPlugin = isString(plugin);
24960
+ // Premium plugins are not allowed
24961
+ if (hasPlugin) {
24962
+ reportInvalidPlugin(editor, plugin, hasShownPluginNotification);
24963
+ hasShownPluginNotification = true;
24964
+ }
24965
+ return Promise.resolve(canValidate && !hasPlugin);
24966
+ },
24967
+ };
24968
+ };
24969
+ const NoLicenseKeyManager = createFallbackLicenseKeyManager(false);
24970
+ const GplLicenseKeyManager = createFallbackLicenseKeyManager(true);
24690
24971
  const ADDON_KEY = 'manager';
24691
24972
  const PLUGIN_CODE = PLUGIN_CODE$1;
24692
24973
  const setup$y = () => {
@@ -24867,7 +25148,11 @@
24867
25148
  const isAllowedEventInDisabledMode = (e) => contains$2(allowedEvents, e.type);
24868
25149
  const getAnchorHrefOpt = (editor, elm) => {
24869
25150
  const isRoot = (elm) => eq(elm, SugarElement.fromDom(editor.getBody()));
24870
- return closest$3(elm, 'a', isRoot).bind((a) => getOpt(a, 'href'));
25151
+ return closest$4(elm, 'a', isRoot).bind((a) => getOpt(a, 'href'));
25152
+ };
25153
+ const hasAccordion = (editor, elm) => {
25154
+ const isRoot = (elm) => eq(elm, SugarElement.fromDom(editor.getBody()));
25155
+ return closest$2(elm, 'details', isRoot);
24871
25156
  };
24872
25157
  const processDisabledEvents = (editor, e) => {
24873
25158
  /*
@@ -24878,7 +25163,11 @@
24878
25163
  */
24879
25164
  if (isClickEvent(e) && !VK.metaKeyPressed(e)) {
24880
25165
  const elm = SugarElement.fromDom(e.target);
24881
- getAnchorHrefOpt(editor, elm).each((href) => {
25166
+ getAnchorHrefOpt(editor, elm).fold(() => {
25167
+ if (hasAccordion(editor, elm)) {
25168
+ e.preventDefault();
25169
+ }
25170
+ }, (href) => {
24882
25171
  e.preventDefault();
24883
25172
  if (/^#/.test(href)) {
24884
25173
  const targetEl = editor.dom.select(`${href},[name="${removeLeading(href, '#')}"]`);
@@ -25235,8 +25524,9 @@
25235
25524
  progress = noop; // Once it's closed it's closed
25236
25525
  }
25237
25526
  };
25238
- const success = (url) => {
25527
+ const success = (data) => {
25239
25528
  closeNotification();
25529
+ const url = isString(data) ? data : data.url;
25240
25530
  uploadStatus.markUploaded(blobInfo.blobUri(), url);
25241
25531
  resolvePending(blobInfo.blobUri(), handlerSuccess(blobInfo, url));
25242
25532
  resolve(handlerSuccess(blobInfo, url));
@@ -25748,7 +26038,7 @@
25748
26038
  hilitecolor: { inline: 'span', styles: { backgroundColor: '%value' }, links: true, remove_similar: true, clear_child_styles: true },
25749
26039
  fontname: { inline: 'span', toggle: false, styles: { fontFamily: '%value' }, clear_child_styles: true },
25750
26040
  fontsize: { inline: 'span', toggle: false, styles: { fontSize: '%value' }, clear_child_styles: true },
25751
- lineheight: { selector: 'h1,h2,h3,h4,h5,h6,p,li,td,th,div', styles: { lineHeight: '%value' } },
26041
+ lineheight: { selector: 'h1,h2,h3,h4,h5,h6,p,li,td,th,div', styles: { lineHeight: '%value' }, remove_similar: true },
25752
26042
  fontsize_class: { inline: 'span', attributes: { class: '%value' } },
25753
26043
  blockquote: { block: 'blockquote', wrapper: true, remove: 'all' },
25754
26044
  subscript: { inline: 'sub' },
@@ -26361,7 +26651,7 @@
26361
26651
  editor.nodeChanged();
26362
26652
  }
26363
26653
  // Fire a TypingUndo event on the first character entered
26364
- if (isFirstTypedCharacter.get() && undoManager.typing && !isEq$1(createFromEditor(editor), undoManager.data[0])) {
26654
+ if (isFirstTypedCharacter.get() && undoManager.typing && !isEq$1(editor.readonly, createFromEditor(editor), undoManager.data[0])) {
26365
26655
  if (!editor.isDirty()) {
26366
26656
  editor.setDirty(true);
26367
26657
  }
@@ -27167,7 +27457,7 @@
27167
27457
  const canIndent$1 = (editor) => getListMaxDepth(editor).forall((max) => {
27168
27458
  const blocks = editor.selection.getSelectedBlocks();
27169
27459
  return exists(blocks, (element) => {
27170
- return closest$3(SugarElement.fromDom(element), 'li').forall((sugarElement) => ancestors(sugarElement, 'ol,ul').length <= max);
27460
+ return closest$4(SugarElement.fromDom(element), 'li').forall((sugarElement) => ancestors(sugarElement, 'ol,ul').length <= max);
27171
27461
  });
27172
27462
  });
27173
27463
 
@@ -27779,8 +28069,8 @@
27779
28069
  if (nextCaretContainer && otherLi) {
27780
28070
  const findValidElement = (element) => contains$2(['td', 'th', 'caption'], name(element));
27781
28071
  const findRoot = (node) => node.dom === root;
27782
- const otherLiCell = closest$4(SugarElement.fromDom(otherLi), findValidElement, findRoot);
27783
- const caretCell = closest$4(SugarElement.fromDom(rng.startContainer), findValidElement, findRoot);
28072
+ const otherLiCell = closest$5(SugarElement.fromDom(otherLi), findValidElement, findRoot);
28073
+ const caretCell = closest$5(SugarElement.fromDom(rng.startContainer), findValidElement, findRoot);
27784
28074
  if (!equals(otherLiCell, caretCell, eq)) {
27785
28075
  return false;
27786
28076
  }
@@ -27847,7 +28137,7 @@
27847
28137
  const getClosestHost = (root, scope) => {
27848
28138
  const isRoot = (node) => eq(node, root);
27849
28139
  const isHost = (node) => isTableCell$2(node) || isContentEditableTrue$3(node.dom);
27850
- return closest$4(scope, isHost, isRoot).filter(isElement$8).getOr(root);
28140
+ return closest$5(scope, isHost, isRoot).filter(isElement$8).getOr(root);
27851
28141
  };
27852
28142
  const hasSameHost = (rootNode, blockBoundary) => {
27853
28143
  const root = SugarElement.fromDom(rootNode);
@@ -29243,7 +29533,7 @@
29243
29533
  };
29244
29534
  const backspaceDelete$3 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret(editor, forward) : deleteRange$1(editor, forward);
29245
29535
 
29246
- const isEditable = (target) => closest$4(target, (elm) => isContentEditableTrue$3(elm.dom) || isContentEditableFalse$a(elm.dom))
29536
+ const isEditable = (target) => closest$5(target, (elm) => isContentEditableTrue$3(elm.dom) || isContentEditableFalse$a(elm.dom))
29247
29537
  .exists((elm) => isContentEditableTrue$3(elm.dom));
29248
29538
  const parseIndentValue = (value) => toInt(value ?? '').getOr(0);
29249
29539
  const getIndentStyleName = (useMargin, element) => {
@@ -29763,7 +30053,7 @@
29763
30053
  const isRoot = (el) => eq(el, root);
29764
30054
  const isCet = (el) => isContentEditableTrue$3(el.dom);
29765
30055
  const startNode = SugarElement.fromDom(position.container());
29766
- const closestCetBlock = closest$4(startNode, isCet, isRoot);
30056
+ const closestCetBlock = closest$5(startNode, isCet, isRoot);
29767
30057
  return closestCetBlock.filter((b) => !isRoot(b));
29768
30058
  };
29769
30059
  const moveVertically = (editor, position, down) => {
@@ -29795,7 +30085,7 @@
29795
30085
  const isTarget = (node) => contains$2(['figcaption'], name(node));
29796
30086
  const getClosestTargetBlock = (pos, root, schema) => {
29797
30087
  const isRoot = curry(eq, root);
29798
- return closest$4(SugarElement.fromDom(pos.container()), (el) => schema.isBlock(name(el)), isRoot).filter(isTarget);
30088
+ return closest$5(SugarElement.fromDom(pos.container()), (el) => schema.isBlock(name(el)), isRoot).filter(isTarget);
29799
30089
  };
29800
30090
  const isAtFirstOrLastLine = (root, forward, pos) => forward ? isAtLastLine(root.dom, pos) : isAtFirstLine(root.dom, pos);
29801
30091
  const moveCaretToNewEmptyLine = (editor, forward) => {
@@ -29940,7 +30230,7 @@
29940
30230
  */
29941
30231
  const cell = (element, isRoot) => lookup$1(['td', 'th'], element, isRoot);
29942
30232
  const cells = (ancestor) => firstLayer(ancestor, 'th,td');
29943
- const table = (element, isRoot) => closest$3(element, 'table', isRoot);
30233
+ const table = (element, isRoot) => closest$4(element, 'table', isRoot);
29944
30234
 
29945
30235
  const adt = Adt.generate([
29946
30236
  { none: ['current'] },
@@ -30077,7 +30367,7 @@
30077
30367
  return {
30078
30368
  up: constant({
30079
30369
  selector: ancestor$4,
30080
- closest: closest$3,
30370
+ closest: closest$4,
30081
30371
  predicate: ancestor$5,
30082
30372
  all: parents$1
30083
30373
  }),
@@ -30499,7 +30789,7 @@
30499
30789
  return tabForward(editor, isRoot, current);
30500
30790
  });
30501
30791
  };
30502
- const isCellInEditableTable = (cell) => closest$4(cell, isTag('table')).exists(isEditable$2);
30792
+ const isCellInEditableTable = (cell) => closest$5(cell, isTag('table')).exists(isEditable$2);
30503
30793
  const tabForward = (editor, isRoot, cell) => tabGo(editor, isRoot, next(cell, isCellEditable));
30504
30794
  const tabBackward = (editor, isRoot, cell) => tabGo(editor, isRoot, prev(cell, isCellEditable));
30505
30795
  const isCellEditable = (cell) => isEditable$2(cell) || descendant(cell, isEditableHTMLElement);
@@ -30760,283 +31050,6 @@
30760
31050
  });
30761
31051
  };
30762
31052
 
30763
- var SimpleResultType;
30764
- (function (SimpleResultType) {
30765
- SimpleResultType[SimpleResultType["Error"] = 0] = "Error";
30766
- SimpleResultType[SimpleResultType["Value"] = 1] = "Value";
30767
- })(SimpleResultType || (SimpleResultType = {}));
30768
- const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue);
30769
- const partition = (results) => {
30770
- const values = [];
30771
- const errors = [];
30772
- each$e(results, (obj) => {
30773
- fold$1(obj, (err) => errors.push(err), (val) => values.push(val));
30774
- });
30775
- return { values, errors };
30776
- };
30777
- const mapError = (res, f) => {
30778
- if (res.stype === SimpleResultType.Error) {
30779
- return { stype: SimpleResultType.Error, serror: f(res.serror) };
30780
- }
30781
- else {
30782
- return res;
30783
- }
30784
- };
30785
- const map = (res, f) => {
30786
- if (res.stype === SimpleResultType.Value) {
30787
- return { stype: SimpleResultType.Value, svalue: f(res.svalue) };
30788
- }
30789
- else {
30790
- return res;
30791
- }
30792
- };
30793
- const bind = (res, f) => {
30794
- if (res.stype === SimpleResultType.Value) {
30795
- return f(res.svalue);
30796
- }
30797
- else {
30798
- return res;
30799
- }
30800
- };
30801
- const bindError = (res, f) => {
30802
- if (res.stype === SimpleResultType.Error) {
30803
- return f(res.serror);
30804
- }
30805
- else {
30806
- return res;
30807
- }
30808
- };
30809
- const svalue = (v) => ({ stype: SimpleResultType.Value, svalue: v });
30810
- const serror = (e) => ({ stype: SimpleResultType.Error, serror: e });
30811
- const toResult = (res) => fold$1(res, Result.error, Result.value);
30812
- const fromResult = (res) => res.fold(serror, svalue);
30813
- const SimpleResult = {
30814
- fromResult,
30815
- toResult,
30816
- svalue,
30817
- partition,
30818
- serror,
30819
- bind,
30820
- bindError,
30821
- map,
30822
- mapError,
30823
- fold: fold$1
30824
- };
30825
-
30826
- const formatObj = (input) => {
30827
- return isObject(input) && keys(input).length > 100 ? ' removed due to size' : JSON.stringify(input, null, 2);
30828
- };
30829
- const formatErrors = (errors) => {
30830
- const es = errors.length > 10 ? errors.slice(0, 10).concat([
30831
- {
30832
- path: [],
30833
- getErrorInfo: constant('... (only showing first ten failures)')
30834
- }
30835
- ]) : errors;
30836
- // TODO: Work out a better split between PrettyPrinter and SchemaError
30837
- return map$3(es, (e) => {
30838
- return 'Failed path: (' + e.path.join(' > ') + ')\n' + e.getErrorInfo();
30839
- });
30840
- };
30841
-
30842
- const nu = (path, getErrorInfo) => {
30843
- return SimpleResult.serror([{
30844
- path,
30845
- // This is lazy so that it isn't calculated unnecessarily
30846
- getErrorInfo
30847
- }]);
30848
- };
30849
- const missingRequired = (path, key, obj) => nu(path, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj));
30850
- const custom = (path, err) => nu(path, constant(err));
30851
-
30852
- const value = (validator) => {
30853
- const extract = (path, val) => {
30854
- return SimpleResult.bindError(validator(val), (err) => custom(path, err));
30855
- };
30856
- const toString = constant('val');
30857
- return {
30858
- extract,
30859
- toString
30860
- };
30861
- };
30862
- const anyValue$1 = value(SimpleResult.svalue);
30863
-
30864
- const anyValue = constant(anyValue$1);
30865
- const typedValue = (validator, expectedType) => value((a) => {
30866
- const actualType = typeof a;
30867
- return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${expectedType} but got: ${actualType}`);
30868
- });
30869
- const number = typedValue(isNumber, 'number');
30870
- const string = typedValue(isString, 'string');
30871
- typedValue(isBoolean, 'boolean');
30872
- const functionProcessor = typedValue(isFunction, 'function');
30873
- // Test if a value can be copied by the structured clone algorithm and hence sendable via postMessage
30874
- // https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
30875
- // from https://stackoverflow.com/a/32673910/7377237 with adjustments for typescript
30876
- const isPostMessageable = (val) => {
30877
- if (Object(val) !== val) { // Primitive value
30878
- return true;
30879
- }
30880
- switch ({}.toString.call(val).slice(8, -1)) { // Class
30881
- case 'Boolean':
30882
- case 'Number':
30883
- case 'String':
30884
- case 'Date':
30885
- case 'RegExp':
30886
- case 'Blob':
30887
- case 'FileList':
30888
- case 'ImageData':
30889
- case 'ImageBitmap':
30890
- case 'ArrayBuffer':
30891
- return true;
30892
- case 'Array':
30893
- case 'Object':
30894
- return Object.keys(val).every((prop) => isPostMessageable(val[prop]));
30895
- default:
30896
- return false;
30897
- }
30898
- };
30899
- value((a) => {
30900
- if (isPostMessageable(a)) {
30901
- return SimpleResult.svalue(a);
30902
- }
30903
- else {
30904
- return SimpleResult.serror('Expected value to be acceptable for sending via postMessage');
30905
- }
30906
- });
30907
-
30908
- const required$1 = () => ({ tag: "required" /* FieldPresenceTag.Required */, process: {} });
30909
- const defaultedThunk = (fallbackThunk) => ({ tag: "defaultedThunk" /* FieldPresenceTag.DefaultedThunk */, process: fallbackThunk });
30910
- const defaulted$1 = (fallback) => defaultedThunk(constant(fallback));
30911
- const asOption = () => ({ tag: "option" /* FieldPresenceTag.Option */, process: {} });
30912
-
30913
- const field$1 = (key, newKey, presence, prop) => ({ tag: "field" /* FieldTag.Field */, key, newKey, presence, prop });
30914
- const fold = (value, ifField, ifCustom) => {
30915
- switch (value.tag) {
30916
- case "field" /* FieldTag.Field */:
30917
- return ifField(value.key, value.newKey, value.presence, value.prop);
30918
- case "custom" /* FieldTag.CustomField */:
30919
- return ifCustom(value.newKey, value.instantiator);
30920
- }
30921
- };
30922
-
30923
- const mergeValues = (values, base) => {
30924
- return SimpleResult.svalue(deepMerge(base, merge$1.apply(undefined, values)));
30925
- };
30926
- const mergeErrors = (errors) => compose(SimpleResult.serror, flatten$1)(errors);
30927
- const consolidateObj = (objects, base) => {
30928
- const partition = SimpleResult.partition(objects);
30929
- return partition.errors.length > 0 ? mergeErrors(partition.errors) : mergeValues(partition.values, base);
30930
- };
30931
- const consolidateArr = (objects) => {
30932
- const partitions = SimpleResult.partition(objects);
30933
- return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : SimpleResult.svalue(partitions.values);
30934
- };
30935
- const ResultCombine = {
30936
- consolidateObj,
30937
- consolidateArr
30938
- };
30939
-
30940
- const requiredAccess = (path, obj, key, bundle) =>
30941
- // In required mode, if it is undefined, it is an error.
30942
- get$a(obj, key).fold(() => missingRequired(path, key, obj), bundle);
30943
- const fallbackAccess = (obj, key, fallback, bundle) => {
30944
- const v = get$a(obj, key).getOrThunk(() => fallback(obj));
30945
- return bundle(v);
30946
- };
30947
- const optionAccess = (obj, key, bundle) => bundle(get$a(obj, key));
30948
- const optionDefaultedAccess = (obj, key, fallback, bundle) => {
30949
- const opt = get$a(obj, key).map((val) => val === true ? fallback(obj) : val);
30950
- return bundle(opt);
30951
- };
30952
- const extractField = (field, path, obj, key, prop) => {
30953
- const bundle = (av) => prop.extract(path.concat([key]), av);
30954
- const bundleAsOption = (optValue) => optValue.fold(() => SimpleResult.svalue(Optional.none()), (ov) => {
30955
- const result = prop.extract(path.concat([key]), ov);
30956
- return SimpleResult.map(result, Optional.some);
30957
- });
30958
- switch (field.tag) {
30959
- case "required" /* FieldPresenceTag.Required */:
30960
- return requiredAccess(path, obj, key, bundle);
30961
- case "defaultedThunk" /* FieldPresenceTag.DefaultedThunk */:
30962
- return fallbackAccess(obj, key, field.process, bundle);
30963
- case "option" /* FieldPresenceTag.Option */:
30964
- return optionAccess(obj, key, bundleAsOption);
30965
- case "defaultedOptionThunk" /* FieldPresenceTag.DefaultedOptionThunk */:
30966
- return optionDefaultedAccess(obj, key, field.process, bundleAsOption);
30967
- case "mergeWithThunk" /* FieldPresenceTag.MergeWithThunk */: {
30968
- return fallbackAccess(obj, key, constant({}), (v) => {
30969
- const result = deepMerge(field.process(obj), v);
30970
- return bundle(result);
30971
- });
30972
- }
30973
- }
30974
- };
30975
- const extractFields = (path, obj, fields) => {
30976
- const success = {};
30977
- const errors = [];
30978
- // PERFORMANCE: We use a for loop here instead of Arr.each as this is a hot code path
30979
- for (const field of fields) {
30980
- fold(field, (key, newKey, presence, prop) => {
30981
- const result = extractField(presence, path, obj, key, prop);
30982
- SimpleResult.fold(result, (err) => {
30983
- errors.push(...err);
30984
- }, (res) => {
30985
- success[newKey] = res;
30986
- });
30987
- }, (newKey, instantiator) => {
30988
- success[newKey] = instantiator(obj);
30989
- });
30990
- }
30991
- return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success);
30992
- };
30993
- const objOf = (values) => {
30994
- const extract = (path, o) => extractFields(path, o, values);
30995
- const toString = () => {
30996
- const fieldStrings = map$3(values, (value) => fold(value, (key, _okey, _presence, prop) => key + ' -> ' + prop.toString(), (newKey, _instantiator) => 'state(' + newKey + ')'));
30997
- return 'obj{\n' + fieldStrings.join('\n') + '}';
30998
- };
30999
- return {
31000
- extract,
31001
- toString
31002
- };
31003
- };
31004
- const arrOf = (prop) => {
31005
- const extract = (path, array) => {
31006
- const results = map$3(array, (a, i) => prop.extract(path.concat(['[' + i + ']']), a));
31007
- return ResultCombine.consolidateArr(results);
31008
- };
31009
- const toString = () => 'array(' + prop.toString() + ')';
31010
- return {
31011
- extract,
31012
- toString
31013
- };
31014
- };
31015
-
31016
- const extractValue = (label, prop, obj) => {
31017
- const res = prop.extract([label], obj);
31018
- return SimpleResult.mapError(res, (errs) => ({ input: obj, errors: errs }));
31019
- };
31020
- const asRaw = (label, prop, obj) => SimpleResult.toResult(extractValue(label, prop, obj));
31021
- const formatError = (errInfo) => {
31022
- return 'Errors: \n' + formatErrors(errInfo.errors).join('\n') +
31023
- '\n\nInput object: ' + formatObj(errInfo.input);
31024
- };
31025
-
31026
- const field = field$1;
31027
- const required = (key) => field(key, key, required$1(), anyValue());
31028
- const requiredOf = (key, schema) => field(key, key, required$1(), schema);
31029
- const requiredString = (key) => requiredOf(key, string);
31030
- const requiredFunction = (key) => requiredOf(key, functionProcessor);
31031
- const option = (key) => field(key, key, asOption(), anyValue());
31032
- const optionOf = (key, schema) => field(key, key, asOption(), schema);
31033
- const optionString = (key) => optionOf(key, string);
31034
- const optionFunction = (key) => optionOf(key, functionProcessor);
31035
- const defaulted = (key, fallback) => field(key, key, defaulted$1(fallback), anyValue());
31036
- const defaultedOf = (key, fallback, schema) => field(key, key, defaulted$1(fallback), schema);
31037
- const defaultedNumber = (key, fallback) => defaultedOf(key, fallback, number);
31038
- const defaultedArrayOf = (key, fallback, schema) => defaultedOf(key, fallback, arrOf(schema));
31039
-
31040
31053
  const type = requiredString('type');
31041
31054
  const fetch$1 = requiredFunction('fetch');
31042
31055
  const onAction = requiredFunction('onAction');
@@ -31762,7 +31775,10 @@
31762
31775
  }
31763
31776
  }
31764
31777
  } while ((node = node.parentNode) && node !== editableRoot);
31765
- reduceFontStyleNesting(block, caretNode);
31778
+ // Not omitting font sizes of list items otherwise their font size doesn't match its content
31779
+ if (block.nodeName !== 'LI') {
31780
+ reduceFontStyleNesting(block, caretNode);
31781
+ }
31766
31782
  }
31767
31783
  setForcedBlockAttrs(editor, block);
31768
31784
  emptyBlock(caretNode);
@@ -34057,9 +34073,9 @@
34057
34073
  const isContentEditableFalse$2 = (elm) => isContentEditableFalse$a(elm.dom);
34058
34074
  const isContentEditableTrue = (elm) => isContentEditableTrue$3(elm.dom);
34059
34075
  const isRoot = (rootNode) => (elm) => eq(SugarElement.fromDom(rootNode), elm);
34060
- const getClosestScope = (node, rootNode, schema) => closest$4(SugarElement.fromDom(node), (elm) => isContentEditableTrue(elm) || schema.isBlock(name(elm)), isRoot(rootNode))
34076
+ const getClosestScope = (node, rootNode, schema) => closest$5(SugarElement.fromDom(node), (elm) => isContentEditableTrue(elm) || schema.isBlock(name(elm)), isRoot(rootNode))
34061
34077
  .getOr(SugarElement.fromDom(rootNode)).dom;
34062
- const getClosestCef = (node, rootNode) => closest$4(SugarElement.fromDom(node), isContentEditableFalse$2, isRoot(rootNode));
34078
+ const getClosestCef = (node, rootNode) => closest$5(SugarElement.fromDom(node), isContentEditableFalse$2, isRoot(rootNode));
34063
34079
  const findEdgeCaretCandidate = (startNode, scope, forward) => {
34064
34080
  const walker = new DomTreeWalker(startNode, scope);
34065
34081
  const next = forward ? walker.next.bind(walker) : walker.prev.bind(walker);
@@ -37426,7 +37442,7 @@
37426
37442
  required('id'),
37427
37443
  optionString('name'),
37428
37444
  optionString('avatar'),
37429
- option('custom')
37445
+ option$1('custom')
37430
37446
  ]);
37431
37447
  const objectCat = (obj) => {
37432
37448
  const result = {};
@@ -38275,6 +38291,24 @@
38275
38291
  const lowerCaseCommand = command.toLowerCase();
38276
38292
  this.commands.exec[lowerCaseCommand] = (_command, ui, value, args) => callback.call(scope ?? this.editor, ui, value, args);
38277
38293
  }
38294
+ /**
38295
+ * Removes a command from the command collection.
38296
+ *
38297
+ * @method removeCommand
38298
+ * @param {String} command Command name to remove.
38299
+ * @param {String} type Optional type to remove, defaults to removing all types. Can be 'exec', 'state', 'value', or omitted for all.
38300
+ */
38301
+ removeCommand(command, type) {
38302
+ const lowerCaseCommand = command.toLowerCase();
38303
+ if (type) {
38304
+ delete this.commands[type][lowerCaseCommand];
38305
+ }
38306
+ else {
38307
+ delete this.commands.exec[lowerCaseCommand];
38308
+ delete this.commands.state[lowerCaseCommand];
38309
+ delete this.commands.value[lowerCaseCommand];
38310
+ }
38311
+ }
38278
38312
  /**
38279
38313
  * Returns true/false if the command is supported or not.
38280
38314
  *
@@ -40547,14 +40581,14 @@
40547
40581
  * @property minorVersion
40548
40582
  * @type String
40549
40583
  */
40550
- minorVersion: '2.2',
40584
+ minorVersion: '3.0',
40551
40585
  /**
40552
40586
  * Release date of TinyMCE build.
40553
40587
  *
40554
40588
  * @property releaseDate
40555
40589
  * @type String
40556
40590
  */
40557
- releaseDate: '2025-11-17',
40591
+ releaseDate: '2025-12-10',
40558
40592
  /**
40559
40593
  * Collection of language pack data.
40560
40594
  *