tinymce-rails 8.2.1 → 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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/source/tinymce/tinymce.js +502 -464
  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/help/plugin.js +1 -1
  8. data/vendor/assets/javascripts/tinymce/plugins/link/plugin.js +1 -1
  9. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.css +1 -1
  10. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.inline.css +1 -1
  11. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.inline.js +1 -1
  12. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.inline.min.css +1 -1
  13. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.js +1 -1
  14. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.min.css +1 -1
  15. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/skin.css +1 -1
  16. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/skin.js +1 -1
  17. data/vendor/assets/javascripts/tinymce/skins/ui/oxide/skin.min.css +1 -1
  18. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.css +1 -1
  19. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.inline.css +1 -1
  20. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.inline.js +1 -1
  21. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.inline.min.css +1 -1
  22. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.js +1 -1
  23. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.min.css +1 -1
  24. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/skin.css +1 -1
  25. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/skin.js +1 -1
  26. data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/skin.min.css +1 -1
  27. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.css +1 -1
  28. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.inline.css +1 -1
  29. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.inline.js +1 -1
  30. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.inline.min.css +1 -1
  31. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.js +1 -1
  32. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.min.css +1 -1
  33. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/skin.css +1 -1
  34. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/skin.js +1 -1
  35. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/skin.min.css +1 -1
  36. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.css +1 -1
  37. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.inline.css +1 -1
  38. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.inline.js +1 -1
  39. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css +1 -1
  40. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.js +1 -1
  41. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.min.css +1 -1
  42. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/skin.css +1 -1
  43. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/skin.js +1 -1
  44. data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/skin.min.css +1 -1
  45. data/vendor/assets/javascripts/tinymce/themes/silver/theme.js +1 -1
  46. data/vendor/assets/javascripts/tinymce/tinymce.d.ts +15 -1
  47. data/vendor/assets/javascripts/tinymce/tinymce.js +2 -2
  48. metadata +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * TinyMCE version 8.2.1 (2025-11-06)
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
  };
@@ -24643,7 +24929,10 @@
24643
24929
  const determineStrategy = (editor) => {
24644
24930
  const onlineStatus = getOnlineStatus(editor);
24645
24931
  const licenseKeyType = getLicenseKeyType(editor);
24646
- const forcePlugin = (new Set(getPlugins(editor))).has(PLUGIN_CODE$1);
24932
+ const forcePlugin = new Set([
24933
+ ...getPlugins(editor),
24934
+ ...keys(getExternalPlugins$1(editor)),
24935
+ ]).has(PLUGIN_CODE$1);
24647
24936
  if (licenseKeyType !== 'gpl' || onlineStatus === 'online' || forcePlugin) {
24648
24937
  return {
24649
24938
  type: 'use_plugin',
@@ -24662,28 +24951,23 @@
24662
24951
  }
24663
24952
  };
24664
24953
 
24665
- const NoLicenseKeyManager = (editor) => ({
24666
- validate: (data) => {
24667
- const { plugin } = data;
24668
- const hasPlugin = isString(plugin);
24669
- // Premium plugins are not allowed
24670
- if (hasPlugin) {
24671
- reportInvalidPlugin(editor, plugin);
24672
- }
24673
- return Promise.resolve(false);
24674
- },
24675
- });
24676
- const GplLicenseKeyManager = (editor) => ({
24677
- validate: (data) => {
24678
- const { plugin } = data;
24679
- const hasPlugin = isString(plugin);
24680
- // Premium plugins are not allowed if 'gpl' is given as the license_key
24681
- if (hasPlugin) {
24682
- reportInvalidPlugin(editor, plugin);
24683
- }
24684
- return Promise.resolve(!hasPlugin);
24685
- },
24686
- });
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);
24687
24971
  const ADDON_KEY = 'manager';
24688
24972
  const PLUGIN_CODE = PLUGIN_CODE$1;
24689
24973
  const setup$y = () => {
@@ -24694,7 +24978,8 @@
24694
24978
  const load = (editor, suffix) => {
24695
24979
  const strategy = determineStrategy(editor);
24696
24980
  if (strategy.type === 'use_plugin') {
24697
- const url = `plugins/${PLUGIN_CODE}/plugin${suffix}.js`;
24981
+ const externalUrl = get$a(getExternalPlugins$1(editor), PLUGIN_CODE).map(trim$4).filter(isNotEmpty);
24982
+ const url = externalUrl.getOr(`plugins/${PLUGIN_CODE}/plugin${suffix}.js`);
24698
24983
  addOnManager.load(ADDON_KEY, url).catch(() => {
24699
24984
  licenseKeyManagerLoadError(editor, url);
24700
24985
  });
@@ -24863,7 +25148,11 @@
24863
25148
  const isAllowedEventInDisabledMode = (e) => contains$2(allowedEvents, e.type);
24864
25149
  const getAnchorHrefOpt = (editor, elm) => {
24865
25150
  const isRoot = (elm) => eq(elm, SugarElement.fromDom(editor.getBody()));
24866
- 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);
24867
25156
  };
24868
25157
  const processDisabledEvents = (editor, e) => {
24869
25158
  /*
@@ -24874,7 +25163,11 @@
24874
25163
  */
24875
25164
  if (isClickEvent(e) && !VK.metaKeyPressed(e)) {
24876
25165
  const elm = SugarElement.fromDom(e.target);
24877
- getAnchorHrefOpt(editor, elm).each((href) => {
25166
+ getAnchorHrefOpt(editor, elm).fold(() => {
25167
+ if (hasAccordion(editor, elm)) {
25168
+ e.preventDefault();
25169
+ }
25170
+ }, (href) => {
24878
25171
  e.preventDefault();
24879
25172
  if (/^#/.test(href)) {
24880
25173
  const targetEl = editor.dom.select(`${href},[name="${removeLeading(href, '#')}"]`);
@@ -25231,8 +25524,9 @@
25231
25524
  progress = noop; // Once it's closed it's closed
25232
25525
  }
25233
25526
  };
25234
- const success = (url) => {
25527
+ const success = (data) => {
25235
25528
  closeNotification();
25529
+ const url = isString(data) ? data : data.url;
25236
25530
  uploadStatus.markUploaded(blobInfo.blobUri(), url);
25237
25531
  resolvePending(blobInfo.blobUri(), handlerSuccess(blobInfo, url));
25238
25532
  resolve(handlerSuccess(blobInfo, url));
@@ -25744,7 +26038,7 @@
25744
26038
  hilitecolor: { inline: 'span', styles: { backgroundColor: '%value' }, links: true, remove_similar: true, clear_child_styles: true },
25745
26039
  fontname: { inline: 'span', toggle: false, styles: { fontFamily: '%value' }, clear_child_styles: true },
25746
26040
  fontsize: { inline: 'span', toggle: false, styles: { fontSize: '%value' }, clear_child_styles: true },
25747
- 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 },
25748
26042
  fontsize_class: { inline: 'span', attributes: { class: '%value' } },
25749
26043
  blockquote: { block: 'blockquote', wrapper: true, remove: 'all' },
25750
26044
  subscript: { inline: 'sub' },
@@ -26357,7 +26651,7 @@
26357
26651
  editor.nodeChanged();
26358
26652
  }
26359
26653
  // Fire a TypingUndo event on the first character entered
26360
- 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])) {
26361
26655
  if (!editor.isDirty()) {
26362
26656
  editor.setDirty(true);
26363
26657
  }
@@ -27163,7 +27457,7 @@
27163
27457
  const canIndent$1 = (editor) => getListMaxDepth(editor).forall((max) => {
27164
27458
  const blocks = editor.selection.getSelectedBlocks();
27165
27459
  return exists(blocks, (element) => {
27166
- 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);
27167
27461
  });
27168
27462
  });
27169
27463
 
@@ -27775,8 +28069,8 @@
27775
28069
  if (nextCaretContainer && otherLi) {
27776
28070
  const findValidElement = (element) => contains$2(['td', 'th', 'caption'], name(element));
27777
28071
  const findRoot = (node) => node.dom === root;
27778
- const otherLiCell = closest$4(SugarElement.fromDom(otherLi), findValidElement, findRoot);
27779
- 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);
27780
28074
  if (!equals(otherLiCell, caretCell, eq)) {
27781
28075
  return false;
27782
28076
  }
@@ -27843,7 +28137,7 @@
27843
28137
  const getClosestHost = (root, scope) => {
27844
28138
  const isRoot = (node) => eq(node, root);
27845
28139
  const isHost = (node) => isTableCell$2(node) || isContentEditableTrue$3(node.dom);
27846
- return closest$4(scope, isHost, isRoot).filter(isElement$8).getOr(root);
28140
+ return closest$5(scope, isHost, isRoot).filter(isElement$8).getOr(root);
27847
28141
  };
27848
28142
  const hasSameHost = (rootNode, blockBoundary) => {
27849
28143
  const root = SugarElement.fromDom(rootNode);
@@ -29239,7 +29533,7 @@
29239
29533
  };
29240
29534
  const backspaceDelete$3 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret(editor, forward) : deleteRange$1(editor, forward);
29241
29535
 
29242
- 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))
29243
29537
  .exists((elm) => isContentEditableTrue$3(elm.dom));
29244
29538
  const parseIndentValue = (value) => toInt(value ?? '').getOr(0);
29245
29539
  const getIndentStyleName = (useMargin, element) => {
@@ -29759,7 +30053,7 @@
29759
30053
  const isRoot = (el) => eq(el, root);
29760
30054
  const isCet = (el) => isContentEditableTrue$3(el.dom);
29761
30055
  const startNode = SugarElement.fromDom(position.container());
29762
- const closestCetBlock = closest$4(startNode, isCet, isRoot);
30056
+ const closestCetBlock = closest$5(startNode, isCet, isRoot);
29763
30057
  return closestCetBlock.filter((b) => !isRoot(b));
29764
30058
  };
29765
30059
  const moveVertically = (editor, position, down) => {
@@ -29791,7 +30085,7 @@
29791
30085
  const isTarget = (node) => contains$2(['figcaption'], name(node));
29792
30086
  const getClosestTargetBlock = (pos, root, schema) => {
29793
30087
  const isRoot = curry(eq, root);
29794
- 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);
29795
30089
  };
29796
30090
  const isAtFirstOrLastLine = (root, forward, pos) => forward ? isAtLastLine(root.dom, pos) : isAtFirstLine(root.dom, pos);
29797
30091
  const moveCaretToNewEmptyLine = (editor, forward) => {
@@ -29936,7 +30230,7 @@
29936
30230
  */
29937
30231
  const cell = (element, isRoot) => lookup$1(['td', 'th'], element, isRoot);
29938
30232
  const cells = (ancestor) => firstLayer(ancestor, 'th,td');
29939
- const table = (element, isRoot) => closest$3(element, 'table', isRoot);
30233
+ const table = (element, isRoot) => closest$4(element, 'table', isRoot);
29940
30234
 
29941
30235
  const adt = Adt.generate([
29942
30236
  { none: ['current'] },
@@ -30073,7 +30367,7 @@
30073
30367
  return {
30074
30368
  up: constant({
30075
30369
  selector: ancestor$4,
30076
- closest: closest$3,
30370
+ closest: closest$4,
30077
30371
  predicate: ancestor$5,
30078
30372
  all: parents$1
30079
30373
  }),
@@ -30495,7 +30789,7 @@
30495
30789
  return tabForward(editor, isRoot, current);
30496
30790
  });
30497
30791
  };
30498
- const isCellInEditableTable = (cell) => closest$4(cell, isTag('table')).exists(isEditable$2);
30792
+ const isCellInEditableTable = (cell) => closest$5(cell, isTag('table')).exists(isEditable$2);
30499
30793
  const tabForward = (editor, isRoot, cell) => tabGo(editor, isRoot, next(cell, isCellEditable));
30500
30794
  const tabBackward = (editor, isRoot, cell) => tabGo(editor, isRoot, prev(cell, isCellEditable));
30501
30795
  const isCellEditable = (cell) => isEditable$2(cell) || descendant(cell, isEditableHTMLElement);
@@ -30756,283 +31050,6 @@
30756
31050
  });
30757
31051
  };
30758
31052
 
30759
- var SimpleResultType;
30760
- (function (SimpleResultType) {
30761
- SimpleResultType[SimpleResultType["Error"] = 0] = "Error";
30762
- SimpleResultType[SimpleResultType["Value"] = 1] = "Value";
30763
- })(SimpleResultType || (SimpleResultType = {}));
30764
- const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue);
30765
- const partition = (results) => {
30766
- const values = [];
30767
- const errors = [];
30768
- each$e(results, (obj) => {
30769
- fold$1(obj, (err) => errors.push(err), (val) => values.push(val));
30770
- });
30771
- return { values, errors };
30772
- };
30773
- const mapError = (res, f) => {
30774
- if (res.stype === SimpleResultType.Error) {
30775
- return { stype: SimpleResultType.Error, serror: f(res.serror) };
30776
- }
30777
- else {
30778
- return res;
30779
- }
30780
- };
30781
- const map = (res, f) => {
30782
- if (res.stype === SimpleResultType.Value) {
30783
- return { stype: SimpleResultType.Value, svalue: f(res.svalue) };
30784
- }
30785
- else {
30786
- return res;
30787
- }
30788
- };
30789
- const bind = (res, f) => {
30790
- if (res.stype === SimpleResultType.Value) {
30791
- return f(res.svalue);
30792
- }
30793
- else {
30794
- return res;
30795
- }
30796
- };
30797
- const bindError = (res, f) => {
30798
- if (res.stype === SimpleResultType.Error) {
30799
- return f(res.serror);
30800
- }
30801
- else {
30802
- return res;
30803
- }
30804
- };
30805
- const svalue = (v) => ({ stype: SimpleResultType.Value, svalue: v });
30806
- const serror = (e) => ({ stype: SimpleResultType.Error, serror: e });
30807
- const toResult = (res) => fold$1(res, Result.error, Result.value);
30808
- const fromResult = (res) => res.fold(serror, svalue);
30809
- const SimpleResult = {
30810
- fromResult,
30811
- toResult,
30812
- svalue,
30813
- partition,
30814
- serror,
30815
- bind,
30816
- bindError,
30817
- map,
30818
- mapError,
30819
- fold: fold$1
30820
- };
30821
-
30822
- const formatObj = (input) => {
30823
- return isObject(input) && keys(input).length > 100 ? ' removed due to size' : JSON.stringify(input, null, 2);
30824
- };
30825
- const formatErrors = (errors) => {
30826
- const es = errors.length > 10 ? errors.slice(0, 10).concat([
30827
- {
30828
- path: [],
30829
- getErrorInfo: constant('... (only showing first ten failures)')
30830
- }
30831
- ]) : errors;
30832
- // TODO: Work out a better split between PrettyPrinter and SchemaError
30833
- return map$3(es, (e) => {
30834
- return 'Failed path: (' + e.path.join(' > ') + ')\n' + e.getErrorInfo();
30835
- });
30836
- };
30837
-
30838
- const nu = (path, getErrorInfo) => {
30839
- return SimpleResult.serror([{
30840
- path,
30841
- // This is lazy so that it isn't calculated unnecessarily
30842
- getErrorInfo
30843
- }]);
30844
- };
30845
- const missingRequired = (path, key, obj) => nu(path, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj));
30846
- const custom = (path, err) => nu(path, constant(err));
30847
-
30848
- const value = (validator) => {
30849
- const extract = (path, val) => {
30850
- return SimpleResult.bindError(validator(val), (err) => custom(path, err));
30851
- };
30852
- const toString = constant('val');
30853
- return {
30854
- extract,
30855
- toString
30856
- };
30857
- };
30858
- const anyValue$1 = value(SimpleResult.svalue);
30859
-
30860
- const anyValue = constant(anyValue$1);
30861
- const typedValue = (validator, expectedType) => value((a) => {
30862
- const actualType = typeof a;
30863
- return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${expectedType} but got: ${actualType}`);
30864
- });
30865
- const number = typedValue(isNumber, 'number');
30866
- const string = typedValue(isString, 'string');
30867
- typedValue(isBoolean, 'boolean');
30868
- const functionProcessor = typedValue(isFunction, 'function');
30869
- // Test if a value can be copied by the structured clone algorithm and hence sendable via postMessage
30870
- // https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
30871
- // from https://stackoverflow.com/a/32673910/7377237 with adjustments for typescript
30872
- const isPostMessageable = (val) => {
30873
- if (Object(val) !== val) { // Primitive value
30874
- return true;
30875
- }
30876
- switch ({}.toString.call(val).slice(8, -1)) { // Class
30877
- case 'Boolean':
30878
- case 'Number':
30879
- case 'String':
30880
- case 'Date':
30881
- case 'RegExp':
30882
- case 'Blob':
30883
- case 'FileList':
30884
- case 'ImageData':
30885
- case 'ImageBitmap':
30886
- case 'ArrayBuffer':
30887
- return true;
30888
- case 'Array':
30889
- case 'Object':
30890
- return Object.keys(val).every((prop) => isPostMessageable(val[prop]));
30891
- default:
30892
- return false;
30893
- }
30894
- };
30895
- value((a) => {
30896
- if (isPostMessageable(a)) {
30897
- return SimpleResult.svalue(a);
30898
- }
30899
- else {
30900
- return SimpleResult.serror('Expected value to be acceptable for sending via postMessage');
30901
- }
30902
- });
30903
-
30904
- const required$1 = () => ({ tag: "required" /* FieldPresenceTag.Required */, process: {} });
30905
- const defaultedThunk = (fallbackThunk) => ({ tag: "defaultedThunk" /* FieldPresenceTag.DefaultedThunk */, process: fallbackThunk });
30906
- const defaulted$1 = (fallback) => defaultedThunk(constant(fallback));
30907
- const asOption = () => ({ tag: "option" /* FieldPresenceTag.Option */, process: {} });
30908
-
30909
- const field$1 = (key, newKey, presence, prop) => ({ tag: "field" /* FieldTag.Field */, key, newKey, presence, prop });
30910
- const fold = (value, ifField, ifCustom) => {
30911
- switch (value.tag) {
30912
- case "field" /* FieldTag.Field */:
30913
- return ifField(value.key, value.newKey, value.presence, value.prop);
30914
- case "custom" /* FieldTag.CustomField */:
30915
- return ifCustom(value.newKey, value.instantiator);
30916
- }
30917
- };
30918
-
30919
- const mergeValues = (values, base) => {
30920
- return SimpleResult.svalue(deepMerge(base, merge$1.apply(undefined, values)));
30921
- };
30922
- const mergeErrors = (errors) => compose(SimpleResult.serror, flatten$1)(errors);
30923
- const consolidateObj = (objects, base) => {
30924
- const partition = SimpleResult.partition(objects);
30925
- return partition.errors.length > 0 ? mergeErrors(partition.errors) : mergeValues(partition.values, base);
30926
- };
30927
- const consolidateArr = (objects) => {
30928
- const partitions = SimpleResult.partition(objects);
30929
- return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : SimpleResult.svalue(partitions.values);
30930
- };
30931
- const ResultCombine = {
30932
- consolidateObj,
30933
- consolidateArr
30934
- };
30935
-
30936
- const requiredAccess = (path, obj, key, bundle) =>
30937
- // In required mode, if it is undefined, it is an error.
30938
- get$a(obj, key).fold(() => missingRequired(path, key, obj), bundle);
30939
- const fallbackAccess = (obj, key, fallback, bundle) => {
30940
- const v = get$a(obj, key).getOrThunk(() => fallback(obj));
30941
- return bundle(v);
30942
- };
30943
- const optionAccess = (obj, key, bundle) => bundle(get$a(obj, key));
30944
- const optionDefaultedAccess = (obj, key, fallback, bundle) => {
30945
- const opt = get$a(obj, key).map((val) => val === true ? fallback(obj) : val);
30946
- return bundle(opt);
30947
- };
30948
- const extractField = (field, path, obj, key, prop) => {
30949
- const bundle = (av) => prop.extract(path.concat([key]), av);
30950
- const bundleAsOption = (optValue) => optValue.fold(() => SimpleResult.svalue(Optional.none()), (ov) => {
30951
- const result = prop.extract(path.concat([key]), ov);
30952
- return SimpleResult.map(result, Optional.some);
30953
- });
30954
- switch (field.tag) {
30955
- case "required" /* FieldPresenceTag.Required */:
30956
- return requiredAccess(path, obj, key, bundle);
30957
- case "defaultedThunk" /* FieldPresenceTag.DefaultedThunk */:
30958
- return fallbackAccess(obj, key, field.process, bundle);
30959
- case "option" /* FieldPresenceTag.Option */:
30960
- return optionAccess(obj, key, bundleAsOption);
30961
- case "defaultedOptionThunk" /* FieldPresenceTag.DefaultedOptionThunk */:
30962
- return optionDefaultedAccess(obj, key, field.process, bundleAsOption);
30963
- case "mergeWithThunk" /* FieldPresenceTag.MergeWithThunk */: {
30964
- return fallbackAccess(obj, key, constant({}), (v) => {
30965
- const result = deepMerge(field.process(obj), v);
30966
- return bundle(result);
30967
- });
30968
- }
30969
- }
30970
- };
30971
- const extractFields = (path, obj, fields) => {
30972
- const success = {};
30973
- const errors = [];
30974
- // PERFORMANCE: We use a for loop here instead of Arr.each as this is a hot code path
30975
- for (const field of fields) {
30976
- fold(field, (key, newKey, presence, prop) => {
30977
- const result = extractField(presence, path, obj, key, prop);
30978
- SimpleResult.fold(result, (err) => {
30979
- errors.push(...err);
30980
- }, (res) => {
30981
- success[newKey] = res;
30982
- });
30983
- }, (newKey, instantiator) => {
30984
- success[newKey] = instantiator(obj);
30985
- });
30986
- }
30987
- return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success);
30988
- };
30989
- const objOf = (values) => {
30990
- const extract = (path, o) => extractFields(path, o, values);
30991
- const toString = () => {
30992
- const fieldStrings = map$3(values, (value) => fold(value, (key, _okey, _presence, prop) => key + ' -> ' + prop.toString(), (newKey, _instantiator) => 'state(' + newKey + ')'));
30993
- return 'obj{\n' + fieldStrings.join('\n') + '}';
30994
- };
30995
- return {
30996
- extract,
30997
- toString
30998
- };
30999
- };
31000
- const arrOf = (prop) => {
31001
- const extract = (path, array) => {
31002
- const results = map$3(array, (a, i) => prop.extract(path.concat(['[' + i + ']']), a));
31003
- return ResultCombine.consolidateArr(results);
31004
- };
31005
- const toString = () => 'array(' + prop.toString() + ')';
31006
- return {
31007
- extract,
31008
- toString
31009
- };
31010
- };
31011
-
31012
- const extractValue = (label, prop, obj) => {
31013
- const res = prop.extract([label], obj);
31014
- return SimpleResult.mapError(res, (errs) => ({ input: obj, errors: errs }));
31015
- };
31016
- const asRaw = (label, prop, obj) => SimpleResult.toResult(extractValue(label, prop, obj));
31017
- const formatError = (errInfo) => {
31018
- return 'Errors: \n' + formatErrors(errInfo.errors).join('\n') +
31019
- '\n\nInput object: ' + formatObj(errInfo.input);
31020
- };
31021
-
31022
- const field = field$1;
31023
- const required = (key) => field(key, key, required$1(), anyValue());
31024
- const requiredOf = (key, schema) => field(key, key, required$1(), schema);
31025
- const requiredString = (key) => requiredOf(key, string);
31026
- const requiredFunction = (key) => requiredOf(key, functionProcessor);
31027
- const option = (key) => field(key, key, asOption(), anyValue());
31028
- const optionOf = (key, schema) => field(key, key, asOption(), schema);
31029
- const optionString = (key) => optionOf(key, string);
31030
- const optionFunction = (key) => optionOf(key, functionProcessor);
31031
- const defaulted = (key, fallback) => field(key, key, defaulted$1(fallback), anyValue());
31032
- const defaultedOf = (key, fallback, schema) => field(key, key, defaulted$1(fallback), schema);
31033
- const defaultedNumber = (key, fallback) => defaultedOf(key, fallback, number);
31034
- const defaultedArrayOf = (key, fallback, schema) => defaultedOf(key, fallback, arrOf(schema));
31035
-
31036
31053
  const type = requiredString('type');
31037
31054
  const fetch$1 = requiredFunction('fetch');
31038
31055
  const onAction = requiredFunction('onAction');
@@ -31758,7 +31775,10 @@
31758
31775
  }
31759
31776
  }
31760
31777
  } while ((node = node.parentNode) && node !== editableRoot);
31761
- 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
+ }
31762
31782
  }
31763
31783
  setForcedBlockAttrs(editor, block);
31764
31784
  emptyBlock(caretNode);
@@ -34053,9 +34073,9 @@
34053
34073
  const isContentEditableFalse$2 = (elm) => isContentEditableFalse$a(elm.dom);
34054
34074
  const isContentEditableTrue = (elm) => isContentEditableTrue$3(elm.dom);
34055
34075
  const isRoot = (rootNode) => (elm) => eq(SugarElement.fromDom(rootNode), elm);
34056
- 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))
34057
34077
  .getOr(SugarElement.fromDom(rootNode)).dom;
34058
- 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));
34059
34079
  const findEdgeCaretCandidate = (startNode, scope, forward) => {
34060
34080
  const walker = new DomTreeWalker(startNode, scope);
34061
34081
  const next = forward ? walker.next.bind(walker) : walker.prev.bind(walker);
@@ -37422,7 +37442,7 @@
37422
37442
  required('id'),
37423
37443
  optionString('name'),
37424
37444
  optionString('avatar'),
37425
- option('custom')
37445
+ option$1('custom')
37426
37446
  ]);
37427
37447
  const objectCat = (obj) => {
37428
37448
  const result = {};
@@ -38271,6 +38291,24 @@
38271
38291
  const lowerCaseCommand = command.toLowerCase();
38272
38292
  this.commands.exec[lowerCaseCommand] = (_command, ui, value, args) => callback.call(scope ?? this.editor, ui, value, args);
38273
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
+ }
38274
38312
  /**
38275
38313
  * Returns true/false if the command is supported or not.
38276
38314
  *
@@ -40543,14 +40581,14 @@
40543
40581
  * @property minorVersion
40544
40582
  * @type String
40545
40583
  */
40546
- minorVersion: '2.1',
40584
+ minorVersion: '3.0',
40547
40585
  /**
40548
40586
  * Release date of TinyMCE build.
40549
40587
  *
40550
40588
  * @property releaseDate
40551
40589
  * @type String
40552
40590
  */
40553
- releaseDate: '2025-11-06',
40591
+ releaseDate: '2025-12-10',
40554
40592
  /**
40555
40593
  * Collection of language pack data.
40556
40594
  *