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