button.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /*!
  2. * jQuery UI Button 1.14.1
  3. * https://jqueryui.com
  4. *
  5. * Copyright OpenJS Foundation and other contributors
  6. * Released under the MIT license.
  7. * https://jquery.org/license
  8. */
  9. //>>label: Button
  10. //>>group: Widgets
  11. //>>description: Enhances a form with themeable buttons.
  12. //>>docs: https://api.jqueryui.com/button/
  13. //>>demos: https://jqueryui.com/button/
  14. //>>css.structure: ../../themes/base/core.css
  15. //>>css.structure: ../../themes/base/button.css
  16. //>>css.theme: ../../themes/base/theme.css
  17. ( function( factory ) {
  18. "use strict";
  19. if ( typeof define === "function" && define.amd ) {
  20. // AMD. Register as an anonymous module.
  21. define( [
  22. "jquery",
  23. // These are only for backcompat
  24. // TODO: Remove after 1.12
  25. "./controlgroup",
  26. "./checkboxradio",
  27. "../keycode",
  28. "../widget"
  29. ], factory );
  30. } else {
  31. // Browser globals
  32. factory( jQuery );
  33. }
  34. } )( function( $ ) {
  35. "use strict";
  36. $.widget( "ui.button", {
  37. version: "1.14.1",
  38. defaultElement: "<button>",
  39. options: {
  40. classes: {
  41. "ui-button": "ui-corner-all"
  42. },
  43. disabled: null,
  44. icon: null,
  45. iconPosition: "beginning",
  46. label: null,
  47. showLabel: true
  48. },
  49. _getCreateOptions: function() {
  50. var disabled,
  51. // This is to support cases like in jQuery Mobile where the base widget does have
  52. // an implementation of _getCreateOptions
  53. options = this._super() || {};
  54. this.isInput = this.element.is( "input" );
  55. disabled = this.element[ 0 ].disabled;
  56. if ( disabled != null ) {
  57. options.disabled = disabled;
  58. }
  59. this.originalLabel = this.isInput ? this.element.val() : this.element.html();
  60. if ( this.originalLabel ) {
  61. options.label = this.originalLabel;
  62. }
  63. return options;
  64. },
  65. _create: function() {
  66. if ( !this.option.showLabel & !this.options.icon ) {
  67. this.options.showLabel = true;
  68. }
  69. // We have to check the option again here even though we did in _getCreateOptions,
  70. // because null may have been passed on init which would override what was set in
  71. // _getCreateOptions
  72. if ( this.options.disabled == null ) {
  73. this.options.disabled = this.element[ 0 ].disabled || false;
  74. }
  75. this.hasTitle = !!this.element.attr( "title" );
  76. // Check to see if the label needs to be set or if its already correct
  77. if ( this.options.label && this.options.label !== this.originalLabel ) {
  78. if ( this.isInput ) {
  79. this.element.val( this.options.label );
  80. } else {
  81. this.element.html( this.options.label );
  82. }
  83. }
  84. this._addClass( "ui-button", "ui-widget" );
  85. this._setOption( "disabled", this.options.disabled );
  86. this._enhance();
  87. if ( this.element.is( "a" ) ) {
  88. this._on( {
  89. "keyup": function( event ) {
  90. if ( event.keyCode === $.ui.keyCode.SPACE ) {
  91. event.preventDefault();
  92. // If a native click is available use it, so we
  93. // actually cause navigation. Otherwise, just trigger
  94. // a click event.
  95. if ( this.element[ 0 ].click ) {
  96. this.element[ 0 ].click();
  97. } else {
  98. this.element.trigger( "click" );
  99. }
  100. }
  101. }
  102. } );
  103. }
  104. },
  105. _enhance: function() {
  106. if ( !this.element.is( "button" ) ) {
  107. this.element.attr( "role", "button" );
  108. }
  109. if ( this.options.icon ) {
  110. this._updateIcon( "icon", this.options.icon );
  111. this._updateTooltip();
  112. }
  113. },
  114. _updateTooltip: function() {
  115. this.title = this.element.attr( "title" );
  116. if ( !this.options.showLabel && !this.title ) {
  117. this.element.attr( "title", this.options.label );
  118. }
  119. },
  120. _updateIcon: function( option, value ) {
  121. var icon = option !== "iconPosition",
  122. position = icon ? this.options.iconPosition : value,
  123. displayBlock = position === "top" || position === "bottom";
  124. // Create icon
  125. if ( !this.icon ) {
  126. this.icon = $( "<span>" );
  127. this._addClass( this.icon, "ui-button-icon", "ui-icon" );
  128. if ( !this.options.showLabel ) {
  129. this._addClass( "ui-button-icon-only" );
  130. }
  131. } else if ( icon ) {
  132. // If we are updating the icon remove the old icon class
  133. this._removeClass( this.icon, null, this.options.icon );
  134. }
  135. // If we are updating the icon add the new icon class
  136. if ( icon ) {
  137. this._addClass( this.icon, null, value );
  138. }
  139. this._attachIcon( position );
  140. // If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove
  141. // the iconSpace if there is one.
  142. if ( displayBlock ) {
  143. this._addClass( this.icon, null, "ui-widget-icon-block" );
  144. if ( this.iconSpace ) {
  145. this.iconSpace.remove();
  146. }
  147. } else {
  148. // Position is beginning or end so remove the ui-widget-icon-block class and add the
  149. // space if it does not exist
  150. if ( !this.iconSpace ) {
  151. this.iconSpace = $( "<span> </span>" );
  152. this._addClass( this.iconSpace, "ui-button-icon-space" );
  153. }
  154. this._removeClass( this.icon, null, "ui-wiget-icon-block" );
  155. this._attachIconSpace( position );
  156. }
  157. },
  158. _destroy: function() {
  159. this.element.removeAttr( "role" );
  160. if ( this.icon ) {
  161. this.icon.remove();
  162. }
  163. if ( this.iconSpace ) {
  164. this.iconSpace.remove();
  165. }
  166. if ( !this.hasTitle ) {
  167. this.element.removeAttr( "title" );
  168. }
  169. },
  170. _attachIconSpace: function( iconPosition ) {
  171. this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace );
  172. },
  173. _attachIcon: function( iconPosition ) {
  174. this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon );
  175. },
  176. _setOptions: function( options ) {
  177. var newShowLabel = options.showLabel === undefined ?
  178. this.options.showLabel :
  179. options.showLabel,
  180. newIcon = options.icon === undefined ? this.options.icon : options.icon;
  181. if ( !newShowLabel && !newIcon ) {
  182. options.showLabel = true;
  183. }
  184. this._super( options );
  185. },
  186. _setOption: function( key, value ) {
  187. if ( key === "icon" ) {
  188. if ( value ) {
  189. this._updateIcon( key, value );
  190. } else if ( this.icon ) {
  191. this.icon.remove();
  192. if ( this.iconSpace ) {
  193. this.iconSpace.remove();
  194. }
  195. }
  196. }
  197. if ( key === "iconPosition" ) {
  198. this._updateIcon( key, value );
  199. }
  200. // Make sure we can't end up with a button that has neither text nor icon
  201. if ( key === "showLabel" ) {
  202. this._toggleClass( "ui-button-icon-only", null, !value );
  203. this._updateTooltip();
  204. }
  205. if ( key === "label" ) {
  206. if ( this.isInput ) {
  207. this.element.val( value );
  208. } else {
  209. // If there is an icon, append it, else nothing then append the value
  210. // this avoids removal of the icon when setting label text
  211. this.element.html( value );
  212. if ( this.icon ) {
  213. this._attachIcon( this.options.iconPosition );
  214. this._attachIconSpace( this.options.iconPosition );
  215. }
  216. }
  217. }
  218. this._super( key, value );
  219. if ( key === "disabled" ) {
  220. this._toggleClass( null, "ui-state-disabled", value );
  221. this.element[ 0 ].disabled = value;
  222. if ( value ) {
  223. this.element.trigger( "blur" );
  224. }
  225. }
  226. },
  227. refresh: function() {
  228. // Make sure to only check disabled if its an element that supports this otherwise
  229. // check for the disabled class to determine state
  230. var isDisabled = this.element.is( "input, button" ) ?
  231. this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" );
  232. if ( isDisabled !== this.options.disabled ) {
  233. this._setOptions( { disabled: isDisabled } );
  234. }
  235. this._updateTooltip();
  236. }
  237. } );
  238. // DEPRECATED
  239. if ( $.uiBackCompat === true ) {
  240. // Text and Icons options
  241. $.widget( "ui.button", $.ui.button, {
  242. options: {
  243. text: true,
  244. icons: {
  245. primary: null,
  246. secondary: null
  247. }
  248. },
  249. _create: function() {
  250. if ( this.options.showLabel && !this.options.text ) {
  251. this.options.showLabel = this.options.text;
  252. }
  253. if ( !this.options.showLabel && this.options.text ) {
  254. this.options.text = this.options.showLabel;
  255. }
  256. if ( !this.options.icon && ( this.options.icons.primary ||
  257. this.options.icons.secondary ) ) {
  258. if ( this.options.icons.primary ) {
  259. this.options.icon = this.options.icons.primary;
  260. } else {
  261. this.options.icon = this.options.icons.secondary;
  262. this.options.iconPosition = "end";
  263. }
  264. } else if ( this.options.icon ) {
  265. this.options.icons.primary = this.options.icon;
  266. }
  267. this._super();
  268. },
  269. _setOption: function( key, value ) {
  270. if ( key === "text" ) {
  271. this._super( "showLabel", value );
  272. return;
  273. }
  274. if ( key === "showLabel" ) {
  275. this.options.text = value;
  276. }
  277. if ( key === "icon" ) {
  278. this.options.icons.primary = value;
  279. }
  280. if ( key === "icons" ) {
  281. if ( value.primary ) {
  282. this._super( "icon", value.primary );
  283. this._super( "iconPosition", "beginning" );
  284. } else if ( value.secondary ) {
  285. this._super( "icon", value.secondary );
  286. this._super( "iconPosition", "end" );
  287. }
  288. }
  289. this._superApply( arguments );
  290. }
  291. } );
  292. $.fn.button = ( function( orig ) {
  293. return function( options ) {
  294. var isMethodCall = typeof options === "string";
  295. var args = Array.prototype.slice.call( arguments, 1 );
  296. var returnValue = this;
  297. if ( isMethodCall ) {
  298. // If this is an empty collection, we need to have the instance method
  299. // return undefined instead of the jQuery instance
  300. if ( !this.length && options === "instance" ) {
  301. returnValue = undefined;
  302. } else {
  303. this.each( function() {
  304. var methodValue;
  305. var type = $( this ).attr( "type" );
  306. var name = type !== "checkbox" && type !== "radio" ?
  307. "button" :
  308. "checkboxradio";
  309. var instance = $.data( this, "ui-" + name );
  310. if ( options === "instance" ) {
  311. returnValue = instance;
  312. return false;
  313. }
  314. if ( !instance ) {
  315. return $.error( "cannot call methods on button" +
  316. " prior to initialization; " +
  317. "attempted to call method '" + options + "'" );
  318. }
  319. if ( typeof instance[ options ] !== "function" ||
  320. options.charAt( 0 ) === "_" ) {
  321. return $.error( "no such method '" + options + "' for button" +
  322. " widget instance" );
  323. }
  324. methodValue = instance[ options ].apply( instance, args );
  325. if ( methodValue !== instance && methodValue !== undefined ) {
  326. returnValue = methodValue && methodValue.jquery ?
  327. returnValue.pushStack( methodValue.get() ) :
  328. methodValue;
  329. return false;
  330. }
  331. } );
  332. }
  333. } else {
  334. // Allow multiple hashes to be passed on init
  335. if ( args.length ) {
  336. options = $.widget.extend.apply( null, [ options ].concat( args ) );
  337. }
  338. this.each( function() {
  339. var type = $( this ).attr( "type" );
  340. var name = type !== "checkbox" && type !== "radio" ? "button" : "checkboxradio";
  341. var instance = $.data( this, "ui-" + name );
  342. if ( instance ) {
  343. instance.option( options || {} );
  344. if ( instance._init ) {
  345. instance._init();
  346. }
  347. } else {
  348. if ( name === "button" ) {
  349. orig.call( $( this ), options );
  350. return;
  351. }
  352. $( this ).checkboxradio( $.extend( { icon: false }, options ) );
  353. }
  354. } );
  355. }
  356. return returnValue;
  357. };
  358. } )( $.fn.button );
  359. $.fn.buttonset = function() {
  360. if ( !$.ui.controlgroup ) {
  361. $.error( "Controlgroup widget missing" );
  362. }
  363. if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) {
  364. return this.controlgroup.apply( this,
  365. [ arguments[ 0 ], "items.button", arguments[ 2 ] ] );
  366. }
  367. if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) {
  368. return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] );
  369. }
  370. if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) {
  371. arguments[ 0 ].items = {
  372. button: arguments[ 0 ].items
  373. };
  374. }
  375. return this.controlgroup.apply( this, arguments );
  376. };
  377. }
  378. return $.ui.button;
  379. } );