|
1191 | 1191 | function buildSwipe(stage, img) { |
1192 | 1192 | var pos = 0.5; |
1193 | 1193 | var layer = h('div', { class: 'layer' }, [ |
1194 | | - h('img', { src: img.control, alt: 'Baseline screenshot' }), |
| 1194 | + h('img', { |
| 1195 | + src: img.control, |
| 1196 | + alt: 'Baseline screenshot', |
| 1197 | + // String 'false', not boolean: the h() helper drops false-valued |
| 1198 | + // props, and draggable is an enumerated attribute anyway. |
| 1199 | + draggable: 'false', |
| 1200 | + }), |
1195 | 1201 | ]); |
1196 | 1202 | var divider = h( |
1197 | 1203 | 'div', |
|
1216 | 1222 | }; |
1217 | 1223 | var dragging = false; |
1218 | 1224 | var shot = h('div', { class: 'shot swipe-stage' }, [ |
1219 | | - h('img', { src: img.capture, alt: 'Current screenshot' }), |
| 1225 | + h('img', { |
| 1226 | + src: img.capture, |
| 1227 | + alt: 'Current screenshot', |
| 1228 | + draggable: 'false', |
| 1229 | + }), |
1220 | 1230 | layer, |
1221 | 1231 | divider, |
1222 | 1232 | h('span', { class: 'taglabel l', text: 'baseline' }), |
|
1226 | 1236 | var rect = shot.getBoundingClientRect(); |
1227 | 1237 | return clamp01((e.clientX - rect.left) / rect.width); |
1228 | 1238 | }; |
| 1239 | + var endDrag = function (e) { |
| 1240 | + dragging = false; |
| 1241 | + // Release capture so the stage stops receiving pointer events once |
| 1242 | + // the gesture is over. |
| 1243 | + if (e && shot.hasPointerCapture(e.pointerId)) { |
| 1244 | + shot.releasePointerCapture(e.pointerId); |
| 1245 | + } |
| 1246 | + }; |
1229 | 1247 | shot.addEventListener('pointerdown', function (e) { |
| 1248 | + // Primary button / touch / pen only — ignore right- and middle-click. |
| 1249 | + if (e.button !== 0) { |
| 1250 | + return; |
| 1251 | + } |
| 1252 | + // Suppress the browser's native image drag and text selection, which |
| 1253 | + // would otherwise hijack the gesture and fire pointercancel instead |
| 1254 | + // of pointerup, leaving the divider stuck to the cursor. |
| 1255 | + e.preventDefault(); |
1230 | 1256 | dragging = true; |
1231 | 1257 | shot.setPointerCapture(e.pointerId); |
1232 | 1258 | setPos(posFromEvent(e)); |
|
1236 | 1262 | setPos(posFromEvent(e)); |
1237 | 1263 | } |
1238 | 1264 | }); |
1239 | | - shot.addEventListener('pointerup', function () { |
| 1265 | + // End on up and on cancel/lost-capture, so an interrupted gesture can |
| 1266 | + // never leave dragging stuck on. |
| 1267 | + shot.addEventListener('pointerup', endDrag); |
| 1268 | + shot.addEventListener('pointercancel', endDrag); |
| 1269 | + shot.addEventListener('lostpointercapture', function () { |
1240 | 1270 | dragging = false; |
1241 | 1271 | }); |
1242 | 1272 | stage.appendChild(shot); |
|
0 commit comments