diff --git a/ckeditor/plugins/justify/icons/hidpi/justifyblock.png b/ckeditor/plugins/justify/icons/hidpi/justifyblock.png new file mode 100644 index 0000000..5c0cf43 Binary files /dev/null and b/ckeditor/plugins/justify/icons/hidpi/justifyblock.png differ diff --git a/ckeditor/plugins/justify/icons/hidpi/justifycenter.png b/ckeditor/plugins/justify/icons/hidpi/justifycenter.png new file mode 100644 index 0000000..fd751be Binary files /dev/null and b/ckeditor/plugins/justify/icons/hidpi/justifycenter.png differ diff --git a/ckeditor/plugins/justify/icons/hidpi/justifyleft.png b/ckeditor/plugins/justify/icons/hidpi/justifyleft.png new file mode 100644 index 0000000..a109ad3 Binary files /dev/null and b/ckeditor/plugins/justify/icons/hidpi/justifyleft.png differ diff --git a/ckeditor/plugins/justify/icons/hidpi/justifyright.png b/ckeditor/plugins/justify/icons/hidpi/justifyright.png new file mode 100644 index 0000000..5125d56 Binary files /dev/null and b/ckeditor/plugins/justify/icons/hidpi/justifyright.png differ diff --git a/ckeditor/plugins/justify/icons/justifyblock.png b/ckeditor/plugins/justify/icons/justifyblock.png new file mode 100644 index 0000000..ffe0620 Binary files /dev/null and b/ckeditor/plugins/justify/icons/justifyblock.png differ diff --git a/ckeditor/plugins/justify/icons/justifycenter.png b/ckeditor/plugins/justify/icons/justifycenter.png new file mode 100644 index 0000000..8b5b40f Binary files /dev/null and b/ckeditor/plugins/justify/icons/justifycenter.png differ diff --git a/ckeditor/plugins/justify/icons/justifyleft.png b/ckeditor/plugins/justify/icons/justifyleft.png new file mode 100644 index 0000000..a60d079 Binary files /dev/null and b/ckeditor/plugins/justify/icons/justifyleft.png differ diff --git a/ckeditor/plugins/justify/icons/justifyright.png b/ckeditor/plugins/justify/icons/justifyright.png new file mode 100644 index 0000000..21de814 Binary files /dev/null and b/ckeditor/plugins/justify/icons/justifyright.png differ diff --git a/ckeditor/plugins/justify/plugin.js b/ckeditor/plugins/justify/plugin.js new file mode 100644 index 0000000..51d2ed5 --- /dev/null +++ b/ckeditor/plugins/justify/plugin.js @@ -0,0 +1,265 @@ +/** + * @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 + */ + +/** + * @fileOverview Justify commands. + */ + +( function() { + function getAlignment( element, useComputedState ) { + + var align; + if ( useComputedState ) + align = element.getComputedStyle( 'text-align' ); + else { + while ( !element.hasAttribute || !( element.hasAttribute( 'align' ) || element.getStyle( 'text-align' ) ) ) { + var parent = element.getParent(); + if ( !parent ) + break; + element = parent; + } + align = element.getStyle( 'text-align' ) || element.getAttribute( 'align' ) || ''; + } + + // Sometimes computed values doesn't tell. + align && ( align = align.replace( /(?:-(?:moz|webkit)-)?(?:start|auto)/i, '' ) ); + + !align && useComputedState && ( align = element.getComputedStyle( 'direction' ) == 'rtl' ? 'right' : 'left' ); + + return align; + } + + function justifyCommand( editor, name, value ) { + this.editor = editor; + this.name = name; + this.value = value; + this.context = 'p'; + var classes = editor.config.justifyClasses, + blockTag = editor.config.enterMode == CKEDITOR.ENTER_P ? 'p' : 'div'; + + if ( classes ) { + switch ( value ) { + case 'left': + this.cssClassName = classes[ 0 ]; + break; + case 'center': + this.cssClassName = classes[ 1 ]; + break; + case 'right': + this.cssClassName = classes[ 2 ]; + break; + case 'justify': + this.cssClassName = classes[ 3 ]; + break; + } + + this.cssClassRegex = new RegExp( '(?:^|\\s+)(?:' + classes.join( '|' ) + ')(?=$|\\s)' ); + this.requiredContent = blockTag + '(' + this.cssClassName + ')'; + } + else { + this.requiredContent = blockTag + '{text-align}'; + } + + this.allowedContent = { + 'caption div h1 h2 h3 h4 h5 h6 p pre td th li': { + // Do not add elements, but only text-align style if element is validated by other rule. + propertiesOnly: true, + styles: this.cssClassName ? null : 'text-align', + classes: this.cssClassName || null + } + }; + + // In enter mode BR we need to allow here for div, because when non other + // feature allows div justify is the only plugin that uses it. + if ( editor.config.enterMode == CKEDITOR.ENTER_BR ) + this.allowedContent.div = true; + } + + function onDirChanged( e ) { + var editor = e.editor; + + var range = editor.createRange(); + range.setStartBefore( e.data.node ); + range.setEndAfter( e.data.node ); + + var walker = new CKEDITOR.dom.walker( range ), + node; + + while ( ( node = walker.next() ) ) { + if ( node.type == CKEDITOR.NODE_ELEMENT ) { + // A child with the defined dir is to be ignored. + if ( !node.equals( e.data.node ) && node.getDirection() ) { + range.setStartAfter( node ); + walker = new CKEDITOR.dom.walker( range ); + continue; + } + + // Switch the alignment. + var classes = editor.config.justifyClasses; + if ( classes ) { + // The left align class. + if ( node.hasClass( classes[ 0 ] ) ) { + node.removeClass( classes[ 0 ] ); + node.addClass( classes[ 2 ] ); + } + // The right align class. + else if ( node.hasClass( classes[ 2 ] ) ) { + node.removeClass( classes[ 2 ] ); + node.addClass( classes[ 0 ] ); + } + } + + // Always switch CSS margins. + var style = 'text-align'; + var align = node.getStyle( style ); + + if ( align == 'left' ) + node.setStyle( style, 'right' ); + else if ( align == 'right' ) + node.setStyle( style, 'left' ); + } + } + } + + justifyCommand.prototype = { + exec: function( editor ) { + var selection = editor.getSelection(), + enterMode = editor.config.enterMode; + + if ( !selection ) + return; + + var bookmarks = selection.createBookmarks(), + ranges = selection.getRanges(); + + var cssClassName = this.cssClassName, + iterator, block; + + var useComputedState = editor.config.useComputedState; + + for ( var i = ranges.length - 1; i >= 0; i-- ) { + iterator = ranges[ i ].createIterator(); + iterator.enlargeBr = enterMode != CKEDITOR.ENTER_BR; + + while ( ( block = iterator.getNextParagraph( enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ) ) ) { + if ( block.isReadOnly() ) + continue; + + // Check if style or class might be applied to currently processed element (#455). + var tag = block.getName(), + isAllowedTextAlign, isAllowedCssClass; + + isAllowedTextAlign = editor.activeFilter.check( tag + '{text-align}' ); + isAllowedCssClass = editor.activeFilter.check( tag + '(' + cssClassName + ')' ); + + if ( !isAllowedCssClass && !isAllowedTextAlign ) { + continue; + } + + block.removeAttribute( 'align' ); + block.removeStyle( 'text-align' ); + + // Remove any of the alignment classes from the className. + var className = cssClassName && ( block.$.className = CKEDITOR.tools.ltrim( block.$.className.replace( this.cssClassRegex, '' ) ) ); + + var apply = ( this.state == CKEDITOR.TRISTATE_OFF ) && ( !useComputedState || ( getAlignment( block, true ) != this.value ) ); + + if ( cssClassName && isAllowedCssClass ) { + // Append the desired class name. + if ( apply ) + block.addClass( cssClassName ); + else if ( !className ) + block.removeAttribute( 'class' ); + } else if ( apply && isAllowedTextAlign ) { + block.setStyle( 'text-align', this.value ); + } + } + + } + + editor.focus(); + editor.forceNextSelectionCheck(); + selection.selectBookmarks( bookmarks ); + }, + + refresh: function( editor, path ) { + var firstBlock = path.block || path.blockLimit, + name = firstBlock.getName(), + isEditable = firstBlock.equals( editor.editable() ), + isStylable = this.cssClassName ? editor.activeFilter.check( name + '(' + this.cssClassName + ')' ) : + editor.activeFilter.check( name + '{text-align}' ); + + // #455 + // 1. Check if we are directly in editbale. Justification should be always allowed, and not highlighted. + // Checking situation `body > ul` where ul is selected and path.blockLimit returns editable. + // 2. Check if current element can have applied specific class. + // 3. Check if current element can have applied text-align style. + if ( isEditable && !CKEDITOR.dtd.$list[ path.lastElement.getName() ] ) { + this.setState( CKEDITOR.TRISTATE_OFF ); + } else if ( !isEditable && isStylable ) { + // 2 & 3 in one condition. + this.setState( getAlignment( firstBlock, this.editor.config.useComputedState ) == this.value ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF ); + } else { + this.setState( CKEDITOR.TRISTATE_DISABLED ); + } + } + }; + + CKEDITOR.plugins.add( 'justify', { + icons: 'justifyblock,justifycenter,justifyleft,justifyright', // %REMOVE_LINE_CORE% + hidpi: true, // %REMOVE_LINE_CORE% + init: function( editor ) { + if ( editor.blockless ) + return; + + var left = new justifyCommand( editor, 'justifyleft', 'left' ), + center = new justifyCommand( editor, 'justifycenter', 'center' ), + right = new justifyCommand( editor, 'justifyright', 'right' ), + justify = new justifyCommand( editor, 'justifyblock', 'justify' ); + + editor.addCommand( 'justifyleft', left ); + editor.addCommand( 'justifycenter', center ); + editor.addCommand( 'justifyright', right ); + editor.addCommand( 'justifyblock', justify ); + + if ( editor.ui.addButton ) { + editor.ui.addButton( 'JustifyLeft', { + label: editor.lang.common.alignLeft, + command: 'justifyleft', + toolbar: 'align,10' + } ); + editor.ui.addButton( 'JustifyCenter', { + label: editor.lang.common.center, + command: 'justifycenter', + toolbar: 'align,20' + } ); + editor.ui.addButton( 'JustifyRight', { + label: editor.lang.common.alignRight, + command: 'justifyright', + toolbar: 'align,30' + } ); + editor.ui.addButton( 'JustifyBlock', { + label: editor.lang.common.justify, + command: 'justifyblock', + toolbar: 'align,40' + } ); + } + editor.on( 'dirChanged', onDirChanged ); + } + } ); +} )(); + +/** + * List of classes to use for aligning the contents. If it's `null`, no classes will be used + * and instead the corresponding CSS values will be used. + * + * The array should contain 4 members, in the following order: left, center, right, justify. + * + * // Use the classes 'AlignLeft', 'AlignCenter', 'AlignRight', 'AlignJustify' + * config.justifyClasses = [ 'AlignLeft', 'AlignCenter', 'AlignRight', 'AlignJustify' ]; + * + * @cfg {Array} [justifyClasses=null] + * @member CKEDITOR.config + */