8
0

buttonview.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /**
  2. * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /**
  6. * @module ui/button/buttonview
  7. */
  8. import View from '../view';
  9. import Template from '../template';
  10. import IconView from '../icon/iconview';
  11. import TooltipView from '../tooltip/tooltipview';
  12. import { getEnvKeystrokeText } from '@ckeditor/ckeditor5-utils/src/keyboard';
  13. /**
  14. * The button view class.
  15. *
  16. * @extends module:ui/view~View
  17. */
  18. export default class ButtonView extends View {
  19. /**
  20. * @inheritDoc
  21. */
  22. constructor( locale ) {
  23. super( locale );
  24. /**
  25. * The label of the button view visible to the user.
  26. *
  27. * @observable
  28. * @member {String} #label
  29. */
  30. this.set( 'label' );
  31. /**
  32. * (Optional) The keystroke associated with the button, i.e. <kbd>CTRL+B</kbd>,
  33. * in the string format compatible with {@link module:utils/keyboard}.
  34. *
  35. * @observable
  36. * @member {Boolean} #keystroke
  37. */
  38. this.set( 'keystroke' );
  39. /**
  40. * (Optional) Tooltip of the button, i.e. displayed when hovering the button with the mouse cursor.
  41. *
  42. * * If defined as a `Boolean` (e.g. `true`), then combination of `label` and `keystroke` will be set as a tooltip.
  43. * * If defined as a `String`, tooltip will equal the exact text of that `String`.
  44. * * If defined as a `Function`, `label` and `keystroke` will be passed to that function, which is to return
  45. * a string with the tooltip text.
  46. *
  47. * const view = new ButtonView( locale );
  48. * view.tooltip = ( label, keystroke ) => `A tooltip for ${ label } and ${ keystroke }.`
  49. *
  50. * @observable
  51. * @default false
  52. * @member {Boolean|String|Function} #tooltip
  53. */
  54. this.set( 'tooltip' );
  55. /**
  56. * The position of the tooltip. See {@link module:ui/tooltip/tooltipview~TooltipView#position}
  57. * to learn more about the available position values.
  58. *
  59. * **Note:** It makes sense only when the {@link #tooltip} is active.
  60. *
  61. * @observable
  62. * @default 's'
  63. * @member {'s'|'n'} #position
  64. */
  65. this.set( 'tooltipPosition', 's' );
  66. /**
  67. * The HTML type of the button. Default `button`.
  68. *
  69. * @observable
  70. * @member {'button'|'submit'|'reset'|'menu'} #type
  71. */
  72. this.set( 'type', 'button' );
  73. /**
  74. * Controls whether the button view is "on", e.g. some feature which it represents
  75. * is currently enabled.
  76. *
  77. * @observable
  78. * @member {Boolean} #isOn
  79. */
  80. this.set( 'isOn', false );
  81. /**
  82. * Controls whether the button view is enabled (can be clicked).
  83. *
  84. * @observable
  85. * @member {Boolean} #isEnabled
  86. */
  87. this.set( 'isEnabled', true );
  88. /**
  89. * Controls whether the button view is visible.
  90. *
  91. * @observable
  92. * @member {Boolean} #isVisible
  93. */
  94. this.set( 'isVisible', true );
  95. /**
  96. * (Optional) Whether the label of the button is hidden (e.g. button with icon only).
  97. *
  98. * @observable
  99. * @member {Boolean} #withText
  100. */
  101. this.set( 'withText', false );
  102. /**
  103. * (Optional) Source of the icon. See {@link module:ui/icon/iconview~IconView#content}.
  104. *
  105. * @observable
  106. * @member {String} #icon
  107. */
  108. this.set( 'icon' );
  109. /**
  110. * Controls the `tabindex` attribute of the button.
  111. *
  112. * @observable
  113. * @default -1
  114. * @member {String} #tabindex
  115. */
  116. this.set( 'tabindex', -1 );
  117. /**
  118. * Tooltip of the button bound to the template.
  119. *
  120. * @see #tooltip
  121. * @see #_getTooltipString
  122. * @private
  123. * @observable
  124. * @member {Boolean} #_tooltipString
  125. */
  126. this.bind( '_tooltipString' ).to(
  127. this, 'tooltip',
  128. this, 'label',
  129. this, 'keystroke',
  130. this._getTooltipString.bind( this )
  131. );
  132. /**
  133. * Tooltip of the button view.
  134. *
  135. * @readonly
  136. * @member {module:ui/tooltip/tooltipview~TooltipView} #tooltipView
  137. */
  138. this.tooltipView = this._createTooltipView();
  139. /**
  140. * Icon of the button view.
  141. *
  142. * @readonly
  143. * @member {module:ui/icon/iconview~IconView} #iconView
  144. */
  145. const bind = this.bindTemplate;
  146. this.template = new Template( {
  147. tag: 'button',
  148. attributes: {
  149. class: [
  150. 'ck-button',
  151. bind.to( 'isEnabled', value => value ? 'ck-enabled' : 'ck-disabled' ),
  152. bind.if( 'isVisible', 'ck-hidden', value => !value ),
  153. bind.to( 'isOn', value => value ? 'ck-on' : 'ck-off' ),
  154. bind.if( 'withText', 'ck-button_with-text' )
  155. ],
  156. type: bind.to( 'type', value => value ? value : 'button' ),
  157. tabindex: bind.to( 'tabindex' )
  158. },
  159. children: [
  160. {
  161. tag: 'span',
  162. attributes: {
  163. class: [ 'ck-button__label' ]
  164. },
  165. children: [
  166. {
  167. text: bind.to( 'label' )
  168. }
  169. ]
  170. },
  171. this.tooltipView
  172. ],
  173. on: {
  174. mousedown: bind.to( evt => {
  175. evt.preventDefault();
  176. } ),
  177. click: bind.to( evt => {
  178. // We can't make the button disabled using the disabled attribute, because it won't be focusable.
  179. // Though, shouldn't this condition be moved to the button controller?
  180. if ( this.isEnabled ) {
  181. this.fire( 'execute' );
  182. } else {
  183. // Prevent the default when button is disabled, to block e.g.
  184. // automatic form submitting. See ckeditor/ckeditor5-link#74.
  185. evt.preventDefault();
  186. }
  187. } )
  188. }
  189. } );
  190. /**
  191. * Fired when the button view is clicked. It won't be fired when the button is disabled.
  192. *
  193. * @event #execute
  194. */
  195. }
  196. /**
  197. * @inheritDoc
  198. */
  199. init() {
  200. if ( this.icon ) {
  201. const iconView = this.iconView = new IconView();
  202. iconView.bind( 'content' ).to( this, 'icon' );
  203. this.element.insertBefore( iconView.element, this.element.firstChild );
  204. // Make sure the icon will be destroyed along with the button.
  205. this.addChildren( iconView );
  206. }
  207. super.init();
  208. }
  209. /**
  210. * Focuses the button.
  211. */
  212. focus() {
  213. this.element.focus();
  214. }
  215. /**
  216. * Creates TooltipView instance and bind with button properties.
  217. *
  218. * @private
  219. * @returns {module:ui/tooltip/tooltipview~TooltipView}
  220. */
  221. _createTooltipView() {
  222. const tooltipView = new TooltipView();
  223. tooltipView.bind( 'text' ).to( this, '_tooltipString' );
  224. tooltipView.bind( 'position' ).to( this, 'tooltipPosition' );
  225. return tooltipView;
  226. }
  227. /**
  228. * Gets the text for the {@link #tooltipView} from the combination of
  229. * {@link #tooltip}, {@link #label} and {@link #keystroke} attributes.
  230. *
  231. * @private
  232. * @see #tooltip
  233. * @see #_tooltipString
  234. * @param {Boolean|String|Function} tooltip Button tooltip.
  235. * @param {String} label Button label.
  236. * @param {String} keystroke Button keystroke.
  237. * @returns {String}
  238. */
  239. _getTooltipString( tooltip, label, keystroke ) {
  240. if ( tooltip ) {
  241. if ( typeof tooltip == 'string' ) {
  242. return tooltip;
  243. } else {
  244. if ( keystroke ) {
  245. keystroke = getEnvKeystrokeText( keystroke );
  246. }
  247. if ( tooltip instanceof Function ) {
  248. return tooltip( label, keystroke );
  249. } else {
  250. return `${ label }${ keystroke ? ` (${ keystroke })` : '' }`;
  251. }
  252. }
  253. }
  254. return '';
  255. }
  256. }