From ba95cf238576bb99a610ef996da6d4057cccd9fc Mon Sep 17 00:00:00 2001 From: Don Mitchell Date: Tue, 29 Jan 2013 13:10:23 -0500 Subject: [PATCH 1/5] Auto expand on hover of drag&drop unit --- cms/static/js/base.js | 67 +++++++++++++++++-- cms/static/js/hesitate.js | 31 +++++---- .../static/js/vendor/jquery.ui.draggable.js | 8 +++ 3 files changed, 86 insertions(+), 20 deletions(-) diff --git a/cms/static/js/base.js b/cms/static/js/base.js index ee8df97b28..a39056bde3 100644 --- a/cms/static/js/base.js +++ b/cms/static/js/base.js @@ -88,6 +88,9 @@ $(document).ready(function() { axis: 'y', handle: '.drag-handle', stack: '.unit', + start: initiateHesitate, + drag: checkHoverState, + stop: removeHesitate, revert: "invalid" }); @@ -179,10 +182,12 @@ function toggleSections(e) { if($button.hasClass('is-activated')) { $section.addClass('collapsed'); - $section.find('.expand-collapse-icon').removeClass('collapsed').addClass('expand'); + // first child in order to avoid the icons on the subsection lists which are not in the first child + $section.find('header .expand-collapse-icon').removeClass('collapse').addClass('expand'); } else { $section.removeClass('collapsed'); - $section.find('.expand-collapse-icon').removeClass('expand').addClass('collapse'); + // first child in order to avoid the icons on the subsection lists which are not in the first child + $section.find('header .expand-collapse-icon').removeClass('expand').addClass('collapse'); } } @@ -271,9 +276,63 @@ function removePolicyMetadata(e) { saveSubsection() } +CMS.HesitateEvent.toggleXpandHesitation = null; +function initiateHesitate(event, ui) { + CMS.HesitateEvent.toggleXpandHesitation = new CMS.HesitateEvent(expandSection, 'dragLeave', true); + $('.collapsed').on('dragEnter', CMS.HesitateEvent.toggleXpandHesitation, CMS.HesitateEvent.toggleXpandHesitation.trigger); + $('.collapsed').each(function() { + this.proportions = {width : this.offsetWidth, height : this.offsetHeight }; + // reset b/c these were holding values from aborts + this.isover = false; + }); +} +function checkHoverState(event, ui) { + // copied from jquery.ui.droppable.js $.ui.ddmanager.drag & other ui.intersect + var draggable = $(this).data("ui-draggable"), + x1 = (draggable.positionAbs || draggable.position.absolute).left + (draggable.helperProportions.width / 2), + y1 = (draggable.positionAbs || draggable.position.absolute).top + (draggable.helperProportions.height / 2); +var debugEle = $('article:first-of-type > section > div > ol:first-of-type > li:nth-of-type(2)').first(); + $('.collapsed').each(function() { + $.extend(this, {offset : $(this).offset()}); + + var droppable = this, + l = droppable.offset.left, + r = l + droppable.proportions.width, + t = droppable.offset.top, + b = t + droppable.proportions.height; + + if (l === r) { + // probably wrong values b/c invisible at the time of caching + droppable.proportions = { width : droppable.offsetWidth, height : droppable.offsetHeight }; + r = l + droppable.proportions.width; + b = t + droppable.proportions.height; + } + // equivalent to the intersects test + var intersects = (l < x1 && // Right Half + x1 < r && // Left Half + t < y1 && // Bottom Half + y1 < b ), // Top Half + + c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null); + + if(!c) { + return; + } + + this[c] = true; + this[c === "isout" ? "isover" : "isout"] = false; + $(this).trigger(c === "isover" ? "dragEnter" : "dragLeave"); + }); +} +function removeHesitate(event, ui) { + $('.collapsed').off('dragEnter', CMS.HesitateEvent.toggleXpandHesitation.trigger); + CMS.HesitateEvent.toggleXpandHesitation = null; +} + function expandSection(event) { - $(event.delegateTarget).removeClass('collapsed'); - $(event.delegateTarget).find('.expand-collapse-icon').removeClass('expand').addClass('collapse'); + $(event.delegateTarget).removeClass('collapsed', 400); + // don't descend to icon's on children (which aren't under first child) only to this element's icon + $(event.delegateTarget).children().first().find('.expand-collapse-icon').removeClass('expand', 400).addClass('collapse', 400); } function onUnitReordered(event, ui) { diff --git a/cms/static/js/hesitate.js b/cms/static/js/hesitate.js index 63806ba0ec..a261f036e6 100644 --- a/cms/static/js/hesitate.js +++ b/cms/static/js/hesitate.js @@ -20,31 +20,30 @@ CMS.HesitateEvent = function(executeOnTimeOut, cancelSelector, onlyOnce) { this.onlyOnce = (onlyOnce === true); } -CMS.HesitateEvent.DURATION = 400; +CMS.HesitateEvent.DURATION = 800; CMS.HesitateEvent.prototype.trigger = function(event) { -console.log('trigger'); - if (this.timeoutEventId === null) { - this.timeoutEventId = window.setTimeout(this.fireEvent, CMS.HesitateEvent.DURATION); - this.originalEvent = event; + if (event.data.timeoutEventId == null) { + event.data.timeoutEventId = window.setTimeout( + function() { event.data.fireEvent(event); }, + CMS.HesitateEvent.DURATION); + event.data.originalEvent = event; // is it wrong to bind to the below v $(event.currentTarget)? - $(this.originalEvent.delegateTarget).on(this.cancelSelector, this.untrigger); + $(event.data.originalEvent.delegateTarget).on(event.data.cancelSelector, event.data, event.data.untrigger); } } CMS.HesitateEvent.prototype.fireEvent = function(event) { -console.log('fire'); - this.timeoutEventId = null; - $(this.originalEvent.delegateTarget).off(this.cancelSelector, this.untrigger); - if (this.onlyOnce) $(this.originalEvent.delegateTarget).off(this.originalEvent.type, this.trigger); - this.executeOnTimeOut(this.originalEvent); + event.data.timeoutEventId = null; + $(event.data.originalEvent.delegateTarget).off(event.data.cancelSelector, event.data.untrigger); + if (event.data.onlyOnce) $(event.data.originalEvent.delegateTarget).off(event.data.originalEvent.type, event.data.trigger); + event.data.executeOnTimeOut(event.data.originalEvent); } CMS.HesitateEvent.prototype.untrigger = function(event) { -console.log('untrigger'); - if (this.timeoutEventId) { - window.clearTimeout(this.timeoutEventId); - $(this.originalEvent.delegateTarget).off(this.cancelSelector, this.untrigger); + if (event.data.timeoutEventId) { + window.clearTimeout(event.data.timeoutEventId); + $(event.data.originalEvent.delegateTarget).off(event.data.cancelSelector, event.data.untrigger); } - this.timeoutEventId = null; + event.data.timeoutEventId = null; } \ No newline at end of file diff --git a/common/static/js/vendor/jquery.ui.draggable.js b/common/static/js/vendor/jquery.ui.draggable.js index b04686507c..4fa5066bb4 100644 --- a/common/static/js/vendor/jquery.ui.draggable.js +++ b/common/static/js/vendor/jquery.ui.draggable.js @@ -209,6 +209,14 @@ $.widget("ui.draggable", $.ui.mouse, { // computation of pageY or scrollTop() or caching of scrollTop at same state as pageY // btw: known bug in jqueryui http://bugs.jqueryui.com/ticket/5718 if (this.scrollParent.is(document) && this.cssPosition === 'relative') { + // need to catch the original parent having been shoved down during drag (perhaps by + // events) + // update cached originals if it shifted + if (this.offset && this.offset.parent && this.offset.parent.top !== this._getParentOffset().top) { + var deltaY = this.offset.parent.top - this._getParentOffset().top; + this.offset.parent.top = this._getParentOffset().top; + this.originalPageY -= deltaY; + } this.helper[0].style.top = (event.pageY - this.originalPageY) +"px"; } else this.helper[0].style.top = this.position.top+"px"; From 5fcb6bfcd42d88a6198ba87d5c5ffbe89f814102 Mon Sep 17 00:00:00 2001 From: Don Mitchell Date: Tue, 29 Jan 2013 13:16:21 -0500 Subject: [PATCH 2/5] Remove debug code --- cms/static/js/base.js | 1 - 1 file changed, 1 deletion(-) diff --git a/cms/static/js/base.js b/cms/static/js/base.js index a39056bde3..9f5e493aad 100644 --- a/cms/static/js/base.js +++ b/cms/static/js/base.js @@ -291,7 +291,6 @@ function checkHoverState(event, ui) { var draggable = $(this).data("ui-draggable"), x1 = (draggable.positionAbs || draggable.position.absolute).left + (draggable.helperProportions.width / 2), y1 = (draggable.positionAbs || draggable.position.absolute).top + (draggable.helperProportions.height / 2); -var debugEle = $('article:first-of-type > section > div > ol:first-of-type > li:nth-of-type(2)').first(); $('.collapsed').each(function() { $.extend(this, {offset : $(this).offset()}); From 87d8598abe097328ddf766cb262a2bc78c695e90 Mon Sep 17 00:00:00 2001 From: Don Mitchell Date: Tue, 29 Jan 2013 13:43:58 -0500 Subject: [PATCH 3/5] subsection drag --- cms/static/js/base.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cms/static/js/base.js b/cms/static/js/base.js index 9f5e493aad..14a467c066 100644 --- a/cms/static/js/base.js +++ b/cms/static/js/base.js @@ -99,6 +99,9 @@ $(document).ready(function() { axis: 'y', handle: '.section-item .drag-handle', stack: '.id-holder', + start: initiateHesitate, + drag: checkHoverState, + stop: removeHesitate, revert: "invalid" }); @@ -292,6 +295,9 @@ function checkHoverState(event, ui) { x1 = (draggable.positionAbs || draggable.position.absolute).left + (draggable.helperProportions.width / 2), y1 = (draggable.positionAbs || draggable.position.absolute).top + (draggable.helperProportions.height / 2); $('.collapsed').each(function() { + // don't expand the thing being carried + if ($(draggable).is(this)) return; + $.extend(this, {offset : $(this).offset()}); var droppable = this, From 63d269acf1f122047163713bcf598b0940f430c6 Mon Sep 17 00:00:00 2001 From: Don Mitchell Date: Tue, 29 Jan 2013 14:31:14 -0500 Subject: [PATCH 4/5] draggable is not the collapsed item :-( but ui.helper seems to be. --- cms/static/js/base.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cms/static/js/base.js b/cms/static/js/base.js index 14a467c066..fe43fe2d71 100644 --- a/cms/static/js/base.js +++ b/cms/static/js/base.js @@ -87,7 +87,7 @@ $(document).ready(function() { $('.unit').draggable({ axis: 'y', handle: '.drag-handle', - stack: '.unit', + stack: '.unit, .id-holder', start: initiateHesitate, drag: checkHoverState, stop: removeHesitate, @@ -296,7 +296,9 @@ function checkHoverState(event, ui) { y1 = (draggable.positionAbs || draggable.position.absolute).top + (draggable.helperProportions.height / 2); $('.collapsed').each(function() { // don't expand the thing being carried - if ($(draggable).is(this)) return; + if (ui.helper.is(this)) { + return; + } $.extend(this, {offset : $(this).offset()}); From 574d6e8e28c5a840dd2931436d7326e99ec2b693 Mon Sep 17 00:00:00 2001 From: Don Mitchell Date: Tue, 29 Jan 2013 15:00:49 -0500 Subject: [PATCH 5/5] Simple zIndex rather than fancy stack works best. --- cms/static/js/base.js | 6 +++--- cms/static/js/hesitate.js | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/cms/static/js/base.js b/cms/static/js/base.js index fe43fe2d71..41c1ee3cdb 100644 --- a/cms/static/js/base.js +++ b/cms/static/js/base.js @@ -87,7 +87,7 @@ $(document).ready(function() { $('.unit').draggable({ axis: 'y', handle: '.drag-handle', - stack: '.unit, .id-holder', + zIndex: 999, start: initiateHesitate, drag: checkHoverState, stop: removeHesitate, @@ -98,7 +98,7 @@ $(document).ready(function() { $('.id-holder').draggable({ axis: 'y', handle: '.section-item .drag-handle', - stack: '.id-holder', + zIndex: 999, start: initiateHesitate, drag: checkHoverState, stop: removeHesitate, @@ -339,7 +339,7 @@ function removeHesitate(event, ui) { function expandSection(event) { $(event.delegateTarget).removeClass('collapsed', 400); // don't descend to icon's on children (which aren't under first child) only to this element's icon - $(event.delegateTarget).children().first().find('.expand-collapse-icon').removeClass('expand', 400).addClass('collapse', 400); + $(event.delegateTarget).children().first().find('.expand-collapse-icon').removeClass('expand', 400).addClass('collapse'); } function onUnitReordered(event, ui) { diff --git a/cms/static/js/hesitate.js b/cms/static/js/hesitate.js index a261f036e6..c5848a6c0c 100644 --- a/cms/static/js/hesitate.js +++ b/cms/static/js/hesitate.js @@ -18,7 +18,7 @@ CMS.HesitateEvent = function(executeOnTimeOut, cancelSelector, onlyOnce) { this.timeoutEventId = null; this.originalEvent = null; this.onlyOnce = (onlyOnce === true); -} +}; CMS.HesitateEvent.DURATION = 800; @@ -28,17 +28,16 @@ CMS.HesitateEvent.prototype.trigger = function(event) { function() { event.data.fireEvent(event); }, CMS.HesitateEvent.DURATION); event.data.originalEvent = event; - // is it wrong to bind to the below v $(event.currentTarget)? $(event.data.originalEvent.delegateTarget).on(event.data.cancelSelector, event.data, event.data.untrigger); } -} +}; CMS.HesitateEvent.prototype.fireEvent = function(event) { event.data.timeoutEventId = null; $(event.data.originalEvent.delegateTarget).off(event.data.cancelSelector, event.data.untrigger); if (event.data.onlyOnce) $(event.data.originalEvent.delegateTarget).off(event.data.originalEvent.type, event.data.trigger); event.data.executeOnTimeOut(event.data.originalEvent); -} +}; CMS.HesitateEvent.prototype.untrigger = function(event) { if (event.data.timeoutEventId) { @@ -46,4 +45,4 @@ CMS.HesitateEvent.prototype.untrigger = function(event) { $(event.data.originalEvent.delegateTarget).off(event.data.cancelSelector, event.data.untrigger); } event.data.timeoutEventId = null; -} \ No newline at end of file +}; \ No newline at end of file