Since reproduced the original way for network [” # CKEditor series (5) the content of the editor set and get process “] (www.daozhao.com/10324.html)

Let’s take a look at CKEditor4’s editor content setup and retrieval procedures, namely the setData and getData procedures.

When we call editor.setData, we call the setData method in core/editor.js.

// src/core/editor.js setData: function( data, options, internal ) { var fireSnapshot = true, // Backward compatibility. callback = options, eventData;  if ( options && typeof options == 'object' ) { internal = options.internal; callback = options.callback; fireSnapshot = ! options.noSnapshot; } if ( ! internal && fireSnapshot ) this.fire( 'saveSnapshot' ); if ( callback || ! internal ) { this.once( 'dataReady', function( evt ) { if ( ! internal && fireSnapshot ) this.fire( 'saveSnapshot' ); if ( callback ) callback.call( evt.editor ); }); } // Fire "setData" so data manipulation may happen. eventData = { dataValue: data }; ! internal && this.fire( 'setData', eventData ); this._.data = eventData.dataValue; ! internal && this.fire( 'afterSetData', eventData ); },Copy the code

We can see that the set process is actually three steps

  1. Determine whether saveSnapshot is required
  2. Determines whether the setData event needs to be triggered
  3. Determines whether the afterSetData event needs to be triggered

The setData saveSnapshot

SaveSnapshot is mainly used to facilitate undo operations

// src/plugins/undo.plugin.js // Save snapshots before doing custom changes. editor.on( 'saveSnapshot', function( evt ) { undoManager.save( evt.data && evt.data.contentOnly ); });Copy the code

The setData setData

Let’s move on to the handling of the setData event

src/core/section.js editor.on( 'setData', function() { // Invalidate locked selection when unloading DOM. // (https://dev.ckeditor.com/ticket/9521, https://dev.ckeditor.com/ticket/5217#comment:32 and https://dev.ckeditor.com/ticket/11500#comment:11) editor.unlockSelection(); // Webkit's selection will mess up after the data loading. if ( CKEDITOR.env.webkit ) clearSelection(); });Copy the code

As you can see, it does the main work of unlocking the selection, it seems that the actual work is not setData ah, it is a setData preparation might be more appropriate.

The setData afterSetData

// src/core/editable.js
this.attachListener( editor, 'afterSetData', function() {
	this.setData( editor.getData( 1 ) );
}, this );
Copy the code

That’s right, there’s another setData and getData… They are the real setData and getData.

// src/core/editable.js /** * @see CKEDITOR.editor#setData */ setData: function( data, isSnapshot ) { if ( ! isSnapshot ) data = this.editor.dataProcessor.toHtml( data ); this.setHtml( data ); this.fixInitialSelection(); // Editable is ready after first setData. if ( this.status == 'unloaded' ) this.status = 'ready'; this.editor.fire( 'dataReady' ); }, /** * @see CKEDITOR.editor#getData */ getData: function( isSnapshot ) { var data = this.getHtml(); if ( ! isSnapshot ) data = this.editor.dataProcessor.toDataFormat( data ); return data; },Copy the code

SetHtml and getHtml are essentially the innerHTML of a native node, So getData and setData. This is in fact the process editor. DataProcessor. ToHtml and enclosing editor. DataProcessor. ToDataFormat process, the two methods which come of? They are derived from the dataProcessor, which is assigned at editor initialization time.

dataProcessor

// src/core/editor.js // Various other core components that read editor configuration. function initComponents( editor )  { // Documented in dataprocessor.js. editor.dataProcessor = new CKEDITOR.htmlDataProcessor( editor ); // Set activeFilter directly to avoid firing event. editor.filter = editor.activeFilter = new CKEDITOR.filter( editor );  loadSkin( editor ); }Copy the code

The two specific methods of dataProcessor are as follows

// src/core/dataProcessor.js toHtml: function( data, options, fixForBody, dontFilter ) { var editor = this.editor, context, filter, enterMode, protectedWhitespaces; // Typeof null == 'object', so check truthiness of options too. if ( options && typeof options == 'object' ) { context = options.context; fixForBody = options.fixForBody; dontFilter = options.dontFilter; filter = options.filter; enterMode = options.enterMode; protectedWhitespaces = options.protectedWhitespaces; } // Backward compatibility. Since CKEDITOR 4.3.0 every option was a separate argument. Else {context = options; } // Fall back to the editable as context if not specified. if ( ! context && context ! == null ) context = editor.editable().getName(); return editor.fire( 'toHtml', { dataValue: data, context: context, fixForBody: fixForBody, dontFilter: dontFilter, filter: filter || editor.filter, enterMode: enterMode || editor.enterMode, protectedWhitespaces: protectedWhitespaces } ).dataValue; }, toDataFormat: function( html, options ) { var context, filter, enterMode; // Do not shorten this to `options && options.xxx`, because // falsy `options` will be passed instead of undefined. if ( options ) { context = options.context; filter = options.filter; enterMode = options.enterMode; } // Fall back to the editable as context if not specified. if ( ! context && context ! == null ) context = this.editor.editable().getName(); return this.editor.fire( 'toDataFormat', { dataValue: html, filter: filter || this.editor.filter, context: context, enterMode: enterMode || this.editor.enterMode } ).dataValue; },Copy the code

The concrete implementation of these two methods is translated into processing logic for two (toHtml and toDataFormat) events.

The dataProcessor toHtml

So what are the callbacks to these two events? Let’s look at toHtml.

// src/core/dataProcessor.js editor.on( 'toHtml', function( evt ) { var evtData = evt.data, data = evtData.dataValue, fixBodyTag; // Before we start protecting markup, make sure there are no externally injected // protection keywords. data = removeReservedKeywords( data ); // The source data is already HTML, but we need to clean // it up and apply the filter. data = protectSource( data, editor ); // Protect content of textareas. (https://dev.ckeditor.com/ticket/9995) // Do this before protecting attributes to avoid  breaking: // <textarea><img src="..." /></textarea> data = protectElements( data, protectTextareaRegex ); // Before anything, we must protect the URL attributes as the // browser may changing them when setting the innerHTML later in // the code. data = protectAttributes( data ); // Protect elements than can't be set inside a DIV. E.g. IE removes // style tags from innerHTML. (https://dev.ckeditor.com/ticket/3710) data = protectElements( data, protectElementsRegex ); // Certain elements has problem to go through DOM operation, protect // them by prefixing 'cke' namespace. (https://dev.ckeditor.com/ticket/3591) data = protectElementsNames( data ); // All none-IE browsers ignore self-closed custom elements, // protecting them into open-close. (https://dev.ckeditor.com/ticket/3591) data = protectSelfClosingElements( data ); // Compensate one leading line break after <pre> open as browsers // eat it up. (https://dev.ckeditor.com/ticket/5789) data = protectPreFormatted( data ); // There are attributes which may execute JavaScript code inside fixBin. // Encode them greedily. They will be unprotected right after getting HTML from fixBin. (https://dev.ckeditor.com/ticket/10) data = protectInsecureAttributes(  data ); var fixBin = evtData.context || editor.editable().getName(), isPre; // Old IEs loose formats when load html into <pre>. if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 && fixBin == 'pre' ) { fixBin = 'div'; data = '<pre>' + data + '</pre>'; isPre = 1; } // Call the browser to help us fixing a possibly invalid HTML // structure. var el = editor.document.createElement( fixBin ); // Add fake character to workaround IE comments bug. (https://dev.ckeditor.com/ticket/3801) el.setHtml( 'a' + data ); data = el.getHtml().substr( 1 ); // Restore shortly protected attribute names. data = data.replace( new RegExp( 'data-cke-' + CKEDITOR.rnd + '-', 'ig' ), '' ); isPre && ( data = data.replace( /^<pre>|<\/pre>$/gi, '' ) ); // Unprotect "some" of the protected elements at this point. data = unprotectElementNames( data ); data = unprotectElements( data ); // Restore the comments that have been protected, in this way they // can be properly filtered. data = unprotectRealComments( data ); if ( evtData.fixForBody === false ) { fixBodyTag = false; } else { fixBodyTag = getFixBodyTag( evtData.enterMode, editor.config.autoParagraph ); } // Now use our parser to make further fixes to the structure, as // well as apply the filter. data = CKEDITOR.htmlParser.fragment.fromHtml( data, evtData.context, fixBodyTag ); // The empty root element needs to be fixed by adding 'p' or 'div' into it. // This avoids the need to create that element on the first focus (https://dev.ckeditor.com/ticket/12630). if ( fixBodyTag ) { fixEmptyRoot( data, fixBodyTag ); } evtData.dataValue = data; }, null, null, 5 ); // Filter incoming "data". // Add element filter before htmlDataProcessor.dataFilter when purifying input data to correct html. editor.on( 'toHtml', function( evt ) { if ( evt.data.filter.applyTo( evt.data.dataValue, true, evt.data.dontFilter, evt.data.enterMode ) ) editor.fire( 'dataFiltered' ); }, null, null, 6 ); editor.on( 'toHtml', function( evt ) { evt.data.dataValue.filterChildren( that.dataFilter, true ); }, null, null, 10 ); editor.on( 'toHtml', function( evt ) { var evtData = evt.data, data = evtData.dataValue, writer = new CKEDITOR.htmlParser.basicWriter(); data.writeChildrenHtml( writer ); data = writer.getHtml( true ); // Protect the real comments again. evtData.dataValue = protectRealComments( data ); }, null, null, 15 );Copy the code

We can see that the most common words in these callbacks are Protect and Filter, which do the same thing.

The dataProcessor toDataFormat

Take a look at toDataFormat’s callbacks

// src/core/dataProcessor.js editor.on( 'toDataFormat', function( evt ) { var data = evt.data.dataValue; // https://dev.ckeditor.com/ticket/10854 - we need to strip leading blockless <br> which FF adds // automatically when editable contains only non-editable content. // We do that for every browser (so it's a constant behavior) and // not in  BR mode, in which chance of valid leading blockless <br> is higher. if ( evt.data.enterMode ! = CKEDITOR.ENTER_BR ) data = data.replace( /^<br *\/? >/i, '' ); evt.data.dataValue = CKEDITOR.htmlParser.fragment.fromHtml( data, evt.data.context, getFixBodyTag( evt.data.enterMode, editor.config.autoParagraph ) ); }, null, null, 5 ); editor.on( 'toDataFormat', function( evt ) { evt.data.dataValue.filterChildren( that.htmlFilter, true ); }, null, null, 10 ); // Transform outcoming "data". // Add element filter after htmlDataProcessor.htmlFilter when preparing output data HTML.  editor.on( 'toDataFormat', function( evt ) { evt.data.filter.applyTo( evt.data.dataValue, false, true ); }, null, null, 11 ); editor.on( 'toDataFormat', function( evt ) { var data = evt.data.dataValue, writer = that.writer; writer.reset(); data.writeChildrenHtml( writer ); data = writer.getHtml( true ); // Restore those non-HTML protected source. (https://dev.ckeditor.com/ticket/4475,https://dev.ckeditor.com/ticket/4880) data = unprotectRealComments( data ); data = unprotectSource( data, editor ); evt.data.dataValue = data; }, null, null, 15 );Copy the code

conclusion

On the surface, setting and obtaining the contents of the editor is simply done by calling a method, but in fact, the internal process is still very long, which can be roughly divided into:

  1. The message to informsaveSnapshot
  2. The preparatory worksetData
  3. Processing flowdataProcessor
  4. Send the eventtoHtml
  5. System events (priority less than 10) process protect and Filter
  6. System event (priority > 10) processing, final backstop (insert or fetch) logicCKEDITOR.htmlParser.basicWriter