From 26b530a0e7d0a14b49708565b00c7706600bb60c Mon Sep 17 00:00:00 2001 From: Mick McGrath Date: Tue, 11 Aug 2015 12:40:56 -0500 Subject: [PATCH 1/2] Add tolerance functionality and demo page --- event/drop/tolerance/tolerance.html | 125 +++++++++++++++++++++++++++ event/drop/tolerance/tolerance.js | 126 ++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+) create mode 100644 event/drop/tolerance/tolerance.html create mode 100644 event/drop/tolerance/tolerance.js diff --git a/event/drop/tolerance/tolerance.html b/event/drop/tolerance/tolerance.html new file mode 100644 index 00000000..418b4a0a --- /dev/null +++ b/event/drop/tolerance/tolerance.html @@ -0,0 +1,125 @@ + + + + drop + + + +
+

Tolerance Demo - Pointer

+
Drag Me
+

Dropout/Dropover

+
+
+ +
+

Tolerance Demo - Touch

+
Drag Me
+

Dropout/Dropover

+
+
+ +
+

Tolerance Demo - Fit

+
Drag Me
+

Dropout/Dropover

+
+
+ +
+

Tolerance Demo - Intersect

+
Drag Me
+

Dropout/Dropover

+
+
+ + + + + \ No newline at end of file diff --git a/event/drop/tolerance/tolerance.js b/event/drop/tolerance/tolerance.js new file mode 100644 index 00000000..aa897a38 --- /dev/null +++ b/event/drop/tolerance/tolerance.js @@ -0,0 +1,126 @@ +/** + * @add jQuery.Drop.prototype + */ + +steal('jquery', 'jquerypp/event/drop', function( $ ) { + + + var allowedTolerances = [ + 'touch', 'pointer', 'fit', 'intersect' + ]; + + + $.Drop.prototype + /** + * @plugin jquerypp/event/drop/tolerance + * @download http://jmvcsite.heroku.com/pluginify?plugins[]=jquerypp/event/event/drop/tolerance/tolerance.js + * + * @function jQuery.Drop.prototype.tolerance tolerance + * @parent jQuery.Drop.prototype + * + * @body + * `drop.tolerance(tolerance)` sets the tolerance. + * + * $("#todos-droparea").on("dropinit", function( ev, drop ) { + * drop.tolerance('touch'); + * }) + * + * @param {String} tolerance "fit" | "intersect" | "pointer" | "touch" (default: "pointer") + * @return {drop} returns the drop for chaining. + */ + .tolerance = function( tolerance ) { + if(allowedTolerances.indexOf(tolerance) > -1){ + this.tolerance = tolerance; + } + return this; + }; + + + $.extend($.Drop,{ + tolerance: 'pointer', + isAffected: function( point, moveable, responder ) { + switch(responder.tolerance){ + case "touch": + //TODO: would be nice to use this, but it does not handle outerWidth + //return (responder.element != moveable.element) && (moveable.element.withinBox(responder.element.offset().left, responder.element.offset().top, responder.element.outerWidth(), responder.element.outerHeight()).length == 1)); + + //TODO: cache width/height of elements for faster calculations + var $m = moveable.element, + $r = responder.element, + ro = $r.offset(), + rw = $r.outerWidth(), + rh = $r.outerHeight(), + rTop = ro.top, + rBottom = ro.top + rh, + rLeft = ro.left, + rRight = ro.left + rw, + + mo = moveable.element.offset(), + mw = $m.outerWidth(), + mh = $m.outerHeight(), + mTop = mo.top, + mBottom = mo.top + mh, + mLeft = mo.left, + mRight = mo.left + mw, + res = !( (mTop > rBottom) || (mBottom < rTop) || (mLeft > rRight) || (mRight < rLeft)); + + return ((responder.element != moveable.element) && res); + break; + + case "fit": + //TODO: cache width/height of elements for faster calculations + var $m = moveable.element, + $r = responder.element, + ro = $r.offset(), + rw = $r.outerWidth(), + rh = $r.outerHeight(), + rTop = ro.top, + rBottom = ro.top + rh, + rLeft = ro.left, + rRight = ro.left + rw, + + mo = moveable.element.offset(), + mw = $m.outerWidth(), + mh = $m.outerHeight(), + mTop = mo.top, + mBottom = mo.top + mh, + mLeft = mo.left, + mRight = mo.left + mw, + res = (mTop > rTop) && (mBottom < rBottom) && (mLeft > rLeft) && (mRight < rRight); + + return ((responder.element != moveable.element) && res); + break; + + case "intersect": + //TODO: cache width/height of elements for faster calculations + var $m = moveable.element, + $r = responder.element, + ro = $r.offset(), + rw = $r.outerWidth(), + rh = $r.outerHeight(), + rTop = ro.top, + rBottom = ro.top + rh, + rLeft = ro.left, + rRight = ro.left + rw, + + mo = moveable.element.offset(), + mw = $m.outerWidth(), + mh = $m.outerHeight(), + mTop = mo.top, + mBottom = mo.top + mh, + mLeft = mo.left, + mRight = mo.left + mw, + res = !( (mTop+(mh/2) > rBottom) || (mBottom-(mh/2) < rTop) || (mLeft+(mw/2) > rRight) || (mRight-(mw/2) < rLeft)); + + return ((responder.element != moveable.element) && res); + break; + case "pointer": + default: + return ((responder.element != moveable.element) && (responder.element.within(point[0], point[1], responder._cache).length == 1)); + break; + } + } + }); + + return $; +}); From a53bd5440b93b444e325e24e5194816636c092ff Mon Sep 17 00:00:00 2001 From: Mick McGrath Date: Thu, 24 Sep 2015 13:48:35 -0500 Subject: [PATCH 2/2] added tolerance demo to the drop.html page | added tests for drop dolerance to drop_test.js --- event/drop/drop.html | 152 +++++++++++ event/drop/drop_test.js | 587 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 704 insertions(+), 35 deletions(-) diff --git a/event/drop/drop.html b/event/drop/drop.html index 5859f39d..fc12ea98 100644 --- a/event/drop/drop.html +++ b/event/drop/drop.html @@ -4,6 +4,10 @@ drop + .demo-block{ + border:1px solid #555555; + margin:2em 5em; + } .handle { width: 100px; height: 25px; @@ -17,6 +21,11 @@ cursor : pointer; background-color: white; } + #droparea, .drop-area { + padding: 20px; + border: solid 1px blue; + margin:4em 6em; + } #dropout { padding: 20px; border: solid 1px blue; @@ -79,5 +88,148 @@

Dropmove/Dropon

}) + + +
+

Option: tolerance

+
+

Tolerance Demo - Pointer

+
Drag Me
+

Dropout/Dropover

+
+
+$('#droparea-pointer')
+  .bind("dropinit", function(ev, drop, drag){
+    drop.tolerance("pointer");
+  })
+  .bind("dropover", function(){ 
+    $(this).addClass('over') 
+  })
+  .bind("dropout", function(){ 
+    $(this).removeClass('over') 
+  });
+          
+
+
+ +
+

Tolerance Demo - Touch

+
Drag Me
+

Dropout/Dropover

+
+
+$('#droparea-touch')
+  .bind("dropinit", function(ev, drop, drag){
+    drop.tolerance("touch");
+  })
+  .bind("dropover", function(){ 
+    $(this).addClass('over') 
+  })
+  .bind("dropout", function(){ 
+    $(this).removeClass('over') 
+  });
+        
+
+
+ +
+

Tolerance Demo - Fit

+
Drag Me
+

Dropout/Dropover

+
+
+$('#droparea-fit')
+  .bind("dropinit", function(ev, drop, drag){
+    drop.tolerance("fit");
+  })
+  .bind("dropover", function(){ 
+    $(this).addClass('over') 
+  })
+  .bind("dropout", function(){ 
+    $(this).removeClass('over') 
+  });
+        
+
+
+ +
+

Tolerance Demo - Intersect

+
Drag Me
+

Dropout/Dropover

+
+
+$('#droparea-intersect')
+  .bind("dropinit", function(ev, drop, drag){
+    drop.tolerance("intersect");
+  })
+  .bind("dropover", function(){ 
+    $(this).addClass('over') 
+  })
+  .bind("dropout", function(){ 
+    $(this).removeClass('over') 
+  });
+        
+
+
+ + \ No newline at end of file diff --git a/event/drop/drop_test.js b/event/drop/drop_test.js index f32111a9..5e7f1527 100644 --- a/event/drop/drop_test.js +++ b/event/drop/drop_test.js @@ -1,52 +1,569 @@ -steal("jquerypp/event/drop",'syn', 'steal-qunit', function($, syn) { +steal("jquerypp/event/drop",'syn', 'jquerypp/event/drag/limit', 'jquerypp/event/drop/tolerance', 'steal-qunit', function($, syn) { -module("jquerypp/event/drop"); - -test("new drop added", 3, function(){ - var div = $("
"+ - "
"+ - "
"+ - "
"+ - "
"); - - div.appendTo($("#qunit-fixture")); - var basicCss = { - width: "20px", - height: "20px", - position: "absolute", - border: "solid 1px black" + module("jquerypp/event/drop"); + + + + var visibleFixture = function(){ + //make fixture visible + var $qunitFixture = $("#qunit-fixture"); + + $qunitFixture.css({ + "width": "100px", + "height": "100px", + "position": "absolute", + "top": "0", + "left": "0", + "background-color": "rgba(0,0,0,0.3)" + }); + }, + undoVisibleFixture = function(){ + var $qunitFixture = $("#qunit-fixture"); + + //undo make fixture visible + $qunitFixture.css({ + "width": "", + "height": "", + "position": "", + "top": "", + "left": "", + "background-color": "" + }); + }, + unbindDragDrop = function($drag, $drop){ + $drag.bind("draginit"); + $drop.unbind("dropinit").unbind("dropover").unbind("dropout"); }; - $("#drag").css(basicCss).css({top: "0px", left: "0px", zIndex: 1000, backgroundColor: "red"}); - $("#midpoint").css(basicCss).css({top: "0px", left: "30px"}); - $("#drop").css(basicCss).css({top: "0px", left: "60px"}); - $('#drag').bind("draginit", function(){}); + test("new drop added", 3, function(){ + var div = $("
"+ + "
"+ + "
"+ + "
"+ + "
"); + + div.appendTo($("#qunit-fixture")); + var basicCss = { + width: "20px", + height: "20px", + position: "absolute", + border: "solid 1px black" + }; + $("#drag").css(basicCss).css({top: "0px", left: "0px", zIndex: 1000, backgroundColor: "red"}); + $("#midpoint").css(basicCss).css({top: "0px", left: "30px"}); + $("#drop").css(basicCss).css({top: "0px", left: "60px"}); - $("#midpoint").bind("dropover",function(){ - ok(true, "midpoint called"); + $('#drag').bind("draginit", function(){}); - $("#drop").bind("dropover", function(){ - ok(true, "drop called"); + $("#midpoint").bind("dropover",function(){ + ok(true, "midpoint called"); + + $("#drop").bind("dropover", function(){ + ok(true, "drop called"); + }); + + $('body').on("dropon", function(ev) { + ok(false, 'parent dropon should not be called'); + }); + + $('#drop').on("dropon", function(ev) { + ok(true, 'dropon called'); + ev.stopPropagation(); + }); + + $.Drop.compile(); }); + stop(); + syn.drag("drag",{to: "#drop"}, function(){ + $('body').off('dropon'); + start(); + }); + }); + + - $('body').on("dropon", function(ev) { - ok(false, 'parent dropon should not be called'); + // ------- TOLERANCE POINTER ------- + test("tolerance - pointer", 2, function(){ + + stop(); + + var $qunitFixture = $("#qunit-fixture"), + $div = $("
").appendTo($qunitFixture), + $drag = $("
").appendTo($div), + $drop = $("
").appendTo($div), + basicCss = { + width: "18px", //18 + 2px for border === 20px square + height: "18px", + position: "absolute", + border: "solid 1px black" + }; + + + + visibleFixture(); + + + $drag.css(basicCss).css({top: "0px", left: "0px", zIndex: 1000, backgroundColor: "green"}); + $drop.css(basicCss).css({ + top: "0px", + left: "50px" }); - $('#drop').on("dropon", function(ev) { - ok(true, 'dropon called'); - ev.stopPropagation(); + $drag.bind("draginit", function(){}); + + $drop.bind("dropinit", function(ev, drop, drag){ + drop.tolerance("pointer"); + }) + .bind("dropover", function(){ + ok(true, "dropover called"); + }) + .bind("dropout", function(){ + ok(true, "dropout called"); + }); + + + + + //start the drag at 50 (which should trigger dragover) + //then move one to the left (which should trigger dragout) + syn.drag($drag.css("left","50px"),{ + from: { + pageX: 50, + pageY: 0 + }, + to: { + pageX: 49, + pageY: 0 + } + }, function(){ + undoVisibleFixture(); + unbindDragDrop($drag, $drop); + start(); }); + }); + + test("tolerance - pointer - no pointer", 0, function(){ + + stop(); + + var $qunitFixture = $("#qunit-fixture"), + $div = $("
").appendTo($qunitFixture), + $drag = $("
").appendTo($div), + $drop = $("
").appendTo($div), + basicCss = { + width: "18px", //18 + 2px for border === 20px square + height: "18px", + position: "absolute", + border: "solid 1px black" + }; + + + + visibleFixture(); + - $.Drop.compile(); + $drag.css(basicCss).css({top: "0px", left: "0px", zIndex: 1000, backgroundColor: "green"}); + $drop.css(basicCss).css({ + top: "0px", + left: "50px" + }); + + $drag.bind("draginit", function(){}); + + $drop.bind("dropinit", function(ev, drop, drag){ + drop.tolerance("pointer"); + }) + .bind("dropover", function(){ + ok(false, "dropover called"); + }) + .bind("dropout", function(){ + ok(false, "dropout called"); + }); + + + + + //start the drag at 0 + //then move until all but the piece with the pointer is inside drop + syn.drag($drag,{ + from: { + pageX: 0, + pageY: 0 + }, + to: { + pageX: 49, + pageY: 0 + } + }, function(){ + undoVisibleFixture(); + unbindDragDrop($drag, $drop); + start(); + }); }); - stop(); - syn.drag("drag",{to: "#drop"}, function(){ - $('body').off('dropon'); - start(); + // ------- END TOLERANCE POINTER ------- + + + // ------- TOLERANCE TOUCH ------- + test("tolerance - touch", 2, function(){ + + stop(); + + var $qunitFixture = $("#qunit-fixture"), + $div = $("
").appendTo($qunitFixture), + $drag = $("
").appendTo($div), + $drop = $("
").appendTo($div), + basicCss = { + width: "18px", //18 + 2px for border === 20px square + height: "18px", + position: "absolute", + border: "solid 1px black" + }; + + + + visibleFixture(); + + + $drag.css(basicCss).css({top: "0px", left: "0px", zIndex: 1000, backgroundColor: "green"}); + $drop.css(basicCss).css({ + top: "0px", + left: "50px" + }); + + $drag.bind("draginit", function(){}); + + $drop.bind("dropinit", function(ev, drop, drag){ + drop.tolerance("touch"); + }) + .bind("dropover", function(){ + ok(true, "dropover called"); + }) + .bind("dropout", function(){ + ok(true, "dropout called"); + }); + + + + + //start the drag at 30 (which should trigger dragover) + //then move one to the left (which should trigger dragout) + syn.drag($drag.css("left","30px"),{ + from: { + pageX: 30, + pageY: 0 + }, + to: { + pageX: 29, + pageY: 0 + } + }, function(){ + undoVisibleFixture(); + unbindDragDrop($drag, $drop); + start(); + }); }); -}); + test("tolerance - touch - no touch", 0, function(){ + + stop(); + + var $qunitFixture = $("#qunit-fixture"), + $div = $("
").appendTo($qunitFixture), + $drag = $("
").appendTo($div), + $drop = $("
").appendTo($div), + basicCss = { + width: "18px", //18 + 2px for border === 20px square + height: "18px", + position: "absolute", + border: "solid 1px black" + }; + + + + visibleFixture(); + + + $drag.css(basicCss).css({top: "0px", left: "0px", zIndex: 1000, backgroundColor: "green"}); + $drop.css(basicCss).css({ + top: "0px", + left: "50px" + }); + + $drag.bind("draginit", function(){}); + + $drop.bind("dropinit", function(ev, drop, drag){ + drop.tolerance("touch"); + }) + .bind("dropover", function(){ + ok(false, "dropover called"); + }) + .bind("dropout", function(){ + ok(false, "dropout called"); + }); + + + + + //start the drag at 29 (which shouldn't trigger dragover) + //then move one to the left (which shouldn't trigger dragout) + syn.drag($drag.css("left","29px"),{ + from: { + pageX: 29, + pageY: 0 + }, + to: { + pageX: 28, + pageY: 0 + } + }, function(){ + undoVisibleFixture(); + unbindDragDrop($drag, $drop); + start(); + }); + }); + // ------- END TOLERANCE TOUCH ------- + + + // ------- TOLERANCE FIT ------- + test("tolerance - fit", 2, function(){ + + stop(); + + var $qunitFixture = $("#qunit-fixture"), + $div = $("
").appendTo($qunitFixture), + $drag = $("
").appendTo($div), + $drop = $("
").appendTo($div), + basicCss = { + width: "18px", //18 + 2px for border === 20px square + height: "18px", + position: "absolute", + border: "solid 1px black" + }; + + + + visibleFixture(); + + + $drag.css(basicCss).css({top: "0px", left: "0px", zIndex: 1000, backgroundColor: "green"}); + $drop.css(basicCss).css({ + top: "0px", + left: "50px", + width: "28px", + height: "28px" + }); + + $drag.bind("draginit", function(){}); + + $drop.bind("dropinit", function(ev, drop, drag){ + drop.tolerance("fit"); + }) + .bind("dropover", function(){ + ok(true, "dropover called"); + }) + .bind("dropout", function(){ + ok(true, "dropout called"); + }); + + + + + //start the drag at 50 (which should trigger dragover) + //then move 10 to the right (which should trigger dragout) + //the top should be 1 so that the drag resides *within* the drop + syn.drag($drag.css({left: "50px", top: "1px"}),{ + from: { + pageX: 50, + pageY: 1 + }, + to: { + pageX: 60, + pageY: 1 + } + }, function(){ + undoVisibleFixture(); + unbindDragDrop($drag, $drop); + start(); + }); + }); + + test("tolerance - fit - no fit", 0, function(){ + + stop(); + + var $qunitFixture = $("#qunit-fixture"), + $div = $("
").appendTo($qunitFixture), + $drag = $("
").appendTo($div), + $drop = $("
").appendTo($div), + basicCss = { + width: "18px", //18 + 2px for border === 20px square + height: "18px", + position: "absolute", + border: "solid 1px black" + }; + + + + visibleFixture(); + + + $drag.css(basicCss).css({top: "0px", left: "0px", zIndex: 1000, backgroundColor: "green"}); + $drop.css(basicCss).css({ + top: "0px", + left: "50px", + width: "28px", + height: "28px" + }); + + $drag.bind("draginit", function(){}); + + $drop.bind("dropinit", function(ev, drop, drag){ + drop.tolerance("fit"); + }) + .bind("dropover", function(){ + ok(false, "dropover called"); + }) + .bind("dropout", function(){ + ok(false, "dropout called"); + }); + + + //since the top is 0, it should't trigger the drop (its outside is equal to the drop, not within) + syn.drag($drag.css({left: "50px", top: "0px"}),{ + from: { + pageX: 50, + pageY: 0 + }, + to: { + pageX: 60, + pageY: 0 + } + }, function(){ + undoVisibleFixture(); + unbindDragDrop($drag, $drop); + start(); + }); + }); + // ------- END TOLERANCE FIT ------- + + + + // ------- TOLERANCE INTERSECT ------- + test("tolerance - intersect", 2, function(){ + + stop(); + + var $qunitFixture = $("#qunit-fixture"), + $div = $("
").appendTo($qunitFixture), + $drag = $("
").appendTo($div), + $drop = $("
").appendTo($div), + basicCss = { + width: "18px", //18 + 2px for border === 20px square + height: "18px", + position: "absolute", + border: "solid 1px black" + }; + + + + visibleFixture(); + + + $drag.css(basicCss).css({top: "0px", left: "0px", zIndex: 1000, backgroundColor: "green"}); + $drop.css(basicCss).css({ + top: "0px", + left: "50px" + }); + + $drag.bind("draginit", function(){}); + + $drop.bind("dropinit", function(ev, drop, drag){ + drop.tolerance("intersect"); + }) + .bind("dropover", function(){ + ok(true, "dropover called"); + }) + .bind("dropout", function(){ + ok(true, "dropout called"); + }); + + + + + //start the drag at 40 (which should trigger dragover) + //then move 1 to the left (which should trigger dragout) + syn.drag($drag.css("left", "40px"),{ + from: { + pageX: 40, + pageY: 0 + }, + to: { + pageX: 39, + pageY: 0 + } + }, function(){ + undoVisibleFixture(); + unbindDragDrop($drag, $drop); + start(); + }); + }); + + test("tolerance - intersect - no intersect", 0, function(){ + + stop(); + + var $qunitFixture = $("#qunit-fixture"), + $div = $("
").appendTo($qunitFixture), + $drag = $("
").appendTo($div), + $drop = $("
").appendTo($div), + basicCss = { + width: "18px", //18 + 2px for border === 20px square + height: "18px", + position: "absolute", + border: "solid 1px black" + }; + + + + visibleFixture(); + + + $drag.css(basicCss).css({top: "0px", left: "0px", zIndex: 1000, backgroundColor: "green"}); + $drop.css(basicCss).css({ + top: "0px", + left: "50px" + }); + + $drag.bind("draginit", function(){}); + + $drop.bind("dropinit", function(ev, drop, drag){ + drop.tolerance("intersect"); + }) + .bind("dropover", function(){ + ok(false, "dropover called"); + }) + .bind("dropout", function(){ + ok(false, "dropout called"); + }); + + + //start at 0, move to where drag is 1 less than half-way over drop + syn.drag($drag,{ + from: { + pageX: 0, + pageY: 0 + }, + to: { + pageX: 39, + pageY: 0 + } + }, function(){ + undoVisibleFixture(); + unbindDragDrop($drag, $drop); + start(); + }); + }); + // ------- END TOLERANCE INTERSECT ------- });