plugin.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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. /**
  6. * @fileOverview Justify commands.
  7. */
  8. ( function() {
  9. function getAlignment( element, useComputedState ) {
  10. useComputedState = useComputedState === undefined || useComputedState;
  11. var align;
  12. if ( useComputedState )
  13. align = element.getComputedStyle( 'text-align' );
  14. else {
  15. while ( !element.hasAttribute || !( element.hasAttribute( 'align' ) || element.getStyle( 'text-align' ) ) ) {
  16. var parent = element.getParent();
  17. if ( !parent )
  18. break;
  19. element = parent;
  20. }
  21. align = element.getStyle( 'text-align' ) || element.getAttribute( 'align' ) || '';
  22. }
  23. // Sometimes computed values doesn't tell.
  24. align && ( align = align.replace( /(?:-(?:moz|webkit)-)?(?:start|auto)/i, '' ) );
  25. !align && useComputedState && ( align = element.getComputedStyle( 'direction' ) == 'rtl' ? 'right' : 'left' );
  26. return align;
  27. }
  28. function justifyCommand( editor, name, value ) {
  29. this.editor = editor;
  30. this.name = name;
  31. this.value = value;
  32. this.context = 'p';
  33. var classes = editor.config.justifyClasses,
  34. blockTag = editor.config.enterMode == CKEDITOR.ENTER_P ? 'p' : 'div';
  35. if ( classes ) {
  36. switch ( value ) {
  37. case 'left':
  38. this.cssClassName = classes[ 0 ];
  39. break;
  40. case 'center':
  41. this.cssClassName = classes[ 1 ];
  42. break;
  43. case 'right':
  44. this.cssClassName = classes[ 2 ];
  45. break;
  46. case 'justify':
  47. this.cssClassName = classes[ 3 ];
  48. break;
  49. }
  50. this.cssClassRegex = new RegExp( '(?:^|\\s+)(?:' + classes.join( '|' ) + ')(?=$|\\s)' );
  51. this.requiredContent = blockTag + '(' + this.cssClassName + ')';
  52. }
  53. else {
  54. this.requiredContent = blockTag + '{text-align}';
  55. }
  56. this.allowedContent = {
  57. 'caption div h1 h2 h3 h4 h5 h6 p pre td th li': {
  58. // Do not add elements, but only text-align style if element is validated by other rule.
  59. propertiesOnly: true,
  60. styles: this.cssClassName ? null : 'text-align',
  61. classes: this.cssClassName || null
  62. }
  63. };
  64. // In enter mode BR we need to allow here for div, because when non other
  65. // feature allows div justify is the only plugin that uses it.
  66. if ( editor.config.enterMode == CKEDITOR.ENTER_BR )
  67. this.allowedContent.div = true;
  68. }
  69. function onDirChanged( e ) {
  70. var editor = e.editor;
  71. var range = editor.createRange();
  72. range.setStartBefore( e.data.node );
  73. range.setEndAfter( e.data.node );
  74. var walker = new CKEDITOR.dom.walker( range ),
  75. node;
  76. while ( ( node = walker.next() ) ) {
  77. if ( node.type == CKEDITOR.NODE_ELEMENT ) {
  78. // A child with the defined dir is to be ignored.
  79. if ( !node.equals( e.data.node ) && node.getDirection() ) {
  80. range.setStartAfter( node );
  81. walker = new CKEDITOR.dom.walker( range );
  82. continue;
  83. }
  84. // Switch the alignment.
  85. var classes = editor.config.justifyClasses;
  86. if ( classes ) {
  87. // The left align class.
  88. if ( node.hasClass( classes[ 0 ] ) ) {
  89. node.removeClass( classes[ 0 ] );
  90. node.addClass( classes[ 2 ] );
  91. }
  92. // The right align class.
  93. else if ( node.hasClass( classes[ 2 ] ) ) {
  94. node.removeClass( classes[ 2 ] );
  95. node.addClass( classes[ 0 ] );
  96. }
  97. }
  98. // Always switch CSS margins.
  99. var style = 'text-align';
  100. var align = node.getStyle( style );
  101. if ( align == 'left' )
  102. node.setStyle( style, 'right' );
  103. else if ( align == 'right' )
  104. node.setStyle( style, 'left' );
  105. }
  106. }
  107. }
  108. justifyCommand.prototype = {
  109. exec: function( editor ) {
  110. var selection = editor.getSelection(),
  111. enterMode = editor.config.enterMode;
  112. if ( !selection )
  113. return;
  114. var bookmarks = selection.createBookmarks(),
  115. ranges = selection.getRanges();
  116. var cssClassName = this.cssClassName,
  117. iterator, block;
  118. var useComputedState = editor.config.useComputedState;
  119. useComputedState = useComputedState === undefined || useComputedState;
  120. for ( var i = ranges.length - 1; i >= 0; i-- ) {
  121. iterator = ranges[ i ].createIterator();
  122. iterator.enlargeBr = enterMode != CKEDITOR.ENTER_BR;
  123. while ( ( block = iterator.getNextParagraph( enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ) ) ) {
  124. if ( block.isReadOnly() )
  125. continue;
  126. block.removeAttribute( 'align' );
  127. block.removeStyle( 'text-align' );
  128. // Remove any of the alignment classes from the className.
  129. var className = cssClassName && ( block.$.className = CKEDITOR.tools.ltrim( block.$.className.replace( this.cssClassRegex, '' ) ) );
  130. var apply = ( this.state == CKEDITOR.TRISTATE_OFF ) && ( !useComputedState || ( getAlignment( block, true ) != this.value ) );
  131. if ( cssClassName ) {
  132. // Append the desired class name.
  133. if ( apply )
  134. block.addClass( cssClassName );
  135. else if ( !className )
  136. block.removeAttribute( 'class' );
  137. } else if ( apply ) {
  138. block.setStyle( 'text-align', this.value );
  139. }
  140. }
  141. }
  142. editor.focus();
  143. editor.forceNextSelectionCheck();
  144. selection.selectBookmarks( bookmarks );
  145. },
  146. refresh: function( editor, path ) {
  147. var firstBlock = path.block || path.blockLimit;
  148. this.setState( firstBlock.getName() != 'body' && getAlignment( firstBlock, this.editor.config.useComputedState ) == this.value ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );
  149. }
  150. };
  151. CKEDITOR.plugins.add( 'justify', {
  152. // jscs:disable maximumLineLength
  153. lang: 'af,ar,bg,bn,bs,ca,cs,cy,da,de,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
  154. // jscs:enable maximumLineLength
  155. icons: 'justifyblock,justifycenter,justifyleft,justifyright', // %REMOVE_LINE_CORE%
  156. hidpi: true, // %REMOVE_LINE_CORE%
  157. init: function( editor ) {
  158. if ( editor.blockless )
  159. return;
  160. var left = new justifyCommand( editor, 'justifyleft', 'left' ),
  161. center = new justifyCommand( editor, 'justifycenter', 'center' ),
  162. right = new justifyCommand( editor, 'justifyright', 'right' ),
  163. justify = new justifyCommand( editor, 'justifyblock', 'justify' );
  164. editor.addCommand( 'justifyleft', left );
  165. editor.addCommand( 'justifycenter', center );
  166. editor.addCommand( 'justifyright', right );
  167. editor.addCommand( 'justifyblock', justify );
  168. if ( editor.ui.addButton ) {
  169. editor.ui.addButton( 'JustifyLeft', {
  170. label: editor.lang.justify.left,
  171. command: 'justifyleft',
  172. toolbar: 'align,10'
  173. } );
  174. editor.ui.addButton( 'JustifyCenter', {
  175. label: editor.lang.justify.center,
  176. command: 'justifycenter',
  177. toolbar: 'align,20'
  178. } );
  179. editor.ui.addButton( 'JustifyRight', {
  180. label: editor.lang.justify.right,
  181. command: 'justifyright',
  182. toolbar: 'align,30'
  183. } );
  184. editor.ui.addButton( 'JustifyBlock', {
  185. label: editor.lang.justify.block,
  186. command: 'justifyblock',
  187. toolbar: 'align,40'
  188. } );
  189. }
  190. editor.on( 'dirChanged', onDirChanged );
  191. }
  192. } );
  193. } )();
  194. /**
  195. * List of classes to use for aligning the contents. If it's `null`, no classes will be used
  196. * and instead the corresponding CSS values will be used.
  197. *
  198. * The array should contain 4 members, in the following order: left, center, right, justify.
  199. *
  200. * // Use the classes 'AlignLeft', 'AlignCenter', 'AlignRight', 'AlignJustify'
  201. * config.justifyClasses = [ 'AlignLeft', 'AlignCenter', 'AlignRight', 'AlignJustify' ];
  202. *
  203. * @cfg {Array} [justifyClasses=null]
  204. * @member CKEDITOR.config
  205. */