/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */

/**
 * @fileOverview The [Language](https://ckeditor.com/cke4/addon/language) plugin.
 */

'use strict';

( function() {

	var allowedContent = 'span[!lang,dir]',
		requiredContent = 'span[lang]';

	CKEDITOR.plugins.add( 'language', {
		requires: 'menubutton',
		// jscs:disable maximumLineLength
		lang: 'ar,az,bg,ca,cs,cy,da,de,de-ch,el,en,en-au,en-gb,eo,es,es-mx,et,eu,fa,fi,fo,fr,gl,he,hr,hu,id,it,ja,km,ko,ku,lt,lv,nb,nl,no,oc,pl,pt,pt-br,ro,ru,sk,sl,sq,sr,sr-latn,sv,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
		// jscs:enable maximumLineLength
		icons: 'language', // %REMOVE_LINE_CORE%
		hidpi: true, // %REMOVE_LINE_CORE%

		init: function( editor ) {
			var languagesConfigStrings = ( editor.config.language_list || [ 'ar:Arabic:rtl', 'fr:French', 'es:Spanish' ] ),
				plugin = this,
				lang = editor.lang.language,
				items = {},
				parts,
				curLanguageId, // 2-letter language identifier.
				languageButtonId, // Will store button namespaced identifier, like "language_en".
				i;

			// Registers command.
			editor.addCommand( 'language', {
				allowedContent: allowedContent,
				requiredContent: requiredContent,
				contextSensitive: true,
				exec: function( editor, languageId ) {
					var item = items[ 'language_' + languageId ];

					if ( item )
						editor[ item.style.checkActive( editor.elementPath(), editor ) ? 'removeStyle' : 'applyStyle' ]( item.style );
				},
				refresh: function( editor ) {
					this.setState( plugin.getCurrentLangElement( editor ) ?
						CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );
				}
			} );

			// Parse languagesConfigStrings, and create items entry for each lang.
			for ( i = 0; i < languagesConfigStrings.length; i++ ) {
				parts = languagesConfigStrings[ i ].split( ':' );
				curLanguageId = parts[ 0 ];
				languageButtonId = 'language_' + curLanguageId;

				items[ languageButtonId ] = {
					label: parts[ 1 ],
					langId: curLanguageId,
					group: 'language',
					order: i,
					// Tells if this language is left-to-right oriented (default: true).
					ltr: ( '' + parts[ 2 ] ).toLowerCase() != 'rtl',
					onClick: function() {
						editor.execCommand( 'language', this.langId );
					},
					role: 'menuitemcheckbox'
				};

				// Init style property.
				items[ languageButtonId ].style = new CKEDITOR.style( {
					element: 'span',
					attributes: {
						lang: curLanguageId,
						dir: items[ languageButtonId ].ltr ? 'ltr' : 'rtl'
					}
				} );
			}

			// Remove language indicator button.
			items.language_remove = {
				label: lang.remove,
				group: 'language_remove',
				state: CKEDITOR.TRISTATE_DISABLED,
				order: items.length,
				onClick: function() {
					var currentLanguagedElement = plugin.getCurrentLangElement( editor );

					if ( currentLanguagedElement )
						editor.execCommand( 'language', currentLanguagedElement.getAttribute( 'lang' ) );
				}
			};

			// Initialize groups for menu.
			editor.addMenuGroup( 'language', 1 );
			editor.addMenuGroup( 'language_remove' ); // Group order is skipped intentionally, it will be placed at the end.
			editor.addMenuItems( items );

			editor.ui.add( 'Language', CKEDITOR.UI_MENUBUTTON, {
				label: lang.button,
				// MenuButtons do not (yet) has toFeature method, so we cannot do this:
				// toFeature: function( editor ) { return editor.getCommand( 'language' ); }
				// Set feature's properties directly on button.
				allowedContent: allowedContent,
				requiredContent: requiredContent,
				toolbar: 'bidi,30',
				command: 'language',
				contentTransformations: [
					[
						// Add missing proper `dir` attribute when <span> element has only `lang` attribute (#5085).
						{
							element: 'span',
							left: function( element ) {
								return element.attributes.lang && ( !element.attributes.dir || element.attributes.dir === '' );
							},
							right: function( element ) {
								var rtlLanguages = CKEDITOR.tools.object.keys( CKEDITOR.lang.rtl ),
									isRtlLanguage = CKEDITOR.tools.array.indexOf( rtlLanguages, element.attributes.lang ) !== -1,
									dirAttribute = isRtlLanguage ? 'rtl' : 'ltr';

								element.attributes.dir = dirAttribute;
							}
						}
					]
				],
				onMenu: function() {
					var activeItems = {},
						currentLanguagedElement = plugin.getCurrentLangElement( editor );

					for ( var prop in items )
						activeItems[ prop ] = CKEDITOR.TRISTATE_OFF;

					activeItems.language_remove = currentLanguagedElement ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED;

					if ( currentLanguagedElement )
						activeItems[ 'language_' + currentLanguagedElement.getAttribute( 'lang' ) ] = CKEDITOR.TRISTATE_ON;

					return activeItems;
				}
			} );

			// Prevent of removing `span` element with `lang` and `dir` attribute (#779).
			if ( editor.addRemoveFormatFilter ) {
				editor.addRemoveFormatFilter( function( element ) {
					return !( element.is( 'span' ) && element.getAttribute( 'dir' ) && element.getAttribute( 'lang' ) );
				} );
			}
		},

		// Gets the first language element for the current editor selection.
		// @param {CKEDITOR.editor} editor
		// @returns {CKEDITOR.dom.element} The language element, if any.
		getCurrentLangElement: function( editor ) {
			var elementPath = editor.elementPath(),
				activePath = elementPath && elementPath.elements,
				pathMember, ret;

			// IE8: upon initialization if there is no path elementPath() returns null.
			if ( elementPath ) {
				for ( var i = 0; i < activePath.length; i++ ) {
					pathMember = activePath[ i ];

					if ( !ret && pathMember.getName() == 'span' && pathMember.hasAttribute( 'lang' ) )
						ret = pathMember;
				}
			}

			return ret;
		}
	} );
} )();

/**
 * Specifies the list of languages available in the
 * [Language](https://ckeditor.com/cke4/addon/language) plugin. Each entry
 * should be a string in the following format:
 *
 *		<languageCode>:<languageLabel>[:<textDirection>]
 *
 * * _languageCode_: The language code used for the `lang` attribute in ISO 639 format.
 * 	Language codes can be found [here](http://www.loc.gov/standards/iso639-2/php/English_list.php).
 * 	You can use both 2-letter ISO-639-1 codes and 3-letter ISO-639-2 codes, though
 * 	for consistency it is recommended to stick to ISO-639-1 2-letter codes.
 * * _languageLabel_: The label to show for this language in the list.
 * * _textDirection_: (optional) One of the following values: `rtl` or `ltr`,
 * 	indicating the reading direction of the language. Defaults to `ltr`.
 *
 * See the {@glink examples/language example}.
 *
 *		config.language_list = [ 'he:Hebrew:rtl', 'pt:Portuguese', 'de:German' ];
 *
 * @cfg {Array} [language_list = [ 'ar:Arabic:rtl', 'fr:French', 'es:Spanish' ]]
 * @member CKEDITOR.config
 */
