Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
591247a
INT-3359: Support jQuery v4
tiny-ben-tran May 14, 2026
78e2bf5
Use jquery 4 in storybook
tiny-ben-tran May 14, 2026
0c4bd9a
Upgrade storybook to v10
tiny-ben-tran May 14, 2026
87c12fe
Update type checking
tiny-ben-tran May 15, 2026
9dd3134
Update storybook
tiny-ben-tran May 15, 2026
b45f497
Add changelog
tiny-ben-tran May 15, 2026
2dd97e7
Fix invalid typescript option
tiny-ben-tran May 15, 2026
4bf0469
Add lint rules for storybook
tiny-ben-tran May 15, 2026
7c66dd6
Re-add the baseUrl config which is needed for bedrock webpack
tiny-ben-tran May 15, 2026
4124e3c
Unwrap setupIntegration in jqAppendTest
tiny-ben-tran May 18, 2026
b5a0a63
Remove a heading
tiny-ben-tran May 18, 2026
7d9b57a
Undo change to fix test failing
tiny-ben-tran May 18, 2026
66c576f
Use jquery 4 in test
tiny-ben-tran May 19, 2026
3893229
Attempt to fix test
tiny-ben-tran May 19, 2026
b578668
Fix tests keeping timeout before tinymce being loaded
tiny-ben-tran May 19, 2026
41e7d77
Remove gpl license key
tiny-ben-tran May 19, 2026
35cfb87
Add license key gpl to tests which uses self-hosted tinymce
tiny-ben-tran May 19, 2026
002138f
Bump the minor version
tiny-ben-tran May 19, 2026
d4cbb03
Remove unnecessary test
tiny-ben-tran May 20, 2026
f36e4a0
Fix lint
tiny-ben-tran May 20, 2026
7411469
Use local tinymce
tiny-ben-tran May 20, 2026
d05081c
Disabled jqAppentest
tiny-ben-tran May 20, 2026
493d76e
Fix flaky tests in OriginalTest
tiny-ben-tran May 21, 2026
fc73e9f
Another attempt to fix test
tiny-ben-tran May 21, 2026
1ea4bd9
fix lint
tiny-ben-tran May 21, 2026
fed891a
Another fix
tiny-ben-tran May 21, 2026
d14e345
Stack trace any error
tiny-ben-tran May 21, 2026
659aeba
lint
tiny-ben-tran May 21, 2026
288e3c9
Undo some changes
tiny-ben-tran May 21, 2026
6fe5e21
Another attempt
tiny-ben-tran May 21, 2026
dc0be10
Remove all try catches
tiny-ben-tran May 21, 2026
a2fd317
Strip more try/catch
tiny-ben-tran May 21, 2026
c67d56a
Use different predicate
tiny-ben-tran May 21, 2026
b35d68a
Undo jquery restrictin
tiny-ben-tran May 21, 2026
8333b54
Skip some tests to try out
tiny-ben-tran May 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 0 additions & 31 deletions .storybook/main.js

This file was deleted.

21 changes: 21 additions & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { StorybookConfig } from '@storybook/html-vite';

const config: StorybookConfig = {
stories: [
"../src/**/*.stories.mdx",
"../src/**/*.stories.@(js|jsx|ts|tsx)"
],
addons: [
"@storybook/addon-links",
"@storybook/addon-docs"
],
framework: {
"name": "@storybook/html-vite",
"options": {}
},
async viteFinal(config) {
return config;
}
};

export default config;
5 changes: 1 addition & 4 deletions .storybook/preview-head.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
<!-- load jQuery -->
<script
src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-4.0.0.js" integrity="sha256-9fsHeVnKBvqh3FB2HYu7g2xseAZ5MlN6Kz/qnkASV8U=" crossorigin="anonymous"></script>
<!-- load TinyMCE -->
<script
src="https://cdn.tiny.cloud/1/qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc/tinymce/8/tinymce.min.js"
Expand Down
1 change: 0 additions & 1 deletion .storybook/preview.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
Expand Down
14 changes: 14 additions & 0 deletions .storybook/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"moduleResolution": "nodenext",
"target": "es6",
"module": "nodenext",
"lib": ["es2015", "dom"],
"types": ["jquery"]
},
"include": [
"../src/**/*",
"../.storybook/**/*"
]
}
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Changed

- Updated to support jQuery 4. #INT-3359

## 2.2.0 - 2025-10-16

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ Have you found an issue with tinymce-jquery or do you have a feature request?
Open up an [issue](https://github.com/tinymce/tinymce-jquery/issues) and let us
know or submit a [pull request](https://github.com/tinymce/tinymce-jquery/pulls).
*Note: For issues concerning TinyMCE please visit the
[TinyMCE repository](https://github.com/tinymce/tinymce).*
[TinyMCE repository](https://github.com/tinymce/tinymce).*
19 changes: 19 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,25 @@ export default defineConfig([
},
},
rules: {}
},
{
files: [
".storybook/*.ts",
"src/stories/**/*.ts"
],
plugins: {
"@tinymce": tinymceEslintPlugin
},
extends: [ '@tinymce/standard' ],
languageOptions: {
parserOptions: {
sourceType: "module",
project: [
".storybook/tsconfig.json"
]
},
},
rules: {}
},
{
files: [
Expand Down
34 changes: 14 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tinymce/tinymce-jquery",
"version": "2.2.1-rc",
"version": "2.3.0-rc",
"description": "Official TinyMCE integration for jQuery",
"main": "dist/tinymce-jquery.js",
"files": [
Expand All @@ -19,15 +19,14 @@
"test-manual": "bedrock -d src/test/ts",
"build": "yarn run clean && tsc -p ./tsconfig.json && rollup -c rollup.config.js",
"lint": "eslint src",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"deploy-storybook": "yarn storybook-to-ghpages --source-branch=main"
},
"repository": "https://github.com/tinymce/tinymce-jquery",
"author": "Tiny Technologies",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.21.3",
"@ephox/agar": "^7.4.1",
"@ephox/bedrock-client": "^14.0.0",
"@ephox/bedrock-server": "^14.0.0",
Expand All @@ -37,31 +36,26 @@
"@ephox/sugar": "^9.2.1",
"@ephox/swag": "^4.6.0",
"@rollup/plugin-terser": "^0.4.0",
"@storybook/addon-actions": "^6.5.16",
"@storybook/addon-essentials": "^6.5.16",
"@storybook/addon-interactions": "^6.5.16",
"@storybook/addon-links": "^6.5.16",
"@storybook/builder-webpack5": "^6.5.16",
"@storybook/html": "^6.5.16",
"@storybook/manager-webpack5": "^6.5.16",
"@storybook/addon-docs": "^10.0.0",
"@storybook/addon-links": "^10.0.0",
"@storybook/html": "^10.0.0",
"@storybook/html-vite": "^10.0.0",
"@storybook/storybook-deployer": "^2.8.16",
"@storybook/testing-library": "^0.0.13",
"@tinymce/beehive-flow": "^0.19.0",
"@tinymce/eslint-plugin": "^3.0.0",
"@types/jquery": "^3.5.16",
"@types/react": "^17.0.0",
"babel-loader": "^8.3.0",
"react": "^17.0.0",
"react-dom": "^17.0.0",
"@types/jquery": "^4.0.0",
"rimraf": "^4.4.1",
"rollup": "^3.20.2",
"tinymce": "^8.0.1",
"storybook": "^10.0.0",
"tinymce": "^8.5.1",
"tslib": "^2.5.0",
"typescript": "^5.9.3",
"webpack": "^5.9.0"
"vite": "^8.0.0",
"vite-tsconfig-paths": "^6.1.1"
},
"dependencies": {},
"resolutions": {
"@types/node": "^16"
"@types/node": "^16",
"jquery": "^4.0.0"
}
}
4 changes: 2 additions & 2 deletions src/demo/html/demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Page Title</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<script src="http://code.jquery.com/jquery-3.5.1.js" integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script>
<script src='../../../dist/tinymce-min.js'></script>
<script src="https://code.jquery.com/jquery-4.0.0.js" integrity="sha256-9fsHeVnKBvqh3FB2HYu7g2xseAZ5MlN6Kz/qnkASV8U=" crossorigin="anonymous"></script>
<script src='../../../dist/tinymce-jquery.js'></script>
</head>
<body>
<textarea></textarea>
Expand Down
7 changes: 6 additions & 1 deletion src/main/ts/Integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,14 @@ const tinymceFn = function (this: JQuery<HTMLElement>, settings?: RawEditorExten

export const setupIntegration = () => {
const jq = getJquery();

// Add :tinymce pseudo selector this will select elements that has been converted into editor instances
// it's now possible to use things like $('*:tinymce') to get all TinyMCE bound elements.
jq.expr.pseudos.tinymce = (e: Element) => !!getTinymceInstance(e);
// Take advantage of jQuery's createPseudo API in v4 while still supports the older versions
jq.expr.pseudos.tinymce = jq.expr.createPseudo ?
jq.expr.createPseudo(( _text ) => ( elem ) => !!getTinymceInstance( elem ))
: (e: Element) => !!getTinymceInstance(e);

// Add a tinymce function for creating editors
(jq.fn as any).tinymce = tinymceFn;
};
2 changes: 1 addition & 1 deletion src/main/ts/JQuery.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Global } from './Global';

const jquery = (): (typeof import('jquery')) | null => (Global && Global.jQuery) ?? null;
const jquery = (): JQueryStatic | null => (Global && Global.jQuery) ?? null;

export const getJquery = () => {
const jq = jquery();
Expand Down
12 changes: 3 additions & 9 deletions src/stories/Editor.stories.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import { setupIntegration, RawEditorExtendedSettings } from '../main/ts/Integration';
import { Story, Meta } from '@storybook/html';
import { StoryFn, Meta } from '@storybook/html';

setupIntegration();

// More on default export: https://storybook.js.org/docs/html/writing-stories/introduction#default-export
export default {
title: 'TinyMCE Editor',
// More on argTypes: https://storybook.js.org/docs/html/api/argtypes
argTypes: {
},
title: 'TinyMCE Editor'
} as Meta;

let count = 0;
// More on component templates: https://storybook.js.org/docs/html/writing-stories/introduction#using-args
const Template: Story<RawEditorExtendedSettings> = (args) => {
const Template: StoryFn<RawEditorExtendedSettings> = (args) => {
const mount = `${count++}`;

const mountNode = document.createElement('div');
Expand Down Expand Up @@ -54,7 +49,6 @@ const Template: Story<RawEditorExtendedSettings> = (args) => {
};

export const IframeEditor = Template.bind({});
// More on args: https://storybook.js.org/docs/html/writing-stories/args
IframeEditor.args = {
inline: false,
};
Expand Down
43 changes: 23 additions & 20 deletions src/test/ts/Utils.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,39 @@

import { Waiter } from '@ephox/agar';
import { Insert, Remove, SugarBody, SugarElement } from '@ephox/sugar';
import { Editor } from 'tinymce';

export const createEditor = async (action: (targetElm: JQuery<HTMLElement>, editors: Editor) => void | Promise<void>) => {
// TinyMCE must be in the document to work
const ce = SugarElement.fromTag('textarea');
Insert.append(SugarBody.body(), ce);
try {
const targetElm = $(ce.dom);
const editors = await targetElm.tinymce({ });
try {
const maybeAsync = action(targetElm, editors[0]);
if (maybeAsync) {
await maybeAsync;
}
} finally {
editors[0].remove();
}
} finally {
Remove.remove(ce);
const targetElm = $(ce.dom);
const editors = await targetElm.tinymce({
license_key: 'gpl',
script_url: '/project/node_modules/tinymce/tinymce.js',
});

await Waiter.pTryUntil('Editor should be initialized', () => editors[0]?.initialized);

const maybeAsync = action(targetElm, editors[0]);
if (maybeAsync) {
await maybeAsync;
}
editors[0].remove();
await Waiter.pTryUntil('Editor should be removed', () => $(ce.dom).tinymce() === undefined);
Remove.remove(ce);
};

export const createHTML = async (html: string, action: (root: HTMLElement) => void | Promise<void>) => {
const ce = SugarElement.fromHtml<HTMLElement>(html);
Insert.append(SugarBody.body(), ce);
try {
const maybeAsync = action(ce.dom);
if (maybeAsync) {
await maybeAsync;
}
} finally {
Remove.remove(ce);

await Waiter.pTryUntil('Editor should be initialized', () => $(ce.dom)?.tinymce()?.initialized);

const maybeAsync = action(ce.dom);
if (maybeAsync) {
await maybeAsync;
}

Remove.remove(ce);
};
Loading
Loading