Merge branch 'feature/dhm/drag' of github.com:MITx/mitx into feature/dhm/drag
Conflicts: cms/envs/common.py
This commit is contained in:
@@ -55,13 +55,6 @@ $(document).ready(function() {
|
||||
$("#start_date, #start_time, #due_date, #due_time").bind('change', autosaveInput);
|
||||
$('.sync-date, .remove-date').bind('click', autosaveInput);
|
||||
|
||||
// making the unit list sortable
|
||||
$('.sortable-unit-list').sortable({
|
||||
axis: 'y',
|
||||
handle: '.drag-handle',
|
||||
update: onUnitReordered
|
||||
});
|
||||
|
||||
// expand/collapse methods for optional date setters
|
||||
$('.set-date').bind('click', showDateSetter);
|
||||
$('.remove-date').bind('click', removeDateSetter);
|
||||
@@ -87,18 +80,54 @@ $(document).ready(function() {
|
||||
$('.import .file-input').click();
|
||||
});
|
||||
|
||||
// Subsection reordering
|
||||
$('.subsection-list > ol').sortable({
|
||||
axis: 'y',
|
||||
handle: '.section-item .drag-handle',
|
||||
update: onSubsectionReordered
|
||||
// making the unit list draggable. Note: sortable didn't work b/c it considered
|
||||
// drop points which the user hovered over as destinations and proactively changed
|
||||
// the dom; so, if the user subsequently dropped at an illegal spot, the reversion
|
||||
// point was the last dom change.
|
||||
$('.unit').draggable({
|
||||
axis: 'y',
|
||||
handle: '.drag-handle',
|
||||
stack: '.unit',
|
||||
revert: "invalid"
|
||||
});
|
||||
|
||||
|
||||
// Subsection reordering
|
||||
$('.id-holder').draggable({
|
||||
axis: 'y',
|
||||
handle: '.section-item .drag-handle',
|
||||
stack: '.id-holder',
|
||||
revert: "invalid"
|
||||
});
|
||||
|
||||
// Section reordering
|
||||
$('.courseware-overview').sortable({
|
||||
axis: 'y',
|
||||
handle: 'header .drag-handle',
|
||||
update: onSectionReordered
|
||||
$('.courseware-section').draggable({
|
||||
axis: 'y',
|
||||
handle: 'header .drag-handle',
|
||||
stack: '.courseware-section',
|
||||
revert: "invalid"
|
||||
});
|
||||
|
||||
|
||||
$('.sortable-unit-list').droppable({
|
||||
accept : '.unit',
|
||||
greedy: true,
|
||||
tolerance: "pointer",
|
||||
drop: onUnitReordered
|
||||
});
|
||||
$('.subsection-list > ol').droppable({
|
||||
// why don't we have a more useful class for subsections than id-holder?
|
||||
accept : '.id-holder', // '.unit, .id-holder',
|
||||
tolerance: "pointer",
|
||||
drop: onSubsectionReordered,
|
||||
greedy: true
|
||||
});
|
||||
|
||||
// Section reordering
|
||||
$('.courseware-overview').droppable({
|
||||
accept : '.courseware-section',
|
||||
tolerance: "pointer",
|
||||
drop: onSectionReordered,
|
||||
greedy: true
|
||||
});
|
||||
|
||||
$('.new-course-button').bind('click', addNewCourse);
|
||||
@@ -240,54 +269,87 @@ function removePolicyMetadata(e) {
|
||||
saveSubsection()
|
||||
}
|
||||
|
||||
function expandSection(event) {
|
||||
$(event.delegateTarget).removeClass('collapsed');
|
||||
$(event.delegateTarget).find('.expand-collapse-icon').removeClass('expand').addClass('collapse');
|
||||
}
|
||||
|
||||
// This method only changes the ordering of the child objects in a subsection
|
||||
function onUnitReordered() {
|
||||
var subsection_id = $(this).data('subsection-id');
|
||||
function checkDropValidity(event, ui) {
|
||||
var posInDestination = ui.item.position().top - $(event.target).position().top;
|
||||
if (posInDestination <= -ui.item.height() || posInDestination >= $(event.target).height()) {
|
||||
$(event.target).sortable("cancel");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
var _els = $(this).children('li:.leaf');
|
||||
function onUnitReordered(event, ui) {
|
||||
// a unit's been dropped on this subsection,
|
||||
// figure out where it came from and where it slots in.
|
||||
_handleReorder(event, ui, 'subsection-id', 'li:.leaf');
|
||||
}
|
||||
|
||||
function onSubsectionReordered(event, ui) {
|
||||
// a subsection has been dropped on this section,
|
||||
// figure out where it came from and where it slots in.
|
||||
_handleReorder(event, ui, 'section-id', 'li:.branch');
|
||||
}
|
||||
|
||||
function onSectionReordered(event, ui) {
|
||||
// a section moved w/in the overall (cannot change course via this, so no parentage change possible, just order)
|
||||
_handleReorder(event, ui, 'course-id', '.courseware-section');
|
||||
}
|
||||
|
||||
function _handleReorder(event, ui, parentIdField, childrenSelector) {
|
||||
// figure out where it came from and where it slots in.
|
||||
var subsection_id = $(event.target).data(parentIdField);
|
||||
var _els = $(event.target).children(childrenSelector);
|
||||
var children = _els.map(function(idx, el) { return $(el).data('id'); }).get();
|
||||
|
||||
// call into server to commit the new order
|
||||
$.ajax({
|
||||
url: "/save_item",
|
||||
// if new to this parent, figure out which parent to remove it from and do so
|
||||
if (!_.contains(children, ui.draggable.data('id'))) {
|
||||
var old_parent = ui.draggable.parent();
|
||||
var old_children = old_parent.children(childrenSelector).map(function(idx, el) { return $(el).data('id'); }).get();
|
||||
old_children = _.without(old_children, ui.draggable.data('id'));
|
||||
// call into server to commit the new order
|
||||
$.ajax({
|
||||
url: "/save_item",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json",
|
||||
data:JSON.stringify({ 'id' : old_parent.data(parentIdField), 'children' : old_children})
|
||||
});
|
||||
//
|
||||
}
|
||||
else {
|
||||
// staying in same parent
|
||||
// remove so that the replacement in the right place doesn't double it
|
||||
children = _.without(children, ui.draggable.data('id'));
|
||||
}
|
||||
// add to this parent (figure out where)
|
||||
for (var i = 0; i < _els.length; i++) {
|
||||
if (!ui.draggable.is(_els[i]) && ui.offset.top < $(_els[i]).offset().top) {
|
||||
// insert at i in children and _els
|
||||
ui.draggable.insertBefore($(_els[i]));
|
||||
// TODO figure out correct way to have it format (and similar line below)
|
||||
ui.draggable.attr("style", "position:relative;");
|
||||
children.splice(i, 0, ui.draggable.data('id'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// see if it goes at end (the above loop didn't insert it)
|
||||
if (!_.contains(children, ui.draggable.data('id'))) {
|
||||
$(event.target).append(ui.draggable);
|
||||
ui.draggable.attr("style", "position:relative;"); // STYLE hack too
|
||||
children.push(ui.draggable.data('id'));
|
||||
}
|
||||
$.ajax({
|
||||
url: "/save_item",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json",
|
||||
data:JSON.stringify({ 'id' : subsection_id, 'children' : children})
|
||||
});
|
||||
}
|
||||
|
||||
function onSubsectionReordered() {
|
||||
var section_id = $(this).data('section-id');
|
||||
|
||||
var _els = $(this).children('li:.branch');
|
||||
var children = _els.map(function(idx, el) { return $(el).data('id'); }).get();
|
||||
|
||||
// call into server to commit the new order
|
||||
$.ajax({
|
||||
url: "/save_item",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json",
|
||||
data:JSON.stringify({ 'id' : section_id, 'children' : children})
|
||||
});
|
||||
}
|
||||
|
||||
function onSectionReordered() {
|
||||
var course_id = $(this).data('course-id');
|
||||
|
||||
var _els = $(this).children('section:.branch');
|
||||
var children = _els.map(function(idx, el) { return $(el).data('id'); }).get();
|
||||
|
||||
// call into server to commit the new order
|
||||
$.ajax({
|
||||
url: "/save_item",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
contentType: "application/json",
|
||||
data:JSON.stringify({ 'id' : course_id, 'children' : children})
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function getEdxTimeFromDateTimeVals(date_val, time_val, format) {
|
||||
|
||||
50
cms/static/js/hesitate.js
Normal file
50
cms/static/js/hesitate.js
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Create a HesitateEvent and assign it as the event to execute:
|
||||
* $(el).on('mouseEnter', CMS.HesitateEvent( expand, 'mouseLeave').trigger);
|
||||
* It calls the executeOnTimeOut function with the event.currentTarget after the configurable timeout IFF the cancelSelector event
|
||||
* did not occur on the event.currentTarget.
|
||||
*
|
||||
* More specifically, when trigger is called (triggered by the event you bound it to), it starts a timer
|
||||
* which the cancelSelector event will cancel or if the timer finished, it executes the executeOnTimeOut function
|
||||
* passing it the original event (whose currentTarget s/b the specific ele). It never accumulates events; however, it doesn't hurt for your
|
||||
* code to minimize invocations of trigger by binding to mouseEnter v mouseOver and such.
|
||||
*
|
||||
* NOTE: if something outside of this wants to cancel the event, invoke cachedhesitation.untrigger(null | anything);
|
||||
*/
|
||||
|
||||
CMS.HesitateEvent = function(executeOnTimeOut, cancelSelector, onlyOnce) {
|
||||
this.executeOnTimeOut = executeOnTimeOut;
|
||||
this.cancelSelector = cancelSelector;
|
||||
this.timeoutEventId = null;
|
||||
this.originalEvent = null;
|
||||
this.onlyOnce = (onlyOnce === true);
|
||||
}
|
||||
|
||||
CMS.HesitateEvent.DURATION = 400;
|
||||
|
||||
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;
|
||||
// is it wrong to bind to the below v $(event.currentTarget)?
|
||||
$(this.originalEvent.delegateTarget).on(this.cancelSelector, this.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);
|
||||
}
|
||||
|
||||
CMS.HesitateEvent.prototype.untrigger = function(event) {
|
||||
console.log('untrigger');
|
||||
if (this.timeoutEventId) {
|
||||
window.clearTimeout(this.timeoutEventId);
|
||||
$(this.originalEvent.delegateTarget).off(this.cancelSelector, this.untrigger);
|
||||
}
|
||||
this.timeoutEventId = null;
|
||||
}
|
||||
@@ -425,7 +425,6 @@ courseware_js = (
|
||||
# 'js/vendor/RequireJS.js' - Require JS wrapper.
|
||||
# See https://edx-wiki.atlassian.net/wiki/display/LMS/Integration+of+Require+JS+into+the+system
|
||||
main_vendor_js = [
|
||||
'js/vendor/RequireJS.js',
|
||||
'js/vendor/json2.js',
|
||||
'js/vendor/jquery.min.js',
|
||||
'js/vendor/jquery-ui.min.js',
|
||||
|
||||
Reference in New Issue
Block a user