X-Git-Url: https://scm.cri.ensmp.fr/git/ckeditor.git/blobdiff_plain/256592bf803e851aa7fc953e08a6e9e58d970f8c..871bad8291b6dbc29d489d95d185458caab25158:/skins/ckeditor/_source/plugins/link/dialogs/link.js diff --git a/skins/ckeditor/_source/plugins/link/dialogs/link.js b/skins/ckeditor/_source/plugins/link/dialogs/link.js new file mode 100644 index 0000000..51f5623 --- /dev/null +++ b/skins/ckeditor/_source/plugins/link/dialogs/link.js @@ -0,0 +1,1424 @@ +/* +Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ + +CKEDITOR.dialog.add( 'link', function( editor ) +{ + var plugin = CKEDITOR.plugins.link; + // Handles the event when the "Target" selection box is changed. + var targetChanged = function() + { + var dialog = this.getDialog(), + popupFeatures = dialog.getContentElement( 'target', 'popupFeatures' ), + targetName = dialog.getContentElement( 'target', 'linkTargetName' ), + value = this.getValue(); + + if ( !popupFeatures || !targetName ) + return; + + popupFeatures = popupFeatures.getElement(); + popupFeatures.hide(); + targetName.setValue( '' ); + + switch ( value ) + { + case 'frame' : + targetName.setLabel( editor.lang.link.targetFrameName ); + targetName.getElement().show(); + break; + case 'popup' : + popupFeatures.show(); + targetName.setLabel( editor.lang.link.targetPopupName ); + targetName.getElement().show(); + break; + default : + targetName.setValue( value ); + targetName.getElement().hide(); + break; + } + + }; + + // Handles the event when the "Type" selection box is changed. + var linkTypeChanged = function() + { + var dialog = this.getDialog(), + partIds = [ 'urlOptions', 'anchorOptions', 'emailOptions' ], + typeValue = this.getValue(), + uploadTab = dialog.definition.getContents( 'upload' ), + uploadInitiallyHidden = uploadTab && uploadTab.hidden; + + if ( typeValue == 'url' ) + { + if ( editor.config.linkShowTargetTab ) + dialog.showPage( 'target' ); + if ( !uploadInitiallyHidden ) + dialog.showPage( 'upload' ); + } + else + { + dialog.hidePage( 'target' ); + if ( !uploadInitiallyHidden ) + dialog.hidePage( 'upload' ); + } + + for ( var i = 0 ; i < partIds.length ; i++ ) + { + var element = dialog.getContentElement( 'info', partIds[i] ); + if ( !element ) + continue; + + element = element.getElement().getParent().getParent(); + if ( partIds[i] == typeValue + 'Options' ) + element.show(); + else + element.hide(); + } + + dialog.layout(); + }; + + // Loads the parameters in a selected link to the link dialog fields. + var javascriptProtocolRegex = /^javascript:/, + emailRegex = /^mailto:([^?]+)(?:\?(.+))?$/, + emailSubjectRegex = /subject=([^;?:@&=$,\/]*)/, + emailBodyRegex = /body=([^;?:@&=$,\/]*)/, + anchorRegex = /^#(.*)$/, + urlRegex = /^((?:http|https|ftp|news):\/\/)?(.*)$/, + selectableTargets = /^(_(?:self|top|parent|blank))$/, + encodedEmailLinkRegex = /^javascript:void\(location\.href='mailto:'\+String\.fromCharCode\(([^)]+)\)(?:\+'(.*)')?\)$/, + functionCallProtectedEmailLinkRegex = /^javascript:([^(]+)\(([^)]+)\)$/; + + var popupRegex = + /\s*window.open\(\s*this\.href\s*,\s*(?:'([^']*)'|null)\s*,\s*'([^']*)'\s*\)\s*;\s*return\s*false;*\s*/; + var popupFeaturesRegex = /(?:^|,)([^=]+)=(\d+|yes|no)/gi; + + var parseLink = function( editor, element ) + { + var href = ( element && ( element.data( 'cke-saved-href' ) || element.getAttribute( 'href' ) ) ) || '', + javascriptMatch, + emailMatch, + anchorMatch, + urlMatch, + retval = {}; + + if ( ( javascriptMatch = href.match( javascriptProtocolRegex ) ) ) + { + if ( emailProtection == 'encode' ) + { + href = href.replace( encodedEmailLinkRegex, + function ( match, protectedAddress, rest ) + { + return 'mailto:' + + String.fromCharCode.apply( String, protectedAddress.split( ',' ) ) + + ( rest && unescapeSingleQuote( rest ) ); + }); + } + // Protected email link as function call. + else if ( emailProtection ) + { + href.replace( functionCallProtectedEmailLinkRegex, function( match, funcName, funcArgs ) + { + if ( funcName == compiledProtectionFunction.name ) + { + retval.type = 'email'; + var email = retval.email = {}; + + var paramRegex = /[^,\s]+/g, + paramQuoteRegex = /(^')|('$)/g, + paramsMatch = funcArgs.match( paramRegex ), + paramsMatchLength = paramsMatch.length, + paramName, + paramVal; + + for ( var i = 0; i < paramsMatchLength; i++ ) + { + paramVal = decodeURIComponent( unescapeSingleQuote( paramsMatch[ i ].replace( paramQuoteRegex, '' ) ) ); + paramName = compiledProtectionFunction.params[ i ].toLowerCase(); + email[ paramName ] = paramVal; + } + email.address = [ email.name, email.domain ].join( '@' ); + } + } ); + } + } + + if ( !retval.type ) + { + if ( ( anchorMatch = href.match( anchorRegex ) ) ) + { + retval.type = 'anchor'; + retval.anchor = {}; + retval.anchor.name = retval.anchor.id = anchorMatch[1]; + } + // Protected email link as encoded string. + else if ( ( emailMatch = href.match( emailRegex ) ) ) + { + var subjectMatch = href.match( emailSubjectRegex ), + bodyMatch = href.match( emailBodyRegex ); + + retval.type = 'email'; + var email = ( retval.email = {} ); + email.address = emailMatch[ 1 ]; + subjectMatch && ( email.subject = decodeURIComponent( subjectMatch[ 1 ] ) ); + bodyMatch && ( email.body = decodeURIComponent( bodyMatch[ 1 ] ) ); + } + // urlRegex matches empty strings, so need to check for href as well. + else if ( href && ( urlMatch = href.match( urlRegex ) ) ) + { + retval.type = 'url'; + retval.url = {}; + retval.url.protocol = urlMatch[1]; + retval.url.url = urlMatch[2]; + } + else + retval.type = 'url'; + } + + // Load target and popup settings. + if ( element ) + { + var target = element.getAttribute( 'target' ); + retval.target = {}; + retval.adv = {}; + + // IE BUG: target attribute is an empty string instead of null in IE if it's not set. + if ( !target ) + { + var onclick = element.data( 'cke-pa-onclick' ) || element.getAttribute( 'onclick' ), + onclickMatch = onclick && onclick.match( popupRegex ); + if ( onclickMatch ) + { + retval.target.type = 'popup'; + retval.target.name = onclickMatch[1]; + + var featureMatch; + while ( ( featureMatch = popupFeaturesRegex.exec( onclickMatch[2] ) ) ) + { + // Some values should remain numbers (#7300) + if ( ( featureMatch[2] == 'yes' || featureMatch[2] == '1' ) && !( featureMatch[1] in { height:1, width:1, top:1, left:1 } ) ) + retval.target[ featureMatch[1] ] = true; + else if ( isFinite( featureMatch[2] ) ) + retval.target[ featureMatch[1] ] = featureMatch[2]; + } + } + } + else + { + var targetMatch = target.match( selectableTargets ); + if ( targetMatch ) + retval.target.type = retval.target.name = target; + else + { + retval.target.type = 'frame'; + retval.target.name = target; + } + } + + var me = this; + var advAttr = function( inputName, attrName ) + { + var value = element.getAttribute( attrName ); + if ( value !== null ) + retval.adv[ inputName ] = value || ''; + }; + advAttr( 'advId', 'id' ); + advAttr( 'advLangDir', 'dir' ); + advAttr( 'advAccessKey', 'accessKey' ); + + retval.adv.advName = + element.data( 'cke-saved-name' ) + || element.getAttribute( 'name' ) + || ''; + advAttr( 'advLangCode', 'lang' ); + advAttr( 'advTabIndex', 'tabindex' ); + advAttr( 'advTitle', 'title' ); + advAttr( 'advContentType', 'type' ); + CKEDITOR.plugins.link.synAnchorSelector ? + retval.adv.advCSSClasses = getLinkClass( element ) + : advAttr( 'advCSSClasses', 'class' ); + advAttr( 'advCharset', 'charset' ); + advAttr( 'advStyles', 'style' ); + advAttr( 'advRel', 'rel' ); + } + + // Find out whether we have any anchors in the editor. + var anchors = retval.anchors = [], + item; + + // For some browsers we set contenteditable="false" on anchors, making document.anchors not to include them, so we must traverse the links manually (#7893). + if ( CKEDITOR.plugins.link.emptyAnchorFix ) + { + var links = editor.document.getElementsByTag( 'a' ); + for ( i = 0, count = links.count(); i < count; i++ ) + { + item = links.getItem( i ); + if ( item.data( 'cke-saved-name' ) || item.hasAttribute( 'name' ) ) + anchors.push( { name : item.data( 'cke-saved-name' ) || item.getAttribute( 'name' ), id : item.getAttribute( 'id' ) } ); + } + } + else + { + var anchorList = new CKEDITOR.dom.nodeList( editor.document.$.anchors ); + for ( var i = 0, count = anchorList.count(); i < count; i++ ) + { + item = anchorList.getItem( i ); + anchors[ i ] = { name : item.getAttribute( 'name' ), id : item.getAttribute( 'id' ) }; + } + } + + if ( CKEDITOR.plugins.link.fakeAnchor ) + { + var imgs = editor.document.getElementsByTag( 'img' ); + for ( i = 0, count = imgs.count(); i < count; i++ ) + { + if ( ( item = CKEDITOR.plugins.link.tryRestoreFakeAnchor( editor, imgs.getItem( i ) ) ) ) + anchors.push( { name : item.getAttribute( 'name' ), id : item.getAttribute( 'id' ) } ); + } + } + + // Record down the selected element in the dialog. + this._.selectedElement = element; + return retval; + }; + + var setupParams = function( page, data ) + { + if ( data[page] ) + this.setValue( data[page][this.id] || '' ); + }; + + var setupPopupParams = function( data ) + { + return setupParams.call( this, 'target', data ); + }; + + var setupAdvParams = function( data ) + { + return setupParams.call( this, 'adv', data ); + }; + + var commitParams = function( page, data ) + { + if ( !data[page] ) + data[page] = {}; + + data[page][this.id] = this.getValue() || ''; + }; + + var commitPopupParams = function( data ) + { + return commitParams.call( this, 'target', data ); + }; + + var commitAdvParams = function( data ) + { + return commitParams.call( this, 'adv', data ); + }; + + function unescapeSingleQuote( str ) + { + return str.replace( /\\'/g, '\'' ); + } + + function escapeSingleQuote( str ) + { + return str.replace( /'/g, '\\$&' ); + } + + var emailProtection = editor.config.emailProtection || ''; + + // Compile the protection function pattern. + if ( emailProtection && emailProtection != 'encode' ) + { + var compiledProtectionFunction = {}; + + emailProtection.replace( /^([^(]+)\(([^)]+)\)$/, function( match, funcName, params ) + { + compiledProtectionFunction.name = funcName; + compiledProtectionFunction.params = []; + params.replace( /[^,\s]+/g, function( param ) + { + compiledProtectionFunction.params.push( param ); + } ); + } ); + } + + function protectEmailLinkAsFunction( email ) + { + var retval, + name = compiledProtectionFunction.name, + params = compiledProtectionFunction.params, + paramName, + paramValue; + + retval = [ name, '(' ]; + for ( var i = 0; i < params.length; i++ ) + { + paramName = params[ i ].toLowerCase(); + paramValue = email[ paramName ]; + + i > 0 && retval.push( ',' ); + retval.push( '\'', + paramValue ? + escapeSingleQuote( encodeURIComponent( email[ paramName ] ) ) + : '', + '\''); + } + retval.push( ')' ); + return retval.join( '' ); + } + + function protectEmailAddressAsEncodedString( address ) + { + var charCode, + length = address.length, + encodedChars = []; + for ( var i = 0; i < length; i++ ) + { + charCode = address.charCodeAt( i ); + encodedChars.push( charCode ); + } + return 'String.fromCharCode(' + encodedChars.join( ',' ) + ')'; + } + + function getLinkClass( ele ) + { + var className = ele.getAttribute( 'class' ); + return className ? className.replace( /\s*(?:cke_anchor_empty|cke_anchor)(?:\s*$)?/g, '' ) : ''; + } + + var commonLang = editor.lang.common, + linkLang = editor.lang.link; + + return { + title : linkLang.title, + minWidth : 350, + minHeight : 230, + contents : [ + { + id : 'info', + label : linkLang.info, + title : linkLang.info, + elements : + [ + { + id : 'linkType', + type : 'select', + label : linkLang.type, + 'default' : 'url', + items : + [ + [ linkLang.toUrl, 'url' ], + [ linkLang.toAnchor, 'anchor' ], + [ linkLang.toEmail, 'email' ] + ], + onChange : linkTypeChanged, + setup : function( data ) + { + if ( data.type ) + this.setValue( data.type ); + }, + commit : function( data ) + { + data.type = this.getValue(); + } + }, + { + type : 'vbox', + id : 'urlOptions', + children : + [ + { + type : 'hbox', + widths : [ '25%', '75%' ], + children : + [ + { + id : 'protocol', + type : 'select', + label : commonLang.protocol, + 'default' : 'http://', + items : + [ + // Force 'ltr' for protocol names in BIDI. (#5433) + [ 'http://\u200E', 'http://' ], + [ 'https://\u200E', 'https://' ], + [ 'ftp://\u200E', 'ftp://' ], + [ 'news://\u200E', 'news://' ], + [ linkLang.other , '' ] + ], + setup : function( data ) + { + if ( data.url ) + this.setValue( data.url.protocol || '' ); + }, + commit : function( data ) + { + if ( !data.url ) + data.url = {}; + + data.url.protocol = this.getValue(); + } + }, + { + type : 'text', + id : 'url', + label : commonLang.url, + required: true, + onLoad : function () + { + this.allowOnChange = true; + }, + onKeyUp : function() + { + this.allowOnChange = false; + var protocolCmb = this.getDialog().getContentElement( 'info', 'protocol' ), + url = this.getValue(), + urlOnChangeProtocol = /^(http|https|ftp|news):\/\/(?=.)/i, + urlOnChangeTestOther = /^((javascript:)|[#\/\.\?])/i; + + var protocol = urlOnChangeProtocol.exec( url ); + if ( protocol ) + { + this.setValue( url.substr( protocol[ 0 ].length ) ); + protocolCmb.setValue( protocol[ 0 ].toLowerCase() ); + } + else if ( urlOnChangeTestOther.test( url ) ) + protocolCmb.setValue( '' ); + + this.allowOnChange = true; + }, + onChange : function() + { + if ( this.allowOnChange ) // Dont't call on dialog load. + this.onKeyUp(); + }, + validate : function() + { + var dialog = this.getDialog(); + + if ( dialog.getContentElement( 'info', 'linkType' ) && + dialog.getValueOf( 'info', 'linkType' ) != 'url' ) + return true; + + if ( this.getDialog().fakeObj ) // Edit Anchor. + return true; + + var func = CKEDITOR.dialog.validate.notEmpty( linkLang.noUrl ); + return func.apply( this ); + }, + setup : function( data ) + { + this.allowOnChange = false; + if ( data.url ) + this.setValue( data.url.url ); + this.allowOnChange = true; + + }, + commit : function( data ) + { + // IE will not trigger the onChange event if the mouse has been used + // to carry all the operations #4724 + this.onChange(); + + if ( !data.url ) + data.url = {}; + + data.url.url = this.getValue(); + this.allowOnChange = false; + } + } + ], + setup : function( data ) + { + if ( !this.getDialog().getContentElement( 'info', 'linkType' ) ) + this.getElement().show(); + } + }, + { + type : 'button', + id : 'browse', + hidden : 'true', + filebrowser : 'info:url', + label : commonLang.browseServer + } + ] + }, + { + type : 'vbox', + id : 'anchorOptions', + width : 260, + align : 'center', + padding : 0, + children : + [ + { + type : 'fieldset', + id : 'selectAnchorText', + label : linkLang.selectAnchor, + setup : function( data ) + { + if ( data.anchors.length > 0 ) + this.getElement().show(); + else + this.getElement().hide(); + }, + children : + [ + { + type : 'hbox', + id : 'selectAnchor', + children : + [ + { + type : 'select', + id : 'anchorName', + 'default' : '', + label : linkLang.anchorName, + style : 'width: 100%;', + items : + [ + [ '' ] + ], + setup : function( data ) + { + this.clear(); + this.add( '' ); + for ( var i = 0 ; i < data.anchors.length ; i++ ) + { + if ( data.anchors[i].name ) + this.add( data.anchors[i].name ); + } + + if ( data.anchor ) + this.setValue( data.anchor.name ); + + var linkType = this.getDialog().getContentElement( 'info', 'linkType' ); + if ( linkType && linkType.getValue() == 'email' ) + this.focus(); + }, + commit : function( data ) + { + if ( !data.anchor ) + data.anchor = {}; + + data.anchor.name = this.getValue(); + } + }, + { + type : 'select', + id : 'anchorId', + 'default' : '', + label : linkLang.anchorId, + style : 'width: 100%;', + items : + [ + [ '' ] + ], + setup : function( data ) + { + this.clear(); + this.add( '' ); + for ( var i = 0 ; i < data.anchors.length ; i++ ) + { + if ( data.anchors[i].id ) + this.add( data.anchors[i].id ); + } + + if ( data.anchor ) + this.setValue( data.anchor.id ); + }, + commit : function( data ) + { + if ( !data.anchor ) + data.anchor = {}; + + data.anchor.id = this.getValue(); + } + } + ], + setup : function( data ) + { + if ( data.anchors.length > 0 ) + this.getElement().show(); + else + this.getElement().hide(); + } + } + ] + }, + { + type : 'html', + id : 'noAnchors', + style : 'text-align: center;', + html : '