Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Sun, Jan 5, 7:26 PM

in-portal

Index: branches/5.2.x/core/ckeditor/plugins/my_link/plugin.js
===================================================================
--- branches/5.2.x/core/ckeditor/plugins/my_link/plugin.js (revision 16480)
+++ branches/5.2.x/core/ckeditor/plugins/my_link/plugin.js (revision 16481)
@@ -1,706 +1,682 @@
(
function() {
CKEDITOR.plugins.add('my_link');
CKEDITOR.on(
'dialogDefinition',
function(ev) {
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
var editor = this;
if (dialogName == 'link') {
var plugin = CKEDITOR.plugins.link;
var $internal_page_mapping = {}; // mapping between @@PAGE_ID@@ and real url (for anchor loading)
var load_page_anchors = function ($page_id, dialog) {
var $url;
var $tmp_iframe = $('#tmp_iframe');
var $internal_page_anchors = dialog.getContentElement( 'info', 'internalPageAnchors' );
var $current_anchor = $('#' + $internal_page_anchors.domId).data('anchor');
$internal_page_anchors.clear();
$internal_page_anchors.add( 'Loading ...', '' );
if ( $tmp_iframe.length == 0 ) {
$tmp_iframe = $('<iframe width="0" height="0" id="tmp_iframe"></iframe>').appendTo('body');
$tmp_iframe.get(0).onload = function () {
var $anchors = $('a[name]', $tmp_iframe.get(0).contentWindow.document);
$internal_page_anchors.allowOnChange = false;
$internal_page_anchors.clear();
$internal_page_anchors.add( $anchors.length > 0 ? '' : '(No anchors available in the document)', '' );
$anchors.each(
function () {
$internal_page_anchors.add( $(this).attr('name') );
}
);
$internal_page_anchors.setValue($current_anchor);
$internal_page_anchors.allowOnChange = true;
}
}
$url = $internal_page_mapping[$page_id];
$url += ($url.indexOf('?') ? '&' : '?') + 'skip_last_template=1';
$tmp_iframe.attr('src', $url);
}
// Handles the event when the "Type" selection box is changed.
var linkTypeChanged = function()
{
var dialog = this.getDialog(),
partIds = [ 'internalOptions', 'urlOptions', 'anchorOptions', 'emailOptions' ],
typeValue = this.getValue(),
uploadTab = dialog.definition.getContents( 'upload' ),
uploadInitiallyHidden = uploadTab && uploadTab.hidden;
switch ( typeValue ) {
case 'url':
if ( editor.config.linkShowTargetTab )
dialog.showPage( 'target' );
if ( !uploadInitiallyHidden )
dialog.showPage( 'upload' );
break;
case 'internal':
if ( editor.config.linkShowTargetTab )
dialog.showPage( 'target' );
if ( !uploadInitiallyHidden )
dialog.hidePage( 'upload' );
// select internal page according to link url (on link type change)
var $url = dialog.getContentElement('info', 'url').getValue();
if ( $internal_page_mapping[$url] !== undefined ) {
dialog.getContentElement('info', 'internal_page').setValue($url);
}
break;
default:
dialog.hidePage( 'target' );
if ( !uploadInitiallyHidden )
dialog.hidePage( 'upload' );
break;
}
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();
};
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:([^(]+)\(([^)]+)\)$/,
internalPageRegex = /^@@[\d]+@@(#.*$|$)/; // CUSTOM
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 ) ) )
{
var emailProtection = editor.config.emailProtection || '';
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 ] ) );
}
// CUSTOM: begin
else if ( href && href.match( internalPageRegex ) )
{
retval.type = 'internal';
retval.url = {};
retval.url.protocol = '';
retval.anchor = {};
if ( href.match(/^(.*)#(.*)$/) ) {
retval.url.url = RegExp.$1;
retval.internal_anchor = RegExp.$2;
}
else {
retval.url.url = href;
retval.internal_anchor = '';
}
}
// CUSTOM: end
// 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];
}
// CUSTOM: begin
else {
retval.type = 'internal';
retval.url = {};
retval.url.protocol = '';
retval.url.url = '';
retval.internal_anchor = '';
}
// CUSTOM: end
}
// 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' );
advAttr( 'advCSSClasses', 'class' );
advAttr( 'advCharset', 'charset' );
advAttr( 'advStyles', 'style' );
advAttr( 'advRel', 'rel' );
}
// Find out whether we have any anchors in the editor.
// Get all IMG elements in CK document.
var elements = editor.document.getElementsByTag( 'img' ),
realAnchors = new CKEDITOR.dom.nodeList( editor.document.$.anchors ),
anchors = retval.anchors = [];
for ( var i = 0; i < elements.count() ; i++ )
{
var item = elements.getItem( i );
if ( item.data( 'cke-realelement' ) && item.data( 'cke-real-element-type' ) == 'anchor' )
anchors.push( editor.restoreRealElement( item ) );
}
for ( i = 0 ; i < realAnchors.count() ; i++ )
anchors.push( realAnchors.getItem( i ) );
for ( i = 0 ; i < anchors.length ; i++ )
{
item = anchors[ i ];
anchors[ i ] = { name : item.getAttribute( 'name' ), id : item.getAttribute( 'id' ) };
}
// Record down the selected element in the dialog.
this._.selectedElement = element;
return retval;
};
var infoTab = dialogDefinition.getContents( 'info' );
var linkType = infoTab.get('linkType');
linkType['items'].unshift( ['Internal Web Page', 'internal'] );
linkType['default'] = 'internal';
linkType['onChange'] = linkTypeChanged;
infoTab.add(
{
type : 'vbox',
id : 'internalOptions',
children :
[
{
type : 'select',
id : 'internal_page',
label : 'Internal Page Name',
items : [
[ '' ]
],
onChange: function ( ) {
// place internal page ID from this dropdown into URL field of the dialog
var dialog = this.getDialog();
this.allowOnChange = false;
dialog.getContentElement('info', 'url').setValue( this.getValue() );
this.allowOnChange = true;
load_page_anchors( this.getValue(), dialog );
},
setup : function( data ) {
var $me = this;
var $link_url = data.url ? data.url.url : '';
var $ajax_url = CKEDITOR.basePath.replace( /core.*$/, 'admin/index.php?events[fck]=OnLoadCmsTree' );
var $internal_page_anchors = this.getDialog().getContentElement( 'info', 'internalPageAnchors' );
$('#' + $internal_page_anchors.domId).data('anchor', data.internal_anchor);
$.ajax(
{
type: 'GET',
url: $ajax_url,
async: false,
success: function ($xml) {
$me.allowOnChange = false;
$me.clear();
$me.add( '' );
$('CmsPage', $xml).each(
function ($i) {
var $node = $(this);
var cms_id = $node.attr('st_id');
var cms_page = $node.attr('path');
var real_url = $node.attr('real_url');
$internal_page_mapping[cms_page] = real_url;
$me.add( $node.attr('title').replace(/&amp;/g, '&') , cms_page );
if ( $link_url && $link_url.match(cms_page + '$') ) {
$me.setValue(cms_page);
load_page_anchors( cms_page, $me.getDialog() );
}
}
);
// undo CKEditor default "htmlspecialchars" on all HTML
$('option', '#' + $me.domId).each(
function ($index) {
var $option = $(this),
$level_indicator = '&mdash;',
$html = $option.html().replace(/&amp;/g, '&'),
$level = ($html.length - $html.replace(new RegExp($level_indicator, 'g'), '').length ) / $level_indicator.length;
if ( $html.match(/^(.*?) (.*?) (\(.*?\))$/) ) {
// "&mdash;&mdash; rss (news/rss.html)"
$level_indicator = RegExp.$1;
var $page_name = RegExp.$2,
$page_url = RegExp.$3;
$html = $level_indicator + ' ' + $page_name + ' ' + $page_url;
}
$option.html($html);
}
);
$me.allowOnChange = true;
$me.getDialog().layout();
},
dataType: 'xml'
}
);
var linkType = this.getDialog().getContentElement( 'info', 'linkType' );
if ( linkType && linkType.getValue() == 'internal' ) {
this.focus();
}
},
},
{
type : 'select',
id : 'internalPageAnchors',
label : 'Select an Anchor',
items : [
[ '' ]
],
commit : function( data ) {
data.internal_anchor = this.getValue();
this.allowOnChange = false;
}
}
]
}
);
dialogDefinition['onShow'] = function() {
this.fakeObj = false;
var editor = this.getParentEditor(),
selection = editor.getSelection(),
element = null;
// Fill in all the relevant fields if there's already one link selected.
if ( ( element = plugin.getSelectedLink( editor ) ) && element.hasAttribute( 'href' ) )
selection.selectElement( element );
else if ( ( element = selection.getSelectedElement() ) && element.is( 'img' )
&& element.data( 'cke-real-element-type' )
&& element.data( 'cke-real-element-type' ) == 'anchor' )
{
this.fakeObj = element;
element = editor.restoreRealElement( this.fakeObj );
selection.selectElement( this.fakeObj );
}
else
element = null;
this.setupContent( parseLink.apply( this, [ editor, element ] ) );
};
dialogDefinition['onOk'] = function() {
var attributes = {},
removeAttributes = [],
data = {},
me = this,
editor = this.getParentEditor();
this.commitContent( data );
// Compose the URL.
switch ( data.type || 'internal' )
{
// CUSTOM: begin
case 'internal':
var url = ( data.url && data.url.url ) || '';
var anchor = data.internal_anchor || '';
attributes[ 'data-cke-saved-href' ] = url;
if ( anchor ) {
attributes[ 'data-cke-saved-href' ] += '#' + anchor;
}
break;
// CUSTOM: end
case 'url':
var protocol = ( data.url && data.url.protocol != undefined ) ? data.url.protocol : 'http://',
url = ( data.url && data.url.url ) || '';
attributes[ 'data-cke-saved-href' ] = ( url.indexOf( '/' ) === 0 ) ? url : protocol + url;
break;
case 'anchor':
var name = ( data.anchor && data.anchor.name ),
id = ( data.anchor && data.anchor.id );
attributes[ 'data-cke-saved-href' ] = '#' + ( name || id || '' );
break;
case 'email':
var linkHref,
email = data.email,
address = email.address,
emailProtection = editor.config.emailProtection || '';
switch( emailProtection )
{
case '' :
case 'encode' :
{
var subject = encodeURIComponent( email.subject || '' ),
body = encodeURIComponent( email.body || '' );
// Build the e-mail parameters first.
var argList = [];
subject && argList.push( 'subject=' + subject );
body && argList.push( 'body=' + body );
argList = argList.length ? '?' + argList.join( '&' ) : '';
if ( emailProtection == 'encode' )
{
linkHref = [ 'javascript:void(location.href=\'mailto:\'+',
protectEmailAddressAsEncodedString( address ) ];
// parameters are optional.
argList && linkHref.push( '+\'', escapeSingleQuote( argList ), '\'' );
linkHref.push( ')' );
}
else
linkHref = [ 'mailto:', address, argList ];
break;
}
default :
{
// Separating name and domain.
var nameAndDomain = address.split( '@', 2 );
email.name = nameAndDomain[ 0 ];
email.domain = nameAndDomain[ 1 ];
linkHref = [ 'javascript:', protectEmailLinkAsFunction( email ) ];
}
}
attributes[ 'data-cke-saved-href' ] = linkHref.join( '' );
break;
}
// Popups and target.
if ( data.target )
{
if ( data.target.type == 'popup' )
{
var onclickList = [ 'window.open(this.href, \'',
data.target.name || '', '\', \'' ];
var featureList = [ 'resizable', 'status', 'location', 'toolbar', 'menubar', 'fullscreen',
'scrollbars', 'dependent' ];
var featureLength = featureList.length;
var addFeature = function( featureName )
{
if ( data.target[ featureName ] )
featureList.push( featureName + '=' + data.target[ featureName ] );
};
for ( var i = 0 ; i < featureLength ; i++ )
featureList[i] = featureList[i] + ( data.target[ featureList[i] ] ? '=yes' : '=no' ) ;
addFeature( 'width' );
addFeature( 'left' );
addFeature( 'height' );
addFeature( 'top' );
onclickList.push( featureList.join( ',' ), '\'); return false;' );
attributes[ 'data-cke-pa-onclick' ] = onclickList.join( '' );
// Add the "target" attribute. (#5074)
removeAttributes.push( 'target' );
}
else
{
if ( data.target.type != 'notSet' && data.target.name )
attributes.target = data.target.name;
else
removeAttributes.push( 'target' );
removeAttributes.push( 'data-cke-pa-onclick', 'onclick' );
}
}
// Advanced attributes.
if ( data.adv )
{
var advAttr = function( inputName, attrName )
{
var value = data.adv[ inputName ];
if ( value )
attributes[attrName] = value;
else
removeAttributes.push( attrName );
};
advAttr( 'advId', 'id' );
advAttr( 'advLangDir', 'dir' );
advAttr( 'advAccessKey', 'accessKey' );
if ( data.adv[ 'advName' ] )
{
attributes[ 'name' ] = attributes[ 'data-cke-saved-name' ] = data.adv[ 'advName' ];
attributes[ 'class' ] = ( attributes[ 'class' ] ? attributes[ 'class' ] + ' ' : '' ) + 'cke_anchor';
}
else
removeAttributes = removeAttributes.concat( [ 'data-cke-saved-name', 'name' ] );
advAttr( 'advLangCode', 'lang' );
advAttr( 'advTabIndex', 'tabindex' );
advAttr( 'advTitle', 'title' );
advAttr( 'advContentType', 'type' );
advAttr( 'advCSSClasses', 'class' );
advAttr( 'advCharset', 'charset' );
advAttr( 'advStyles', 'style' );
advAttr( 'advRel', 'rel' );
}
+ var selection = editor.getSelection();
// Browser need the "href" fro copy/paste link to work. (#6641)
- attributes.href = attributes[ 'data-cke-saved-href' ];
+ attributes.href = attributes['data-cke-saved-href'];
- if ( !this._.selectedElement )
- {
- // Create element if current selection is collapsed.
- var selection = editor.getSelection(),
- ranges = selection.getRanges( true );
- if ( ranges.length == 1 && ranges[0].collapsed )
- {
+ if ( !this._.selectedElement ) {
+ var range = selection.getRanges(1)[0];
+
+ // Use link URL as text with a collapsed cursor.
+ if ( range.collapsed ) {
// Short mailto link text view (#5736).
- var text = new CKEDITOR.dom.text( data.type == 'email' ?
- data.email.address : attributes[ 'data-cke-saved-href' ], editor.document );
- ranges[0].insertNode( text );
- ranges[0].selectNodeContents( text );
- selection.selectRanges( ranges );
+ var text = new CKEDITOR.dom.text(data.type == 'email' ? data.email.address : attributes['data-cke-saved-href'], editor.document);
+ range.insertNode(text);
+ range.selectNodeContents(text);
}
// Apply style.
- var style = new CKEDITOR.style( { element : 'a', attributes : attributes } );
- style.type = CKEDITOR.STYLE_INLINE; // need to override... dunno why.
- style.apply( editor.document );
+ var style = new CKEDITOR.style({element: 'a', attributes: attributes});
+ style.type = CKEDITOR.STYLE_INLINE; // need to override... dunno why.
+ style.applyToRange(range);
+ range.select();
}
- else
- {
+ else {
// We're only editing an existing link, so just overwrite the attributes.
var element = this._.selectedElement,
- href = element.data( 'cke-saved-href' ),
+ href = element.data('cke-saved-href'),
textView = element.getHtml();
- // IE BUG: Setting the name attribute to an existing link doesn't work.
- // Must re-create the link from weired syntax to workaround.
- if ( CKEDITOR.env.ie && !( CKEDITOR.document.$.documentMode >= 8 ) && attributes.name != element.getAttribute( 'name' ) )
- {
- var newElement = new CKEDITOR.dom.element( '<a name="' + CKEDITOR.tools.htmlEncode( attributes.name ) + '">',
- editor.document );
+ element.setAttributes(attributes);
+ element.removeAttributes(removeAttributes);
- selection = editor.getSelection();
-
- element.copyAttributes( newElement, { name : 1 } );
- element.moveChildren( newElement );
- newElement.replace( element );
- element = newElement;
-
- selection.selectElement( element );
+ if ( data.adv && data.adv.advName && CKEDITOR.plugins.link.synAnchorSelector ) {
+ element.addClass(element.getChildCount() ? 'cke_anchor' : 'cke_anchor_empty');
}
- element.setAttributes( attributes );
- element.removeAttributes( removeAttributes );
// Update text view when user changes protocol (#4612).
- if ( href == textView || data.type == 'email' && textView.indexOf( '@' ) != -1 )
- {
+ if ( href == textView || data.type == 'email' && textView.indexOf('@') != -1 ) {
// Short mailto link text view (#5736).
- element.setHtml( data.type == 'email' ?
- data.email.address : attributes[ 'data-cke-saved-href' ] );
+ element.setHtml(data.type == 'email' ? data.email.address : attributes['data-cke-saved-href']);
}
- // Make the element display as an anchor if a name has been set.
- if ( element.getAttribute( 'name' ) )
- element.addClass( 'cke_anchor' );
- else
- element.removeClass( 'cke_anchor' );
-
- if ( this.fakeObj )
- editor.createFakeElement( element, 'cke_anchor', 'anchor' ).replace( this.fakeObj );
+ selection.selectElement(element);
delete this._.selectedElement;
}
};
}
}
);
}
)();

Event Timeline