selectable.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. /*!
  2. * jQuery UI Selectable 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: Selectable
  10. //>>group: Interactions
  11. //>>description: Allows groups of elements to be selected with the mouse.
  12. //>>docs: https://api.jqueryui.com/selectable/
  13. //>>demos: https://jqueryui.com/selectable/
  14. //>>css.structure: ../../themes/base/selectable.css
  15. ( function( factory ) {
  16. "use strict";
  17. if ( typeof define === "function" && define.amd ) {
  18. // AMD. Register as an anonymous module.
  19. define( [
  20. "jquery",
  21. "./mouse",
  22. "../version",
  23. "../widget"
  24. ], factory );
  25. } else {
  26. // Browser globals
  27. factory( jQuery );
  28. }
  29. } )( function( $ ) {
  30. "use strict";
  31. return $.widget( "ui.selectable", $.ui.mouse, {
  32. version: "1.14.1",
  33. options: {
  34. appendTo: "body",
  35. autoRefresh: true,
  36. distance: 0,
  37. filter: "*",
  38. tolerance: "touch",
  39. // Callbacks
  40. selected: null,
  41. selecting: null,
  42. start: null,
  43. stop: null,
  44. unselected: null,
  45. unselecting: null
  46. },
  47. _create: function() {
  48. var that = this;
  49. this._addClass( "ui-selectable" );
  50. this.dragged = false;
  51. // Cache selectee children based on filter
  52. this.refresh = function() {
  53. that.elementPos = $( that.element[ 0 ] ).offset();
  54. that.selectees = $( that.options.filter, that.element[ 0 ] );
  55. that._addClass( that.selectees, "ui-selectee" );
  56. that.selectees.each( function() {
  57. var $this = $( this ),
  58. selecteeOffset = $this.offset(),
  59. pos = {
  60. left: selecteeOffset.left - that.elementPos.left,
  61. top: selecteeOffset.top - that.elementPos.top
  62. };
  63. $.data( this, "selectable-item", {
  64. element: this,
  65. $element: $this,
  66. left: pos.left,
  67. top: pos.top,
  68. right: pos.left + $this.outerWidth(),
  69. bottom: pos.top + $this.outerHeight(),
  70. startselected: false,
  71. selected: $this.hasClass( "ui-selected" ),
  72. selecting: $this.hasClass( "ui-selecting" ),
  73. unselecting: $this.hasClass( "ui-unselecting" )
  74. } );
  75. } );
  76. };
  77. this.refresh();
  78. this._mouseInit();
  79. this.helper = $( "<div>" );
  80. this._addClass( this.helper, "ui-selectable-helper" );
  81. },
  82. _destroy: function() {
  83. this.selectees.removeData( "selectable-item" );
  84. this._mouseDestroy();
  85. },
  86. _mouseStart: function( event ) {
  87. var that = this,
  88. options = this.options;
  89. this.opos = [ event.pageX, event.pageY ];
  90. this.elementPos = $( this.element[ 0 ] ).offset();
  91. if ( this.options.disabled ) {
  92. return;
  93. }
  94. this.selectees = $( options.filter, this.element[ 0 ] );
  95. this._trigger( "start", event );
  96. $( options.appendTo ).append( this.helper );
  97. // position helper (lasso)
  98. this.helper.css( {
  99. "left": event.pageX,
  100. "top": event.pageY,
  101. "width": 0,
  102. "height": 0
  103. } );
  104. if ( options.autoRefresh ) {
  105. this.refresh();
  106. }
  107. this.selectees.filter( ".ui-selected" ).each( function() {
  108. var selectee = $.data( this, "selectable-item" );
  109. selectee.startselected = true;
  110. if ( !event.metaKey && !event.ctrlKey ) {
  111. that._removeClass( selectee.$element, "ui-selected" );
  112. selectee.selected = false;
  113. that._addClass( selectee.$element, "ui-unselecting" );
  114. selectee.unselecting = true;
  115. // selectable UNSELECTING callback
  116. that._trigger( "unselecting", event, {
  117. unselecting: selectee.element
  118. } );
  119. }
  120. } );
  121. $( event.target ).parents().addBack().each( function() {
  122. var doSelect,
  123. selectee = $.data( this, "selectable-item" );
  124. if ( selectee ) {
  125. doSelect = ( !event.metaKey && !event.ctrlKey ) ||
  126. !selectee.$element.hasClass( "ui-selected" );
  127. that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" )
  128. ._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" );
  129. selectee.unselecting = !doSelect;
  130. selectee.selecting = doSelect;
  131. selectee.selected = doSelect;
  132. // selectable (UN)SELECTING callback
  133. if ( doSelect ) {
  134. that._trigger( "selecting", event, {
  135. selecting: selectee.element
  136. } );
  137. } else {
  138. that._trigger( "unselecting", event, {
  139. unselecting: selectee.element
  140. } );
  141. }
  142. return false;
  143. }
  144. } );
  145. },
  146. _mouseDrag: function( event ) {
  147. this.dragged = true;
  148. if ( this.options.disabled ) {
  149. return;
  150. }
  151. var tmp,
  152. that = this,
  153. options = this.options,
  154. x1 = this.opos[ 0 ],
  155. y1 = this.opos[ 1 ],
  156. x2 = event.pageX,
  157. y2 = event.pageY;
  158. if ( x1 > x2 ) {
  159. tmp = x2; x2 = x1; x1 = tmp;
  160. }
  161. if ( y1 > y2 ) {
  162. tmp = y2; y2 = y1; y1 = tmp;
  163. }
  164. this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } );
  165. this.selectees.each( function() {
  166. var selectee = $.data( this, "selectable-item" ),
  167. hit = false,
  168. offset = {};
  169. //prevent helper from being selected if appendTo: selectable
  170. if ( !selectee || selectee.element === that.element[ 0 ] ) {
  171. return;
  172. }
  173. offset.left = selectee.left + that.elementPos.left;
  174. offset.right = selectee.right + that.elementPos.left;
  175. offset.top = selectee.top + that.elementPos.top;
  176. offset.bottom = selectee.bottom + that.elementPos.top;
  177. if ( options.tolerance === "touch" ) {
  178. hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 ||
  179. offset.bottom < y1 ) );
  180. } else if ( options.tolerance === "fit" ) {
  181. hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 &&
  182. offset.bottom < y2 );
  183. }
  184. if ( hit ) {
  185. // SELECT
  186. if ( selectee.selected ) {
  187. that._removeClass( selectee.$element, "ui-selected" );
  188. selectee.selected = false;
  189. }
  190. if ( selectee.unselecting ) {
  191. that._removeClass( selectee.$element, "ui-unselecting" );
  192. selectee.unselecting = false;
  193. }
  194. if ( !selectee.selecting ) {
  195. that._addClass( selectee.$element, "ui-selecting" );
  196. selectee.selecting = true;
  197. // selectable SELECTING callback
  198. that._trigger( "selecting", event, {
  199. selecting: selectee.element
  200. } );
  201. }
  202. } else {
  203. // UNSELECT
  204. if ( selectee.selecting ) {
  205. if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) {
  206. that._removeClass( selectee.$element, "ui-selecting" );
  207. selectee.selecting = false;
  208. that._addClass( selectee.$element, "ui-selected" );
  209. selectee.selected = true;
  210. } else {
  211. that._removeClass( selectee.$element, "ui-selecting" );
  212. selectee.selecting = false;
  213. if ( selectee.startselected ) {
  214. that._addClass( selectee.$element, "ui-unselecting" );
  215. selectee.unselecting = true;
  216. }
  217. // selectable UNSELECTING callback
  218. that._trigger( "unselecting", event, {
  219. unselecting: selectee.element
  220. } );
  221. }
  222. }
  223. if ( selectee.selected ) {
  224. if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) {
  225. that._removeClass( selectee.$element, "ui-selected" );
  226. selectee.selected = false;
  227. that._addClass( selectee.$element, "ui-unselecting" );
  228. selectee.unselecting = true;
  229. // selectable UNSELECTING callback
  230. that._trigger( "unselecting", event, {
  231. unselecting: selectee.element
  232. } );
  233. }
  234. }
  235. }
  236. } );
  237. return false;
  238. },
  239. _mouseStop: function( event ) {
  240. var that = this;
  241. this.dragged = false;
  242. $( ".ui-unselecting", this.element[ 0 ] ).each( function() {
  243. var selectee = $.data( this, "selectable-item" );
  244. that._removeClass( selectee.$element, "ui-unselecting" );
  245. selectee.unselecting = false;
  246. selectee.startselected = false;
  247. that._trigger( "unselected", event, {
  248. unselected: selectee.element
  249. } );
  250. } );
  251. $( ".ui-selecting", this.element[ 0 ] ).each( function() {
  252. var selectee = $.data( this, "selectable-item" );
  253. that._removeClass( selectee.$element, "ui-selecting" )
  254. ._addClass( selectee.$element, "ui-selected" );
  255. selectee.selecting = false;
  256. selectee.selected = true;
  257. selectee.startselected = true;
  258. that._trigger( "selected", event, {
  259. selected: selectee.element
  260. } );
  261. } );
  262. this._trigger( "stop", event );
  263. this.helper.remove();
  264. return false;
  265. }
  266. } );
  267. } );