Skip to content

Commit

Permalink
Feature: implement drag start action (lolmaus#45)
Browse files Browse the repository at this point in the history
* Chore: pin nise

Something that sinon/nise did has caused ember-auto-import to throw an error when trying to import it, so pin nise (which we don't use anyway) to an old version that doesn't blow up.

* Feature: implement drag start action

Implement an onDragStart action that gives consumers access to the event object so they can do things like customize the drag image.

* Drag start action: minor fixes

Co-authored-by: Andrey Mikhaylov (lolmaus) <[email protected]>

Conflicts:
	addon/templates/components/drag-sort-list.hbs
	yarn.lock
  • Loading branch information
Ben Demboski authored and lolmaus committed Aug 17, 2020
1 parent c84749a commit 8c44fa0
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 13 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@
/.idea/
/*.iml
/jsconfig.json
/.history/
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,22 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.



## [0.0.0-beta.0] - 2020-01-05
## [3.0.0] - 2020-08-17

### Added
* `dragStartAction` allows updating drag image, by [@bendemboski](https://github.com/bendemboski).



## [3.0.0-beta.0] - 2020-01-05

### Changed
* ⚠ Dropped support for Ember CLI below 3.12.

### Maintenance
* Upgraded Ember CLI to 3.15 and dependencies.
* Converted templates to angle brackets.
* Minor maintenance changes.



Expand Down
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
- [Usage](#usage)
- [Basic usage](#basic-usage)
- [The drag end action](#the-drag-end-action)
- [The drag start action](#the-drag-start-action)
- [The determine foreign position action](#the-determine-foreign-position-action)
- [Marking a list as a source only bucket](#marking-a-list-as-a-source-only-bucket)
- [Passing additional arguments](#passing-additional-arguments)
Expand Down Expand Up @@ -203,6 +204,50 @@ Here's the reference implementation of the `dragEndAction` action:



### The drag start action

This action is called when a drag is beginning, and can be used to customize the drag image, or otherwise modify the data transfer. It's called with a single argument -- an object with the following properties:

| Property | Type | Description |
|:---------------|:-------------|:--------------------------------------------------|
| `event` | Event | The `dragstart` event. |
| `element` | DOMElement | The DOM element being dragged. |
| `draggedItem` | <any> | The list item being dragged. |

This can be used to put margins around the list items without those margins being included in the drag image:

```css
.the-item {
margin: 20px;
}
```

```handlebars
{{#drag-sort-list
items = items1
dragStartAction = (action 'dragStart')
dragEndAction = (action 'dragEnd')
as |item|
}}
<div class="the-item">
{{item.name}}
</div>
{{/drag-sort-list}}
```

```javascript
actions: {
dragStart({ event, element }) {
let target = element.querySelector('.the-item');
let { x, y } = element.getBoundingClientRect();
// Set drag image, positioning it to align with `.the-item`'s position
event.dataTransfer.setDragImage(target, event.clientX - x, event.clientY - y);
}
}
```



### The determine foreign position action

You may want to let the user drag items in and out of a list, without letting him rearrange items within a list. In that case the order of items is determined by the app.
Expand Down Expand Up @@ -331,6 +376,7 @@ dragEndAction({ sourceList, sourceIndex, sourceArgs, targetList, targetIndex, ta
|:---------------------------------|:---------------------------------------------|:--------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `items` | Ember Array | <required> | An array of items to display and offer sorting. |
| `dragEndAction` | Closure action | <required> | This callback will be called on source list when sorting is complete. See above for details. |
| `dragStartAction` | Closure action | <required> | This callback will be called on source list when dragging is starting. See above for details. |
| `determineForeignPositionAction` | Closure action or `undefined` | `undefined` | When provided, used to determine the position of the placeholder when dragging a foreign item into the list. When not provided, the user is able to determine the order. See above for details. |
| `group` | <any> | `undefined` | Used to restrict dragging between multiple lists to only some of those lists. Typically a string. |
| `draggingEnabled` | Boolean | `true` | Disables sorting. Useful when `dragEndAction` is an async operation. |
Expand Down
14 changes: 14 additions & 0 deletions addon/components/drag-sort-item.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export default Component.extend({
sourceOnly : false,

dragEndAction : undefined,
dragStartAction : undefined,
determineForeignPositionAction : undefined,


Expand Down Expand Up @@ -162,6 +163,19 @@ export default Component.extend({
if (event.dataTransfer.setDragImage) event.dataTransfer.setDragImage(this.element, 0, 0)
}

const dragStartAction = this.get('dragStartAction')

if (dragStartAction) {
const element = this.get('element')
const item = this.get('item')

dragStartAction({
event,
element,
draggedItem : item,
})
}

this.startDragging(event)
},

Expand Down
1 change: 1 addition & 0 deletions addon/components/drag-sort-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default Component.extend({
isRtl : false,

dragEndAction : undefined,
dragStartAction : undefined,
determineForeignPositionAction : undefined,


Expand Down
5 changes: 3 additions & 2 deletions addon/templates/components/drag-sort-list.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
@isHorizontal = {{this.isHorizontal}}
@isRtl = {{this.isRtl}}
@draggingEnabled = {{this.draggingEnabled}}
@dragEndAction = {{this.dragEndAction}}
@determineForeignPositionAction = {{this.determineForeignPositionAction}}
@sourceOnly = {{this.sourceOnly}}

@dragEndAction = {{this.dragEndAction}}
@dragStartAction = {{this.dragStartAction}}
@determineForeignPositionAction = {{this.determineForeignPositionAction}}

class = {{this.childClass}}
>
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
"demoURL": "https://kaliber5.github.io/ember-drag-sort/"
},
"resolutions": {
"gift": "^0.10.2"
"gift": "^0.10.2",
"**/nise": "1.5.2"
}
}
17 changes: 17 additions & 0 deletions tests/dummy/app/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,15 @@ export default Controller.extend({
])
),

dragImage : computed(() =>
A([
{name : 'Foo'},
{name : 'Bar'},
{name : 'Baz'},
{name : 'Quux'},
])
),

nestedItem : computed(() => (
{
name : 'Foo',
Expand Down Expand Up @@ -244,6 +253,14 @@ export default Controller.extend({

if (targetList !== sourceOnlyList) targetList.insertAt(targetIndex, item)
},

setDragImage ({ event, element }) {
const target = element.querySelector('.the-item')
const { x, y } = element.getBoundingClientRect()

// Set drag image, positioning it to align with `.the-item`'s position
event.dataTransfer.setDragImage(target, event.clientX - x, event.clientY - y)
},
},

dragEndTask : task(function * ({sourceList, sourceIndex, targetList, targetIndex}) {
Expand Down
29 changes: 29 additions & 0 deletions tests/dummy/app/templates/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,8 @@
</section>
</div>



<div class="list-group-wrapper">
<h2>Horizontal list wwith RTL</h2>

Expand All @@ -433,6 +435,33 @@
</article>
</section>
</div>



<div class="list-group-wrapper">
<h2>Custom drag image</h2>

<p>
Note that the drag image does not contain the gray margins around the boxes
</p>

<section class="list-group">
<article class="list">
<DragSortList
id = "drag-image"
@items = {{this.dragImage}}
@group = "dragImage"
@dragStartAction = {{action "setDragImage"}}
@dragEndAction = {{action "dragEnd"}}
as |item|
>
<div class="the-item">
{{item.name}}
</div>
</DragSortList>
</article>
</section>
</div>
</div>


Expand Down
48 changes: 47 additions & 1 deletion tests/integration/components/drag-sort-list-test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { module, test } from 'qunit'
import { setupRenderingTest } from 'ember-qunit'
import { find, findAll, render, settled } from '@ember/test-helpers'
import { find, findAll, render, settled, triggerEvent } from '@ember/test-helpers'
import hbs from 'htmlbars-inline-precompile'
import trigger from 'ember-drag-sort/utils/trigger'
import sinon from 'sinon'
Expand Down Expand Up @@ -212,4 +212,50 @@ module('Integration | Component | drag-sort-list', function (hooks) {
targetIndex : 1,
}))
})

test('drag start action', async function (assert) {
const items = A([
{name : 'foo'},
{name : 'bar'},
{name : 'baz'},
])

const dragStartCallback = sinon.stub()

dragStartCallback.callsFake(({ event, element }) => {
event.dataTransfer.setDragImage(element.querySelector('.item-wrapper'), 20, 30)
})

this.setProperties({items, dragStartCallback})

await render(hbs`
{{#drag-sort-list
items = items
dragStartAction = (action dragStartCallback)
as |item|
}}
<div class="item-wrapper">
{{item.name}}
</div>
{{/drag-sort-list}}
`)


const itemElements = findAll('.dragSortItem')
const [item0] = itemElements

const dataTransfer = new DataTransfer()
sinon.spy(dataTransfer, 'setDragImage')

await triggerEvent(item0, 'dragstart', { dataTransfer })

assert.ok(dragStartCallback.calledOnce)

assert.ok(dragStartCallback.calledWithMatch({
draggedItem : items.objectAt(0),
element : item0,
}))
assert.ok(dataTransfer.setDragImage.called)
assert.ok(dataTransfer.setDragImage.lastCall.calledWithExactly(item0.querySelector('.item-wrapper'), 20, 30))
})
})
28 changes: 20 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,14 @@
dependencies:
type-detect "4.0.8"

"@sinonjs/formatio@^3.2.1":
version "3.2.1"
resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-3.2.1.tgz#52310f2f9bcbc67bdac18c94ad4901b95fde267e"
integrity sha512-tsHvOB24rvyvV2+zKMmPkZ7dXX6LSLKZ7aOtXY6Edklp0uRcgGpOsQTTGTcWViFyx4uhWc6GV8QdnALbIbIdeQ==
dependencies:
"@sinonjs/commons" "^1"
"@sinonjs/samsam" "^3.1.0"

"@sinonjs/formatio@^4.0.1":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-4.0.1.tgz#50ac1da0c3eaea117ca258b06f4f88a471668bdb"
Expand Down Expand Up @@ -7552,7 +7560,12 @@ log-symbols@^2.2.0:
dependencies:
chalk "^2.0.1"

lolex@^5.0.1, lolex@^5.1.2:
lolex@^4.1.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lolex/-/lolex-4.2.0.tgz#ddbd7f6213ca1ea5826901ab1222b65d714b3cd7"
integrity sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==

lolex@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/lolex/-/lolex-5.1.2.tgz#953694d098ce7c07bc5ed6d0e42bc6c0c6d5a367"
integrity sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==
Expand Down Expand Up @@ -8021,16 +8034,15 @@ nice-try@^1.0.4:
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==

nise@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/nise/-/nise-3.0.1.tgz#0659982af515e5aac15592226246243e8da0013d"
integrity sha512-fYcH9y0drBGSoi88kvhpbZEsenX58Yr+wOJ4/Mi1K4cy+iGP/a73gNoyNhu5E9QxPdgTlVChfIaAlnyOy/gHUA==
nise@1.5.2, nise@^3.0.1:
version "1.5.2"
resolved "https://registry.yarnpkg.com/nise/-/nise-1.5.2.tgz#b6d29af10e48b321b307e10e065199338eeb2652"
integrity sha512-/6RhOUlicRCbE9s+94qCUsyE+pKlVJ5AhIv+jEE7ESKwnbXqulKZ1FYU+XAtHHWE9TinYvAxDUJAb912PwPoWA==
dependencies:
"@sinonjs/commons" "^1.7.0"
"@sinonjs/formatio" "^4.0.1"
"@sinonjs/formatio" "^3.2.1"
"@sinonjs/text-encoding" "^0.7.1"
just-extend "^4.0.2"
lolex "^5.0.1"
lolex "^4.1.0"
path-to-regexp "^1.7.0"

no-case@^3.0.3:
Expand Down

0 comments on commit 8c44fa0

Please sign in to comment.