X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=_source%2Fplugins%2Flink%2Fdialogs%2Flink.js;h=c7388ca639efad04b417e2349785a9e4f68305dc;hb=refs%2Ftags%2Fv3.2;hp=8d4e74b5d1ee029bb49632a0f57cf7086504912b;hpb=941b0a9ba4e673e292510d80a5a86806994b8ea6;p=ckeditor.git
diff --git a/_source/plugins/link/dialogs/link.js b/_source/plugins/link/dialogs/link.js
index 8d4e74b..c7388ca 100644
--- a/_source/plugins/link/dialogs/link.js
+++ b/_source/plugins/link/dialogs/link.js
@@ -17,18 +17,26 @@ CKEDITOR.dialog.add( 'link', function( editor )
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;
+ }
- if ( value == 'popup' )
- {
- popupFeatures.show();
- targetName.setLabel( editor.lang.link.targetPopupName );
- }
- else
- {
- popupFeatures.hide();
- targetName.setLabel( editor.lang.link.targetFrameName );
- this.getDialog().setValueOf( 'target', 'linkTargetName', value.charAt( 0 ) == '_' ? value : '' );
- }
};
// Handles the event when the "Type" selection box is changed.
@@ -69,11 +77,12 @@ CKEDITOR.dialog.add( 'link', function( editor )
};
// Loads the parameters in a selected link to the link dialog fields.
- var emailRegex = /^mailto:([^?]+)(?:\?(.+))?$/,
+ var javascriptProtocolRegex = /^javascript:/,
+ emailRegex = /^mailto:([^?]+)(?:\?(.+))?$/,
emailSubjectRegex = /subject=([^;?:@&=$,\/]*)/,
emailBodyRegex = /body=([^;?:@&=$,\/]*)/,
anchorRegex = /^#(.*)$/,
- urlRegex = /^(?!javascript)((?:http|https|ftp|news):\/\/)?(.*)$/,
+ urlRegex = /^((?:http|https|ftp|news):\/\/)?(.*)$/,
selectableTargets = /^(_(?:self|top|parent|blank))$/,
encodedEmailLinkRegex = /^javascript:void\(location\.href='mailto:'\+String\.fromCharCode\(([^)]+)\)(?:\+'(.*)')?\)$/,
functionCallProtectedEmailLinkRegex = /^javascript:([^(]+)\(([^)]+)\)$/;
@@ -85,29 +94,15 @@ CKEDITOR.dialog.add( 'link', function( editor )
var parseLink = function( editor, element )
{
var href = element ? ( element.getAttribute( '_cke_saved_href' ) || element.getAttribute( 'href' ) ) : '',
+ javascriptMatch,
emailMatch,
anchorMatch,
urlMatch,
retval = {};
- if ( ( anchorMatch = href.match( anchorRegex ) ) )
+ if ( ( javascriptMatch = href.match( javascriptProtocolRegex ) ) )
{
- retval.type = 'anchor';
- retval.anchor = {};
- retval.anchor.name = retval.anchor.id = anchorMatch[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];
- }
- // Protected email link as encoded string.
- else if ( !emailProtection || emailProtection == 'encode' )
- {
- if( emailProtection == 'encode' )
+ if ( emailProtection == 'encode' )
{
href = href.replace( encodedEmailLinkRegex,
function ( match, protectedAddress, rest )
@@ -115,12 +110,47 @@ CKEDITOR.dialog.add( 'link', function( editor )
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;
- emailMatch = href.match( emailRegex );
+ 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( emailMatch )
+ 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 );
@@ -131,36 +161,17 @@ CKEDITOR.dialog.add( 'link', function( editor )
subjectMatch && ( email.subject = decodeURIComponent( subjectMatch[ 1 ] ) );
bodyMatch && ( email.body = decodeURIComponent( bodyMatch[ 1 ] ) );
}
- }
- // Protected email link as function call.
- else if( emailProtection )
- {
- href.replace( functionCallProtectedEmailLinkRegex, function( match, funcName, funcArgs )
+ // urlRegex matches empty strings, so need to check for href as well.
+ else if ( href && ( urlMatch = href.match( urlRegex ) ) )
{
- 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( '@' );
- }
- } );
+ retval.type = 'url';
+ retval.url = {};
+ retval.url.protocol = urlMatch[1];
+ retval.url.url = urlMatch[2];
+ }
+ else
+ retval.type = 'url';
}
- else
- retval.type = 'url';
// Load target and popup settings.
if ( element )
@@ -227,7 +238,7 @@ CKEDITOR.dialog.add( 'link', function( editor )
realAnchors = new CKEDITOR.dom.nodeList( editor.document.$.anchors ),
anchors = retval.anchors = [];
- for( var i = 0; i < elements.count() ; i++ )
+ for ( var i = 0; i < elements.count() ; i++ )
{
var item = elements.getItem( i );
if ( item.getAttribute( '_cke_realelement' ) && item.getAttribute( '_cke_real_element_type' ) == 'anchor' )
@@ -298,7 +309,7 @@ CKEDITOR.dialog.add( 'link', function( editor )
var emailProtection = editor.config.emailProtection || '';
// Compile the protection function pattern.
- if( emailProtection && emailProtection != 'encode' )
+ if ( emailProtection && emailProtection != 'encode' )
{
var compiledProtectionFunction = {};
@@ -369,7 +380,7 @@ CKEDITOR.dialog.add( 'link', function( editor )
'default' : 'url',
items :
[
- [ editor.lang.common.url, 'url' ],
+ [ editor.lang.link.toUrl, 'url' ],
[ editor.lang.link.toAnchor, 'anchor' ],
[ editor.lang.link.toEmail, 'email' ]
],
@@ -425,6 +436,7 @@ CKEDITOR.dialog.add( 'link', function( editor )
type : 'text',
id : 'url',
label : editor.lang.common.url,
+ required: true,
onLoad : function ()
{
this.allowOnChange = true;
@@ -474,13 +486,13 @@ CKEDITOR.dialog.add( 'link', function( editor )
this.setValue( data.url.url );
this.allowOnChange = true;
- var linkType = this.getDialog().getContentElement( 'info', 'linkType' );
- if ( linkType && linkType.getValue() == 'url' )
- this.select();
-
},
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 = {};
@@ -513,105 +525,110 @@ CKEDITOR.dialog.add( 'link', function( editor )
children :
[
{
- type : 'html',
+ type : 'fieldset',
id : 'selectAnchorText',
- html : CKEDITOR.tools.htmlEncode( editor.lang.link.selectAnchor ),
+ label : editor.lang.link.selectAnchor,
setup : function( data )
{
if ( data.anchors.length > 0 )
this.getElement().show();
else
this.getElement().hide();
- }
- },
- {
- type : 'html',
- id : 'noAnchors',
- style : 'text-align: center;',
- html : '
' + CKEDITOR.tools.htmlEncode( editor.lang.link.noAnchors ) + '
',
- setup : function( data )
- {
- if ( data.anchors.length < 1 )
- this.getElement().show();
- else
- this.getElement().hide();
- }
- },
- {
- type : 'hbox',
- id : 'selectAnchor',
+ },
children :
[
{
- type : 'select',
- id : 'anchorName',
- 'default' : '',
- label : editor.lang.link.anchorName,
- style : 'width: 100%;',
- items :
+ type : 'hbox',
+ id : 'selectAnchor',
+ children :
[
- [ '' ]
- ],
- 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 );
+ type : 'select',
+ id : 'anchorName',
+ 'default' : '',
+ label : editor.lang.link.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 : editor.lang.link.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();
+ }
}
-
- 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 : editor.lang.link.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();
+ if ( data.anchors.length > 0 )
+ this.getElement().show();
+ else
+ this.getElement().hide();
}
}
- ],
+ ]
+ },
+ {
+ type : 'html',
+ id : 'noAnchors',
+ style : 'text-align: center;',
+ html : '' + CKEDITOR.tools.htmlEncode( editor.lang.link.noAnchors ) + '
',
+ // Focus the first element defined in above html.
+ focus : true,
setup : function( data )
{
- if ( data.anchors.length > 0 )
+ if ( data.anchors.length < 1 )
this.getElement().show();
else
this.getElement().hide();
@@ -634,6 +651,7 @@ CKEDITOR.dialog.add( 'link', function( editor )
type : 'text',
id : 'emailAddress',
label : editor.lang.link.emailAddress,
+ required : true,
validate : function()
{
var dialog = this.getDialog();
@@ -721,18 +739,18 @@ CKEDITOR.dialog.add( 'link', function( editor )
{
type : 'select',
id : 'linkTargetType',
- label : editor.lang.link.target,
+ label : editor.lang.common.target,
'default' : 'notSet',
style : 'width : 100%;',
'items' :
[
- [ editor.lang.link.targetNotSet, 'notSet' ],
+ [ editor.lang.common.notSet, 'notSet' ],
[ editor.lang.link.targetFrame, 'frame' ],
[ editor.lang.link.targetPopup, 'popup' ],
- [ editor.lang.link.targetNew, '_blank' ],
- [ editor.lang.link.targetTop, '_top' ],
- [ editor.lang.link.targetSelf, '_self' ],
- [ editor.lang.link.targetParent, '_parent' ]
+ [ editor.lang.common.targetNew, '_blank' ],
+ [ editor.lang.common.targetTop, '_top' ],
+ [ editor.lang.common.targetSelf, '_self' ],
+ [ editor.lang.common.targetParent, '_parent' ]
],
onChange : targetChanged,
setup : function( data )
@@ -777,145 +795,148 @@ CKEDITOR.dialog.add( 'link', function( editor )
children :
[
{
- type : 'html',
- html : CKEDITOR.tools.htmlEncode( editor.lang.link.popupFeatures )
- },
- {
- type : 'hbox',
+ type : 'fieldset',
+ label : editor.lang.link.popupFeatures,
children :
[
{
- type : 'checkbox',
- id : 'resizable',
- label : editor.lang.link.popupResizable,
- setup : setupPopupParams,
- commit : commitPopupParams
- },
- {
- type : 'checkbox',
- id : 'status',
- label : editor.lang.link.popupStatusBar,
- setup : setupPopupParams,
- commit : commitPopupParams
-
- }
- ]
- },
- {
- type : 'hbox',
- children :
- [
- {
- type : 'checkbox',
- id : 'location',
- label : editor.lang.link.popupLocationBar,
- setup : setupPopupParams,
- commit : commitPopupParams
+ type : 'hbox',
+ children :
+ [
+ {
+ type : 'checkbox',
+ id : 'resizable',
+ label : editor.lang.link.popupResizable,
+ setup : setupPopupParams,
+ commit : commitPopupParams
+ },
+ {
+ type : 'checkbox',
+ id : 'status',
+ label : editor.lang.link.popupStatusBar,
+ setup : setupPopupParams,
+ commit : commitPopupParams
+ }
+ ]
},
{
- type : 'checkbox',
- id : 'toolbar',
- label : editor.lang.link.popupToolbar,
- setup : setupPopupParams,
- commit : commitPopupParams
+ type : 'hbox',
+ children :
+ [
+ {
+ type : 'checkbox',
+ id : 'location',
+ label : editor.lang.link.popupLocationBar,
+ setup : setupPopupParams,
+ commit : commitPopupParams
- }
- ]
- },
- {
- type : 'hbox',
- children :
- [
- {
- type : 'checkbox',
- id : 'menubar',
- label : editor.lang.link.popupMenuBar,
- setup : setupPopupParams,
- commit : commitPopupParams
+ },
+ {
+ type : 'checkbox',
+ id : 'toolbar',
+ label : editor.lang.link.popupToolbar,
+ setup : setupPopupParams,
+ commit : commitPopupParams
+ }
+ ]
},
{
- type : 'checkbox',
- id : 'fullscreen',
- label : editor.lang.link.popupFullScreen,
- setup : setupPopupParams,
- commit : commitPopupParams
+ type : 'hbox',
+ children :
+ [
+ {
+ type : 'checkbox',
+ id : 'menubar',
+ label : editor.lang.link.popupMenuBar,
+ setup : setupPopupParams,
+ commit : commitPopupParams
- }
- ]
- },
- {
- type : 'hbox',
- children :
- [
- {
- type : 'checkbox',
- id : 'scrollbars',
- label : editor.lang.link.popupScrollBars,
- setup : setupPopupParams,
- commit : commitPopupParams
+ },
+ {
+ type : 'checkbox',
+ id : 'fullscreen',
+ label : editor.lang.link.popupFullScreen,
+ setup : setupPopupParams,
+ commit : commitPopupParams
+ }
+ ]
},
{
- type : 'checkbox',
- id : 'dependent',
- label : editor.lang.link.popupDependent,
- setup : setupPopupParams,
- commit : commitPopupParams
+ type : 'hbox',
+ children :
+ [
+ {
+ type : 'checkbox',
+ id : 'scrollbars',
+ label : editor.lang.link.popupScrollBars,
+ setup : setupPopupParams,
+ commit : commitPopupParams
- }
- ]
- },
- {
- type : 'hbox',
- children :
- [
- {
- type : 'text',
- widths : [ '30%', '70%' ],
- labelLayout : 'horizontal',
- label : editor.lang.link.popupWidth,
- id : 'width',
- setup : setupPopupParams,
- commit : commitPopupParams
+ },
+ {
+ type : 'checkbox',
+ id : 'dependent',
+ label : editor.lang.link.popupDependent,
+ setup : setupPopupParams,
+ commit : commitPopupParams
+ }
+ ]
},
{
- type : 'text',
- labelLayout : 'horizontal',
- widths : [ '55%', '45%' ],
- label : editor.lang.link.popupLeft,
- id : 'left',
- setup : setupPopupParams,
- commit : commitPopupParams
-
- }
- ]
- },
- {
- type : 'hbox',
- children :
- [
- {
- type : 'text',
- labelLayout : 'horizontal',
- widths : [ '30%', '70%' ],
- label : editor.lang.link.popupHeight,
- id : 'height',
- setup : setupPopupParams,
- commit : commitPopupParams
+ type : 'hbox',
+ children :
+ [
+ {
+ type : 'text',
+ widths : [ '30%', '70%' ],
+ labelLayout : 'horizontal',
+ label : editor.lang.link.popupWidth,
+ id : 'width',
+ setup : setupPopupParams,
+ commit : commitPopupParams
+
+ },
+ {
+ type : 'text',
+ labelLayout : 'horizontal',
+ widths : [ '55%', '45%' ],
+ label : editor.lang.link.popupLeft,
+ id : 'left',
+ setup : setupPopupParams,
+ commit : commitPopupParams
+ }
+ ]
},
{
- type : 'text',
- labelLayout : 'horizontal',
- label : editor.lang.link.popupTop,
- widths : [ '55%', '45%' ],
- id : 'top',
- setup : setupPopupParams,
- commit : commitPopupParams
+ type : 'hbox',
+ children :
+ [
+ {
+ type : 'text',
+ labelLayout : 'horizontal',
+ widths : [ '30%', '70%' ],
+ label : editor.lang.link.popupHeight,
+ id : 'height',
+ setup : setupPopupParams,
+ commit : commitPopupParams
+
+ },
+ {
+ type : 'text',
+ labelLayout : 'horizontal',
+ label : editor.lang.link.popupTop,
+ widths : [ '55%', '45%' ],
+ id : 'top',
+ setup : setupPopupParams,
+ commit : commitPopupParams
+ }
+ ]
}
]
}
@@ -978,7 +999,7 @@ CKEDITOR.dialog.add( 'link', function( editor )
style : 'width:110px',
items :
[
- [ editor.lang.link.langDirNotSet, '' ],
+ [ editor.lang.common.notSet, '' ],
[ editor.lang.link.langDirLTR, 'ltr' ],
[ editor.lang.link.langDirRTL, 'rtl' ]
],
@@ -1312,7 +1333,9 @@ CKEDITOR.dialog.add( 'link', function( editor )
else
{
// We're only editing an existing link, so just overwrite the attributes.
- var element = this._.selectedElement;
+ var element = this._.selectedElement,
+ href = element.getAttribute( '_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.
@@ -1333,7 +1356,9 @@ CKEDITOR.dialog.add( 'link', function( editor )
element.setAttributes( attributes );
element.removeAttributes( removeAttributes );
-
+ // Update text view when user changes protocol #4612.
+ if (href == textView)
+ element.setHtml( attributes._cke_saved_href );
// Make the element display as an anchor if a name has been set.
if ( element.getAttribute( 'name' ) )
element.addClass( 'cke_anchor' );
@@ -1354,26 +1379,43 @@ CKEDITOR.dialog.add( 'link', function( editor )
if ( !editor.config.linkShowTargetTab )
this.hidePage( 'target' ); //Hide Target tab.
+ },
+ // Inital focus on 'url' field if link is of type URL.
+ onFocus : function()
+ {
+ var linkType = this.getContentElement( 'info', 'linkType' ),
+ urlField;
+ if ( linkType && linkType.getValue( ) == 'url' )
+ {
+ urlField = this.getContentElement( 'info', 'url' );
+ urlField.select();
+ }
}
};
});
/**
- * The e-mail address anti-spam protection option.
+ * The e-mail address anti-spam protection option. The protection will be
+ * applied when creating or modifying e-mail links through the editor interface.
+ * Two methods of protection can be choosed:
+ * - The e-mail parts (name, domain and any other query string) are
+ * assembled into a function call pattern. Such function must be
+ * provided by the developer in the pages that will use the contents.
+ *
- Only the e-mail address is obfuscated into a special string that
+ * has no meaning for humans or spam bots, but which is properly
+ * rendered and accepted by the browser.
+ * Both approaches require JavaScript to be enabled.
* @name CKEDITOR.config.emailProtection
- * @type {String}
- * Two forms of protection could be choosed from :
- * 1. The whole address parts ( name, domain with any other query string ) are assembled into a
- * function call pattern which invoke you own provided function, with the specified arguments.
- * 2. Only the e-mail address is obfuscated into unicode code point sequences, replacement are
- * done by a String.fromCharCode() call.
- * Note: Both approaches require JavaScript to be enabled.
- * @default ''
+ * @since 3.1
+ * @type String
+ * @default '' (empty string = disabled)
+ * @example
+ * // href="mailto:tester@ckeditor.com?subject=subject&body=body"
+ * config.emailProtection = '';
+ * @example
+ * // href="e-mail"
+ * config.emailProtection = 'encode';
* @example
- * config.emailProtection = '';
- * // href="mailto:tester@ckeditor.com?subject=subject&body=body"
- * config.emailProtection = 'encode';
- * // href="e-mail"
- * config.emailProtection = 'mt(NAME,DOMAIN,SUBJECT,BODY)';
- * // href="javascript:mt('tester','ckeditor.com','subject','body')"
+ * // href="javascript:mt('tester','ckeditor.com','subject','body')"
+ * config.emailProtection = 'mt(NAME,DOMAIN,SUBJECT,BODY)';
*/