PageRenderTime 50ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/clientscript/ckeplugins/vblink/dialogs/link.js

https://gitlab.com/elasa/vb-elasa.ir
JavaScript | 1426 lines | 698 code | 91 blank | 637 comment | 145 complexity | e3383ac83b04fe1ca5a41a0a7101c909 MD5 | raw file
  1. /*
  2. Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
  3. For licensing, see LICENSE.html or http://ckeditor.com/license
  4. */
  5. CKEDITOR.dialog.add( 'link', function( editor )
  6. {
  7. var plugin = CKEDITOR.plugins.vblink;
  8. // Handles the event when the "Target" selection box is changed.
  9. var targetChanged = function()
  10. {
  11. var dialog = this.getDialog(),
  12. popupFeatures = dialog.getContentElement( 'target', 'popupFeatures' ),
  13. targetName = dialog.getContentElement( 'target', 'linkTargetName' ),
  14. value = this.getValue();
  15. if ( !popupFeatures || !targetName )
  16. return;
  17. popupFeatures = popupFeatures.getElement();
  18. popupFeatures.hide();
  19. targetName.setValue( '' );
  20. switch ( value )
  21. {
  22. case 'frame' :
  23. targetName.setLabel( editor.lang.link.targetFrameName );
  24. targetName.getElement().show();
  25. break;
  26. case 'popup' :
  27. popupFeatures.show();
  28. targetName.setLabel( editor.lang.link.targetPopupName );
  29. targetName.getElement().show();
  30. break;
  31. default :
  32. targetName.setValue( value );
  33. targetName.getElement().hide();
  34. break;
  35. }
  36. };
  37. // Handles the event when the "Type" selection box is changed.
  38. var linkTypeChanged = function()
  39. {
  40. var dialog = this.getDialog(),
  41. partIds = [ 'urlOptions', 'anchorOptions', 'emailOptions' ],
  42. typeValue = this.getValue(),
  43. uploadTab = dialog.definition.getContents( 'upload' ),
  44. uploadInitiallyHidden = uploadTab && uploadTab.hidden;
  45. if ( typeValue == 'url' )
  46. {
  47. if ( editor.config.linkShowTargetTab )
  48. dialog.showPage( 'target' );
  49. if ( !uploadInitiallyHidden )
  50. dialog.showPage( 'upload' );
  51. }
  52. else
  53. {
  54. dialog.hidePage( 'target' );
  55. if ( !uploadInitiallyHidden )
  56. dialog.hidePage( 'upload' );
  57. }
  58. for ( var i = 0 ; i < partIds.length ; i++ )
  59. {
  60. var element = dialog.getContentElement( 'info', partIds[i] );
  61. if ( !element )
  62. continue;
  63. element = element.getElement().getParent().getParent();
  64. if ( partIds[i] == typeValue + 'Options' )
  65. element.show();
  66. else
  67. element.hide();
  68. }
  69. dialog.layout();
  70. };
  71. // Loads the parameters in a selected link to the link dialog fields.
  72. var javascriptProtocolRegex = /^javascript:/,
  73. emailRegex = /^mailto:([^?]+)(?:\?(.+))?$/,
  74. emailSubjectRegex = /subject=([^;?:@&=$,\/]*)/,
  75. emailBodyRegex = /body=([^;?:@&=$,\/]*)/,
  76. anchorRegex = /^#(.*)$/,
  77. urlRegex = /^((?:http|https|ftp|news):\/\/)?(.*)$/,
  78. selectableTargets = /^(_(?:self|top|parent|blank))$/,
  79. encodedEmailLinkRegex = /^javascript:void\(location\.href='mailto:'\+String\.fromCharCode\(([^)]+)\)(?:\+'(.*)')?\)$/,
  80. functionCallProtectedEmailLinkRegex = /^javascript:([^(]+)\(([^)]+)\)$/;
  81. var popupRegex =
  82. /\s*window.open\(\s*this\.href\s*,\s*(?:'([^']*)'|null)\s*,\s*'([^']*)'\s*\)\s*;\s*return\s*false;*\s*/;
  83. var popupFeaturesRegex = /(?:^|,)([^=]+)=(\d+|yes|no)/gi;
  84. var parseLink = function( editor, element )
  85. {
  86. var href = ( element && ( element.data( 'cke-saved-href' ) || element.getAttribute( 'href' ) ) ) || '',
  87. javascriptMatch,
  88. emailMatch,
  89. anchorMatch,
  90. urlMatch,
  91. retval = {};
  92. if ( ( javascriptMatch = href.match( javascriptProtocolRegex ) ) )
  93. {
  94. if ( emailProtection == 'encode' )
  95. {
  96. href = href.replace( encodedEmailLinkRegex,
  97. function ( match, protectedAddress, rest )
  98. {
  99. return 'mailto:' +
  100. String.fromCharCode.apply( String, protectedAddress.split( ',' ) ) +
  101. ( rest && unescapeSingleQuote( rest ) );
  102. });
  103. }
  104. // Protected email link as function call.
  105. else if ( emailProtection )
  106. {
  107. href.replace( functionCallProtectedEmailLinkRegex, function( match, funcName, funcArgs )
  108. {
  109. if ( funcName == compiledProtectionFunction.name )
  110. {
  111. retval.type = 'email';
  112. var email = retval.email = {};
  113. var paramRegex = /[^,\s]+/g,
  114. paramQuoteRegex = /(^')|('$)/g,
  115. paramsMatch = funcArgs.match( paramRegex ),
  116. paramsMatchLength = paramsMatch.length,
  117. paramName,
  118. paramVal;
  119. for ( var i = 0; i < paramsMatchLength; i++ )
  120. {
  121. paramVal = decodeURIComponent( unescapeSingleQuote( paramsMatch[ i ].replace( paramQuoteRegex, '' ) ) );
  122. paramName = compiledProtectionFunction.params[ i ].toLowerCase();
  123. email[ paramName ] = paramVal;
  124. }
  125. email.address = [ email.name, email.domain ].join( '@' );
  126. }
  127. } );
  128. }
  129. }
  130. if ( !retval.type )
  131. {
  132. if ( ( anchorMatch = href.match( anchorRegex ) ) )
  133. {
  134. retval.type = 'anchor';
  135. retval.anchor = {};
  136. retval.anchor.name = retval.anchor.id = anchorMatch[1];
  137. }
  138. // Protected email link as encoded string.
  139. else if ( ( emailMatch = href.match( emailRegex ) ) )
  140. {
  141. var subjectMatch = href.match( emailSubjectRegex ),
  142. bodyMatch = href.match( emailBodyRegex );
  143. retval.type = 'email';
  144. var email = ( retval.email = {} );
  145. email.address = emailMatch[ 1 ];
  146. subjectMatch && ( email.subject = decodeURIComponent( subjectMatch[ 1 ] ) );
  147. bodyMatch && ( email.body = decodeURIComponent( bodyMatch[ 1 ] ) );
  148. }
  149. // urlRegex matches empty strings, so need to check for href as well.
  150. else if ( href && ( urlMatch = href.match( urlRegex ) ) )
  151. {
  152. retval.type = 'url';
  153. retval.url = {};
  154. retval.url.protocol = urlMatch[1];
  155. retval.url.url = urlMatch[2];
  156. }
  157. else
  158. retval.type = 'url';
  159. }
  160. // Load target and popup settings.
  161. if ( element )
  162. {
  163. var target = element.getAttribute( 'target' );
  164. retval.target = {};
  165. retval.adv = {};
  166. // IE BUG: target attribute is an empty string instead of null in IE if it's not set.
  167. if ( !target )
  168. {
  169. var onclick = element.data( 'cke-pa-onclick' ) || element.getAttribute( 'onclick' ),
  170. onclickMatch = onclick && onclick.match( popupRegex );
  171. if ( onclickMatch )
  172. {
  173. retval.target.type = 'popup';
  174. retval.target.name = onclickMatch[1];
  175. var featureMatch;
  176. while ( ( featureMatch = popupFeaturesRegex.exec( onclickMatch[2] ) ) )
  177. {
  178. // Some values should remain numbers (#7300)
  179. if ( ( featureMatch[2] == 'yes' || featureMatch[2] == '1' ) && !( featureMatch[1] in { height:1, width:1, top:1, left:1 } ) )
  180. retval.target[ featureMatch[1] ] = true;
  181. else if ( isFinite( featureMatch[2] ) )
  182. retval.target[ featureMatch[1] ] = featureMatch[2];
  183. }
  184. }
  185. }
  186. else
  187. {
  188. var targetMatch = target.match( selectableTargets );
  189. if ( targetMatch )
  190. retval.target.type = retval.target.name = target;
  191. else
  192. {
  193. retval.target.type = 'frame';
  194. retval.target.name = target;
  195. }
  196. }
  197. var me = this;
  198. var advAttr = function( inputName, attrName )
  199. {
  200. var value = element.getAttribute( attrName );
  201. if ( value !== null )
  202. retval.adv[ inputName ] = value || '';
  203. };
  204. advAttr( 'advId', 'id' );
  205. advAttr( 'advLangDir', 'dir' );
  206. advAttr( 'advAccessKey', 'accessKey' );
  207. retval.adv.advName =
  208. element.data( 'cke-saved-name' )
  209. || element.getAttribute( 'name' )
  210. || '';
  211. advAttr( 'advLangCode', 'lang' );
  212. advAttr( 'advTabIndex', 'tabindex' );
  213. advAttr( 'advTitle', 'title' );
  214. advAttr( 'advContentType', 'type' );
  215. CKEDITOR.plugins.vblink.synAnchorSelector ?
  216. retval.adv.advCSSClasses = getLinkClass( element )
  217. : advAttr( 'advCSSClasses', 'class' );
  218. advAttr( 'advCharset', 'charset' );
  219. advAttr( 'advStyles', 'style' );
  220. advAttr( 'advRel', 'rel' );
  221. }
  222. // Find out whether we have any anchors in the editor.
  223. var anchors = retval.anchors = [],
  224. item;
  225. // For some browsers we set contenteditable="false" on anchors, making document.anchors not to include them, so we must traverse the links manually (#7893).
  226. if ( CKEDITOR.plugins.vblink.emptyAnchorFix )
  227. {
  228. var links = editor.document.getElementsByTag( 'a' );
  229. for ( i = 0, count = links.count(); i < count; i++ )
  230. {
  231. item = links.getItem( i );
  232. if ( item.data( 'cke-saved-name' ) || item.hasAttribute( 'name' ) )
  233. anchors.push( { name : item.data( 'cke-saved-name' ) || item.getAttribute( 'name' ), id : item.getAttribute( 'id' ) } );
  234. }
  235. }
  236. else
  237. {
  238. var anchorList = new CKEDITOR.dom.nodeList( editor.document.$.anchors );
  239. for ( var i = 0, count = anchorList.count(); i < count; i++ )
  240. {
  241. item = anchorList.getItem( i );
  242. anchors[ i ] = { name : item.getAttribute( 'name' ), id : item.getAttribute( 'id' ) };
  243. }
  244. }
  245. if ( CKEDITOR.plugins.vblink.fakeAnchor )
  246. {
  247. var imgs = editor.document.getElementsByTag( 'img' );
  248. for ( i = 0, count = imgs.count(); i < count; i++ )
  249. {
  250. if ( ( item = CKEDITOR.plugins.vblink.tryRestoreFakeAnchor( editor, imgs.getItem( i ) ) ) )
  251. anchors.push( { name : item.getAttribute( 'name' ), id : item.getAttribute( 'id' ) } );
  252. }
  253. }
  254. // Record down the selected element in the dialog.
  255. this._.selectedElement = element;
  256. return retval;
  257. };
  258. var setupParams = function( page, data )
  259. {
  260. if ( data[page] )
  261. this.setValue( data[page][this.id] || '' );
  262. };
  263. var setupPopupParams = function( data )
  264. {
  265. return setupParams.call( this, 'target', data );
  266. };
  267. var setupAdvParams = function( data )
  268. {
  269. return setupParams.call( this, 'adv', data );
  270. };
  271. var commitParams = function( page, data )
  272. {
  273. if ( !data[page] )
  274. data[page] = {};
  275. data[page][this.id] = this.getValue() || '';
  276. };
  277. var commitPopupParams = function( data )
  278. {
  279. return commitParams.call( this, 'target', data );
  280. };
  281. var commitAdvParams = function( data )
  282. {
  283. return commitParams.call( this, 'adv', data );
  284. };
  285. function unescapeSingleQuote( str )
  286. {
  287. return str.replace( /\\'/g, '\'' );
  288. }
  289. function escapeSingleQuote( str )
  290. {
  291. return str.replace( /'/g, '\\$&' );
  292. }
  293. var emailProtection = editor.config.emailProtection || '';
  294. // Compile the protection function pattern.
  295. if ( emailProtection && emailProtection != 'encode' )
  296. {
  297. var compiledProtectionFunction = {};
  298. emailProtection.replace( /^([^(]+)\(([^)]+)\)$/, function( match, funcName, params )
  299. {
  300. compiledProtectionFunction.name = funcName;
  301. compiledProtectionFunction.params = [];
  302. params.replace( /[^,\s]+/g, function( param )
  303. {
  304. compiledProtectionFunction.params.push( param );
  305. } );
  306. } );
  307. }
  308. function protectEmailLinkAsFunction( email )
  309. {
  310. var retval,
  311. name = compiledProtectionFunction.name,
  312. params = compiledProtectionFunction.params,
  313. paramName,
  314. paramValue;
  315. retval = [ name, '(' ];
  316. for ( var i = 0; i < params.length; i++ )
  317. {
  318. paramName = params[ i ].toLowerCase();
  319. paramValue = email[ paramName ];
  320. i > 0 && retval.push( ',' );
  321. retval.push( '\'',
  322. paramValue ?
  323. escapeSingleQuote( encodeURIComponent( email[ paramName ] ) )
  324. : '',
  325. '\'');
  326. }
  327. retval.push( ')' );
  328. return retval.join( '' );
  329. }
  330. function protectEmailAddressAsEncodedString( address )
  331. {
  332. var charCode,
  333. length = address.length,
  334. encodedChars = [];
  335. for ( var i = 0; i < length; i++ )
  336. {
  337. charCode = address.charCodeAt( i );
  338. encodedChars.push( charCode );
  339. }
  340. return 'String.fromCharCode(' + encodedChars.join( ',' ) + ')';
  341. }
  342. function getLinkClass( ele )
  343. {
  344. var className = ele.getAttribute( 'class' );
  345. return className ? className.replace( /\s*(?:cke_anchor_empty|cke_anchor)(?:\s*$)?/g, '' ) : '';
  346. }
  347. var commonLang = editor.lang.common,
  348. linkLang = editor.lang.link;
  349. return {
  350. title : linkLang.title,
  351. minWidth : 350,
  352. minHeight : 230,
  353. contents : [
  354. {
  355. id : 'info',
  356. label : linkLang.info,
  357. title : linkLang.info,
  358. elements :
  359. [
  360. {
  361. id : 'linkType',
  362. type : 'select',
  363. label : linkLang.type,
  364. 'default' : 'url',
  365. items :
  366. [
  367. [ linkLang.toUrl, 'url' ],
  368. /*[ linkLang.toAnchor, 'anchor' ],*/
  369. [ linkLang.toEmail, 'email' ]
  370. ],
  371. onChange : linkTypeChanged,
  372. setup : function( data )
  373. {
  374. if ( data.type )
  375. this.setValue( data.type );
  376. },
  377. commit : function( data )
  378. {
  379. data.type = this.getValue();
  380. }
  381. },
  382. {
  383. type : 'vbox',
  384. id : 'urlOptions',
  385. children :
  386. [
  387. {
  388. type : 'hbox',
  389. widths : [ '25%', '75%' ],
  390. children :
  391. [
  392. {
  393. id : 'protocol',
  394. type : 'select',
  395. label : commonLang.protocol,
  396. 'default' : 'http://',
  397. items :
  398. [
  399. // Force 'ltr' for protocol names in BIDI. (#5433)
  400. [ 'http://\u200E', 'http://' ],
  401. [ 'https://\u200E', 'https://' ],
  402. [ 'ftp://\u200E', 'ftp://' ],
  403. [ 'news://\u200E', 'news://' ],
  404. [ linkLang.other , '' ]
  405. ],
  406. setup : function( data )
  407. {
  408. if ( data.url )
  409. this.setValue( data.url.protocol || '' );
  410. },
  411. commit : function( data )
  412. {
  413. if ( !data.url )
  414. data.url = {};
  415. data.url.protocol = this.getValue();
  416. }
  417. },
  418. {
  419. type : 'text',
  420. id : 'url',
  421. label : commonLang.url,
  422. required: true,
  423. onLoad : function ()
  424. {
  425. this.allowOnChange = true;
  426. },
  427. onKeyUp : function()
  428. {
  429. this.allowOnChange = false;
  430. var protocolCmb = this.getDialog().getContentElement( 'info', 'protocol' ),
  431. url = this.getValue(),
  432. urlOnChangeProtocol = /^(http|https|ftp|news):\/\/(?=.)/i,
  433. urlOnChangeTestOther = /^((javascript:)|[#\/\.\?])/i;
  434. var protocol = urlOnChangeProtocol.exec( url );
  435. if ( protocol )
  436. {
  437. this.setValue( url.substr( protocol[ 0 ].length ) );
  438. protocolCmb.setValue( protocol[ 0 ].toLowerCase() );
  439. }
  440. else if ( urlOnChangeTestOther.test( url ) )
  441. protocolCmb.setValue( '' );
  442. this.allowOnChange = true;
  443. },
  444. onChange : function()
  445. {
  446. if ( this.allowOnChange ) // Dont't call on dialog load.
  447. this.onKeyUp();
  448. },
  449. validate : function()
  450. {
  451. var dialog = this.getDialog();
  452. if ( dialog.getContentElement( 'info', 'linkType' ) &&
  453. dialog.getValueOf( 'info', 'linkType' ) != 'url' )
  454. return true;
  455. if ( this.getDialog().fakeObj ) // Edit Anchor.
  456. return true;
  457. var func = CKEDITOR.dialog.validate.notEmpty( linkLang.noUrl );
  458. return func.apply( this );
  459. },
  460. setup : function( data )
  461. {
  462. this.allowOnChange = false;
  463. if ( data.url )
  464. this.setValue( data.url.url );
  465. this.allowOnChange = true;
  466. },
  467. commit : function( data )
  468. {
  469. // IE will not trigger the onChange event if the mouse has been used
  470. // to carry all the operations #4724
  471. this.onChange();
  472. if ( !data.url )
  473. data.url = {};
  474. data.url.url = this.getValue();
  475. this.allowOnChange = false;
  476. }
  477. }
  478. ],
  479. setup : function( data )
  480. {
  481. if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
  482. this.getElement().show();
  483. }
  484. },
  485. {
  486. type : 'button',
  487. id : 'browse',
  488. hidden : 'true',
  489. filebrowser : 'info:url',
  490. label : commonLang.browseServer
  491. }
  492. ]
  493. }/*,
  494. {
  495. type : 'vbox',
  496. id : 'anchorOptions',
  497. width : 260,
  498. align : 'center',
  499. padding : 0,
  500. children :
  501. [
  502. {
  503. type : 'fieldset',
  504. id : 'selectAnchorText',
  505. label : linkLang.selectAnchor,
  506. setup : function( data )
  507. {
  508. if ( data.anchors.length > 0 )
  509. this.getElement().show();
  510. else
  511. this.getElement().hide();
  512. },
  513. children :
  514. [
  515. {
  516. type : 'hbox',
  517. id : 'selectAnchor',
  518. children :
  519. [
  520. {
  521. type : 'select',
  522. id : 'anchorName',
  523. 'default' : '',
  524. label : linkLang.anchorName,
  525. style : 'width: 100%;',
  526. items :
  527. [
  528. [ '' ]
  529. ],
  530. setup : function( data )
  531. {
  532. this.clear();
  533. this.add( '' );
  534. for ( var i = 0 ; i < data.anchors.length ; i++ )
  535. {
  536. if ( data.anchors[i].name )
  537. this.add( data.anchors[i].name );
  538. }
  539. if ( data.anchor )
  540. this.setValue( data.anchor.name );
  541. var linkType = this.getDialog().getContentElement( 'info', 'linkType' );
  542. if ( linkType && linkType.getValue() == 'email' )
  543. this.focus();
  544. },
  545. commit : function( data )
  546. {
  547. if ( !data.anchor )
  548. data.anchor = {};
  549. data.anchor.name = this.getValue();
  550. }
  551. },
  552. {
  553. type : 'select',
  554. id : 'anchorId',
  555. 'default' : '',
  556. label : linkLang.anchorId,
  557. style : 'width: 100%;',
  558. items :
  559. [
  560. [ '' ]
  561. ],
  562. setup : function( data )
  563. {
  564. this.clear();
  565. this.add( '' );
  566. for ( var i = 0 ; i < data.anchors.length ; i++ )
  567. {
  568. if ( data.anchors[i].id )
  569. this.add( data.anchors[i].id );
  570. }
  571. if ( data.anchor )
  572. this.setValue( data.anchor.id );
  573. },
  574. commit : function( data )
  575. {
  576. if ( !data.anchor )
  577. data.anchor = {};
  578. data.anchor.id = this.getValue();
  579. }
  580. }
  581. ],
  582. setup : function( data )
  583. {
  584. if ( data.anchors.length > 0 )
  585. this.getElement().show();
  586. else
  587. this.getElement().hide();
  588. }
  589. }
  590. ]
  591. },
  592. {
  593. type : 'html',
  594. id : 'noAnchors',
  595. style : 'text-align: center;',
  596. html : '<div role="label" tabIndex="-1">' + CKEDITOR.tools.htmlEncode( linkLang.noAnchors ) + '</div>',
  597. // Focus the first element defined in above html.
  598. focus : true,
  599. setup : function( data )
  600. {
  601. if ( data.anchors.length < 1 )
  602. this.getElement().show();
  603. else
  604. this.getElement().hide();
  605. }
  606. }
  607. ],
  608. setup : function( data )
  609. {
  610. if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
  611. this.getElement().hide();
  612. }
  613. }*/,
  614. {
  615. type : 'vbox',
  616. id : 'emailOptions',
  617. padding : 1,
  618. children :
  619. [
  620. {
  621. type : 'text',
  622. id : 'emailAddress',
  623. label : linkLang.emailAddress,
  624. required : true,
  625. validate : function()
  626. {
  627. var dialog = this.getDialog();
  628. if ( !dialog.getContentElement( 'info', 'linkType' ) ||
  629. dialog.getValueOf( 'info', 'linkType' ) != 'email' )
  630. return true;
  631. var func = CKEDITOR.dialog.validate.notEmpty( linkLang.noEmail );
  632. return func.apply( this );
  633. },
  634. setup : function( data )
  635. {
  636. if ( data.email )
  637. this.setValue( data.email.address );
  638. var linkType = this.getDialog().getContentElement( 'info', 'linkType' );
  639. if ( linkType && linkType.getValue() == 'email' )
  640. this.select();
  641. },
  642. commit : function( data )
  643. {
  644. if ( !data.email )
  645. data.email = {};
  646. data.email.address = this.getValue();
  647. }
  648. }/*,
  649. {
  650. type : 'text',
  651. id : 'emailSubject',
  652. label : linkLang.emailSubject,
  653. setup : function( data )
  654. {
  655. if ( data.email )
  656. this.setValue( data.email.subject );
  657. },
  658. commit : function( data )
  659. {
  660. if ( !data.email )
  661. data.email = {};
  662. data.email.subject = this.getValue();
  663. }
  664. },
  665. {
  666. type : 'textarea',
  667. id : 'emailBody',
  668. label : linkLang.emailBody,
  669. rows : 3,
  670. 'default' : '',
  671. setup : function( data )
  672. {
  673. if ( data.email )
  674. this.setValue( data.email.body );
  675. },
  676. commit : function( data )
  677. {
  678. if ( !data.email )
  679. data.email = {};
  680. data.email.body = this.getValue();
  681. }
  682. }*/
  683. ],
  684. setup : function( data )
  685. {
  686. if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
  687. this.getElement().hide();
  688. }
  689. }
  690. ]
  691. }/*,
  692. {
  693. id : 'target',
  694. label : linkLang.target,
  695. title : linkLang.target,
  696. elements :
  697. [
  698. {
  699. type : 'hbox',
  700. widths : [ '50%', '50%' ],
  701. children :
  702. [
  703. {
  704. type : 'select',
  705. id : 'linkTargetType',
  706. label : commonLang.target,
  707. 'default' : 'notSet',
  708. style : 'width : 100%;',
  709. 'items' :
  710. [
  711. [ commonLang.notSet, 'notSet' ],
  712. [ linkLang.targetFrame, 'frame' ],
  713. [ linkLang.targetPopup, 'popup' ],
  714. [ commonLang.targetNew, '_blank' ],
  715. [ commonLang.targetTop, '_top' ],
  716. [ commonLang.targetSelf, '_self' ],
  717. [ commonLang.targetParent, '_parent' ]
  718. ],
  719. onChange : targetChanged,
  720. setup : function( data )
  721. {
  722. if ( data.target )
  723. this.setValue( data.target.type || 'notSet' );
  724. targetChanged.call( this );
  725. },
  726. commit : function( data )
  727. {
  728. if ( !data.target )
  729. data.target = {};
  730. data.target.type = this.getValue();
  731. }
  732. },
  733. {
  734. type : 'text',
  735. id : 'linkTargetName',
  736. label : linkLang.targetFrameName,
  737. 'default' : '',
  738. setup : function( data )
  739. {
  740. if ( data.target )
  741. this.setValue( data.target.name );
  742. },
  743. commit : function( data )
  744. {
  745. if ( !data.target )
  746. data.target = {};
  747. data.target.name = this.getValue().replace(/\W/gi, '');
  748. }
  749. }
  750. ]
  751. },
  752. {
  753. type : 'vbox',
  754. width : '100%',
  755. align : 'center',
  756. padding : 2,
  757. id : 'popupFeatures',
  758. children :
  759. [
  760. {
  761. type : 'fieldset',
  762. label : linkLang.popupFeatures,
  763. children :
  764. [
  765. {
  766. type : 'hbox',
  767. children :
  768. [
  769. {
  770. type : 'checkbox',
  771. id : 'resizable',
  772. label : linkLang.popupResizable,
  773. setup : setupPopupParams,
  774. commit : commitPopupParams
  775. },
  776. {
  777. type : 'checkbox',
  778. id : 'status',
  779. label : linkLang.popupStatusBar,
  780. setup : setupPopupParams,
  781. commit : commitPopupParams
  782. }
  783. ]
  784. },
  785. {
  786. type : 'hbox',
  787. children :
  788. [
  789. {
  790. type : 'checkbox',
  791. id : 'location',
  792. label : linkLang.popupLocationBar,
  793. setup : setupPopupParams,
  794. commit : commitPopupParams
  795. },
  796. {
  797. type : 'checkbox',
  798. id : 'toolbar',
  799. label : linkLang.popupToolbar,
  800. setup : setupPopupParams,
  801. commit : commitPopupParams
  802. }
  803. ]
  804. },
  805. {
  806. type : 'hbox',
  807. children :
  808. [
  809. {
  810. type : 'checkbox',
  811. id : 'menubar',
  812. label : linkLang.popupMenuBar,
  813. setup : setupPopupParams,
  814. commit : commitPopupParams
  815. },
  816. {
  817. type : 'checkbox',
  818. id : 'fullscreen',
  819. label : linkLang.popupFullScreen,
  820. setup : setupPopupParams,
  821. commit : commitPopupParams
  822. }
  823. ]
  824. },
  825. {
  826. type : 'hbox',
  827. children :
  828. [
  829. {
  830. type : 'checkbox',
  831. id : 'scrollbars',
  832. label : linkLang.popupScrollBars,
  833. setup : setupPopupParams,
  834. commit : commitPopupParams
  835. },
  836. {
  837. type : 'checkbox',
  838. id : 'dependent',
  839. label : linkLang.popupDependent,
  840. setup : setupPopupParams,
  841. commit : commitPopupParams
  842. }
  843. ]
  844. },
  845. {
  846. type : 'hbox',
  847. children :
  848. [
  849. {
  850. type : 'text',
  851. widths : [ '50%', '50%' ],
  852. labelLayout : 'horizontal',
  853. label : commonLang.width,
  854. id : 'width',
  855. setup : setupPopupParams,
  856. commit : commitPopupParams
  857. },
  858. {
  859. type : 'text',
  860. labelLayout : 'horizontal',
  861. widths : [ '50%', '50%' ],
  862. label : linkLang.popupLeft,
  863. id : 'left',
  864. setup : setupPopupParams,
  865. commit : commitPopupParams
  866. }
  867. ]
  868. },
  869. {
  870. type : 'hbox',
  871. children :
  872. [
  873. {
  874. type : 'text',
  875. labelLayout : 'horizontal',
  876. widths : [ '50%', '50%' ],
  877. label : commonLang.height,
  878. id : 'height',
  879. setup : setupPopupParams,
  880. commit : commitPopupParams
  881. },
  882. {
  883. type : 'text',
  884. labelLayout : 'horizontal',
  885. label : linkLang.popupTop,
  886. widths : [ '50%', '50%' ],
  887. id : 'top',
  888. setup : setupPopupParams,
  889. commit : commitPopupParams
  890. }
  891. ]
  892. }
  893. ]
  894. }
  895. ]
  896. }
  897. ]
  898. },
  899. {
  900. id : 'upload',
  901. label : linkLang.upload,
  902. title : linkLang.upload,
  903. hidden : true,
  904. filebrowser : 'uploadButton',
  905. elements :
  906. [
  907. {
  908. type : 'file',
  909. id : 'upload',
  910. label : commonLang.upload,
  911. style: 'height:40px',
  912. size : 29
  913. },
  914. {
  915. type : 'fileButton',
  916. id : 'uploadButton',
  917. label : commonLang.uploadSubmit,
  918. filebrowser : 'info:url',
  919. 'for' : [ 'upload', 'upload' ]
  920. }
  921. ]
  922. },
  923. {
  924. id : 'advanced',
  925. label : linkLang.advanced,
  926. title : linkLang.advanced,
  927. elements :
  928. [
  929. {
  930. type : 'vbox',
  931. padding : 1,
  932. children :
  933. [
  934. {
  935. type : 'hbox',
  936. widths : [ '45%', '35%', '20%' ],
  937. children :
  938. [
  939. {
  940. type : 'text',
  941. id : 'advId',
  942. label : linkLang.id,
  943. setup : setupAdvParams,
  944. commit : commitAdvParams
  945. },
  946. {
  947. type : 'select',
  948. id : 'advLangDir',
  949. label : linkLang.langDir,
  950. 'default' : '',
  951. style : 'width:110px',
  952. items :
  953. [
  954. [ commonLang.notSet, '' ],
  955. [ linkLang.langDirLTR, 'ltr' ],
  956. [ linkLang.langDirRTL, 'rtl' ]
  957. ],
  958. setup : setupAdvParams,
  959. commit : commitAdvParams
  960. },
  961. {
  962. type : 'text',
  963. id : 'advAccessKey',
  964. width : '80px',
  965. label : linkLang.acccessKey,
  966. maxLength : 1,
  967. setup : setupAdvParams,
  968. commit : commitAdvParams
  969. }
  970. ]
  971. },
  972. {
  973. type : 'hbox',
  974. widths : [ '45%', '35%', '20%' ],
  975. children :
  976. [
  977. {
  978. type : 'text',
  979. label : linkLang.name,
  980. id : 'advName',
  981. setup : setupAdvParams,
  982. commit : commitAdvParams
  983. },
  984. {
  985. type : 'text',
  986. label : linkLang.langCode,
  987. id : 'advLangCode',
  988. width : '110px',
  989. 'default' : '',
  990. setup : setupAdvParams,
  991. commit : commitAdvParams
  992. },
  993. {
  994. type : 'text',
  995. label : linkLang.tabIndex,
  996. id : 'advTabIndex',
  997. width : '80px',
  998. maxLength : 5,
  999. setup : setupAdvParams,
  1000. commit : commitAdvParams
  1001. }
  1002. ]
  1003. }
  1004. ]
  1005. },
  1006. {
  1007. type : 'vbox',
  1008. padding : 1,
  1009. children :
  1010. [
  1011. {
  1012. type : 'hbox',
  1013. widths : [ '45%', '55%' ],
  1014. children :
  1015. [
  1016. {
  1017. type : 'text',
  1018. label : linkLang.advisoryTitle,
  1019. 'default' : '',
  1020. id : 'advTitle',
  1021. setup : setupAdvParams,
  1022. commit : commitAdvParams
  1023. },
  1024. {
  1025. type : 'text',
  1026. label : linkLang.advisoryContentType,
  1027. 'default' : '',
  1028. id : 'advContentType',
  1029. setup : setupAdvParams,
  1030. commit : commitAdvParams
  1031. }
  1032. ]
  1033. },
  1034. {
  1035. type : 'hbox',
  1036. widths : [ '45%', '55%' ],
  1037. children :
  1038. [
  1039. {
  1040. type : 'text',
  1041. label : linkLang.cssClasses,
  1042. 'default' : '',
  1043. id : 'advCSSClasses',
  1044. setup : setupAdvParams,
  1045. commit : commitAdvParams
  1046. },
  1047. {
  1048. type : 'text',
  1049. label : linkLang.charset,
  1050. 'default' : '',
  1051. id : 'advCharset',
  1052. setup : setupAdvParams,
  1053. commit : commitAdvParams
  1054. }
  1055. ]
  1056. },
  1057. {
  1058. type : 'hbox',
  1059. widths : [ '45%', '55%' ],
  1060. children :
  1061. [
  1062. {
  1063. type : 'text',
  1064. label : linkLang.rel,
  1065. 'default' : '',
  1066. id : 'advRel',
  1067. setup : setupAdvParams,
  1068. commit : commitAdvParams
  1069. },
  1070. {
  1071. type : 'text',
  1072. label : linkLang.styles,
  1073. 'default' : '',
  1074. id : 'advStyles',
  1075. validate : CKEDITOR.dialog.validate.inlineStyle( editor.lang.common.invalidInlineStyle ),
  1076. setup : setupAdvParams,
  1077. commit : commitAdvParams
  1078. }
  1079. ]
  1080. }
  1081. ]
  1082. }
  1083. ]
  1084. }*/
  1085. ],
  1086. onShow : function()
  1087. {
  1088. var editor = this.getParentEditor(),
  1089. selection = editor.getSelection(),
  1090. element = null;
  1091. // Fill in all the relevant fields if there's already one link selected.
  1092. if ( ( element = plugin.getSelectedLink( editor ) ) && element.hasAttribute( 'href' ) )
  1093. selection.selectElement( element );
  1094. else
  1095. element = null;
  1096. this.setupContent( parseLink.apply( this, [ editor, element ] ) );
  1097. },
  1098. onOk : function()
  1099. {
  1100. var attributes = {},
  1101. removeAttributes = [],
  1102. data = {},
  1103. me = this,
  1104. editor = this.getParentEditor();
  1105. this.commitContent( data );
  1106. // Compose the URL.
  1107. switch ( data.type || 'url' )
  1108. {
  1109. case 'url':
  1110. var protocol = ( data.url && data.url.protocol != undefined ) ? data.url.protocol : 'http://',
  1111. url = ( data.url && CKEDITOR.tools.trim( data.url.url ) ) || '';
  1112. attributes[ 'data-cke-saved-href' ] = ( url.indexOf( '/' ) === 0 ) ? url : protocol + url;
  1113. break;
  1114. case 'anchor':
  1115. var name = ( data.anchor && data.anchor.name ),
  1116. id = ( data.anchor && data.anchor.id );
  1117. attributes[ 'data-cke-saved-href' ] = '#' + ( name || id || '' );
  1118. break;
  1119. case 'email':
  1120. var linkHref,
  1121. email = data.email,
  1122. address = email.address;
  1123. switch( emailProtection )
  1124. {
  1125. case '' :
  1126. case 'encode' :
  1127. {
  1128. var subject = encodeURIComponent( email.subject || '' ),
  1129. body = encodeURIComponent( email.body || '' );
  1130. // Build the e-mail parameters first.
  1131. var argList = [];
  1132. subject && argList.push( 'subject=' + subject );
  1133. body && argList.push( 'body=' + body );
  1134. argList = argList.length ? '?' + argList.join( '&' ) : '';
  1135. if ( emailProtection == 'encode' )
  1136. {
  1137. linkHref = [ 'javascript:void(location.href=\'mailto:\'+',
  1138. protectEmailAddressAsEncodedString( address ) ];
  1139. // parameters are optional.
  1140. argList && linkHref.push( '+\'', escapeSingleQuote( argList ), '\'' );
  1141. linkHref.push( ')' );
  1142. }
  1143. else
  1144. linkHref = [ 'mailto:', address, argList ];
  1145. break;
  1146. }
  1147. default :
  1148. {
  1149. // Separating name and domain.
  1150. var nameAndDomain = address.split( '@', 2 );
  1151. email.name = nameAndDomain[ 0 ];
  1152. email.domain = nameAndDomain[ 1 ];
  1153. linkHref = [ 'javascript:', protectEmailLinkAsFunction( email ) ];
  1154. }
  1155. }
  1156. attributes[ 'data-cke-saved-href' ] = linkHref.join( '' );
  1157. break;
  1158. }
  1159. // Popups and target.
  1160. if ( data.target )
  1161. {
  1162. if ( data.target.type == 'popup' )
  1163. {
  1164. var onclickList = [ 'window.open(this.href, \'',
  1165. data.target.name || '', '\', \'' ];
  1166. var featureList = [ 'resizable', 'status', 'location', 'toolbar', 'menubar', 'fullscreen',
  1167. 'scrollbars', 'dependent' ];
  1168. var featureLength = featureList.length;
  1169. var addFeature = function( featureName )
  1170. {
  1171. if ( data.target[ featureName ] )
  1172. featureList.push( featureName + '=' + data.target[ featureName ] );
  1173. };
  1174. for ( var i = 0 ; i < featureLength ; i++ )
  1175. featureList[i] = featureList[i] + ( data.target[ featureList[i] ] ? '=yes' : '=no' ) ;
  1176. addFeature( 'width' );
  1177. addFeature( 'left' );
  1178. addFeature( 'height' );
  1179. addFeature( 'top' );
  1180. onclickList.push( featureList.join( ',' ), '\'); return false;' );
  1181. attributes[ 'data-cke-pa-onclick' ] = onclickList.join( '' );
  1182. // Add the "target" attribute. (#5074)
  1183. removeAttributes.push( 'target' );
  1184. }
  1185. else
  1186. {
  1187. if ( data.target.type != 'notSet' && data.target.name )
  1188. attributes.target = data.target.name;
  1189. else
  1190. removeAttributes.push( 'target' );
  1191. removeAttributes.push( 'data-cke-pa-onclick', 'onclick' );
  1192. }
  1193. }
  1194. // Advanced attributes.
  1195. if ( data.adv )
  1196. {
  1197. var advAttr = function( inputName, attrName )
  1198. {
  1199. var value = data.adv[ inputName ];
  1200. if ( value )
  1201. attributes[attrName] = value;
  1202. else
  1203. removeAttributes.push( attrName );
  1204. };
  1205. advAttr( 'advId', 'id' );
  1206. advAttr( 'advLangDir', 'dir' );
  1207. advAttr( 'advAccessKey', 'accessKey' );
  1208. if ( data.adv[ 'advName' ] )
  1209. attributes[ 'name' ] = attributes[ 'data-cke-saved-name' ] = data.adv[ 'advName' ];
  1210. else
  1211. removeAttributes = removeAttributes.concat( [ 'data-cke-saved-name', 'name' ] );
  1212. advAttr( 'advLangCode', 'lang' );
  1213. advAttr( 'advTabIndex', 'tabindex' );
  1214. advAttr( 'advTitle', 'title' );
  1215. advAttr( 'advContentType', 'type' );
  1216. advAttr( 'advCSSClasses', 'class' );
  1217. advAttr( 'advCharset', 'charset' );
  1218. advAttr( 'advStyles', 'style' );
  1219. advAttr( 'advRel', 'rel' );
  1220. }
  1221. // Browser need the "href" fro copy/paste link to work. (#6641)
  1222. attributes.href = attributes[ 'data-cke-saved-href' ];
  1223. if ( !this._.selectedElement )
  1224. {
  1225. // Create element if current selection is collapsed.
  1226. var selection = editor.getSelection(),
  1227. ranges = selection.getRanges( true );
  1228. if ( ranges.length == 1 && ranges[0].collapsed )
  1229. {
  1230. // Short mailto link text view (#5736).
  1231. var text = new CKEDITOR.dom.text( data.type == 'email' ?
  1232. data.email.address : attributes[ 'data-cke-saved-href' ], editor.document );
  1233. ranges[0].insertNode( text );
  1234. ranges[0].selectNodeContents( text );
  1235. selection.selectRanges( ranges );
  1236. }
  1237. // Apply style.
  1238. var style = new CKEDITOR.style( { element : 'a', attributes : attributes } );
  1239. style.type = CKEDITOR.STYLE_INLINE; // need to override... dunno why.
  1240. style.apply( editor.document );
  1241. }
  1242. else
  1243. {
  1244. // We're only editing an existing link, so just overwrite the attributes.
  1245. var element = this._.selectedElement,
  1246. href = element.data( 'cke-saved-href' ),
  1247. textView = element.getHtml();
  1248. element.setAttributes( attributes );
  1249. element.removeAttributes( removeAttributes );
  1250. if ( data.adv && data.adv.advName && CKEDITOR.plugins.vblink.synAnchorSelector )
  1251. element.addClass( element.getChildCount() ? 'cke_anchor' : 'cke_anchor_empty' );
  1252. // Update text view when user changes protocol (#4612).
  1253. if ( href == textView || data.type == 'email' && textView.indexOf( '@' ) != -1 )
  1254. {
  1255. // Short mailto link text view (#5736).
  1256. element.setHtml( data.type == 'email' ?
  1257. data.email.address : attributes[ 'data-cke-saved-href' ] );
  1258. }
  1259. delete this._.selectedElement;
  1260. }
  1261. },
  1262. onLoad : function()
  1263. {
  1264. if ( !editor.config.linkShowAdvancedTab )
  1265. this.hidePage( 'advanced' ); //Hide Advanded tab.
  1266. if ( !editor.config.linkShowTargetTab )
  1267. this.hidePage( 'target' ); //Hide Target tab.
  1268. },
  1269. // Inital focus on 'url' field if link is of type URL.
  1270. onFocus : function()
  1271. {
  1272. var linkType = this.getContentElement( 'info', 'linkType' ),
  1273. urlField;
  1274. if ( linkType && linkType.getValue() == 'url' )
  1275. {
  1276. urlField = this.getContentElement( 'info', 'url' );
  1277. urlField.select();
  1278. }
  1279. }
  1280. };
  1281. });
  1282. /**
  1283. * The e-mail address anti-spam protection option. The protection will be
  1284. * applied when creating or modifying e-mail links through the editor interface.<br>
  1285. * Two methods of protection can be choosed:
  1286. * <ol> <li>The e-mail parts (name, domain and any other query string) are
  1287. * assembled into a function call pattern. Such function must be
  1288. * provided by the developer in the pages that will use the contents.
  1289. * <li>Only the e-mail address is obfuscated into a special string that
  1290. * has no meaning for humans or spam bots, but which is properly
  1291. * rendered and accepted by the browser.</li></ol>
  1292. * Both approaches require JavaScript to be enabled.
  1293. * @name CKEDITOR.config.emailProtection
  1294. * @since 3.1
  1295. * @type String
  1296. * @default '' (empty string = disabled)
  1297. * @example
  1298. * // href="mailto:tester@ckeditor.com?subject=subject&body=body"
  1299. * config.emailProtection = '';
  1300. * @example
  1301. * // href="<a href=\"javascript:void(location.href=\'mailto:\'+String.fromCharCode(116,101,115,116,101,114,64,99,107,101,100,105,116,111,114,46,99,111,109)+\'?subject=subject&body=body\')\">e-mail</a>"
  1302. * config.emailProtection = 'encode';
  1303. * @example
  1304. * // href="javascript:mt('tester','ckeditor.com','subject','body')"
  1305. * config.emailProtection = 'mt(NAME,DOMAIN,SUBJECT,BODY)';
  1306. */