Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 1, 2025

Ticket

https://community.openproject.org/wp/69553

jQuery Removal - Complete

This PR removes all direct jQuery usage from the commonmark-ckeditor-build repository.

Changes Made

  • Replaced jQuery.each() with native Array.forEach() in button-disabler.js
  • Replaced jQuery.getJSON() with fetch() API in user-mentions.js and work-package-mentions.js
  • Replaced jQuery.ajax() with fetch() API in op-preview.plugin.js
  • Replaced jQuery DOM manipulation with native DOM APIs in op-preview.plugin.js and op-source-code.plugin.js
  • Fixed selector logic to match jQuery .siblings() behavior using Array.from().filter()
  • Added optional chaining (?.) for null-safe property access
  • Added early return guards with error logging for invalid DOM structures
  • Added error handling to reset previewing state on fetch failure
  • Consistent sibling filtering logic with mainEditor exclusion
  • Added CHANGELOG.md documenting the removal
  • Updated README.md with migration notes for downstream consumers
  • All tests passing (16 test suites, 219 tests)
  • Build succeeds
  • Linter passes
  • All code review feedback addressed

Files Changed (7 files)

  1. src/helpers/button-disabler.js - Replaced jQuery.each with forEach
  2. src/mentions/user-mentions.js - Replaced jQuery.getJSON with fetch
  3. src/mentions/work-package-mentions.js - Replaced jQuery.getJSON with fetch
  4. src/plugins/op-preview.plugin.js - Replaced jQuery.ajax, DOM manipulation, improved error handling
  5. src/plugins/op-source-code.plugin.js - Replaced jQuery DOM manipulation, added null checks
  6. CHANGELOG.md - Added (new file)
  7. README.md - Updated with migration notes

Testing & Verification

✅ All 219 tests pass without modifications
✅ Build succeeds (webpack compiled successfully)
✅ ESLint passes with no errors
✅ All code review comments addressed
✅ No new issues in final code review

Migration Notes for Downstream Consumers

This library no longer uses jQuery internally. However, downstream applications (OpenProject) should continue to expose the jQuery global until other components are migrated.

Related downstream PR: opf/openproject#19429


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits December 1, 2025 18:49
- Replace jQuery.each() with native forEach() in button-disabler.js
- Replace jQuery.getJSON() with fetch() API in user-mentions.js and work-package-mentions.js
- Replace jQuery.ajax() with fetch() API in op-preview.plugin.js
- Replace jQuery DOM manipulation with native DOM APIs in op-preview.plugin.js and op-source-code.plugin.js
- All tests pass, build succeeds, and linter passes

Co-authored-by: myabc <[email protected]>
Copilot AI changed the title [WIP] Remove jQuery from CKEditor build [#69553] Remove jQuery from CKEditor build Dec 1, 2025
Copilot AI requested a review from myabc December 1, 2025 18:59
@myabc myabc marked this pull request as ready for review December 3, 2025 13:00
Copilot AI review requested due to automatic review settings December 3, 2025 13:00
@myabc myabc added the enhancement New feature or request label Dec 3, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request removes jQuery as a dependency from the CKEditor build, replacing all jQuery usage with vanilla JavaScript equivalents using modern DOM APIs and the Fetch API.

Key changes:

  • Replaced jQuery AJAX methods ($.getJSON(), $.ajax()) with native fetch() API
  • Converted jQuery DOM manipulation to native DOM APIs (document.createElement(), parentElement, querySelectorAll(), etc.)
  • Replaced jQuery.each() with native Array.forEach()

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/plugins/op-source-code.plugin.js Converted jQuery DOM traversal and manipulation to vanilla JS for source code mode toggling
src/plugins/op-preview.plugin.js Replaced jQuery AJAX with fetch API and converted DOM manipulation for preview functionality
src/mentions/work-package-mentions.js Replaced jQuery.getJSON() with fetch API for work package autocomplete
src/mentions/user-mentions.js Replaced jQuery.getJSON() with fetch API for user mentions autocomplete
src/helpers/button-disabler.js Converted jQuery.each() to native Array.forEach() for toolbar item iteration
README.md Added migration notes warning downstream consumers to keep jQuery global available
CHANGELOG.md Documented the jQuery removal with implementation details and migration guidance

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

sourceWrapper.className = 'ck-editor__source';

// Remove existing source elements
const existingSources = reference.parentElement.querySelectorAll('.ck-editor__source');
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The selector logic has changed from the original jQuery behavior. $reference.siblings('.ck-editor__source') only selected sibling elements of reference, but reference.parentElement.querySelectorAll('.ck-editor__source') selects ALL descendants matching the selector within the parent element, not just siblings. This could remove unintended elements if there are nested structures.

Consider using a more precise selector or filtering to match only siblings:

const existingSources = Array.from(reference.parentElement.children)
  .filter(el => el.classList.contains('ck-editor__source'));
existingSources.forEach(el => el.remove());

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot please fix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 0497dc1 - replaced querySelectorAll with Array.from(parentElement.children).filter() to match jQuery's .siblings() behavior

Comment on lines 33 to 34
const editableElement = editor.ui.getEditableElement();
const reference = editableElement.parentElement;
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential null reference error if editableElement.parentElement is null. The code immediately accesses reference.parentElement on lines 39 and 46 without checking if reference (which is editableElement.parentElement) is null first.

Consider adding a null check:

const editableElement = editor.ui.getEditableElement();
const reference = editableElement.parentElement;
if (!reference || !reference.parentElement) {
  console.error('Cannot show preview: invalid editor structure');
  return;
}

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@myabc myabc Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply suggestion, but use optional chaining

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 0497dc1 - added optional chaining (?.) and early return guard with error logging

let disablePreviewing = function() {
let $mainEditor = jQuery(editor.ui.getEditableElement()).parent();
const editableElement = editor.ui.getEditableElement();
const mainEditor = editableElement.parentElement;
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential null reference error if editableElement.parentElement is null. The code immediately accesses mainEditor.parentElement on line 83 without checking if mainEditor (which is editableElement.parentElement) is null first.

Consider adding a null check:

const editableElement = editor.ui.getEditableElement();
const mainEditor = editableElement.parentElement;
if (!mainEditor || !mainEditor.parentElement) {
  console.error('Cannot disable preview: invalid editor structure');
  return;
}
Suggested change
const mainEditor = editableElement.parentElement;
const mainEditor = editableElement && editableElement.parentElement;
if (!mainEditor || !mainEditor.parentElement) {
console.error('Cannot disable preview: invalid editor structure');
return;
}

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@myabc myabc Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply suggestion, but use optional chaining

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 0497dc1 - added optional chaining (?.) and early return guard with error logging as requested

Comment on lines 38 to 39
const editableElement = editor.ui.getEditableElement();
const reference = editableElement.parentElement;
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential null reference error if editableElement.parentElement is null. The code immediately accesses reference.parentElement on lines 44 and 48 without checking if reference (which is editableElement.parentElement) is null first.

Consider adding a null check:

const editableElement = editor.ui.getEditableElement();
const reference = editableElement.parentElement;
if (!reference || !reference.parentElement) {
  console.error('Cannot show source: invalid editor structure');
  return;
}

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@myabc myabc Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply suggestion, but use optional chaining

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 0497dc1 - added optional chaining (?.) and early return guard with error logging

let hideSource = function() {
let $mainEditor = jQuery(editor.ui.getEditableElement()).parent();
const editableElement = editor.ui.getEditableElement();
const mainEditor = editableElement.parentElement;
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential null reference error if editableElement.parentElement is null. The code immediately accesses mainEditor.parentElement on line 70 without checking if mainEditor (which is editableElement.parentElement) is null first.

Consider adding a null check:

const editableElement = editor.ui.getEditableElement();
const mainEditor = editableElement.parentElement;
if (!mainEditor || !mainEditor.parentElement) {
  console.error('Cannot hide source: invalid editor structure');
  return;
}
Suggested change
const mainEditor = editableElement.parentElement;
const mainEditor = editableElement.parentElement;
if (!mainEditor || !mainEditor.parentElement) {
console.error('Cannot hide source: invalid editor structure');
return;
}

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply suggestion, but use optional chaining

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 0497dc1 - added optional chaining (?.) and early return guard with error logging

@myabc myabc requested a review from a team December 3, 2025 13:07
myabc and others added 3 commits December 3, 2025 20:31
- Add optional chaining (?.) for null-safe property access as requested by @myabc
- Add early return guards with error logging for invalid DOM structures
- Fix showSource to use Array.from().filter() to match jQuery .siblings() behavior
- All tests passing, linter passing

Co-authored-by: myabc <[email protected]>
- Add `el !== mainEditor` check in disablePreviewing and hideSource filters
- This ensures consistency with showPreview and showSource logic
- Prevents potential edge case where mainEditor could be removed if it had the class

Co-authored-by: myabc <[email protected]>
Copy link
Member

@akabiru akabiru left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice one 👍🏾 I place my confidence in the existing unit tests but I suppose some stuff might break, so we should probably let it hang in dev/edge sooner rather than later.

@myabc myabc merged commit 6789b3b into master Dec 20, 2025
6 checks passed
@myabc myabc deleted the copilot/remove-jquery-usage branch December 20, 2025 16:17
myabc added a commit to opf/openproject that referenced this pull request Jan 17, 2026
myabc added a commit to opf/openproject that referenced this pull request Jan 17, 2026
myabc added a commit to opf/openproject that referenced this pull request Jan 19, 2026
Built from upstream commit: 122e338255f254940dc02a5c2e72681e8d9c5d37

See upstream PRs:
- opf/commonmark-ckeditor-build#107
- opf/commonmark-ckeditor-build#108
myabc added a commit to opf/openproject that referenced this pull request Jan 19, 2026
Built from upstream commit: 509e73464638e45f84d0b713089ea31b8cfb3ced

See upstream PRs:
- opf/commonmark-ckeditor-build#107
- opf/commonmark-ckeditor-build#108
myabc added a commit to opf/openproject that referenced this pull request Jan 19, 2026
Built from upstream commit: 7795208016d3efbf1cd8545aa852824fd2f3b149

See upstream PRs:
- opf/commonmark-ckeditor-build#107
- opf/commonmark-ckeditor-build#108
myabc added a commit to opf/openproject that referenced this pull request Jan 20, 2026
Built from upstream commit: 7795208016d3efbf1cd8545aa852824fd2f3b149

See upstream PRs:
- opf/commonmark-ckeditor-build#107
- opf/commonmark-ckeditor-build#108
myabc added a commit to opf/openproject that referenced this pull request Jan 20, 2026
Built from upstream commit: ec8c1b8b1a0a858467fdd4f15a761a25fd85f801

See upstream PRs:
- opf/commonmark-ckeditor-build#107
- opf/commonmark-ckeditor-build#108
myabc added a commit to opf/openproject that referenced this pull request Jan 20, 2026
Built from upstream commit: ec8c1b8b1a0a858467fdd4f15a761a25fd85f801

See upstream PRs:
- opf/commonmark-ckeditor-build#107
- opf/commonmark-ckeditor-build#108
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Development

Successfully merging this pull request may close these issues.

3 participants