Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent editor creation on detached element #4463

Merged
merged 103 commits into from
Apr 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
fee22b4
WIP: Add working PoC with manual test
sculpt0r Dec 31, 2020
2e1ac29
Clean up manual test & delayed creation
sculpt0r Dec 31, 2020
983a088
Prevent reading property from null config
sculpt0r Jan 5, 2021
ee25c5c
Simplyfied manual test for detached editor
sculpt0r Jan 5, 2021
2fe14ab
Correct manual test scenario
sculpt0r Jan 5, 2021
8993ae9
Move clearInterval before createInstance
sculpt0r Jan 5, 2021
3afdff9
Handle with delay from config
sculpt0r Jan 5, 2021
0a05e43
Mantain config callback for delayed creation
sculpt0r Jan 5, 2021
e4b7c6b
Refactor delayed creation function
sculpt0r Jan 5, 2021
81fcd1d
Rename function & add api docs for delay creation
sculpt0r Jan 5, 2021
53d852a
Rephrase function description
sculpt0r Jan 5, 2021
8d40716
Add unit tests
sculpt0r Jan 6, 2021
c62e727
Refactor names & add config docs
sculpt0r Jan 7, 2021
957e7e7
Fix cfg docs description & error name
sculpt0r Jan 7, 2021
44a9927
Update config to proper naming
sculpt0r Jan 7, 2021
9a44784
Fix comment: editor mode is a string
sculpt0r Mar 1, 2021
416c701
Simplyfy delayCreation function logic
sculpt0r Mar 1, 2021
b58ecae
REmoved else with comment
sculpt0r Mar 1, 2021
d7dd404
Rename config function argument
sculpt0r Mar 1, 2021
6ab5328
Set config registerCallback actuall default value
sculpt0r Mar 1, 2021
9f8275c
Fix extra space before function keyword
sculpt0r Mar 1, 2021
ceb6da1
Fix test naming & code style
sculpt0r Mar 1, 2021
e1fa2f4
Fix test tags, use setTimeout via CKEditor tools
sculpt0r Mar 1, 2021
2fe90d1
Fix manual test code style & description
sculpt0r Mar 1, 2021
fce5286
Correct manual test description
sculpt0r Mar 1, 2021
b88287d
Fix typo in config comment
sculpt0r Mar 1, 2021
66ab18a
Remove unnecessary variable assigment
sculpt0r Mar 4, 2021
e4740cc
Replace bug with feature tag
sculpt0r Mar 4, 2021
7cc43ac
Add creation warnings
sculpt0r Mar 4, 2021
2ea64e1
Simplyfy editor creation callback
sculpt0r Mar 5, 2021
d7cb945
Moved mode as a second param in delayCreation func
sculpt0r Mar 5, 2021
00bf0ee
Rename config properties, rename functions
sculpt0r Mar 5, 2021
128ed83
Make test names starts with lowercase
sculpt0r Mar 5, 2021
5d4f83f
Clean up automatic test. Rename cfg props, remove unused vars
sculpt0r Mar 5, 2021
4da8a22
Remove unused code in test
sculpt0r Mar 5, 2021
c2aee28
Split manual test onto two separate
sculpt0r Mar 5, 2021
15b0642
Add test with warn stubbing
sculpt0r Mar 5, 2021
bf0343d
Add test case with config and not detached element
sculpt0r Mar 5, 2021
4748f47
Add test case with explicit disabled delayIfDetached
sculpt0r Mar 5, 2021
d8eca17
Add test case for editor without config
sculpt0r Mar 5, 2021
eda4cf7
Add interval check test & fix callback option
sculpt0r Mar 6, 2021
493ad89
Remove duplicated empty line
sculpt0r Mar 9, 2021
d02bdb6
Join var statements, removed version tag
sculpt0r Mar 9, 2021
0873997
Reorder editor ids to match test fixture order
sculpt0r Mar 9, 2021
db15f7c
Reorder test cases (non detached element first)
sculpt0r Mar 9, 2021
34b3f2a
Prevents infinite setInterval
sculpt0r Mar 9, 2021
7d0429a
Bump timeout before verify test
sculpt0r Mar 9, 2021
6ce9878
Correct var names
sculpt0r Mar 9, 2021
0a1eb94
Add issue reference
sculpt0r Mar 9, 2021
668a170
Simplyfy delay creation logic
sculpt0r Mar 9, 2021
08ab347
Correct delayIfDetach config docs
sculpt0r Mar 10, 2021
5d674c9
Replace warn msg with code errors
sculpt0r Mar 10, 2021
f95cdc6
Fix whitespaces in test
sculpt0r Mar 15, 2021
88b7c96
Add precise description for test
sculpt0r Mar 15, 2021
a4229e6
Correct config API comment
sculpt0r Mar 15, 2021
6977767
Add since tags for config options
sculpt0r Mar 15, 2021
7fd0431
Add manual test for custom interval time, rename test
sculpt0r Mar 15, 2021
441115c
Correct API comments
sculpt0r Mar 16, 2021
e8ccc14
Added msgs to tests
sculpt0r Mar 16, 2021
e91c29d
Debug CI failing test (try with spy)
sculpt0r Mar 16, 2021
1b71064
Debug warn on CI
sculpt0r Mar 16, 2021
176b3ca
Spy on first two warn calls on delayed creation
sculpt0r Mar 16, 2021
5d95920
Cleanup warn test
sculpt0r Mar 17, 2021
56bdc66
Add timer to manual test [skip ci]
sculpt0r Mar 17, 2021
ccfa4db
Improve test messages [skip ci]
sculpt0r Mar 17, 2021
964dafe
Reduce wait time, correct test expect [skip ci]
sculpt0r Mar 23, 2021
c3e8067
Add warn for delayed creation with callback
sculpt0r Mar 23, 2021
4a5dc8e
Add CKE warn for delayed creation
sculpt0r Mar 23, 2021
374b283
Add warn checks and correct wait time.
sculpt0r Mar 23, 2021
30e4b63
Correct test steps for warning verification
sculpt0r Mar 23, 2021
cd09c6d
Rework warn tests (interval & callback)
sculpt0r Mar 23, 2021
91f8803
Polish manual tests.
Dumluregn Mar 24, 2021
ab9b36a
Try to create instances before logging success.
Dumluregn Mar 24, 2021
39d84b8
Rename warn parameter: 'mode'->'method'.
Dumluregn Mar 24, 2021
42748e0
Fix the example code.
Dumluregn Mar 24, 2021
594449c
Polish docs.
Dumluregn Mar 24, 2021
fbad5d5
Update IE note in manual tests.
Dumluregn Mar 24, 2021
a9611ff
Ignore test failing due to the other ticket.
Dumluregn Mar 24, 2021
b22493a
Create same tests for inline and classic editor
sculpt0r Mar 25, 2021
d5ece7e
Fix test naming
sculpt0r Mar 25, 2021
c24e56b
Add inlineAll, replaceAll test & appendTo method
sculpt0r Mar 25, 2021
0eef280
Add delay for inline editor
sculpt0r Mar 25, 2021
489afe3
Add distinction in assert messages
sculpt0r Mar 25, 2021
c14a48b
Add ticket ref & group var definitions.
sculpt0r Mar 29, 2021
65f3d1b
Extract delay function and docs to editor.
sculpt0r Mar 29, 2021
f643e14
Add detached tests tool
sculpt0r Mar 29, 2021
9d5ad80
Split unit test by editor creation method
sculpt0r Mar 29, 2021
01cc19c
Prepare valid inlineAll test
sculpt0r Mar 30, 2021
c86acdd
replace for with tools.forEach
sculpt0r Mar 30, 2021
c9d2a86
Refactor the signature of delay function.
Dumluregn Apr 1, 2021
0a563d7
Polish unit tests.
Dumluregn Apr 1, 2021
7c493ec
Fix unit test for replaceAll() on IE.
Dumluregn Apr 1, 2021
4775099
Add intendation to Expected sections
sculpt0r Apr 14, 2021
939e4c4
Correct api comments
sculpt0r Apr 14, 2021
128ac96
Split func responsibility (delay creation)
sculpt0r Apr 15, 2021
fe4e94c
Improve API docs slightly.
f1ames Apr 15, 2021
b241e8f
Improve API docs, redefine default cfg value
sculpt0r Apr 16, 2021
f4c19a9
Change docs variable type to `dom.element`
sculpt0r Apr 16, 2021
3d6e718
Add merge delay creation config & rename test case
sculpt0r Apr 19, 2021
d0726a4
Improve API docs wording.
f1ames Apr 20, 2021
ee13308
Ignore dev console manual test for mobile
sculpt0r Apr 22, 2021
806e0f0
Add custom detach editor test for mobile
sculpt0r Apr 22, 2021
46cd968
Add changelog entry.
f1ames Apr 23, 2021
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
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ CKEditor 4 Changelog

New Features:

* [#4461](/~https://github.com/ckeditor/ckeditor4/issues/4461): Introduced possibility to delay editor initialization while it is in detached DOM element.

Fixed Issues:

* [#4604](/~https://github.com/ckeditor/ckeditor4/issues/4604): Fixed: [`CKEDITOR.plugins.clipboard.dataTransfer#getTypes()`](https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_plugins_clipboard_dataTransfer.html#method-getTypes) returns no types.
Expand Down
16 changes: 12 additions & 4 deletions core/creators/inline.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,18 @@
return null;
}

var editor = new CKEDITOR.editor( instanceConfig, element, CKEDITOR.ELEMENT_MODE_INLINE ),
textarea = element.is( 'textarea' ) ? element : null;
// (#4461)
if ( CKEDITOR.editor.shouldDelayEditorCreation( element, instanceConfig ) ) {
CKEDITOR.editor.initializeDelayedEditorCreation( element, instanceConfig, 'inline' );
return null;
}

var textarea = element.is( 'textarea' ) ? element : null,
editorData = textarea ? textarea.getValue() : element.getHtml(),
editor = new CKEDITOR.editor( instanceConfig, element, CKEDITOR.ELEMENT_MODE_INLINE );

if ( textarea ) {
editor.setData( textarea.getValue(), null, true );
editor.setData( editorData, null, true );

//Change element from textarea to div
element = CKEDITOR.dom.element.createFromHtml(
Expand All @@ -63,7 +70,7 @@

// Initial editor data is simply loaded from the page element content to make
// data retrieval possible immediately after the editor creation.
editor.setData( element.getHtml(), null, true );
editor.setData( editorData, null, true );
}

// Once the editor is loaded, start the UI.
Expand Down Expand Up @@ -156,6 +163,7 @@
CKEDITOR.domReady( function() {
!CKEDITOR.disableAutoInline && CKEDITOR.inlineAll();
} );

} )();

/**
Expand Down
6 changes: 6 additions & 0 deletions core/creators/themedui.js
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,12 @@ CKEDITOR.replaceClass = 'ckeditor';
return null;
}

// (#4461)
if ( CKEDITOR.editor.shouldDelayEditorCreation( element, config ) ) {
CKEDITOR.editor.initializeDelayedEditorCreation( element, config, 'replace' );
return null;
}

// Create the editor instance.
var editor = new CKEDITOR.editor( config, element, mode );

Expand Down
155 changes: 155 additions & 0 deletions core/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -1648,6 +1648,103 @@

return element;
};

/**
* Initializes delayed editor creation based on provided configuration.
*
* If the {@link CKEDITOR.config#delayIfDetached_callback} function is declared, it will be invoked with a single argument:
*
* * A callback, that should be called to create editor.
*
* Otherwise, it periodically (with `setInterval()` calls) checks if element is attached to DOM and creates editor automatically.
*
* ```js
* CKEDITOR.inline( detachedEditorElement, {
* delayIfDetached: true,
* delayIfDetached_callback: registerCallback
* } );
* ```
*
* @private
* @since 4.17.0
* @static
* @member CKEDITOR.editor
* @param {CKEDITOR.dom.element} element The DOM element on which editor should be initialized.
* @param {Object} config The specific configuration to apply to the editor instance. Configuration set here will override the global CKEditor settings.
* @param {String} editorCreationMethod Creator function that should be used to initialize editor (inline/replace).
*/
CKEDITOR.editor.initializeDelayedEditorCreation = function( element, config, editorCreationMethod ) {
if ( config.delayIfDetached_callback ) {
CKEDITOR.warn( 'editor-delayed-creation', {
method: 'callback'
} );

config.delayIfDetached_callback( function() {
CKEDITOR[ editorCreationMethod ]( element, config );

CKEDITOR.warn( 'editor-delayed-creation-success', {
method: 'callback'
} );
} );
} else {
var interval = config.delayIfDetached_interval === undefined ? CKEDITOR.config.delayIfDetached_interval : config.delayIfDetached_interval,
intervalId;

CKEDITOR.warn( 'editor-delayed-creation', {
method: 'interval - ' + interval + ' ms'
} );

intervalId = setInterval( function() {
if ( !element.isDetached() ) {
clearInterval( intervalId );

CKEDITOR[ editorCreationMethod ]( element, config );

CKEDITOR.warn( 'editor-delayed-creation-success', {
method: 'interval - ' + interval + ' ms'
} );
}
}, interval );
}
};

/**
* Whether editor creation should be delayed.
*
* @private
* @since 4.17.0
* @static
* @member CKEDITOR.editor
* @param {CKEDITOR.dom.element} element The DOM element on which editor should be initialized.
* @param {Object} config Editor configuration.
* @returns {Boolean} True if creation should be delayed.
*/
CKEDITOR.editor.shouldDelayEditorCreation = function( element, config ) {
CKEDITOR.editor.mergeDelayedCreationConfigs( config );
return config && config.delayIfDetached && element.isDetached();
};

/**
* Merges user provided configuration options for delayed creation with {@link CKEDITOR.config default config}.
*
* User provided options are the preferred ones.
*
* @private
* @since 4.17.0
* @static
* @member CKEDITOR.editor
* @param {Object} userConfig Config provided by the user to create editor.
*/
CKEDITOR.editor.mergeDelayedCreationConfigs = function( userConfig ) {
if ( !userConfig ) {
return;
}

userConfig.delayIfDetached = typeof userConfig.delayIfDetached === 'boolean' ? userConfig.delayIfDetached : CKEDITOR.config.delayIfDetached;
userConfig.delayIfDetached_interval = isNaN( userConfig.delayIfDetached_interval ) ? CKEDITOR.config.delayIfDetached_interval : userConfig.delayIfDetached_interval;
userConfig.delayIfDetached_callback = userConfig.delayIfDetached_callback || CKEDITOR.config.delayIfDetached_callback;
};

} )();

/**
Expand Down Expand Up @@ -2228,3 +2325,61 @@ CKEDITOR.ELEMENT_MODE_INLINE = 3;
* @event contentDomInvalidated
* @param {CKEDITOR.editor} editor This editor instance.
*/

/**
* If set to `true`, editor will be only created when its root element is attached to DOM.
* In case the element is detached, the editor will wait for the element to be attached and initialized then.
*
* For more control over the entire process refer to {@link CKEDITOR.config#delayIfDetached_callback}
* and {@link CKEDITOR.config#delayIfDetached_interval} configuration options.
*
* config.delayIfDetached = true;
*
* @since 4.17.0
* @cfg {Boolean} [delayIfDetached=false]
* @member CKEDITOR.config
*/
CKEDITOR.config.delayIfDetached = false;

/**
* Function used to initialize delayed editor creation.
*
* It accepts a single `callback` argument. A `callback` argument is another function that triggers editor creation.
* This allows to store the editor creation function (`callback`) and invoke it whenever necessary instead of periodically
* check if element is attached to DOM to improve performance.
*
* Used only if {@link CKEDITOR.config#delayIfDetached} is set to `true`.
*
* **Note**: This function (`callback`) should be called only if editor target element is reattached to DOM.
*
* If this option is defined, editor will not run the default {@link CKEDITOR.config#delayIfDetached_interval interval checks}.
*
* // Store the reference to the editor creation function.
* var resumeEditorCreation;
*
* config.delayIfDetached_callback = function( createEditor ) {
* resumeEditorCreation = createEditor;
* };
*
* // Create editor calling `resumeEditorCreation()` whenever you choose (e.g. on button click).
* resumeEditorCreation();
*
* @since 4.17.0
* @cfg {Function} [delayIfDetached_callback = undefined]
* @member CKEDITOR.config
*/
CKEDITOR.config.delayIfDetached_callback = undefined;

/**
* The amount of time (in milliseconds) between consecutive checks whether editor's target element is attached to DOM.
*
* Used only if {@link CKEDITOR.config#delayIfDetached} is set to `true` and
* {@link CKEDITOR.config#delayIfDetached_callback delayIfDetached_callback} not set.
*
* config.delayIfDetached_interval = 2000; // Try to create editor every 2 seconds.
*
* @since 4.17.0
* @cfg {Number} [delayIfDetached_interval=50]
* @member CKEDITOR.config
*/
CKEDITOR.config.delayIfDetached_interval = 50;
Loading