Skip to content

Commit

Permalink
Merge pull request #10 from lemonde/raw-optimisations
Browse files Browse the repository at this point in the history
feat : add a raw version for all handlers, called outside angular $apply
  • Loading branch information
chpill committed Sep 7, 2015
2 parents 2e8468f + 05b3b76 commit 7f8e213
Show file tree
Hide file tree
Showing 3 changed files with 284 additions and 71 deletions.
101 changes: 70 additions & 31 deletions angular-draganddrop.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ function draggableDirective($parse) {
var dragStartHandler = $parse(attrs.dragStart);
var dragEndHandler = $parse(attrs.dragEnd);

var rawDragStartHandler = $parse(attrs.dragStartRaw);
var rawDragEndHandler = $parse(attrs.dragEndRaw);

domElement.addEventListener('dragstart', dragStartListener);
domElement.addEventListener('dragend', dragEndListener);

Expand Down Expand Up @@ -103,10 +106,15 @@ function draggableDirective($parse) {
// Set drag data and drag type.
event.dataTransfer.setData('json/' + draggableType, jsonData);

// Call custom handler
scope.$apply(function () {
dragStartHandler(scope, { $data: data, $event: event });
});
// Call custom handlers
if (attrs.dragStartRaw) {
rawDragStartHandler(scope, { $data: data, $event: event });
}
if (attrs.dragStart) {
scope.$apply(function () {
dragStartHandler(scope, { $data: data, $event: event });
});
}

event.stopPropagation();
}
Expand All @@ -119,10 +127,15 @@ function draggableDirective($parse) {
// Eval and serialize data.
var data = safeDraggableDataEval();

// Call custom handler
scope.$apply(function () {
dragEndHandler(scope, { $data: data, $event: event });
});
// Call custom handlers
if (attrs.dragEndRaw) {
rawDragEndHandler(scope, { $data: data, $event: event });
}
if (attrs.dragEnd) {
scope.$apply(function () {
dragEndHandler(scope, { $data: data, $event: event });
});
}

event.stopPropagation();
}
Expand Down Expand Up @@ -165,6 +178,11 @@ function dropDirective($parse) {
var dragLeaveHandler = $parse(attrs.dragLeave);
var dropHandler = $parse(attrs.drop);

var rawDragOverHandler = $parse(attrs.dragOverRaw);
var rawDragEnterHandler = $parse(attrs.dragEnterRaw);
var rawDragLeaveHandler = $parse(attrs.dragLeaveRaw);
var rawDropHandler = $parse(attrs.dropRaw);

domElement.addEventListener('dragover', dragOverListener);
domElement.addEventListener('dragenter', dragEnterListener);
domElement.addEventListener('dragleave', dragLeaveListener);
Expand Down Expand Up @@ -204,14 +222,18 @@ function dropDirective($parse) {
}
throttledDragover = now;

if (! attrs.dragOver) return;

// Call custom handler
// Call custom handlers
var data = getData(event);
scope.$apply(function () {
debugDroppable(scope, 'dragover callback !');
dragOverHandler(scope, { $data: data, $event: event });
});
if (attrs.dragOverRaw) {
debugDroppable(scope, 'raw dragover callback !');
rawDragOverHandler(scope, { $data: data, $event: event });
}
if (attrs.dragOver) {
scope.$apply(function () {
debugDroppable(scope, 'dragover callback !');
dragOverHandler(scope, { $data: data, $event: event });
});
}
}

function dragEnterListener(event) {
Expand All @@ -225,13 +247,18 @@ function dropDirective($parse) {

if (dragOverClass) element.addClass(dragOverClass);

if (! attrs.dragEnter) return;

// Call custom handler
// Call custom handlers
var data = getData(event);
scope.$apply(function () {
dragEnterHandler(scope, { $data: data, $event: event });
});
if (attrs.dragEnterRaw) {
debugDroppable(scope, 'raw dragenter callback !');
rawDragEnterHandler(scope, { $data: data, $event: event });
}
if (attrs.dragEnter) {
scope.$apply(function () {
debugDroppable(scope, 'dragenter callback !');
dragEnterHandler(scope, { $data: data, $event: event });
});
}
}

function dragLeaveListener(event) {
Expand All @@ -245,13 +272,18 @@ function dropDirective($parse) {

element.removeClass(dragOverClass);

if (! attrs.dragLeave) return;

// Call custom handler
// Call custom handlers
var data = getData(event);
scope.$apply(function () {
dragLeaveHandler(scope, { $data: data, $event: event });
});
if (attrs.dragLeaveRaw) {
debugDroppable(scope, 'raw dragleave callback !');
rawDragLeaveHandler(scope, { $data: data, $event: event });
}
if (attrs.dragLeave) {
scope.$apply(function () {
debugDroppable(scope, 'dragleave callback !');
dragLeaveHandler(scope, { $data: data, $event: event });
});
}
}

function dropListener(event) {
Expand All @@ -262,11 +294,18 @@ function dropDirective($parse) {

element.removeClass(dragOverClass);

// Call custom handler
// Call custom handlers
var data = getData(event);
scope.$apply(function () {
dropHandler(scope, { $data: data, $event: event });
});
if (attrs.dropRaw) {
debugDroppable(scope, 'raw drop callback !');
rawDropHandler(scope, { $data: data, $event: event });
}
if (attrs.drop) {
scope.$apply(function () {
debugDroppable(scope, 'drop callback !');
dropHandler(scope, { $data: data, $event: event });
});
}
}

/**
Expand Down
90 changes: 78 additions & 12 deletions test/draggable.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,52 +160,118 @@ describe('Draggable directive', function () {
});

describe('handlers', function() {
var digestWasInProgress;
beforeEach(function() {
digestWasInProgress = undefined;
$scope.onEvent = sinon.spy(function () {
digestWasInProgress = !!$scope.$$phase;
});
});

describe('dragstart', function() {
describe('"drag-start-raw"', function() {
beforeEach(function() {
$scope.onDrag = sinon.spy();
var tpl = '<div draggable ' +
'draggable-type="image" draggable-data="{foo: \'bar\'}" ' +
'drag-start="onDrag($event, $data)"></div>';
'drag-start-raw="onEvent($event, $data)"></div>';
createElement(tpl);

dispatchEvent(element, testDragStartEvent);
});

it('should be called on dragstart when present', function() {
expect($scope.onDrag).to.have.been.calledOnce;
expect($scope.onEvent).to.have.been.calledOnce;
});

it('should provide correct $event and $data', function() {
expect($scope.onEvent.firstCall.args[0], '$event').to.equal(testDragStartEvent);
expect($scope.onEvent.firstCall.args[1], '$data').to.deep.equal({
foo: 'bar'
});
});

it('should NOT be called in an Angular $apply context', function() {
expect(digestWasInProgress).to.be.false;
});
});

describe('"drag-start', function() {
beforeEach(function() {
var tpl = '<div draggable ' +
'draggable-type="image" draggable-data="{foo: \'bar\'}" ' +
'drag-start="onEvent($event, $data)"></div>';
createElement(tpl);

dispatchEvent(element, testDragStartEvent);
});

it('should be called on dragstart when present', function() {
expect($scope.onEvent).to.have.been.calledOnce;
});

it('should provide correct $event and $data', function() {
expect($scope.onEvent.firstCall.args[0], '$event').to.equal(testDragStartEvent);
expect($scope.onEvent.firstCall.args[1], '$data').to.deep.equal({
foo: 'bar'
});
});

it('should be called in an Angular $apply context', function() {
expect(digestWasInProgress).to.be.true;
});
});

describe('"drag-end-raw"', function() {
beforeEach(function() {
var tpl = '<div draggable ' +
'draggable-type="image" draggable-data="{foo: \'bar\'}" ' +
'drag-end-raw="onEvent($event, $data)"></div>';
createElement(tpl);

dispatchEvent(element, testDragStartEvent);
dispatchEvent(element, testDragEndEvent);
});

it('should be called on dragend when present', function() {
expect($scope.onEvent).to.have.been.calledOnce;
});

it('should provide correct $event and $data', function() {
expect($scope.onDrag.firstCall.args[0], '$event').to.equal(testDragStartEvent);
expect($scope.onDrag.firstCall.args[1], '$data').to.deep.equal({
expect($scope.onEvent.firstCall.args[0], '$event').to.equal(testDragEndEvent);
expect($scope.onEvent.firstCall.args[1], '$data').to.deep.equal({
foo: 'bar'
});
});

it('should NOT be called in an Angular $apply context', function() {
expect(digestWasInProgress).to.be.false;
});
});

describe('dragend', function() {
describe('"drag-end"', function() {
beforeEach(function() {
$scope.onDrag = sinon.spy();
var tpl = '<div draggable ' +
'draggable-type="image" draggable-data="{foo: \'bar\'}" ' +
'drag-end="onDrag($event, $data)"></div>';
'drag-end="onEvent($event, $data)"></div>';
createElement(tpl);

dispatchEvent(element, testDragStartEvent);
dispatchEvent(element, testDragEndEvent);
});

it('should be called on dragend when present', function() {
expect($scope.onDrag).to.have.been.calledOnce;
expect($scope.onEvent).to.have.been.calledOnce;
});

it('should provide correct $event and $data', function() {
expect($scope.onDrag.firstCall.args[0], '$event').to.equal(testDragEndEvent);
expect($scope.onDrag.firstCall.args[1], '$data').to.deep.equal({
expect($scope.onEvent.firstCall.args[0], '$event').to.equal(testDragEndEvent);
expect($scope.onEvent.firstCall.args[1], '$data').to.deep.equal({
foo: 'bar'
});
});

it('should be called in an Angular $apply context', function() {
expect(digestWasInProgress).to.be.true;
});
});
});

Expand Down
Loading

0 comments on commit 7f8e213

Please sign in to comment.