text: /**
   * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
   * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
   */
  
  /**
   * @module link/utils
   */
  
  import { upperFirst } from 'lodash-es';
  
  const ATTRIBUTE_WHITESPACES = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205f\u3000]/g; // eslint-disable-line no-control-regex
  const SAFE_URL = /^(?:(?:https?|ftps?|mailto):|[^a-z]|[a-z+.-]+(?:[^a-z+.:-]|$))/i;
  
  /**
   * A keystroke used by the {@link module:link/linkui~LinkUI link UI feature}.
   */
  export const LINK_KEYSTROKE = 'Ctrl+K';
  
  /**
   * Returns `true` if a given view node is the link element.
   *
   * @param {module:engine/view/node~Node} node
   * @returns {Boolean}
   */
  export function isLinkElement( node ) {
  	return node.is( 'attributeElement' ) && !!node.getCustomProperty( 'link' );
  }
  
  /**
   * Creates link {@link module:engine/view/attributeelement~AttributeElement} with the provided `href` attribute.
   *
   * @param {String} href
   * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi
   * @returns {module:engine/view/attributeelement~AttributeElement}
   */
  export function createLinkElement( href, { writer } ) {
  	// Priority 5 - https://github.com/ckeditor/ckeditor5-link/issues/121.
  	const linkElement = writer.createAttributeElement( 'a', { href }, { priority: 5 } );
  	writer.setCustomProperty( 'link', true, linkElement );
  
  	return linkElement;
  }
  
  /**
   * Returns a safe URL based on a given value.
   *
   * A URL is considered safe if it is safe for the user (does not contain any malicious code).
   *
   * If a URL is considered unsafe, a simple `"#"` is returned.
   *
   * @protected
   * @param {*} url
   * @returns {String} Safe URL.
   */
  export function ensureSafeUrl( url ) {
  	url = String( url );
  
  	return isSafeUrl( url ) ? url : '#';
  }
  
  // Checks whether the given URL is safe for the user (does not contain any malicious code).
  //
  // @param {String} url URL to check.
  function isSafeUrl( url ) {
  	const normalizedUrl = url.replace( ATTRIBUTE_WHITESPACES, '' );
  
  	return normalizedUrl.match( SAFE_URL );
  }
  
  /**
   * Returns the {@link module:link/link~LinkConfig#decorators `config.link.decorators`} configuration processed
   * to respect the locale of the editor, i.e. to display the {@link module:link/link~LinkDecoratorManualDefinition label}
   * in the correct language.
   *
   * **Note**: Only the few most commonly used labels are translated automatically. Other labels should be manually
   * translated in the {@link module:link/link~LinkConfig#decorators `config.link.decorators`} configuration.
   *
   * @param {module:utils/locale~Locale#t} t shorthand for {@link module:utils/locale~Locale#t Locale#t}
   * @param {Array.<module:link/link~LinkDecoratorDefinition>} The decorator reference
   * where the label values should be localized.
   * @returns {Array.<module:link/link~LinkDecoratorDefinition>}
   */
  export function getLocalizedDecorators( t, decorators ) {
  	const localizedDecoratorsLabels = {
  		'Open in a new tab': t( 'Open in a new tab' ),
  		'Downloadable': t( 'Downloadable' )
  	};
  
  	decorators.forEach( decorator => {
  		if ( decorator.label && localizedDecoratorsLabels[ decorator.label ] ) {
  			decorator.label = localizedDecoratorsLabels[ decorator.label ];
  		}
  		return decorator;
  	} );
  
  	return decorators;
  }
  
  /**
   * Converts an object with defined decorators to a normalized array of decorators. The `id` key is added for each decorator and
   * is used as the attribute's name in the model.
   *
   * @param {Object.<String, module:link/link~LinkDecoratorDefinition>} decorators
   * @returns {Array.<module:link/link~LinkDecoratorDefinition>}
   */
  export function normalizeDecorators( decorators ) {
  	const retArray = [];
  
  	if ( decorators ) {
  		for ( const [ key, value ] of Object.entries( decorators ) ) {
  			const decorator = Object.assign(
  				{},
  				value,
  				{ id: `link${ upperFirst( key ) }` }
  			);
  			retArray.push( decorator );
  		}
  	}
  
  	return retArray;
  }
  
  /**
   * Returns `true` if the specified `element` is an image and it can be linked (the element allows having the `linkHref` attribute).
   *
   * @params {module:engine/model/element~Element|null} element
   * @params {module:engine/model/schema~Schema} schema
   * @returns {Boolean}
   */
  export function isImageAllowed( element, schema ) {
  	if ( !element ) {
  		return false;
  	}
  
  	return element.is( 'element', 'image' ) && schema.checkAttribute( 'image', 'linkHref' );
  }
  