From e984d6be4faddea0094b25e25b3794962f98516b Mon Sep 17 00:00:00 2001
From: cahrens
Date: Tue, 22 Jul 2014 14:16:45 -0400
Subject: [PATCH 1/4] Drag and drop support on the course outline page.
---
.../contentstore/features/course-outline.py | 11 --
.../js/spec/utils/drag_and_drop_spec.js | 48 ++++++--
.../spec/views/pages/course_outline_spec.js | 6 +-
cms/static/js/utils/drag_and_drop.js | 104 +++++++++++-------
cms/static/js/views/course_outline.js | 41 ++++++-
cms/static/js/views/overview.js | 29 +----
cms/static/sass/elements/_controls.scss | 3 +
cms/static/sass/views/_outline.scss | 4 +
cms/templates/js/course-outline.underscore | 15 ++-
cms/templates/js/xblock-outline.underscore | 5 -
10 files changed, 168 insertions(+), 98 deletions(-)
diff --git a/cms/djangoapps/contentstore/features/course-outline.py b/cms/djangoapps/contentstore/features/course-outline.py
index 8786cfcaf11f..f9ceb6ff680e 100644
--- a/cms/djangoapps/contentstore/features/course-outline.py
+++ b/cms/djangoapps/contentstore/features/course-outline.py
@@ -131,14 +131,3 @@ def all_sections_are_collapsed_or_expanded(step, text):
def change_grading_status(step):
world.css_find('a.menu-toggle').click()
world.css_find('.menu li').first.click()
-
-
-@step(u'I reorder subsections')
-def reorder_subsections(_step):
- draggable_css = '.subsection-drag-handle'
- ele = world.css_find(draggable_css).first
- ele.action_chains.drag_and_drop_by_offset(
- ele._element,
- 0,
- 25
- ).perform()
diff --git a/cms/static/js/spec/utils/drag_and_drop_spec.js b/cms/static/js/spec/utils/drag_and_drop_spec.js
index 676e6b992a60..9ec7dd592481 100644
--- a/cms/static/js/spec/utils/drag_and_drop_spec.js
+++ b/cms/static/js/spec/utils/drag_and_drop_spec.js
@@ -1,10 +1,32 @@
-define(["js/utils/drag_and_drop", "js/views/feedback_notification", "js/spec_helpers/create_sinon", "jquery"],
- function (ContentDragger, Notification, create_sinon, $) {
+define(["js/utils/drag_and_drop", "js/views/feedback_notification", "js/spec_helpers/create_sinon", "jquery", "underscore"],
+ function (ContentDragger, Notification, create_sinon, $, _) {
describe("Overview drag and drop functionality", function () {
beforeEach(function () {
setFixtures(readFixtures('mock/mock-outline.underscore'));
- ContentDragger.makeDraggable('.unit', '.unit-drag-handle', 'ol.sortable-unit-list', 'li.courseware-subsection, article.subsection-body');
- ContentDragger.makeDraggable('.courseware-subsection', '.subsection-drag-handle', '.sortable-subsection-list', 'section');
+ _.each(
+ $('.unit'),
+ function (element) {
+ ContentDragger.makeDraggable(element, {
+ type: '.unit',
+ handleClass: '.unit-drag-handle',
+ droppableClass: 'ol.sortable-unit-list',
+ parentLocationSelector: 'li.courseware-subsection',
+ refresh: jasmine.createSpy('Spy on Unit')
+ });
+ }
+ );
+ _.each(
+ $('.courseware-subsection'),
+ function (element) {
+ ContentDragger.makeDraggable(element, {
+ type: '.courseware-subsection',
+ handleClass: '.subsection-drag-handle',
+ droppableClass: '.sortable-subsection-list',
+ parentLocationSelector: 'section',
+ refresh: jasmine.createSpy('Spy on Subsection')
+ });
+ }
+ );
});
describe("findDestination", function () {
@@ -115,7 +137,7 @@ define(["js/utils/drag_and_drop", "js/views/feedback_notification", "js/spec_hel
});
it("can drag into a collapsed list", function () {
var $ele, destination;
- $('#subsection-2').addClass('collapsed');
+ $('#subsection-2').addClass('is-collapsed');
$ele = $('#unit-2');
$ele.offset({
top: $('#subsection-2').offset().top + 3,
@@ -142,11 +164,11 @@ define(["js/utils/drag_and_drop", "js/views/feedback_notification", "js/spec_hel
});
});
it("collapses expanded elements", function () {
- expect($('#subsection-1')).not.toHaveClass('collapsed');
+ expect($('#subsection-1')).not.toHaveClass('is-collapsed');
ContentDragger.onDragStart({
element: $('#subsection-1')
}, null, null);
- expect($('#subsection-1')).toHaveClass('collapsed');
+ expect($('#subsection-1')).toHaveClass('is-collapsed');
expect($('#subsection-1')).toHaveClass('expand-on-drop');
});
});
@@ -246,16 +268,16 @@ define(["js/utils/drag_and_drop", "js/views/feedback_notification", "js/spec_hel
expect(['0px', 'auto']).toContain($('#unit-1').css('left'));
});
it("expands an element if it was collapsed on drag start", function () {
- $('#subsection-1').addClass('collapsed');
+ $('#subsection-1').addClass('is-collapsed');
$('#subsection-1').addClass('expand-on-drop');
ContentDragger.onDragEnd({
element: $('#subsection-1')
}, null, null);
- expect($('#subsection-1')).not.toHaveClass('collapsed');
+ expect($('#subsection-1')).not.toHaveClass('is-collapsed');
expect($('#subsection-1')).not.toHaveClass('expand-on-drop');
});
it("expands a collapsed element when something is dropped in it", function () {
- $('#subsection-2').addClass('collapsed');
+ $('#subsection-2').addClass('is-collapsed');
ContentDragger.dragState.dropDestination = $('#list-2');
ContentDragger.dragState.attachMethod = "prepend";
ContentDragger.dragState.parentList = $('#subsection-2');
@@ -264,7 +286,7 @@ define(["js/utils/drag_and_drop", "js/views/feedback_notification", "js/spec_hel
}, null, {
clientX: $('#unit-1').offset().left
});
- expect($('#subsection-2')).not.toHaveClass('collapsed');
+ expect($('#subsection-2')).not.toHaveClass('is-collapsed');
});
});
describe("AJAX", function () {
@@ -306,6 +328,10 @@ define(["js/utils/drag_and_drop", "js/views/feedback_notification", "js/spec_hel
expect(this.savingSpies.hide).toHaveBeenCalled();
this.clock.tick(1001);
expect($('#unit-1')).not.toHaveClass('was-dropped');
+ // source
+ expect($('#subsection-1').data('refresh')).toHaveBeenCalled();
+ // target
+ expect($('#subsection-2').data('refresh')).toHaveBeenCalled();
});
});
});
diff --git a/cms/static/js/spec/views/pages/course_outline_spec.js b/cms/static/js/spec/views/pages/course_outline_spec.js
index 30a7671176f7..0e75353199f6 100644
--- a/cms/static/js/spec/views/pages/course_outline_spec.js
+++ b/cms/static/js/spec/views/pages/course_outline_spec.js
@@ -179,7 +179,7 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers"
create_sinon.expectJsonRequest(requests, 'GET', '/xblock/outline/mock-course');
create_sinon.respondWithJson(requests, mockSingleSectionCourseJSON);
expect(outlinePage.$('.no-content')).not.toExist();
- expect(outlinePage.$('.list-sections li').data('locator')).toEqual('mock-section');
+ expect(outlinePage.$('.list-sections li.outline-section').data('locator')).toEqual('mock-section');
});
it('can add a second section', function() {
@@ -237,7 +237,7 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers"
create_sinon.expectJsonRequest(requests, 'GET', '/xblock/outline/mock-course');
create_sinon.respondWithJson(requests, mockSingleSectionCourseJSON);
expect(outlinePage.$('.no-content')).not.toExist();
- expect(outlinePage.$('.list-sections li').data('locator')).toEqual('mock-section');
+ expect(outlinePage.$('.list-sections li.outline-section').data('locator')).toEqual('mock-section');
});
it('remains empty if an add fails', function() {
@@ -303,7 +303,7 @@ define(["jquery", "js/spec_helpers/create_sinon", "js/spec_helpers/view_helpers"
requestCount = requests.length;
create_sinon.respondWithError(requests);
expect(requests.length).toBe(requestCount); // No additional requests should be made
- expect(outlinePage.$('.list-sections li').data('locator')).toEqual('mock-section');
+ expect(outlinePage.$('.list-sections li.outline-section').data('locator')).toEqual('mock-section');
});
it('can add a subsection', function() {
diff --git a/cms/static/js/utils/drag_and_drop.js b/cms/static/js/utils/drag_and_drop.js
index 2479ec47ba7a..c68329a534da 100644
--- a/cms/static/js/utils/drag_and_drop.js
+++ b/cms/static/js/utils/drag_and_drop.js
@@ -6,6 +6,7 @@ define(["jquery", "jquery.ui", "underscore", "gettext", "js/views/feedback_notif
droppableClasses: 'drop-target drop-target-prepend drop-target-before drop-target-after',
validDropClass: "valid-drop",
expandOnDropClass: "expand-on-drop",
+ collapsedClass: "is-collapsed",
/*
* Determine information about where to drop the currently dragged
@@ -14,7 +15,7 @@ define(["jquery", "jquery.ui", "underscore", "gettext", "js/views/feedback_notif
*/
findDestination: function (ele, yChange) {
var eleY = ele.offset().top;
- var eleYEnd = eleY + ele.height();
+ var eleYEnd = eleY + ele.outerHeight();
var containers = $(ele.data('droppable-class'));
for (var i = 0; i < containers.length; i++) {
@@ -28,7 +29,7 @@ define(["jquery", "jquery.ui", "underscore", "gettext", "js/views/feedback_notif
// element is on top of its parent list -- don't check the
// position of the container
var parentList = container.parents(ele.data('parent-location-selector')).first();
- if (parentList.hasClass('collapsed')) {
+ if (parentList.hasClass(this.collapsedClass)) {
var parentListTop = parentList.offset().top;
// To make it easier to drop subsections into collapsed sections (which have
// a lot of visual padding around them), allow a fudge factor around the
@@ -36,7 +37,7 @@ define(["jquery", "jquery.ui", "underscore", "gettext", "js/views/feedback_notif
var collapseFudge = 10;
if (Math.abs(eleY - parentListTop) < collapseFudge ||
(eleY > parentListTop &&
- eleYEnd - collapseFudge <= parentListTop + parentList.height())
+ eleYEnd - collapseFudge <= parentListTop + parentList.outerHeight())
) {
return {
ele: container,
@@ -65,7 +66,7 @@ define(["jquery", "jquery.ui", "underscore", "gettext", "js/views/feedback_notif
for (var j = 0; j < siblings.length; j++) {
var $sibling = $(siblings[j]);
var siblingY = $sibling.offset().top;
- var siblingHeight = $sibling.height();
+ var siblingHeight = $sibling.outerHeight();
var siblingYEnd = siblingY + siblingHeight;
// Facilitate dropping into the beginning or end of a list
@@ -158,12 +159,16 @@ define(["jquery", "jquery.ui", "underscore", "gettext", "js/views/feedback_notif
// The direction the drag is moving in (negative means up, positive down).
dragDirection: 0
};
- if (!ele.hasClass('collapsed')) {
- ele.addClass('collapsed');
+ if (!ele.hasClass(this.collapsedClass)) {
+ ele.addClass(this.collapsedClass);
ele.find('.expand-collapse').first().addClass('expand').removeClass('collapse');
// onDragStart gets called again after the collapse, so we can't just store a variable in the dragState.
ele.addClass(this.expandOnDropClass);
}
+
+ // We should remove this class name before start dragging to
+ // avoid performance issues.
+ ele.removeClass('was-dragging');
},
onDragMove: function (draggie, event, pointer) {
@@ -251,41 +256,46 @@ define(["jquery", "jquery.ui", "underscore", "gettext", "js/views/feedback_notif
},
pointerInBounds: function (pointer, ele) {
- return pointer.clientX >= ele.offset().left && pointer.clientX < ele.offset().left + ele.width();
+ return pointer.clientX >= ele.offset().left && pointer.clientX < ele.offset().left + ele.outerWidth();
},
expandElement: function (ele) {
- ele.removeClass('collapsed');
+ ele.removeClass(this.collapsedClass);
ele.find('.expand-collapse').first().removeClass('expand').addClass('collapse');
},
/*
* Find all parent-child changes and save them.
*/
- handleReorder: function (ele) {
- var parentSelector = ele.data('parent-location-selector');
- var childrenSelector = ele.data('child-selector');
- var newParentEle = ele.parents(parentSelector).first();
- var newParentLocator = newParentEle.data('locator');
- var oldParentLocator = ele.data('parent');
+ handleReorder: function (element) {
+ var parentSelector = element.data('parent-location-selector'),
+ childrenSelector = element.data('child-selector'),
+ newParentEle = element.parents(parentSelector).first(),
+ newParentLocator = newParentEle.data('locator'),
+ oldParentLocator = element.data('parent'),
+ oldParentEle, saving;
// If the parent has changed, update the children of the old parent.
if (newParentLocator !== oldParentLocator) {
// Find the old parent element.
- var oldParentEle = $(parentSelector).filter(function () {
+ oldParentEle = $(parentSelector).filter(function () {
return $(this).data('locator') === oldParentLocator;
});
this.saveItem(oldParentEle, childrenSelector, function () {
- ele.data('parent', newParentLocator);
+ element.data('parent', newParentLocator);
+ _.each([oldParentEle, newParentEle], function (element) {
+ var refresh = element.data('refresh');
+ if (_.isFunction(refresh)) { refresh(); }
+ });
});
}
- var saving = new NotificationView.Mini({
+ saving = new NotificationView.Mini({
title: gettext('Saving…')
});
saving.show();
- ele.addClass('was-dropped');
+ element.addClass('was-dropped');
// Timeout interval has to match what is in the CSS.
setTimeout(function () {
- ele.removeClass('was-dropped');
+ element.removeClass('was-dropped');
}, 1000);
this.saveItem(newParentEle, childrenSelector, function () {
saving.hide();
@@ -318,27 +328,43 @@ define(["jquery", "jquery.ui", "underscore", "gettext", "js/views/feedback_notif
},
/*
- * Make `type` draggable using `handleClass`, able to be dropped
- * into `droppableClass`, and with parent type
- * `parentLocationSelector`.
+ * Make DOM element with class `type` draggable using `handleClass`, able to be dropped
+ * into `droppableClass`, and with parent type `parentLocationSelector`.
+ * @param {DOM element, jQuery element} element
+ * @param {Object} options The list of options. Possible options:
+ * `type` - class name of the element.
+ * `handleClass` - specifies on what element the drag interaction starts.
+ * `droppableClass` - specifies on what elements draggable element can be dropped.
+ * `parentLocationSelector` - class name of a parent element with data-locator.
+ * `refresh` - method that will be called after dragging to refresh
+ * views of the target and source xblocks.
*/
- makeDraggable: function (type, handleClass, droppableClass, parentLocationSelector) {
- _.each(
- $(type),
- function (ele) {
- // Remember data necessary to reconstruct the parent-child relationships
- $(ele).data('droppable-class', droppableClass);
- $(ele).data('parent-location-selector', parentLocationSelector);
- $(ele).data('child-selector', type);
- var draggable = new Draggabilly(ele, {
- handle: handleClass,
- containment: '.wrapper-dnd'
- });
- draggable.on('dragStart', _.bind(contentDragger.onDragStart, contentDragger));
- draggable.on('dragMove', _.bind(contentDragger.onDragMove, contentDragger));
- draggable.on('dragEnd', _.bind(contentDragger.onDragEnd, contentDragger));
- }
- );
+ makeDraggable: function (element, options) {
+ var draggable;
+ options = _.defaults({
+ type: null,
+ handleClass: null,
+ droppableClass: null,
+ parentLocationSelector: null,
+ refresh: null
+ }, options);
+
+ if ($(element).data('droppable-class') !== options.droppableClass) {
+ $(element).data({
+ 'droppable-class': options.droppableClass,
+ 'parent-location-selector': options.parentLocationSelector,
+ 'child-selector': options.type,
+ 'refresh': options.refresh
+ });
+
+ draggable = new Draggabilly(element, {
+ handle: options.handleClass,
+ containment: '.wrapper-dnd'
+ });
+ draggable.on('dragStart', _.bind(contentDragger.onDragStart, contentDragger));
+ draggable.on('dragMove', _.bind(contentDragger.onDragMove, contentDragger));
+ draggable.on('dragEnd', _.bind(contentDragger.onDragEnd, contentDragger));
+ }
}
};
diff --git a/cms/static/js/views/course_outline.js b/cms/static/js/views/course_outline.js
index adfc1ca365b5..22b222b50b8c 100644
--- a/cms/static/js/views/course_outline.js
+++ b/cms/static/js/views/course_outline.js
@@ -9,15 +9,20 @@
* - adding units will automatically redirect to the unit page rather than showing them inline
*/
define(["jquery", "underscore", "js/views/xblock_outline", "js/views/utils/view_utils",
- "js/models/xblock_outline_info",
- "js/views/modals/edit_outline_item"],
- function($, _, XBlockOutlineView, ViewUtils, XBlockOutlineInfo, EditSectionXBlockModal) {
+ "js/models/xblock_outline_info", "js/views/modals/edit_outline_item", "js/utils/drag_and_drop"],
+ function($, _, XBlockOutlineView, ViewUtils, XBlockOutlineInfo, EditSectionXBlockModal, ContentDragger) {
var CourseOutlineView = XBlockOutlineView.extend({
// takes XBlockOutlineInfo as a model
templateName: 'course-outline',
+ render: function() {
+ var renderResult = XBlockOutlineView.prototype.render.call(this);
+ this.makeContentDraggable(this.el);
+ return renderResult;
+ },
+
shouldExpandChildren: function() {
// Expand the children if this xblock's locator is in the initially expanded state
if (this.initialState && _.contains(this.initialState.expanded_locators, this.model.id)) {
@@ -154,6 +159,36 @@ define(["jquery", "underscore", "js/views/xblock_outline", "js/views/utils/view_
event.preventDefault();
this.editXBlock();
}.bind(this));
+ },
+
+ makeContentDraggable: function(element) {
+ if ($(element).hasClass("outline-section")) {
+ ContentDragger.makeDraggable(element, {
+ type: '.outline-section',
+ handleClass: '.section-drag-handle',
+ droppableClass: 'ol.list-sections',
+ parentLocationSelector: 'article.outline',
+ refresh: this.refresh.bind(this)
+ });
+ }
+ else if ($(element).hasClass("outline-subsection")) {
+ ContentDragger.makeDraggable(element, {
+ type: '.outline-subsection',
+ handleClass: '.subsection-drag-handle',
+ droppableClass: 'ol.list-subsections',
+ parentLocationSelector: 'li.outline-section',
+ refresh: this.refresh.bind(this)
+ });
+ }
+ else if ($(element).hasClass("outline-unit")) {
+ ContentDragger.makeDraggable(element, {
+ type: '.outline-unit',
+ handleClass: '.unit-drag-handle',
+ droppableClass: 'ol.list-units',
+ parentLocationSelector: 'li.outline-subsection',
+ refresh: this.refresh.bind(this)
+ });
+ }
}
});
diff --git a/cms/static/js/views/overview.js b/cms/static/js/views/overview.js
index f05ba24079e2..f33f0c908fef 100644
--- a/cms/static/js/views/overview.js
+++ b/cms/static/js/views/overview.js
@@ -1,6 +1,6 @@
-define(["domReady", "jquery", "jquery.ui", "underscore", "gettext", "js/views/feedback_notification", "js/utils/drag_and_drop",
+define(["domReady", "jquery", "jquery.ui", "underscore", "gettext", "js/views/feedback_notification",
"js/utils/cancel_on_escape", "js/utils/date_utils", "js/utils/module"],
- function (domReady, $, ui, _, gettext, NotificationView, ContentDragger, CancelOnEscape,
+ function (domReady, $, ui, _, gettext, NotificationView, CancelOnEscape,
DateUtils, ModuleUtils) {
var modalSelector = '.edit-section-publish-settings';
@@ -37,9 +37,9 @@ define(["domReady", "jquery", "jquery.ui", "underscore", "gettext", "js/views/fe
var closeModalNew = function (e) {
- if (e) {
+ if (e) {
e.preventDefault();
- };
+ }
$('body').removeClass('modal-window-is-shown');
$('.edit-section-publish-settings').removeClass('is-shown');
};
@@ -230,27 +230,6 @@ define(["domReady", "jquery", "jquery.ui", "underscore", "gettext", "js/views/fe
$('.new-courseware-section-button').bind('click', addNewSection);
$('.new-subsection-item').bind('click', addNewSubsection);
- // Section
- ContentDragger.makeDraggable(
- '.courseware-section',
- '.section-drag-handle',
- '.courseware-overview',
- 'article.courseware-overview'
- );
- // Subsection
- ContentDragger.makeDraggable(
- '.id-holder',
- '.subsection-drag-handle',
- '.subsection-list > ol',
- '.courseware-section'
- );
- // Unit
- ContentDragger.makeDraggable(
- '.unit',
- '.unit-drag-handle',
- 'ol.sortable-unit-list',
- 'li.courseware-subsection, article.subsection-body'
- );
});
return {
diff --git a/cms/static/sass/elements/_controls.scss b/cms/static/sass/elements/_controls.scss
index f0f7179cb7e5..b5447c68cba5 100644
--- a/cms/static/sass/elements/_controls.scss
+++ b/cms/static/sass/elements/_controls.scss
@@ -394,6 +394,9 @@
box-shadow: 0 1px 2px 0 $blue-t2;
}
}
+ .was-dragging {
+ @include transition(transform $tmg-f2 ease-in-out 0);
+ }
// UI: drag state - was dragging
.was-dragging {
diff --git a/cms/static/sass/views/_outline.scss b/cms/static/sass/views/_outline.scss
index 12a21123814c..a0992eefa5aa 100644
--- a/cms/static/sass/views/_outline.scss
+++ b/cms/static/sass/views/_outline.scss
@@ -224,6 +224,10 @@
color: $blue;
}
}
+
+ &.is-dragging {
+ @include transition-property(none);
+ }
}
// item: title
diff --git a/cms/templates/js/course-outline.underscore b/cms/templates/js/course-outline.underscore
index 30037023418a..50294bb55c9c 100644
--- a/cms/templates/js/course-outline.underscore
+++ b/cms/templates/js/course-outline.underscore
@@ -35,6 +35,8 @@ if (statusType === 'warning') {
+
+
@@ -125,10 +133,14 @@ if (statusType === 'warning') {
- <% } else { %>
+ <% } else if (category !== 'vertical') { %>
+ -
+
+
+
<% if (childType) { %>
From 6095e017358c3070f02c16fa66de6ca43e515070 Mon Sep 17 00:00:00 2001
From: Brian Talbot
Date: Thu, 24 Jul 2014 12:19:25 -0400
Subject: [PATCH 2/4] Studio: re-implemeting visual styling for drag and drop:
* adding back in drag and drop indicators to outline DOM
* correcting visual display of drag action in outline UI
* adjusting styling of outline drag and drop indicators
* adjusting styling of drag and drop was-dropped state
---
cms/static/sass/_shame.scss | 19 ++---
cms/static/sass/assets/_anims.scss | 23 ++++++
cms/static/sass/elements/_controls.scss | 20 +++---
cms/static/sass/views/_outline.scss | 93 +++++++++++++++----------
4 files changed, 102 insertions(+), 53 deletions(-)
diff --git a/cms/static/sass/_shame.scss b/cms/static/sass/_shame.scss
index dbd6e61f9780..0549cbf7c5e1 100644
--- a/cms/static/sass/_shame.scss
+++ b/cms/static/sass/_shame.scss
@@ -25,15 +25,18 @@
// ====================
-// needed to override ui-window styling for dragging state (outline selectors get too specific)
-.courseware-section.is-dragging {
- box-shadow: 0 1px 2px 0 $shadow-d1 !important;
- border: 1px solid $gray-d3 !important;
-}
+// overriding outline styling for general drag and drop cases
+.outline-section, .outline-subsection {
+
+ // STATE: is dragging
+ &.is-dragging {
+ border-color: $gray-d3;
+ }
-.courseware-section.is-dragging.valid-drop {
- border-color: $blue-s1 !important;
- box-shadow: 0 1px 2px 0 $blue-t2 !important;
+ // STATE: is dragging + valid drop
+ &.valid-drop {
+ border-color: $ui-action-primary-color-focus;
+ }
}
// ====================
diff --git a/cms/static/sass/assets/_anims.scss b/cms/static/sass/assets/_anims.scss
index cf3f49e59bd2..a8d054a0a50b 100644
--- a/cms/static/sass/assets/_anims.scss
+++ b/cms/static/sass/assets/_anims.scss
@@ -271,3 +271,26 @@
%anim-pulse {
@include animation(pulse $tmg-f1 ease-in-out 1);
}
+
+// ====================
+
+
+// was-dropped
+@include keyframes(was-dropped) {
+ 0% {
+ opacity: 1.0;
+ }
+
+ 50% {
+ opacity: 0.5;
+ }
+
+ 100% {
+ opacity: 1.0;
+ }
+}
+
+// canned animation - use if you want out of the box/non-customized anim
+%anim-was-dropped {
+ @include animation(was-dropped $tmg-f1 ease-in-out 1);
+}
diff --git a/cms/static/sass/elements/_controls.scss b/cms/static/sass/elements/_controls.scss
index b5447c68cba5..5e113f758660 100644
--- a/cms/static/sass/elements/_controls.scss
+++ b/cms/static/sass/elements/_controls.scss
@@ -1,8 +1,6 @@
// studio - elements - UI controls
// ====================
-// ====================
-
// general actions
%action {
@extend %ui-fake-link;
@@ -350,7 +348,7 @@
// UI: elem is draggable
.is-draggable {
- @include transition(border-color $tmg-f2 ease-in-out 0, box-shadow $tmg-f2 ease-in-out 0);
+ @include transition(border-color $tmg-f2 ease-in-out 0, box-shadow $tmg-f2 ease-in-out 0, margin $tmg-f2 ease-in-out 0);
position: relative;
.draggable-drop-indicator {
@@ -390,13 +388,10 @@
// UI: condition - valid drop
&.valid-drop {
- border-color: $blue-s1;
- box-shadow: 0 1px 2px 0 $blue-t2;
+ border-color: $ui-action-primary-color-focus;
+ box-shadow: 0 1px 2px 0 rgba($ui-action-primary-color-focus, 0.50);
}
}
- .was-dragging {
- @include transition(transform $tmg-f2 ease-in-out 0);
- }
// UI: drag state - was dragging
.was-dragging {
@@ -407,6 +402,7 @@
.drop-target {
&.drop-target-before {
+ margin-top: ($baseline*1.5);
> .draggable-drop-indicator-before {
opacity: 1.0;
@@ -414,9 +410,17 @@
}
&.drop-target-after {
+ margin-bottom: ($baseline*1.5);
> .draggable-drop-indicator-after {
opacity: 1.0;
}
}
}
+
+// UI: drop state - was dropped
+.was-dropped {
+ @include animation(was-dropped $tmg-avg ease-in-out 1);
+ border-color: $ui-action-primary-color-focus;
+ box-shadow: 0 1px 2px 0 rgba($ui-action-primary-color-focus, 0.50);
+}
diff --git a/cms/static/sass/views/_outline.scss b/cms/static/sass/views/_outline.scss
index a0992eefa5aa..a061c69eed5f 100644
--- a/cms/static/sass/views/_outline.scss
+++ b/cms/static/sass/views/_outline.scss
@@ -246,6 +246,16 @@
}
}
}
+
+ // STATE: drag and drop
+ .drop-target-prepend .draggable-drop-indicator-initial {
+ opacity: 1.0;
+ }
+
+ // STATE: was dropped
+ &.was-dropped {
+ border-color: $blue;
+ }
}
// outline: sections
@@ -320,6 +330,11 @@
@extend %outline-item-content-hidden;
}
}
+
+ // STATE: drag and drop - was dropped
+ &.was-dropped {
+ border-left-color: $ui-action-primary-color-focus;
+ }
}
// outline: subsections
@@ -439,49 +454,36 @@
// --------------------
.outline-section {
+ .ui-splint-indicator {
+ height: ($baseline/10);
+ margin-left: ($baseline/4);
+ }
+
.draggable-drop-indicator-before {
- top: -($baseline/2);
+ top: -($baseline*0.75);
left: 0;
}
.draggable-drop-indicator-after {
- bottom: -13px;
+ bottom: -($baseline*0.75);
left: 0;
}
-
- // CASE: DnD - empty subsection with unit dropping
- .drop-target-prepend .draggable-drop-indicator-initial {
- opacity: 1.0;
- }
-
- // STATE: was dropped
- &.was-dropped {
- background-color: $ui-update-color;
- }
}
// UI: drag and drop: subsection
.outline-subsection {
- .draggable-drop-indicator-before {
- top: 0;
- }
-
- .draggable-drop-indicator-after {
- bottom: 0;
+ .ui-splint-indicator {
+ height: ($baseline/10);
+ margin-left: ($baseline*1.25);
}
- // CASE: DnD - empty subsection with unit dropping
- .drop-target-prepend .draggable-drop-indicator-initial {
- opacity: 1.0;
+ .draggable-drop-indicator-before {
+ top: -($baseline*0.75);
}
- // STATE: was dropped
- &.was-dropped {
-
- > .section-item {
- background-color: $ui-update-color !important; // nasty, but needed for specificity
- }
+ .draggable-drop-indicator-after {
+ bottom: -($baseline*0.75);
}
}
@@ -489,24 +491,41 @@
.outline-unit {
.draggable-drop-indicator-before {
- top: 0;
+ top: -($baseline*0.75);
}
.draggable-drop-indicator-after {
- bottom: 0;
- }
-
- // STATE: was dropped
- &.was-dropped {
-
- > .section-item {
- background-color: $ui-update-color !important; // nasty, but needed for specificity
- }
+ bottom: -($baseline*0.75);
}
}
// UI: drag and drop: splints
.ui-splint-indicator {
position: relative;
+
+ .draggable-drop-indicator {
+ @extend %ui-depth3;
+ @include transition(opacity $tmg-f2 linear 0s);
+ @include size(100%, auto);
+ position: absolute;
+ border-top: 1px solid $blue-l1;
+ opacity: 0.0;
+
+ *[class^="icon-caret"] {
+ @extend %t-icon5;
+ position: absolute;
+ top: -12px;
+ left: -($baseline/4);
+ color: $blue-s1;
+ }
+ }
+
+ .draggable-drop-indicator-before {
+ top: -($baseline/2);
+ }
+
+ .draggable-drop-indicator-after {
+ bottom: -($baseline/2);
+ }
}
}
From 42ba9e000d18d9df991a61e9f1f50b0eb9e1bc26 Mon Sep 17 00:00:00 2001
From: Brian Talbot
Date: Thu, 31 Jul 2014 13:16:32 -0400
Subject: [PATCH 3/4] resolving mid-drop unit marign issue in Firefox
---
cms/static/sass/views/_outline.scss | 1 +
1 file changed, 1 insertion(+)
diff --git a/cms/static/sass/views/_outline.scss b/cms/static/sass/views/_outline.scss
index a061c69eed5f..a92893d0e0e1 100644
--- a/cms/static/sass/views/_outline.scss
+++ b/cms/static/sass/views/_outline.scss
@@ -423,6 +423,7 @@
}
.outline-unit {
+ @include transition(margin $tmg-f2 linear 0s); // needed for drag and drop transitions
margin-left: $outline-indent-width;
// header
From 8e9a9ecbc42c20e61d993f8a56b0a62745b819d8 Mon Sep 17 00:00:00 2001
From: cahrens
Date: Thu, 31 Jul 2014 13:42:45 -0400
Subject: [PATCH 4/4] Increase "fudge" factor for dragging to top of list with
only 1 element.
---
cms/static/js/utils/drag_and_drop.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cms/static/js/utils/drag_and_drop.js b/cms/static/js/utils/drag_and_drop.js
index c68329a534da..a23e941f3e32 100644
--- a/cms/static/js/utils/drag_and_drop.js
+++ b/cms/static/js/utils/drag_and_drop.js
@@ -71,7 +71,7 @@ define(["jquery", "jquery.ui", "underscore", "gettext", "js/views/feedback_notif
// Facilitate dropping into the beginning or end of a list
// (coming from opposite direction) via a "fudge factor". Math.min is for Jasmine test.
- var fudge = Math.min(Math.ceil(siblingHeight / 2), 20);
+ var fudge = Math.min(Math.ceil(siblingHeight / 2), 35);
// Dragging to top or bottom of a list with only one element is tricky
// because the element being dragged may be the same size as the sibling.