link.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. /**
  2. * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or http://ckeditor.com/license
  4. */
  5. 'use strict';
  6. ( function() {
  7. CKEDITOR.dialog.add( 'link', function( editor ) {
  8. var plugin = CKEDITOR.plugins.link;
  9. // Handles the event when the "Target" selection box is changed.
  10. var targetChanged = function() {
  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. case 'frame':
  22. targetName.setLabel( editor.lang.link.targetFrameName );
  23. targetName.getElement().show();
  24. break;
  25. case 'popup':
  26. popupFeatures.show();
  27. targetName.setLabel( editor.lang.link.targetPopupName );
  28. targetName.getElement().show();
  29. break;
  30. default:
  31. targetName.setValue( value );
  32. targetName.getElement().hide();
  33. break;
  34. }
  35. };
  36. // Handles the event when the "Type" selection box is changed.
  37. var linkTypeChanged = function() {
  38. var dialog = this.getDialog(),
  39. partIds = [ 'urlOptions', 'anchorOptions', 'emailOptions' ],
  40. typeValue = this.getValue(),
  41. uploadTab = dialog.definition.getContents( 'upload' ),
  42. uploadInitiallyHidden = uploadTab && uploadTab.hidden;
  43. if ( typeValue == 'url' ) {
  44. if ( editor.config.linkShowTargetTab )
  45. dialog.showPage( 'target' );
  46. if ( !uploadInitiallyHidden )
  47. dialog.showPage( 'upload' );
  48. } else {
  49. dialog.hidePage( 'target' );
  50. if ( !uploadInitiallyHidden )
  51. dialog.hidePage( 'upload' );
  52. }
  53. for ( var i = 0; i < partIds.length; i++ ) {
  54. var element = dialog.getContentElement( 'info', partIds[ i ] );
  55. if ( !element )
  56. continue;
  57. element = element.getElement().getParent().getParent();
  58. if ( partIds[ i ] == typeValue + 'Options' )
  59. element.show();
  60. else
  61. element.hide();
  62. }
  63. dialog.layout();
  64. };
  65. var setupParams = function( page, data ) {
  66. if ( data[ page ] )
  67. this.setValue( data[ page ][ this.id ] || '' );
  68. };
  69. var setupPopupParams = function( data ) {
  70. return setupParams.call( this, 'target', data );
  71. };
  72. var setupAdvParams = function( data ) {
  73. return setupParams.call( this, 'advanced', data );
  74. };
  75. var commitParams = function( page, data ) {
  76. if ( !data[ page ] )
  77. data[ page ] = {};
  78. data[ page ][ this.id ] = this.getValue() || '';
  79. };
  80. var commitPopupParams = function( data ) {
  81. return commitParams.call( this, 'target', data );
  82. };
  83. var commitAdvParams = function( data ) {
  84. return commitParams.call( this, 'advanced', data );
  85. };
  86. var commonLang = editor.lang.common,
  87. linkLang = editor.lang.link,
  88. anchors;
  89. return {
  90. title: linkLang.title,
  91. minWidth: 350,
  92. minHeight: 230,
  93. contents: [ {
  94. id: 'info',
  95. label: linkLang.info,
  96. title: linkLang.info,
  97. elements: [ {
  98. id: 'linkType',
  99. type: 'select',
  100. label: linkLang.type,
  101. 'default': 'url',
  102. items: [
  103. [ linkLang.toUrl, 'url' ],
  104. [ linkLang.toAnchor, 'anchor' ],
  105. [ linkLang.toEmail, 'email' ]
  106. ],
  107. onChange: linkTypeChanged,
  108. setup: function( data ) {
  109. this.setValue( data.type || 'url' );
  110. },
  111. commit: function( data ) {
  112. data.type = this.getValue();
  113. }
  114. },
  115. {
  116. type: 'vbox',
  117. id: 'urlOptions',
  118. children: [ {
  119. type: 'hbox',
  120. widths: [ '25%', '75%' ],
  121. children: [ {
  122. id: 'protocol',
  123. type: 'select',
  124. label: commonLang.protocol,
  125. 'default': 'http://',
  126. items: [
  127. // Force 'ltr' for protocol names in BIDI. (#5433)
  128. [ 'http://\u200E', 'http://' ],
  129. [ 'https://\u200E', 'https://' ],
  130. [ 'ftp://\u200E', 'ftp://' ],
  131. [ 'news://\u200E', 'news://' ],
  132. [ '2GIS://\u200E', 'http://www.amic.ru/catalog/?' ],
  133. [ linkLang.other, '' ]
  134. ],
  135. setup: function( data ) {
  136. if ( data.url )
  137. this.setValue( data.url.protocol || '' );
  138. },
  139. commit: function( data ) {
  140. if ( !data.url )
  141. data.url = {};
  142. data.url.protocol = this.getValue();
  143. }
  144. },
  145. {
  146. type: 'text',
  147. id: 'url',
  148. label: commonLang.url,
  149. required: true,
  150. onLoad: function() {
  151. this.allowOnChange = true;
  152. },
  153. onKeyUp: function() {
  154. this.allowOnChange = false;
  155. var protocolCmb = this.getDialog().getContentElement( 'info', 'protocol' ),
  156. url = this.getValue(),
  157. urlOnChangeProtocol = /^(http|https|ftp|news|2GIS):\/\/(?=.)/i,
  158. urlOnChangeTestOther = /^((javascript:)|[#\/\.\?])/i;
  159. var protocol = urlOnChangeProtocol.exec( url );
  160. if ( protocol ) {
  161. this.setValue( url.substr( protocol[ 0 ].length ) );
  162. protocolCmb.setValue( protocol[ 0 ].toLowerCase() );
  163. } else if ( urlOnChangeTestOther.test( url ) ) {
  164. protocolCmb.setValue( '' );
  165. }
  166. this.allowOnChange = true;
  167. },
  168. onChange: function() {
  169. if ( this.allowOnChange ) // Dont't call on dialog load.
  170. this.onKeyUp();
  171. },
  172. validate: function() {
  173. var dialog = this.getDialog();
  174. if ( dialog.getContentElement( 'info', 'linkType' ) && dialog.getValueOf( 'info', 'linkType' ) != 'url' )
  175. return true;
  176. if ( !editor.config.linkJavaScriptLinksAllowed && ( /javascript\:/ ).test( this.getValue() ) ) {
  177. alert( commonLang.invalidValue ); // jshint ignore:line
  178. return false;
  179. }
  180. if ( this.getDialog().fakeObj ) // Edit Anchor.
  181. return true;
  182. var func = CKEDITOR.dialog.validate.notEmpty( linkLang.noUrl );
  183. return func.apply( this );
  184. },
  185. setup: function( data ) {
  186. this.allowOnChange = false;
  187. if ( data.url )
  188. this.setValue( data.url.url );
  189. this.allowOnChange = true;
  190. },
  191. commit: function( data ) {
  192. // IE will not trigger the onChange event if the mouse has been used
  193. // to carry all the operations #4724
  194. this.onChange();
  195. if ( !data.url )
  196. data.url = {};
  197. data.url.url = this.getValue();
  198. this.allowOnChange = false;
  199. }
  200. },
  201. ],
  202. setup: function() {
  203. if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
  204. this.getElement().show();
  205. }
  206. },
  207. {
  208. type: 'hbox',
  209. widths: [ '45%', '55%' ],
  210. align: 'center',
  211. padding: 0,
  212. children: [ {
  213. type: 'checkbox',
  214. label: linkLang.rel,
  215. requiredContent: 'a[rel]',
  216. 'default': false,
  217. id: 'advRel',
  218. setup: setupAdvParams, //commitAdvParams
  219. commit: function( data ) {
  220. return commitParams.call( this, 'advanced', data );
  221. }
  222. },
  223. ]
  224. },
  225. //----
  226. {
  227. id: 'target',
  228. type: 'hbox',
  229. widths: [ '50%', '50%' ],
  230. children: [ {
  231. type: 'select',
  232. id: 'linkTargetType',
  233. requiredContent: 'a[target]',
  234. label: commonLang.target,
  235. 'default': '_blank',
  236. style: 'width : 100%;',
  237. 'items': [
  238. [ commonLang.notSet, 'notSet' ],
  239. [ linkLang.targetFrame, 'frame' ],
  240. [ linkLang.targetPopup, 'popup' ],
  241. [ commonLang.targetNew, '_blank' ],
  242. [ commonLang.targetTop, '_top' ],
  243. [ commonLang.targetSelf, '_self' ],
  244. [ commonLang.targetParent, '_parent' ]
  245. ],
  246. onChange: targetChanged,
  247. setup: function( data ) {
  248. if ( data.target )
  249. this.setValue( data.target.type || 'notSet' );
  250. targetChanged.call( this );
  251. },
  252. commit: function( data ) {
  253. if ( !data.target )
  254. data.target = {};
  255. data.target.type = this.getValue();
  256. }
  257. },
  258. {
  259. type: 'text',
  260. id: 'linkTargetName',
  261. label: linkLang.targetFrameName,
  262. 'default': '_blank',
  263. setup: function( data ) {
  264. if ( data.target )
  265. this.setValue( data.target.name );
  266. },
  267. commit: function( data ) {
  268. if ( !data.target )
  269. data.target = {};
  270. console.log(data);
  271. data.target.name = this.getValue().replace( /\W/gi, '' );
  272. }
  273. } ]
  274. },
  275. //----
  276. {
  277. type: 'button',
  278. id: 'browse',
  279. hidden: 'true',
  280. filebrowser: 'info:url',
  281. label: commonLang.browseServer
  282. } ]
  283. },
  284. {
  285. type: 'vbox',
  286. id: 'anchorOptions',
  287. width: 260,
  288. align: 'center',
  289. padding: 0,
  290. children: [ {
  291. type: 'fieldset',
  292. id: 'selectAnchorText',
  293. label: linkLang.selectAnchor,
  294. setup: function() {
  295. anchors = plugin.getEditorAnchors( editor );
  296. this.getElement()[ anchors && anchors.length ? 'show' : 'hide' ]();
  297. },
  298. children: [ {
  299. type: 'hbox',
  300. id: 'selectAnchor',
  301. children: [ {
  302. type: 'select',
  303. id: 'anchorName',
  304. 'default': '',
  305. label: linkLang.anchorName,
  306. style: 'width: 100%;',
  307. items: [
  308. [ '' ]
  309. ],
  310. setup: function( data ) {
  311. this.clear();
  312. this.add( '' );
  313. if ( anchors ) {
  314. for ( var i = 0; i < anchors.length; i++ ) {
  315. if ( anchors[ i ].name )
  316. this.add( anchors[ i ].name );
  317. }
  318. }
  319. if ( data.anchor )
  320. this.setValue( data.anchor.name );
  321. var linkType = this.getDialog().getContentElement( 'info', 'linkType' );
  322. if ( linkType && linkType.getValue() == 'email' )
  323. this.focus();
  324. },
  325. commit: function( data ) {
  326. if ( !data.anchor )
  327. data.anchor = {};
  328. data.anchor.name = this.getValue();
  329. }
  330. },
  331. {
  332. type: 'select',
  333. id: 'anchorId',
  334. 'default': '',
  335. label: linkLang.anchorId,
  336. style: 'width: 100%;',
  337. items: [
  338. [ '' ]
  339. ],
  340. setup: function( data ) {
  341. this.clear();
  342. this.add( '' );
  343. if ( anchors ) {
  344. for ( var i = 0; i < anchors.length; i++ ) {
  345. if ( anchors[ i ].id )
  346. this.add( anchors[ i ].id );
  347. }
  348. }
  349. if ( data.anchor )
  350. this.setValue( data.anchor.id );
  351. },
  352. commit: function( data ) {
  353. if ( !data.anchor )
  354. data.anchor = {};
  355. data.anchor.id = this.getValue();
  356. }
  357. } ],
  358. setup: function() {
  359. this.getElement()[ anchors && anchors.length ? 'show' : 'hide' ]();
  360. }
  361. } ]
  362. },
  363. {
  364. type: 'html',
  365. id: 'noAnchors',
  366. style: 'text-align: center;',
  367. html: '<div role="note" tabIndex="-1">' + CKEDITOR.tools.htmlEncode( linkLang.noAnchors ) + '</div>',
  368. // Focus the first element defined in above html.
  369. focus: true,
  370. setup: function() {
  371. this.getElement()[ anchors && anchors.length ? 'hide' : 'show' ]();
  372. }
  373. } ],
  374. setup: function() {
  375. if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
  376. this.getElement().hide();
  377. }
  378. },
  379. {
  380. type: 'vbox',
  381. id: 'emailOptions',
  382. padding: 1,
  383. children: [ {
  384. type: 'text',
  385. id: 'emailAddress',
  386. label: linkLang.emailAddress,
  387. required: true,
  388. validate: function() {
  389. var dialog = this.getDialog();
  390. if ( !dialog.getContentElement( 'info', 'linkType' ) || dialog.getValueOf( 'info', 'linkType' ) != 'email' )
  391. return true;
  392. var func = CKEDITOR.dialog.validate.notEmpty( linkLang.noEmail );
  393. return func.apply( this );
  394. },
  395. setup: function( data ) {
  396. if ( data.email )
  397. this.setValue( data.email.address );
  398. var linkType = this.getDialog().getContentElement( 'info', 'linkType' );
  399. if ( linkType && linkType.getValue() == 'email' )
  400. this.select();
  401. },
  402. commit: function( data ) {
  403. if ( !data.email )
  404. data.email = {};
  405. data.email.address = this.getValue();
  406. }
  407. },
  408. {
  409. type: 'text',
  410. id: 'emailSubject',
  411. label: linkLang.emailSubject,
  412. setup: function( data ) {
  413. if ( data.email )
  414. this.setValue( data.email.subject );
  415. },
  416. commit: function( data ) {
  417. if ( !data.email )
  418. data.email = {};
  419. data.email.subject = this.getValue();
  420. }
  421. },
  422. {
  423. type: 'textarea',
  424. id: 'emailBody',
  425. label: linkLang.emailBody,
  426. rows: 3,
  427. 'default': '',
  428. setup: function( data ) {
  429. if ( data.email )
  430. this.setValue( data.email.body );
  431. },
  432. commit: function( data ) {
  433. if ( !data.email )
  434. data.email = {};
  435. data.email.body = this.getValue();
  436. }
  437. } ],
  438. setup: function() {
  439. if ( !this.getDialog().getContentElement( 'info', 'linkType' ) )
  440. this.getElement().hide();
  441. }
  442. } ]
  443. },
  444. {
  445. id: 'target',
  446. requiredContent: 'a[target]', // This is not fully correct, because some target option requires JS.
  447. label: linkLang.target,
  448. title: linkLang.target,
  449. elements: [
  450. {
  451. type: 'vbox',
  452. width: '100%',
  453. align: 'center',
  454. padding: 2,
  455. id: 'popupFeatures',
  456. children: [ {
  457. type: 'fieldset',
  458. label: linkLang.popupFeatures,
  459. children: [ {
  460. type: 'hbox',
  461. children: [ {
  462. type: 'checkbox',
  463. id: 'resizable',
  464. label: linkLang.popupResizable,
  465. setup: setupPopupParams,
  466. commit: commitPopupParams
  467. },
  468. {
  469. type: 'checkbox',
  470. id: 'status',
  471. label: linkLang.popupStatusBar,
  472. setup: setupPopupParams,
  473. commit: commitPopupParams
  474. } ]
  475. },
  476. {
  477. type: 'hbox',
  478. children: [ {
  479. type: 'checkbox',
  480. id: 'location',
  481. label: linkLang.popupLocationBar,
  482. setup: setupPopupParams,
  483. commit: commitPopupParams
  484. },
  485. {
  486. type: 'checkbox',
  487. id: 'toolbar',
  488. label: linkLang.popupToolbar,
  489. setup: setupPopupParams,
  490. commit: commitPopupParams
  491. } ]
  492. },
  493. {
  494. type: 'hbox',
  495. children: [ {
  496. type: 'checkbox',
  497. id: 'menubar',
  498. label: linkLang.popupMenuBar,
  499. setup: setupPopupParams,
  500. commit: commitPopupParams
  501. },
  502. {
  503. type: 'checkbox',
  504. id: 'fullscreen',
  505. label: linkLang.popupFullScreen,
  506. setup: setupPopupParams,
  507. commit: commitPopupParams
  508. } ]
  509. },
  510. {
  511. type: 'hbox',
  512. children: [ {
  513. type: 'checkbox',
  514. id: 'scrollbars',
  515. label: linkLang.popupScrollBars,
  516. setup: setupPopupParams,
  517. commit: commitPopupParams
  518. },
  519. {
  520. type: 'checkbox',
  521. id: 'dependent',
  522. label: linkLang.popupDependent,
  523. setup: setupPopupParams,
  524. commit: commitPopupParams
  525. } ]
  526. },
  527. {
  528. type: 'hbox',
  529. children: [ {
  530. type: 'text',
  531. widths: [ '50%', '50%' ],
  532. labelLayout: 'horizontal',
  533. label: commonLang.width,
  534. id: 'width',
  535. setup: setupPopupParams,
  536. commit: commitPopupParams
  537. },
  538. {
  539. type: 'text',
  540. labelLayout: 'horizontal',
  541. widths: [ '50%', '50%' ],
  542. label: linkLang.popupLeft,
  543. id: 'left',
  544. setup: setupPopupParams,
  545. commit: commitPopupParams
  546. } ]
  547. },
  548. {
  549. type: 'hbox',
  550. children: [ {
  551. type: 'text',
  552. labelLayout: 'horizontal',
  553. widths: [ '50%', '50%' ],
  554. label: commonLang.height,
  555. id: 'height',
  556. setup: setupPopupParams,
  557. commit: commitPopupParams
  558. },
  559. {
  560. type: 'text',
  561. labelLayout: 'horizontal',
  562. label: linkLang.popupTop,
  563. widths: [ '50%', '50%' ],
  564. id: 'top',
  565. setup: setupPopupParams,
  566. commit: commitPopupParams
  567. } ]
  568. } ]
  569. } ]
  570. } ]
  571. },
  572. {
  573. id: 'upload',
  574. label: linkLang.upload,
  575. title: linkLang.upload,
  576. hidden: true,
  577. filebrowser: 'uploadButton',
  578. elements: [ {
  579. type: 'file',
  580. id: 'upload',
  581. label: commonLang.upload,
  582. style: 'height:40px',
  583. size: 29
  584. },
  585. {
  586. type: 'fileButton',
  587. id: 'uploadButton',
  588. label: commonLang.uploadSubmit,
  589. filebrowser: 'info:url',
  590. 'for': [ 'upload', 'upload' ]
  591. } ]
  592. },
  593. {
  594. id: 'advanced',
  595. label: linkLang.advanced,
  596. title: linkLang.advanced,
  597. elements: [ {
  598. type: 'vbox',
  599. padding: 1,
  600. children: [ {
  601. type: 'hbox',
  602. widths: [ '45%', '35%', '20%' ],
  603. children: [ {
  604. type: 'text',
  605. id: 'advId',
  606. requiredContent: 'a[id]',
  607. label: linkLang.id,
  608. setup: setupAdvParams,
  609. commit: commitAdvParams
  610. },
  611. {
  612. type: 'select',
  613. id: 'advLangDir',
  614. requiredContent: 'a[dir]',
  615. label: linkLang.langDir,
  616. 'default': '',
  617. style: 'width:110px',
  618. items: [
  619. [ commonLang.notSet, '' ],
  620. [ linkLang.langDirLTR, 'ltr' ],
  621. [ linkLang.langDirRTL, 'rtl' ]
  622. ],
  623. setup: setupAdvParams,
  624. commit: commitAdvParams
  625. },
  626. {
  627. type: 'text',
  628. id: 'advAccessKey',
  629. requiredContent: 'a[accesskey]',
  630. width: '80px',
  631. label: linkLang.acccessKey,
  632. maxLength: 1,
  633. setup: setupAdvParams,
  634. commit: commitAdvParams
  635. } ]
  636. },
  637. {
  638. type: 'hbox',
  639. widths: [ '45%', '35%', '20%' ],
  640. children: [ {
  641. type: 'text',
  642. label: linkLang.name,
  643. id: 'advName',
  644. requiredContent: 'a[name]',
  645. setup: setupAdvParams,
  646. commit: commitAdvParams
  647. },
  648. {
  649. type: 'text',
  650. label: linkLang.langCode,
  651. id: 'advLangCode',
  652. requiredContent: 'a[lang]',
  653. width: '110px',
  654. 'default': '',
  655. setup: setupAdvParams,
  656. commit: commitAdvParams
  657. },
  658. {
  659. type: 'text',
  660. label: linkLang.tabIndex,
  661. id: 'advTabIndex',
  662. requiredContent: 'a[tabindex]',
  663. width: '80px',
  664. maxLength: 5,
  665. setup: setupAdvParams,
  666. commit: commitAdvParams
  667. } ]
  668. } ]
  669. },
  670. {
  671. type: 'vbox',
  672. padding: 1,
  673. children: [ {
  674. type: 'hbox',
  675. widths: [ '45%', '55%' ],
  676. children: [ {
  677. type: 'text',
  678. label: linkLang.advisoryTitle,
  679. requiredContent: 'a[title]',
  680. 'default': '',
  681. id: 'advTitle',
  682. setup: setupAdvParams,
  683. commit: commitAdvParams
  684. },
  685. {
  686. type: 'text',
  687. label: linkLang.advisoryContentType,
  688. requiredContent: 'a[type]',
  689. 'default': '',
  690. id: 'advContentType',
  691. setup: setupAdvParams,
  692. commit: commitAdvParams
  693. } ]
  694. },
  695. {
  696. type: 'hbox',
  697. widths: [ '45%', '55%' ],
  698. children: [ {
  699. type: 'text',
  700. label: linkLang.cssClasses,
  701. requiredContent: 'a(cke-xyz)', // Random text like 'xyz' will check if all are allowed.
  702. 'default': '',
  703. id: 'advCSSClasses',
  704. setup: setupAdvParams,
  705. commit: commitAdvParams
  706. },
  707. {
  708. type: 'text',
  709. label: linkLang.charset,
  710. requiredContent: 'a[charset]',
  711. 'default': '',
  712. id: 'advCharset',
  713. setup: setupAdvParams,
  714. commit: commitAdvParams
  715. } ]
  716. },
  717. ]
  718. } ]
  719. } ],
  720. onShow: function() {
  721. var editor = this.getParentEditor(),
  722. selection = editor.getSelection(),
  723. element = null;
  724. // Fill in all the relevant fields if there's already one link selected.
  725. if ( ( element = plugin.getSelectedLink( editor ) ) && element.hasAttribute( 'href' ) ) {
  726. // Don't change selection if some element is already selected.
  727. // For example - don't destroy fake selection.
  728. if ( !selection.getSelectedElement() )
  729. selection.selectElement( element );
  730. } else {
  731. element = null;
  732. }
  733. var data = plugin.parseLinkAttributes( editor, element );
  734. // Record down the selected element in the dialog.
  735. this._.selectedElement = element;
  736. this.setupContent( data );
  737. },
  738. onOk: function() {
  739. var data = {};
  740. // Collect data from fields.
  741. this.commitContent( data );
  742. var selection = editor.getSelection(),
  743. attributes = plugin.getLinkAttributes( editor, data );
  744. if ( !this._.selectedElement ) {
  745. var range = selection.getRanges()[ 0 ];
  746. // Use link URL as text with a collapsed cursor.
  747. if ( range.collapsed ) {
  748. // Short mailto link text view (#5736).
  749. var text = new CKEDITOR.dom.text( data.type == 'email' ?
  750. data.email.address : attributes.set[ 'data-cke-saved-href' ], editor.document );
  751. range.insertNode( text );
  752. range.selectNodeContents( text );
  753. }
  754. // Apply style.
  755. var style = new CKEDITOR.style( {
  756. element: 'a',
  757. attributes: attributes.set
  758. } );
  759. style.type = CKEDITOR.STYLE_INLINE; // need to override... dunno why.
  760. style.applyToRange( range, editor );
  761. range.select();
  762. } else {
  763. // We're only editing an existing link, so just overwrite the attributes.
  764. var element = this._.selectedElement,
  765. href = element.data( 'cke-saved-href' ),
  766. textView = element.getHtml();
  767. element.setAttributes( attributes.set );
  768. element.removeAttributes( attributes.removed );
  769. // Update text view when user changes protocol (#4612).
  770. if ( href == textView || data.type == 'email' && textView.indexOf( '@' ) != -1 ) {
  771. // Short mailto link text view (#5736).
  772. element.setHtml( data.type == 'email' ?
  773. data.email.address : attributes.set[ 'data-cke-saved-href' ] );
  774. // We changed the content, so need to select it again.
  775. selection.selectElement( element );
  776. }
  777. delete this._.selectedElement;
  778. }
  779. },
  780. onLoad: function() {
  781. if ( !editor.config.linkShowAdvancedTab )
  782. this.hidePage( 'advanced' ); //Hide Advanded tab.
  783. if ( !editor.config.linkShowTargetTab )
  784. this.hidePage( 'target' ); //Hide Target tab.
  785. },
  786. // Inital focus on 'url' field if link is of type URL.
  787. onFocus: function() {
  788. var linkType = this.getContentElement( 'info', 'linkType' ),
  789. urlField;
  790. if ( linkType && linkType.getValue() == 'url' ) {
  791. urlField = this.getContentElement( 'info', 'url' );
  792. urlField.select();
  793. }
  794. }
  795. };
  796. } );
  797. } )();
  798. // jscs:disable maximumLineLength
  799. /**
  800. * The e-mail address anti-spam protection option. The protection will be
  801. * applied when creating or modifying e-mail links through the editor interface.
  802. *
  803. * Two methods of protection can be chosen:
  804. *
  805. * 1. The e-mail parts (name, domain, and any other query string) are
  806. * assembled into a function call pattern. Such function must be
  807. * provided by the developer in the pages that will use the contents.
  808. * 2. Only the e-mail address is obfuscated into a special string that
  809. * has no meaning for humans or spam bots, but which is properly
  810. * rendered and accepted by the browser.
  811. *
  812. * Both approaches require JavaScript to be enabled.
  813. *
  814. * // href="mailto:tester@ckeditor.com?subject=subject&body=body"
  815. * config.emailProtection = '';
  816. *
  817. * // 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>"
  818. * config.emailProtection = 'encode';
  819. *
  820. * // href="javascript:mt('tester','ckeditor.com','subject','body')"
  821. * config.emailProtection = 'mt(NAME,DOMAIN,SUBJECT,BODY)';
  822. *
  823. * @since 3.1
  824. * @cfg {String} [emailProtection='' (empty string = disabled)]
  825. * @member CKEDITOR.config
  826. */