tinymce-rails 8.6.0 → 8.7.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.
- checksums.yaml +4 -4
- data/app/assets/source/tinymce/tinymce.js +269 -50
- data/lib/tinymce/rails/version.rb +2 -2
- data/vendor/assets/javascripts/tinymce/icons/default/icons.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/autolink/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/autosave/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/codesample/plugin.js +2 -2
- data/vendor/assets/javascripts/tinymce/plugins/emoticons/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/help/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/image/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/preview/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/plugins/table/plugin.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/content/dark/content.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/content/dark/content.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/content/dark/content.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.inline.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.inline.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.inline.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide/content.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide/skin.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide/skin.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide/skin.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.inline.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.inline.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.inline.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/content.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/skin.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/skin.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/oxide-dark/skin.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.inline.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.inline.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.inline.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/content.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/skin.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/skin.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5/skin.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.inline.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.inline.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/content.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/skin.css +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/skin.js +1 -1
- data/vendor/assets/javascripts/tinymce/skins/ui/tinymce-5-dark/skin.min.css +1 -1
- data/vendor/assets/javascripts/tinymce/themes/silver/theme.js +2 -2
- data/vendor/assets/javascripts/tinymce/tinymce.d.ts +11 -1
- data/vendor/assets/javascripts/tinymce/tinymce.js +3 -3
- metadata +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* TinyMCE version 8.
|
|
2
|
+
* TinyMCE version 8.7.0 (2026-07-01)
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
(function () {
|
|
@@ -573,14 +573,16 @@
|
|
|
573
573
|
}
|
|
574
574
|
return Optional.none();
|
|
575
575
|
};
|
|
576
|
-
const
|
|
576
|
+
const findLastByPredicate = (arr, pred) => {
|
|
577
577
|
for (let i = arr.length - 1; i >= 0; i--) {
|
|
578
578
|
if (pred(arr[i], i)) {
|
|
579
|
-
return Optional.some(i);
|
|
579
|
+
return Optional.some({ v: arr[i], i });
|
|
580
580
|
}
|
|
581
581
|
}
|
|
582
582
|
return Optional.none();
|
|
583
583
|
};
|
|
584
|
+
const findLast = (arr, pred) => findLastByPredicate(arr, pred).map((r) => r.v);
|
|
585
|
+
const findLastIndex = (arr, pred) => findLastByPredicate(arr, pred).map((r) => r.i);
|
|
584
586
|
const flatten$1 = (xs) => {
|
|
585
587
|
// Note, this is possible because push supports multiple arguments:
|
|
586
588
|
// http://jsperf.com/concat-push/6
|
|
@@ -2198,14 +2200,14 @@
|
|
|
2198
2200
|
const siblings = (element) => {
|
|
2199
2201
|
// TODO: Refactor out children so we can just not add self instead of filtering afterwards
|
|
2200
2202
|
const filterSelf = (elements) => filter$5(elements, (x) => !eq(element, x));
|
|
2201
|
-
return parent(element).map(children$
|
|
2203
|
+
return parent(element).map(children$2).map(filterSelf).getOr([]);
|
|
2202
2204
|
};
|
|
2203
2205
|
const prevSibling = (element) => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom);
|
|
2204
2206
|
const nextSibling = (element) => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
|
|
2205
2207
|
// This one needs to be reversed, so they're still in DOM order
|
|
2206
2208
|
const prevSiblings = (element) => reverse(toArray(element, prevSibling));
|
|
2207
2209
|
const nextSiblings = (element) => toArray(element, nextSibling);
|
|
2208
|
-
const children$
|
|
2210
|
+
const children$2 = (element) => map$3(element.dom.childNodes, SugarElement.fromDom);
|
|
2209
2211
|
const child$1 = (element, index) => {
|
|
2210
2212
|
const cs = element.dom.childNodes;
|
|
2211
2213
|
return Optional.from(cs[index]).map(SugarElement.fromDom);
|
|
@@ -2442,7 +2444,7 @@
|
|
|
2442
2444
|
// than removing every child node manually.
|
|
2443
2445
|
// The following is (probably) safe for performance as 99.9% of the time the trick works and
|
|
2444
2446
|
// Traverse.children will return an empty array.
|
|
2445
|
-
each$e(children$
|
|
2447
|
+
each$e(children$2(element), (rogue) => {
|
|
2446
2448
|
remove$8(rogue);
|
|
2447
2449
|
});
|
|
2448
2450
|
};
|
|
@@ -2453,7 +2455,7 @@
|
|
|
2453
2455
|
}
|
|
2454
2456
|
};
|
|
2455
2457
|
const unwrap = (wrapper) => {
|
|
2456
|
-
const children = children$
|
|
2458
|
+
const children = children$2(wrapper);
|
|
2457
2459
|
if (children.length > 0) {
|
|
2458
2460
|
after$3(wrapper, children);
|
|
2459
2461
|
}
|
|
@@ -2476,7 +2478,7 @@
|
|
|
2476
2478
|
const mutate = (original, tag) => {
|
|
2477
2479
|
const nu = shallowAs(original, tag);
|
|
2478
2480
|
after$4(original, nu);
|
|
2479
|
-
const children = children$
|
|
2481
|
+
const children = children$2(original);
|
|
2480
2482
|
append(nu, children);
|
|
2481
2483
|
remove$8(original);
|
|
2482
2484
|
return nu;
|
|
@@ -2486,7 +2488,7 @@
|
|
|
2486
2488
|
const doc = scope || document;
|
|
2487
2489
|
const div = doc.createElement('div');
|
|
2488
2490
|
div.innerHTML = html;
|
|
2489
|
-
return children$
|
|
2491
|
+
return children$2(SugarElement.fromDom(div));
|
|
2490
2492
|
};
|
|
2491
2493
|
const fromDom$1 = (nodes) => map$3(nodes, SugarElement.fromDom);
|
|
2492
2494
|
|
|
@@ -2526,6 +2528,14 @@
|
|
|
2526
2528
|
const doc = dom.ownerDocument;
|
|
2527
2529
|
return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
|
|
2528
2530
|
};
|
|
2531
|
+
const body = () => getBody(SugarElement.fromDom(document));
|
|
2532
|
+
const getBody = (doc) => {
|
|
2533
|
+
const b = doc.dom.body;
|
|
2534
|
+
if (b === null || b === undefined) {
|
|
2535
|
+
throw new Error('Body is not available yet');
|
|
2536
|
+
}
|
|
2537
|
+
return SugarElement.fromDom(b);
|
|
2538
|
+
};
|
|
2529
2539
|
|
|
2530
2540
|
const internalSet = (dom, property, value) => {
|
|
2531
2541
|
// This is going to hurt. Apologies.
|
|
@@ -2999,11 +3009,11 @@
|
|
|
2999
3009
|
};
|
|
3000
3010
|
|
|
3001
3011
|
const ancestors$1 = (scope, predicate, isRoot) => filter$5(parents$1(scope, isRoot), predicate);
|
|
3002
|
-
const children = (scope, predicate) => filter$5(children$
|
|
3012
|
+
const children$1 = (scope, predicate) => filter$5(children$2(scope), predicate);
|
|
3003
3013
|
const descendants$1 = (scope, predicate) => {
|
|
3004
3014
|
let result = [];
|
|
3005
3015
|
// Recurse.toArray() might help here
|
|
3006
|
-
each$e(children$
|
|
3016
|
+
each$e(children$2(scope), (x) => {
|
|
3007
3017
|
if (predicate(x)) {
|
|
3008
3018
|
result = result.concat([x]);
|
|
3009
3019
|
}
|
|
@@ -3021,6 +3031,10 @@
|
|
|
3021
3031
|
// It may surprise you to learn this is exactly what JQuery does
|
|
3022
3032
|
// TODO: Avoid all this wrapping and unwrapping
|
|
3023
3033
|
ancestors$1(scope, (e) => is$2(e, selector), isRoot);
|
|
3034
|
+
const children = (scope, selector) =>
|
|
3035
|
+
// It may surprise you to learn this is exactly what JQuery does
|
|
3036
|
+
// TODO: Avoid all the wrapping and unwrapping
|
|
3037
|
+
children$1(scope, (e) => is$2(e, selector));
|
|
3024
3038
|
const descendants = (scope, selector) => all(selector, scope);
|
|
3025
3039
|
|
|
3026
3040
|
const ancestor$3 = (scope, predicate, isRoot) => ancestor$5(scope, predicate, isRoot).isSome();
|
|
@@ -3205,6 +3219,20 @@
|
|
|
3205
3219
|
};
|
|
3206
3220
|
const getAtPoint = (win, x, y) => fromPoint$1(win, x, y);
|
|
3207
3221
|
|
|
3222
|
+
const getImageSize = (url) => new Promise((resolve, reject) => {
|
|
3223
|
+
const img = document.createElement('img');
|
|
3224
|
+
img.addEventListener('load', () => {
|
|
3225
|
+
resolve({
|
|
3226
|
+
width: img.naturalWidth,
|
|
3227
|
+
height: img.naturalHeight
|
|
3228
|
+
});
|
|
3229
|
+
});
|
|
3230
|
+
img.addEventListener('error', () => {
|
|
3231
|
+
reject(`Failed to get image dimensions for: ${url}`);
|
|
3232
|
+
});
|
|
3233
|
+
img.src = url;
|
|
3234
|
+
});
|
|
3235
|
+
|
|
3208
3236
|
const get$2 = (_win) => {
|
|
3209
3237
|
const win = _win === undefined ? window : _win;
|
|
3210
3238
|
if (detect$1().browser.isFirefox()) {
|
|
@@ -3660,7 +3688,7 @@
|
|
|
3660
3688
|
const isRoot = (el) => eq(el, rootNode);
|
|
3661
3689
|
each$e(fromDom$1(transparentBlocks), (transparentBlock) => {
|
|
3662
3690
|
ancestor$5(transparentBlock, isBlock, isRoot).each((parentBlock) => {
|
|
3663
|
-
const invalidChildren = children(transparentBlock, (el) => isBlock(el) && !schema.isValidChild(name(parentBlock), name(el)));
|
|
3691
|
+
const invalidChildren = children$1(transparentBlock, (el) => isBlock(el) && !schema.isValidChild(name(parentBlock), name(el)));
|
|
3664
3692
|
if (invalidChildren.length > 0) {
|
|
3665
3693
|
const stateScope = parentElement(parentBlock);
|
|
3666
3694
|
each$e(invalidChildren, (child) => {
|
|
@@ -3711,7 +3739,7 @@
|
|
|
3711
3739
|
// this tries to compensate for that by detecting if that offsets are incorrect and then remove the height
|
|
3712
3740
|
const getTableCaptionDeltaY = (elm) => {
|
|
3713
3741
|
if (browser$2.isFirefox() && name(elm) === 'table') {
|
|
3714
|
-
return firstElement(children$
|
|
3742
|
+
return firstElement(children$2(elm)).filter((elm) => {
|
|
3715
3743
|
return name(elm) === 'caption';
|
|
3716
3744
|
}).bind((caption) => {
|
|
3717
3745
|
return firstElement(nextSiblings(caption)).map((body) => {
|
|
@@ -5594,12 +5622,16 @@
|
|
|
5594
5622
|
let matches;
|
|
5595
5623
|
while ((matches = styleRegExp.exec(css))) {
|
|
5596
5624
|
styleRegExp.lastIndex = matches.index + matches[0].length;
|
|
5597
|
-
let name = matches[1].replace(trimRightRegExp, '')
|
|
5625
|
+
let name = matches[1].replace(trimRightRegExp, '');
|
|
5598
5626
|
let value = matches[2].replace(trimRightRegExp, '');
|
|
5599
5627
|
if (name && value) {
|
|
5600
5628
|
// Decode escaped sequences like \65 -> e
|
|
5601
5629
|
name = decodeHexSequences(name);
|
|
5602
5630
|
value = decodeHexSequences(value);
|
|
5631
|
+
// Custom properties (--*) keep user case; standard names normalize to lowercase
|
|
5632
|
+
if (!name.startsWith('--')) {
|
|
5633
|
+
name = name.toLowerCase();
|
|
5634
|
+
}
|
|
5603
5635
|
// Skip properties with double quotes and sequences like \" \' in their names
|
|
5604
5636
|
// See 'mXSS Attacks: Attacking well-secured Web-Applications by using innerHTML Mutations'
|
|
5605
5637
|
// https://cure53.de/fp170.pdf
|
|
@@ -5614,9 +5646,6 @@
|
|
|
5614
5646
|
if (name === 'font-weight' && value === '700') {
|
|
5615
5647
|
value = 'bold';
|
|
5616
5648
|
}
|
|
5617
|
-
else if (name === 'color' || name === 'background-color') { // Lowercase colors like RED
|
|
5618
|
-
value = value.toLowerCase();
|
|
5619
|
-
}
|
|
5620
5649
|
// Convert RGB colors to HEX
|
|
5621
5650
|
if (getColorFormat(value) === 'rgb') {
|
|
5622
5651
|
fromString(value).each((rgba) => {
|
|
@@ -6591,7 +6620,7 @@
|
|
|
6591
6620
|
const $node = SugarElement.fromDom(n);
|
|
6592
6621
|
if (keepChildren) {
|
|
6593
6622
|
// Unwrap but don't keep any empty text nodes
|
|
6594
|
-
each$e(children$
|
|
6623
|
+
each$e(children$2($node), (child) => {
|
|
6595
6624
|
if (isText$c(child) && child.dom.length === 0) {
|
|
6596
6625
|
remove$8(child);
|
|
6597
6626
|
}
|
|
@@ -12736,7 +12765,7 @@
|
|
|
12736
12765
|
switch (ctx) {
|
|
12737
12766
|
case "invalid-child" /* ChildContext.InvalidChild */: {
|
|
12738
12767
|
finishWrapper();
|
|
12739
|
-
const children = children$
|
|
12768
|
+
const children = children$2(elem);
|
|
12740
12769
|
processElements(children);
|
|
12741
12770
|
finishWrapper();
|
|
12742
12771
|
break;
|
|
@@ -12890,6 +12919,113 @@
|
|
|
12890
12919
|
};
|
|
12891
12920
|
};
|
|
12892
12921
|
|
|
12922
|
+
const announcerContainerId = generate('tiny-aria-announcer');
|
|
12923
|
+
const POLITE_MESSAGE_TTL_MS = 600000; // 10 minutes
|
|
12924
|
+
const CREATE_DELAY_MS = 100; // Delay before creating announcer regions to avoid interfering with screen readers initial announcements.
|
|
12925
|
+
const politeTimestampAttr = 'data-mce-announced-at';
|
|
12926
|
+
const OFFSCREEN_STYLES = {
|
|
12927
|
+
position: 'absolute',
|
|
12928
|
+
left: '-9999px',
|
|
12929
|
+
width: '1px',
|
|
12930
|
+
height: '1px',
|
|
12931
|
+
overflow: 'hidden'
|
|
12932
|
+
};
|
|
12933
|
+
const createRegion = (live) => {
|
|
12934
|
+
const region = SugarElement.fromTag('div');
|
|
12935
|
+
setAll$1(region, {
|
|
12936
|
+
'aria-live': live,
|
|
12937
|
+
'aria-atomic': 'false',
|
|
12938
|
+
'aria-relevant': 'additions'
|
|
12939
|
+
});
|
|
12940
|
+
return region;
|
|
12941
|
+
};
|
|
12942
|
+
const isConnected = (element) => element.dom.isConnected;
|
|
12943
|
+
const createNewState = () => {
|
|
12944
|
+
const container = SugarElement.fromTag('div');
|
|
12945
|
+
const politeRegion = createRegion('polite');
|
|
12946
|
+
const assertiveRegion = createRegion('assertive');
|
|
12947
|
+
set$5(container, 'id', announcerContainerId);
|
|
12948
|
+
setAll(container, OFFSCREEN_STYLES);
|
|
12949
|
+
append$1(container, politeRegion);
|
|
12950
|
+
append$1(container, assertiveRegion);
|
|
12951
|
+
append$1(body(), container);
|
|
12952
|
+
return { container, politeRegion, assertiveRegion };
|
|
12953
|
+
};
|
|
12954
|
+
const cleanupExpiredMessages = (polite, now) => {
|
|
12955
|
+
each$e(children(polite, `div[${politeTimestampAttr}]`), (messageDiv) => {
|
|
12956
|
+
getOpt(messageDiv, politeTimestampAttr)
|
|
12957
|
+
.bind((value) => toInt(value))
|
|
12958
|
+
.filter((announcedAt) => now - announcedAt > POLITE_MESSAGE_TTL_MS)
|
|
12959
|
+
.each(() => remove$8(messageDiv));
|
|
12960
|
+
});
|
|
12961
|
+
};
|
|
12962
|
+
const createAnnouncer = () => {
|
|
12963
|
+
const state = value$1();
|
|
12964
|
+
const mountRegions = async () => {
|
|
12965
|
+
const createNewPendingState = async () => {
|
|
12966
|
+
const promise = new Promise((resolve) => {
|
|
12967
|
+
const newState = createNewState();
|
|
12968
|
+
setTimeout(() => resolve(newState), CREATE_DELAY_MS);
|
|
12969
|
+
});
|
|
12970
|
+
state.set(promise);
|
|
12971
|
+
return promise;
|
|
12972
|
+
};
|
|
12973
|
+
return state.get().fold(createNewPendingState, async (existingPromise) => {
|
|
12974
|
+
const { container } = await existingPromise;
|
|
12975
|
+
if (isConnected(container)) {
|
|
12976
|
+
return existingPromise;
|
|
12977
|
+
}
|
|
12978
|
+
else {
|
|
12979
|
+
// A concurrent caller may have already replaced the stale state while we awaited.
|
|
12980
|
+
// The block after the await runs atomically, so reuse that state if present and
|
|
12981
|
+
// only create a fresh one when the state is still the stale promise we observed.
|
|
12982
|
+
return state.get().filter((current) => current !== existingPromise).getOrThunk(createNewPendingState);
|
|
12983
|
+
}
|
|
12984
|
+
});
|
|
12985
|
+
};
|
|
12986
|
+
const addMessage = (region, message) => {
|
|
12987
|
+
const now = Date.now();
|
|
12988
|
+
cleanupExpiredMessages(region, now);
|
|
12989
|
+
const messageDiv = SugarElement.fromTag('div');
|
|
12990
|
+
set$5(messageDiv, politeTimestampAttr, String(now));
|
|
12991
|
+
append$1(messageDiv, SugarElement.fromText(message));
|
|
12992
|
+
append$1(region, messageDiv);
|
|
12993
|
+
};
|
|
12994
|
+
const polite = async (message) => {
|
|
12995
|
+
const { politeRegion } = await mountRegions();
|
|
12996
|
+
addMessage(politeRegion, message);
|
|
12997
|
+
};
|
|
12998
|
+
const assertive = async (message) => {
|
|
12999
|
+
const { assertiveRegion } = await mountRegions();
|
|
13000
|
+
addMessage(assertiveRegion, message);
|
|
13001
|
+
};
|
|
13002
|
+
return { polite, assertive };
|
|
13003
|
+
};
|
|
13004
|
+
|
|
13005
|
+
const announcer = createAnnouncer();
|
|
13006
|
+
/**
|
|
13007
|
+
* Announces a message to screen readers via an aria-live region, without shifting focus.
|
|
13008
|
+
*
|
|
13009
|
+
* @method announce
|
|
13010
|
+
* @param {String} message The message to announce to screen readers.
|
|
13011
|
+
* @param {Object} options Optional settings.
|
|
13012
|
+
* @param {Boolean} options.assertive If true, uses aria-live="assertive" instead of polite.
|
|
13013
|
+
* @example
|
|
13014
|
+
* tinymce.dom.AriaAnnouncer.announce('Bold on');
|
|
13015
|
+
* tinymce.dom.AriaAnnouncer.announce('Error occurred', { assertive: true });
|
|
13016
|
+
*/
|
|
13017
|
+
const announce = (message, options) => {
|
|
13018
|
+
if (options?.assertive === true) {
|
|
13019
|
+
announcer.assertive(message).catch(noop);
|
|
13020
|
+
}
|
|
13021
|
+
else {
|
|
13022
|
+
announcer.polite(message).catch(noop);
|
|
13023
|
+
}
|
|
13024
|
+
};
|
|
13025
|
+
const AriaAnnouncer = {
|
|
13026
|
+
announce
|
|
13027
|
+
};
|
|
13028
|
+
|
|
12893
13029
|
/**
|
|
12894
13030
|
* Constructs a new BookmarkManager instance for a specific selection instance.
|
|
12895
13031
|
*
|
|
@@ -12954,7 +13090,7 @@
|
|
|
12954
13090
|
};
|
|
12955
13091
|
|
|
12956
13092
|
const clamp$1 = (offset, element) => {
|
|
12957
|
-
const max = isText$c(element) ? get$5(element).length : children$
|
|
13093
|
+
const max = isText$c(element) ? get$5(element).length : children$2(element).length + 1;
|
|
12958
13094
|
if (offset > max) {
|
|
12959
13095
|
return max;
|
|
12960
13096
|
}
|
|
@@ -14226,7 +14362,7 @@
|
|
|
14226
14362
|
editor.dispatch('AfterScrollIntoView', data);
|
|
14227
14363
|
};
|
|
14228
14364
|
const descend = (element, offset) => {
|
|
14229
|
-
const children = children$
|
|
14365
|
+
const children = children$2(element);
|
|
14230
14366
|
if (children.length === 0 || excludeFromDescend(element)) {
|
|
14231
14367
|
return { element, offset };
|
|
14232
14368
|
}
|
|
@@ -14246,7 +14382,7 @@
|
|
|
14246
14382
|
return { element: last, offset: get$5(last).length };
|
|
14247
14383
|
}
|
|
14248
14384
|
else {
|
|
14249
|
-
return { element: last, offset: children$
|
|
14385
|
+
return { element: last, offset: children$2(last).length };
|
|
14250
14386
|
}
|
|
14251
14387
|
}
|
|
14252
14388
|
}
|
|
@@ -15750,7 +15886,7 @@
|
|
|
15750
15886
|
const br = SugarElement.fromHtml('<br data-mce-bogus="1">');
|
|
15751
15887
|
// Remove all bogus elements except caret
|
|
15752
15888
|
if (preserveEmptyCaret) {
|
|
15753
|
-
each$e(children$
|
|
15889
|
+
each$e(children$2(elm), (node) => {
|
|
15754
15890
|
if (!isEmptyCaretFormatElement(node)) {
|
|
15755
15891
|
remove$8(node);
|
|
15756
15892
|
}
|
|
@@ -15922,7 +16058,7 @@
|
|
|
15922
16058
|
// Clean up any additional leftover nodes. If the last block wasn't a direct child, then we also need to clean up siblings
|
|
15923
16059
|
if (!eq(root, lastBlock)) {
|
|
15924
16060
|
const additionalCleanupNodes = is$4(parent(lastBlock), root) ? [] : siblings(lastBlock);
|
|
15925
|
-
each$e(additionalCleanupNodes.concat(children$
|
|
16061
|
+
each$e(additionalCleanupNodes.concat(children$2(root)), (node) => {
|
|
15926
16062
|
if (!eq(node, lastBlock) && !contains(node, lastBlock) && isEmpty$4(editor.schema, node)) {
|
|
15927
16063
|
remove$8(node);
|
|
15928
16064
|
}
|
|
@@ -17695,14 +17831,14 @@
|
|
|
17695
17831
|
});
|
|
17696
17832
|
};
|
|
17697
17833
|
const wrapChildrenInInnerWrapper = (target, wrapper, hasFormat, removeFormatFromElement) => {
|
|
17698
|
-
each$e(children$
|
|
17834
|
+
each$e(children$2(target), (child) => {
|
|
17699
17835
|
if (isElement$8(child) && hasFormat(child)) {
|
|
17700
17836
|
if (removeFormatFromElement(child).isNone()) {
|
|
17701
17837
|
unwrap(child);
|
|
17702
17838
|
}
|
|
17703
17839
|
}
|
|
17704
17840
|
});
|
|
17705
|
-
each$e(children$
|
|
17841
|
+
each$e(children$2(target), (child) => append$1(wrapper, child));
|
|
17706
17842
|
prepend(target, wrapper);
|
|
17707
17843
|
};
|
|
17708
17844
|
const wrapInOuterWrappers = (target, wrappers) => {
|
|
@@ -22068,7 +22204,7 @@
|
|
|
22068
22204
|
append(SugarElement.fromDom(pre1), [
|
|
22069
22205
|
SugarElement.fromTag('br', doc),
|
|
22070
22206
|
SugarElement.fromTag('br', doc),
|
|
22071
|
-
...children$
|
|
22207
|
+
...children$2(sPre2)
|
|
22072
22208
|
]);
|
|
22073
22209
|
};
|
|
22074
22210
|
if (!rng.collapsed) {
|
|
@@ -22215,10 +22351,12 @@
|
|
|
22215
22351
|
const wrapName = format.inline || format.block;
|
|
22216
22352
|
const wrapElm = createWrapElement(wrapName);
|
|
22217
22353
|
const isMatchingWrappingBlock = (node) => isWrappingBlockFormat(format) && matchNode$1(ed, node, name, vars);
|
|
22354
|
+
const canRenameChildBlocks = (node) => forall(node.childNodes, (child) => !isTextBlock$2(ed.schema, child) || isValid(ed, wrapName, child.nodeName.toLowerCase()));
|
|
22218
22355
|
const canRenameBlock = (node, parentName, isEditableDescendant) => {
|
|
22219
22356
|
const isValidBlockFormatForNode = isNonWrappingBlockFormat(format) &&
|
|
22220
22357
|
isTextBlock$2(ed.schema, node) &&
|
|
22221
|
-
isValid(ed, parentName, wrapName)
|
|
22358
|
+
isValid(ed, parentName, wrapName) &&
|
|
22359
|
+
canRenameChildBlocks(node);
|
|
22222
22360
|
return isEditableDescendant && isValidBlockFormatForNode;
|
|
22223
22361
|
};
|
|
22224
22362
|
const canWrapNode = (node, parentName, isEditableDescendant, isWrappableNoneditableElm) => {
|
|
@@ -22375,6 +22513,19 @@
|
|
|
22375
22513
|
// node variable is used by other functions above in the same scope so need to set it here
|
|
22376
22514
|
node = targetNode;
|
|
22377
22515
|
applyNodeStyle(formatList, node);
|
|
22516
|
+
if (isBlockFormat(format) && !dom.isBlock(targetNode)) {
|
|
22517
|
+
const parentBlock = dom.getParent(targetNode, dom.isBlock);
|
|
22518
|
+
if (dom.isEditable(parentBlock)) {
|
|
22519
|
+
const wrapperElementName = format.block;
|
|
22520
|
+
if (parentBlock.nodeName.toLowerCase() === wrapperElementName.toLowerCase()) {
|
|
22521
|
+
setElementFormat(ed, parentBlock, format, vars, node);
|
|
22522
|
+
}
|
|
22523
|
+
else if (!isWrappingBlockFormat(format)) {
|
|
22524
|
+
const elm = dom.rename(parentBlock, wrapperElementName);
|
|
22525
|
+
setElementFormat(ed, elm, format, vars, node);
|
|
22526
|
+
}
|
|
22527
|
+
}
|
|
22528
|
+
}
|
|
22378
22529
|
fireFormatApply(ed, name, node, vars);
|
|
22379
22530
|
return;
|
|
22380
22531
|
}
|
|
@@ -26164,7 +26315,7 @@
|
|
|
26164
26315
|
preview: 'font-family font-size'
|
|
26165
26316
|
},
|
|
26166
26317
|
{
|
|
26167
|
-
selector: '.mce-preview-object,[data-ephox-embed-iri]',
|
|
26318
|
+
selector: '.mce-preview-object,[data-ephox-embed-iri],.tiny-pageembed',
|
|
26168
26319
|
ceFalseOverride: true,
|
|
26169
26320
|
styles: {
|
|
26170
26321
|
float: 'left'
|
|
@@ -26216,7 +26367,7 @@
|
|
|
26216
26367
|
preview: 'font-family font-size'
|
|
26217
26368
|
},
|
|
26218
26369
|
{
|
|
26219
|
-
selector: '.mce-preview-object',
|
|
26370
|
+
selector: '.mce-preview-object,.tiny-pageembed',
|
|
26220
26371
|
ceFalseOverride: true,
|
|
26221
26372
|
styles: {
|
|
26222
26373
|
display: 'table', // Needs to be `table` to properly render while editing
|
|
@@ -26280,7 +26431,7 @@
|
|
|
26280
26431
|
preview: 'font-family font-size'
|
|
26281
26432
|
},
|
|
26282
26433
|
{
|
|
26283
|
-
selector: '.mce-preview-object,[data-ephox-embed-iri]',
|
|
26434
|
+
selector: '.mce-preview-object,[data-ephox-embed-iri],.tiny-pageembed',
|
|
26284
26435
|
ceFalseOverride: true,
|
|
26285
26436
|
styles: {
|
|
26286
26437
|
float: 'right'
|
|
@@ -26967,8 +27118,8 @@
|
|
|
26967
27118
|
isFirstTypedCharacter.set(true);
|
|
26968
27119
|
return;
|
|
26969
27120
|
}
|
|
26970
|
-
const
|
|
26971
|
-
if (
|
|
27121
|
+
const hasMetaOrCtrlModifier = Env.os.isMacOS() ? e.metaKey : e.ctrlKey && !e.altKey;
|
|
27122
|
+
if (hasMetaOrCtrlModifier && (e.key === 'Backspace' || e.key === 'Delete')) {
|
|
26972
27123
|
undoManager.beforeChange();
|
|
26973
27124
|
}
|
|
26974
27125
|
});
|
|
@@ -27533,7 +27684,7 @@
|
|
|
27533
27684
|
const isIndented = (entry) => entry.depth > 0;
|
|
27534
27685
|
const isSelected = (entry) => entry.isSelected;
|
|
27535
27686
|
const cloneItemContent = (li) => {
|
|
27536
|
-
const children = children$
|
|
27687
|
+
const children = children$2(li);
|
|
27537
27688
|
const content = hasLastChildList(li) ? children.slice(0, -1) : children;
|
|
27538
27689
|
return map$3(content, deep);
|
|
27539
27690
|
};
|
|
@@ -27731,7 +27882,7 @@
|
|
|
27731
27882
|
return currentItemEntry.toArray().concat(childListEntries);
|
|
27732
27883
|
};
|
|
27733
27884
|
const parseItem = (depth, itemSelection, selectionState, item) => firstChild(item).filter(isList).fold(() => parseSingleItem(depth, itemSelection, selectionState, item), (list) => {
|
|
27734
|
-
const parsedSiblings = foldl(children$
|
|
27885
|
+
const parsedSiblings = foldl(children$2(item), (acc, liChild, i) => {
|
|
27735
27886
|
if (i === 0) {
|
|
27736
27887
|
return acc;
|
|
27737
27888
|
}
|
|
@@ -27754,7 +27905,7 @@
|
|
|
27754
27905
|
}, []);
|
|
27755
27906
|
return parseList(depth, itemSelection, selectionState, list).concat(parsedSiblings);
|
|
27756
27907
|
});
|
|
27757
|
-
const parseList = (depth, itemSelection, selectionState, list) => bind$3(children$
|
|
27908
|
+
const parseList = (depth, itemSelection, selectionState, list) => bind$3(children$2(list), (element) => {
|
|
27758
27909
|
const parser = isList(element) ? parseList : parseItem;
|
|
27759
27910
|
const newDepth = depth + 1;
|
|
27760
27911
|
return parser(newDepth, itemSelection, selectionState, element);
|
|
@@ -28417,7 +28568,7 @@
|
|
|
28417
28568
|
const rng = normalizeRange(editor.selection.getRng());
|
|
28418
28569
|
const nextCaretContainer = findNextCaretContainer(editor, rng, isForward, root);
|
|
28419
28570
|
const otherLi = dom.getParent(nextCaretContainer, 'LI', root);
|
|
28420
|
-
if (nextCaretContainer && otherLi) {
|
|
28571
|
+
if (nextCaretContainer && otherLi && (isForward || !dom.isChildOf(nextCaretContainer, block))) {
|
|
28421
28572
|
const findValidElement = (element) => contains$2(['td', 'th', 'caption'], name(element));
|
|
28422
28573
|
const findRoot = (node) => node.dom === root;
|
|
28423
28574
|
const otherLiCell = closest$5(SugarElement.fromDom(otherLi), findValidElement, findRoot);
|
|
@@ -28515,7 +28666,7 @@
|
|
|
28515
28666
|
const read$1 = (schema, rootNode, forward, rng) => rng.collapsed ? readFromRange(schema, rootNode, forward, rng) : Optional.none();
|
|
28516
28667
|
|
|
28517
28668
|
const getChildrenUntilBlockBoundary = (block, schema) => {
|
|
28518
|
-
const children = children$
|
|
28669
|
+
const children = children$2(block);
|
|
28519
28670
|
return findIndex$2(children, (el) => schema.isBlock(name(el))).fold(constant(children), (index) => children.slice(0, index));
|
|
28520
28671
|
};
|
|
28521
28672
|
const extractChildren = (block, schema) => {
|
|
@@ -29910,7 +30061,11 @@
|
|
|
29910
30061
|
const canIndent = (editor) => !editor.mode.isReadOnly() && canIndent$1(editor);
|
|
29911
30062
|
const isListComponent = (el) => isList$1(el) || isListItem$2(el);
|
|
29912
30063
|
const parentIsListComponent = (el) => parent(el).exists(isListComponent);
|
|
29913
|
-
const getBlocksToIndent = (editor) =>
|
|
30064
|
+
const getBlocksToIndent = (editor) => {
|
|
30065
|
+
const selectedCells = getCellsFromEditor(editor);
|
|
30066
|
+
return selectedCells.length === 0 ?
|
|
30067
|
+
filter$5(fromDom$1(editor.selection.getSelectedBlocks()), (el) => !isListComponent(el) && !parentIsListComponent(el) && isEditable(el)) : selectedCells;
|
|
30068
|
+
};
|
|
29914
30069
|
const handle = (editor, command) => {
|
|
29915
30070
|
if (editor.mode.isReadOnly()) {
|
|
29916
30071
|
return;
|
|
@@ -30585,7 +30740,7 @@
|
|
|
30585
30740
|
return filterFirstLayer(scope, selector, always);
|
|
30586
30741
|
};
|
|
30587
30742
|
const filterFirstLayer = (scope, selector, predicate) => {
|
|
30588
|
-
return bind$3(children$
|
|
30743
|
+
return bind$3(children$2(scope), (x) => {
|
|
30589
30744
|
if (is$2(x, selector)) {
|
|
30590
30745
|
return predicate(x) ? [x] : [];
|
|
30591
30746
|
}
|
|
@@ -30795,7 +30950,7 @@
|
|
|
30795
30950
|
nextSibling: nextSibling
|
|
30796
30951
|
}),
|
|
30797
30952
|
property: constant({
|
|
30798
|
-
children: children$
|
|
30953
|
+
children: children$2,
|
|
30799
30954
|
name: name,
|
|
30800
30955
|
parent: parent,
|
|
30801
30956
|
document,
|
|
@@ -33902,15 +34057,20 @@
|
|
|
33902
34057
|
blobCache.add(blobInfo);
|
|
33903
34058
|
return blobInfo;
|
|
33904
34059
|
};
|
|
33905
|
-
const pasteImage = (editor, imageItem) => {
|
|
33906
|
-
parseDataUri(imageItem.uri).
|
|
34060
|
+
const pasteImage = async (editor, imageItem) => {
|
|
34061
|
+
return parseDataUri(imageItem.uri).fold(() => Promise.resolve(), ({ data, type, base64Encoded }) => {
|
|
33907
34062
|
const base64 = base64Encoded ? data : btoa(data);
|
|
33908
34063
|
const file = imageItem.file;
|
|
33909
34064
|
// TODO: Move the bulk of the cache logic to EditorUpload
|
|
33910
34065
|
const blobCache = editor.editorUpload.blobCache;
|
|
33911
34066
|
const existingBlobInfo = blobCache.getByData(base64, type);
|
|
33912
34067
|
const blobInfo = existingBlobInfo ?? createBlobInfo(editor, blobCache, file, base64);
|
|
33913
|
-
|
|
34068
|
+
const imgUrl = blobInfo.blobUri();
|
|
34069
|
+
return getImageSize(imgUrl).then(({ width, height }) => {
|
|
34070
|
+
pasteHtml(editor, `<img width="${width}" height="${height}" src="${imgUrl}">`, false, true);
|
|
34071
|
+
}).catch(() => {
|
|
34072
|
+
pasteHtml(editor, `<img src="${imgUrl}">`, false, true);
|
|
34073
|
+
});
|
|
33914
34074
|
});
|
|
33915
34075
|
};
|
|
33916
34076
|
const isClipboardEvent = (event) => event.type === 'paste';
|
|
@@ -33941,13 +34101,13 @@
|
|
|
33941
34101
|
if (images.length > 0) {
|
|
33942
34102
|
e.preventDefault();
|
|
33943
34103
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
33944
|
-
readFilesAsDataUris(images).then((fileResults) => {
|
|
34104
|
+
readFilesAsDataUris(images).then(async (fileResults) => {
|
|
33945
34105
|
if (rng) {
|
|
33946
34106
|
editor.selection.setRng(rng);
|
|
33947
34107
|
}
|
|
33948
|
-
|
|
33949
|
-
pasteImage(editor, result);
|
|
33950
|
-
}
|
|
34108
|
+
for (const result of fileResults) {
|
|
34109
|
+
await pasteImage(editor, result);
|
|
34110
|
+
}
|
|
33951
34111
|
});
|
|
33952
34112
|
return true;
|
|
33953
34113
|
}
|
|
@@ -36095,6 +36255,7 @@
|
|
|
36095
36255
|
const browser = Env.browser;
|
|
36096
36256
|
const isGecko = browser.isFirefox();
|
|
36097
36257
|
const isWebKit = browser.isChromium() || browser.isSafari();
|
|
36258
|
+
const isSafari = browser.isSafari();
|
|
36098
36259
|
const isiOS = Env.deviceType.isiPhone() || Env.deviceType.isiPad();
|
|
36099
36260
|
const isMac = Env.os.isMacOS() || Env.os.isiOS();
|
|
36100
36261
|
/**
|
|
@@ -36701,6 +36862,45 @@
|
|
|
36701
36862
|
}
|
|
36702
36863
|
});
|
|
36703
36864
|
};
|
|
36865
|
+
/**
|
|
36866
|
+
* this is needed to manage the difference between
|
|
36867
|
+
* ```
|
|
36868
|
+
* <li><span class="fake">a</span><div>b</div></li>
|
|
36869
|
+
* ```
|
|
36870
|
+
* and
|
|
36871
|
+
* ```
|
|
36872
|
+
* <li><span class="fake">a</span> <div>b</div></li>
|
|
36873
|
+
* ```
|
|
36874
|
+
* since if the indentation of the HTML has a new line it creates a fake child in the `li` that is an empty text
|
|
36875
|
+
* it's check it trying to get the rects and if it can't it means that it's the false unwanted new line
|
|
36876
|
+
**/
|
|
36877
|
+
const isValidSibling = (el) => getClientRects([el.dom]).length > 0;
|
|
36878
|
+
const firstBlockChildOrNewLine = (target) => child(target, (child) => isBr$6(child) || isElement$8(child) && get$8(child, 'display') === 'block');
|
|
36879
|
+
const clickAfterEl = (clientX, clientY, rect) => clientX >= rect.right && clientY >= rect.top && clientY <= rect.bottom;
|
|
36880
|
+
/**
|
|
36881
|
+
* In Chrome in a `LI` that contains a block element and where the first child is an inline element
|
|
36882
|
+
* clicking on the right side of the first child the carret goes at the start of the element instead that in the end of it
|
|
36883
|
+
* issue: https://issues.chromium.org/issues/40767343
|
|
36884
|
+
**/
|
|
36885
|
+
const fixInLISelection = () => {
|
|
36886
|
+
editor.on('mousedown', (e) => {
|
|
36887
|
+
const target = SugarElement.fromDom(e.target);
|
|
36888
|
+
if (isListItem$2(target)) {
|
|
36889
|
+
firstBlockChildOrNewLine(target).each((firstBlock) => {
|
|
36890
|
+
const prevSiblings$1 = prevSiblings(firstBlock);
|
|
36891
|
+
findLast(prevSiblings$1, isValidSibling).each((lastInlineBeforeBlock) => {
|
|
36892
|
+
if (get$c(getClientRects([lastInlineBeforeBlock.dom]), 0).exists((rect) => clickAfterEl(e.clientX, e.clientY, rect))) {
|
|
36893
|
+
prevPosition(target.dom, CaretPosition(firstBlock.dom, 0)).each((pos) => {
|
|
36894
|
+
e.preventDefault();
|
|
36895
|
+
editor.focus();
|
|
36896
|
+
editor.selection.setRng(pos.toRange());
|
|
36897
|
+
});
|
|
36898
|
+
}
|
|
36899
|
+
});
|
|
36900
|
+
});
|
|
36901
|
+
}
|
|
36902
|
+
});
|
|
36903
|
+
};
|
|
36704
36904
|
// No-op since Mozilla seems to have fixed the caret repaint issues
|
|
36705
36905
|
const refreshContentEditable = noop;
|
|
36706
36906
|
const isHidden = () => {
|
|
@@ -36747,6 +36947,9 @@
|
|
|
36747
36947
|
blockFormSubmitInsideEditor();
|
|
36748
36948
|
disableBackspaceIntoATable();
|
|
36749
36949
|
removeAppleInterchangeBrs();
|
|
36950
|
+
if (!isSafari) {
|
|
36951
|
+
fixInLISelection();
|
|
36952
|
+
}
|
|
36750
36953
|
// touchClickEvent();
|
|
36751
36954
|
// iOS
|
|
36752
36955
|
if (isiOS) {
|
|
@@ -40843,6 +41046,21 @@
|
|
|
40843
41046
|
hasEditableRoot() {
|
|
40844
41047
|
return hasEditableRoot(this);
|
|
40845
41048
|
}
|
|
41049
|
+
/**
|
|
41050
|
+
* Announces a message to screen readers via the page-wide aria-live region, without shifting focus.
|
|
41051
|
+
* Delegates to {@link tinymce.dom.AriaAnnouncer#announce}.
|
|
41052
|
+
*
|
|
41053
|
+
* @method announce
|
|
41054
|
+
* @param {String} message The message to announce to screen readers.
|
|
41055
|
+
* @param {Object} options Optional settings.
|
|
41056
|
+
* @param {Boolean} options.assertive If true, uses aria-live="assertive" (role="alert") instead of polite.
|
|
41057
|
+
* @example
|
|
41058
|
+
* tinymce.activeEditor.announce('Bold on');
|
|
41059
|
+
* tinymce.activeEditor.announce('Error occurred', { assertive: true });
|
|
41060
|
+
*/
|
|
41061
|
+
announce(message, options) {
|
|
41062
|
+
AriaAnnouncer.announce(message, options);
|
|
41063
|
+
}
|
|
40846
41064
|
/**
|
|
40847
41065
|
* Removes the editor from the dom and tinymce collection.
|
|
40848
41066
|
*
|
|
@@ -40967,14 +41185,14 @@
|
|
|
40967
41185
|
* @property minorVersion
|
|
40968
41186
|
* @type String
|
|
40969
41187
|
*/
|
|
40970
|
-
minorVersion: '
|
|
41188
|
+
minorVersion: '7.0',
|
|
40971
41189
|
/**
|
|
40972
41190
|
* Release date of TinyMCE build.
|
|
40973
41191
|
*
|
|
40974
41192
|
* @property releaseDate
|
|
40975
41193
|
* @type String
|
|
40976
41194
|
*/
|
|
40977
|
-
releaseDate: '2026-
|
|
41195
|
+
releaseDate: '2026-07-01',
|
|
40978
41196
|
/**
|
|
40979
41197
|
* Collection of language pack data.
|
|
40980
41198
|
*
|
|
@@ -41832,6 +42050,7 @@
|
|
|
41832
42050
|
ControlSelection,
|
|
41833
42051
|
BookmarkManager,
|
|
41834
42052
|
Selection: EditorSelection,
|
|
42053
|
+
AriaAnnouncer,
|
|
41835
42054
|
Event: EventUtils.Event
|
|
41836
42055
|
},
|
|
41837
42056
|
html: {
|