|
@@ -0,0 +1,239 @@
|
|
|
+/**
|
|
|
+ * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
|
|
|
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
|
+ */
|
|
|
+
|
|
|
+( function() {
|
|
|
+ var cssStyle = CKEDITOR.htmlParser.cssStyle,
|
|
|
+ cssLength = CKEDITOR.tools.cssLength;
|
|
|
+
|
|
|
+ var cssLengthRegex = /^((?:\d*(?:\.\d+))|(?:\d+))(.*)?$/i;
|
|
|
+
|
|
|
+ // Replacing the former CSS length value with the later one, with
|
|
|
+ // adjustment to the length unit.
|
|
|
+ function replaceCssLength( length1, length2 ) {
|
|
|
+ var parts1 = cssLengthRegex.exec( length1 ),
|
|
|
+ parts2 = cssLengthRegex.exec( length2 );
|
|
|
+
|
|
|
+ // Omit pixel length unit when necessary,
|
|
|
+ // e.g. replaceCssLength( 10, '20px' ) -> 20
|
|
|
+ if ( parts1 ) {
|
|
|
+ if ( !parts1[ 2 ] && parts2[ 2 ] == 'px' )
|
|
|
+ return parts2[ 1 ];
|
|
|
+ if ( parts1[ 2 ] == 'px' && !parts2[ 2 ] )
|
|
|
+ return parts2[ 1 ] + 'px';
|
|
|
+ }
|
|
|
+
|
|
|
+ return length2;
|
|
|
+ }
|
|
|
+
|
|
|
+ CKEDITOR.plugins.add( 'fakeobjects', {
|
|
|
+ // jscs:disable maximumLineLength
|
|
|
+ lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,es-mx,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
|
|
|
+ // jscs:enable maximumLineLength
|
|
|
+
|
|
|
+ init: function( editor ) {
|
|
|
+ // Allow image with all styles and classes plus src, alt and title attributes.
|
|
|
+ // We need them when fakeobject is pasted.
|
|
|
+ editor.filter.allow( 'img[!data-cke-realelement,src,alt,title](*){*}', 'fakeobjects' );
|
|
|
+ },
|
|
|
+
|
|
|
+ afterInit: function( editor ) {
|
|
|
+ var dataProcessor = editor.dataProcessor,
|
|
|
+ htmlFilter = dataProcessor && dataProcessor.htmlFilter;
|
|
|
+
|
|
|
+ if ( htmlFilter ) {
|
|
|
+ htmlFilter.addRules( createHtmlFilterRules( editor ), {
|
|
|
+ applyToAll: true
|
|
|
+ } );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } );
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates fake {@link CKEDITOR.dom.element} based on real element.
|
|
|
+ * Fake element is an img with special attributes, which keep real element properties.
|
|
|
+ *
|
|
|
+ * @member CKEDITOR.editor
|
|
|
+ * @param {CKEDITOR.dom.element} realElement Real element to transform.
|
|
|
+ * @param {String} className Class name which will be used as class of fake element.
|
|
|
+ * @param {String} realElementType Stores type of fake element.
|
|
|
+ * @param {Boolean} isResizable Keeps information if element is resizable.
|
|
|
+ * @returns {CKEDITOR.dom.element} Fake element.
|
|
|
+ */
|
|
|
+ CKEDITOR.editor.prototype.createFakeElement = function( realElement, className, realElementType, isResizable ) {
|
|
|
+ var lang = this.lang.fakeobjects,
|
|
|
+ label = lang[ realElementType ] || lang.unknown;
|
|
|
+
|
|
|
+ var attributes = {
|
|
|
+ 'class': className,
|
|
|
+ 'data-cke-realelement': encodeURIComponent( realElement.getOuterHtml() ),
|
|
|
+ 'data-cke-real-node-type': realElement.type,
|
|
|
+ alt: label,
|
|
|
+ title: label,
|
|
|
+ align: realElement.getAttribute( 'align' ) || ''
|
|
|
+ };
|
|
|
+
|
|
|
+ // Do not set "src" on high-contrast so the alt text is displayed. (https://dev.ckeditor.com/ticket/8945)
|
|
|
+ if ( !CKEDITOR.env.hc )
|
|
|
+ attributes.src = CKEDITOR.tools.transparentImageData;
|
|
|
+
|
|
|
+ if ( realElementType )
|
|
|
+ attributes[ 'data-cke-real-element-type' ] = realElementType;
|
|
|
+
|
|
|
+ if ( isResizable ) {
|
|
|
+ attributes[ 'data-cke-resizable' ] = isResizable;
|
|
|
+
|
|
|
+ var fakeStyle = new cssStyle();
|
|
|
+
|
|
|
+ var width = realElement.getAttribute( 'width' ),
|
|
|
+ height = realElement.getAttribute( 'height' );
|
|
|
+
|
|
|
+ width && ( fakeStyle.rules.width = cssLength( width ) );
|
|
|
+ height && ( fakeStyle.rules.height = cssLength( height ) );
|
|
|
+ fakeStyle.populate( attributes );
|
|
|
+ }
|
|
|
+
|
|
|
+ return this.document.createElement( 'img', { attributes: attributes } );
|
|
|
+ };
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates fake {@link CKEDITOR.htmlParser.element} based on real element.
|
|
|
+ *
|
|
|
+ * @member CKEDITOR.editor
|
|
|
+ * @param {CKEDITOR.dom.element} realElement Real element to transform.
|
|
|
+ * @param {String} className Class name which will be used as class of fake element.
|
|
|
+ * @param {String} realElementType Store type of fake element.
|
|
|
+ * @param {Boolean} isResizable Keep information if element is resizable.
|
|
|
+ * @returns {CKEDITOR.htmlParser.element} Fake htmlParser element.
|
|
|
+ */
|
|
|
+ CKEDITOR.editor.prototype.createFakeParserElement = function( realElement, className, realElementType, isResizable ) {
|
|
|
+ var lang = this.lang.fakeobjects,
|
|
|
+ label = lang[ realElementType ] || lang.unknown,
|
|
|
+ html;
|
|
|
+
|
|
|
+ var writer = new CKEDITOR.htmlParser.basicWriter();
|
|
|
+ realElement.writeHtml( writer );
|
|
|
+ html = writer.getHtml();
|
|
|
+
|
|
|
+ var attributes = {
|
|
|
+ 'class': className,
|
|
|
+ 'data-cke-realelement': encodeURIComponent( html ),
|
|
|
+ 'data-cke-real-node-type': realElement.type,
|
|
|
+ alt: label,
|
|
|
+ title: label,
|
|
|
+ align: realElement.attributes.align || ''
|
|
|
+ };
|
|
|
+
|
|
|
+ // Do not set "src" on high-contrast so the alt text is displayed. (https://dev.ckeditor.com/ticket/8945)
|
|
|
+ if ( !CKEDITOR.env.hc )
|
|
|
+ attributes.src = CKEDITOR.tools.transparentImageData;
|
|
|
+
|
|
|
+ if ( realElementType )
|
|
|
+ attributes[ 'data-cke-real-element-type' ] = realElementType;
|
|
|
+
|
|
|
+ if ( isResizable ) {
|
|
|
+ attributes[ 'data-cke-resizable' ] = isResizable;
|
|
|
+ var realAttrs = realElement.attributes,
|
|
|
+ fakeStyle = new cssStyle();
|
|
|
+
|
|
|
+ var width = realAttrs.width,
|
|
|
+ height = realAttrs.height;
|
|
|
+
|
|
|
+ width !== undefined && ( fakeStyle.rules.width = cssLength( width ) );
|
|
|
+ height !== undefined && ( fakeStyle.rules.height = cssLength( height ) );
|
|
|
+ fakeStyle.populate( attributes );
|
|
|
+ }
|
|
|
+
|
|
|
+ return new CKEDITOR.htmlParser.element( 'img', attributes );
|
|
|
+ };
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates {@link CKEDITOR.dom.element} from fake element.
|
|
|
+ *
|
|
|
+ * @member CKEDITOR.editor
|
|
|
+ * @param {CKEDITOR.dom.element} fakeElement Fake element to transform.
|
|
|
+ * @returns {CKEDITOR.dom.element/null} Returns real element or `null` if transformed element wasn't fake.
|
|
|
+ */
|
|
|
+ CKEDITOR.editor.prototype.restoreRealElement = function( fakeElement ) {
|
|
|
+ if ( fakeElement.data( 'cke-real-node-type' ) != CKEDITOR.NODE_ELEMENT )
|
|
|
+ return null;
|
|
|
+
|
|
|
+ var realElementHtml = decodeURIComponent( fakeElement.data( 'cke-realelement' ) ),
|
|
|
+ filteredHtml = filterHtml( this, realElementHtml ),
|
|
|
+ realElement = CKEDITOR.dom.element.createFromHtml( filteredHtml, this.document );
|
|
|
+
|
|
|
+ if ( fakeElement.data( 'cke-resizable' ) ) {
|
|
|
+ var width = fakeElement.getStyle( 'width' ),
|
|
|
+ height = fakeElement.getStyle( 'height' );
|
|
|
+
|
|
|
+ width && realElement.setAttribute( 'width', replaceCssLength( realElement.getAttribute( 'width' ), width ) );
|
|
|
+ height && realElement.setAttribute( 'height', replaceCssLength( realElement.getAttribute( 'height' ), height ) );
|
|
|
+ }
|
|
|
+
|
|
|
+ return realElement;
|
|
|
+ };
|
|
|
+
|
|
|
+ function createHtmlFilterRules( editor ) {
|
|
|
+ return {
|
|
|
+ elements: {
|
|
|
+ $: function( element ) {
|
|
|
+ var attributes = element.attributes,
|
|
|
+ realHtml = attributes && attributes[ 'data-cke-realelement' ],
|
|
|
+ filteredRealHtml = filterHtml( editor, decodeURIComponent( realHtml ) ),
|
|
|
+ realFragment = realHtml && new CKEDITOR.htmlParser.fragment.fromHtml( filteredRealHtml ),
|
|
|
+ realElement = realFragment && realFragment.children[ 0 ];
|
|
|
+
|
|
|
+ // Width/height in the fake object are subjected to clone into the real element.
|
|
|
+ if ( realElement && element.attributes[ 'data-cke-resizable' ] ) {
|
|
|
+ var styles = new cssStyle( element ).rules,
|
|
|
+ realAttrs = realElement.attributes,
|
|
|
+ width = styles.width,
|
|
|
+ height = styles.height;
|
|
|
+
|
|
|
+ width && ( realAttrs.width = replaceCssLength( realAttrs.width, width ) );
|
|
|
+ height && ( realAttrs.height = replaceCssLength( realAttrs.height, height ) );
|
|
|
+ }
|
|
|
+
|
|
|
+ return realElement;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ // Content stored inside fake element is raw and should be explicitly
|
|
|
+ // passed to ACF filter. Additionally some elements can have prefixes in tag names,
|
|
|
+ // which should be removed before filtering and added after it.
|
|
|
+ function filterHtml( editor, html ) {
|
|
|
+ var unprefixedElements = [],
|
|
|
+ prefixRegex = /^cke:/i,
|
|
|
+ dataFilter = new CKEDITOR.htmlParser.filter( {
|
|
|
+ elements: {
|
|
|
+ '^': function( element ) {
|
|
|
+ if ( prefixRegex.test( element.name ) ) {
|
|
|
+ element.name = element.name.replace( prefixRegex, '' );
|
|
|
+
|
|
|
+ unprefixedElements.push( element );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ iframe: function( element ) {
|
|
|
+ element.children = [];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } ),
|
|
|
+ acfFilter = editor.activeFilter,
|
|
|
+ writer = new CKEDITOR.htmlParser.basicWriter(),
|
|
|
+ fragment = CKEDITOR.htmlParser.fragment.fromHtml( html );
|
|
|
+
|
|
|
+ dataFilter.applyTo( fragment );
|
|
|
+ acfFilter.applyTo( fragment );
|
|
|
+
|
|
|
+ CKEDITOR.tools.array.forEach( unprefixedElements, function( element ) {
|
|
|
+ element.name = 'cke:' + element.name;
|
|
|
+ } );
|
|
|
+
|
|
|
+ fragment.writeHtml( writer );
|
|
|
+
|
|
|
+ return writer.getHtml();
|
|
|
+ }
|
|
|
+} )();
|