Commit fbc886aa by cahrens

Store the expanded locators on the page.

STUD-2038
parent 0083cfc4
......@@ -277,7 +277,11 @@ define(["jquery", "jquery.ui", "underscore", "gettext", "js/views/feedback_notif
refreshParent = function (element) {
var refresh = element.data('refresh');
if (_.isFunction(refresh)) { refresh(); }
// If drop was into a collapsed parent, the parent will have been
// expanded. Views using this class may need to track the
// collapse/expand state, so send it with the refresh callback.
var collapsed = element.hasClass(this.collapsedClass);
if (_.isFunction(refresh)) { refresh(collapsed); }
};
// If the parent has changed, update the children of the old parent.
......
......@@ -24,12 +24,7 @@ define(["jquery", "underscore", "js/views/xblock_outline", "js/views/utils/view_
},
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)) {
return true;
}
// Only expand the course and its chapters (aka sections) initially
return this.model.isCourse() || this.model.isChapter();
return this.expandedLocators.contains(this.model.get('id'));
},
shouldRenderChildren: function() {
......@@ -42,22 +37,12 @@ define(["jquery", "underscore", "js/views/xblock_outline", "js/views/utils/view_
model: xblockInfo,
parentInfo: parentInfo,
initialState: this.initialState,
expandedLocators: this.expandedLocators,
template: this.template,
parentView: parentView || this
});
},
getExpandedLocators: function() {
var expandedLocators = [];
this.$('.outline-item.is-collapsible').each(function(index, rawElement) {
var element = $(rawElement);
if (!element.hasClass('is-collapsed')) {
expandedLocators.push(element.data('locator'));
}
});
return expandedLocators;
},
/**
* Refresh the containing section (if there is one) or else refresh the entire course.
* Note that the refresh will preserve the expanded state of this view and all of its
......@@ -76,13 +61,26 @@ define(["jquery", "underscore", "js/views/xblock_outline", "js/views/utils/view_
};
view = getViewToRefresh(this);
expandedLocators = view.getExpandedLocators();
viewState = viewState || {};
viewState.expanded_locators = expandedLocators.concat(viewState.expanded_locators || []);
view.initialState = viewState;
return view.model.fetch({});
},
/**
* Updates the collapse/expand state for this outline element, and then calls refresh.
* @param isCollapsed true if the element should be collapsed, else false
*/
refreshWithCollapsedState: function(isCollapsed) {
var locator = this.model.get('id');
if (isCollapsed) {
this.expandedLocators.remove(locator);
}
else {
this.expandedLocators.add(locator);
}
this.refresh();
},
onChildAdded: function(locator, category, event) {
if (category === 'vertical') {
// For units, redirect to the new unit's page in inline edit mode
......@@ -113,6 +111,7 @@ define(["jquery", "underscore", "js/views/xblock_outline", "js/views/utils/view_
sectionInfo.fetch().done(function() {
sectionView = self.createChildView(sectionInfo, self.model, self);
sectionView.initialState = initialState;
sectionView.expandedLocators = self.expandedLocators;
sectionView.render();
self.addChildView(sectionView);
sectionView.setViewState(initialState);
......@@ -136,10 +135,10 @@ define(["jquery", "underscore", "js/views/xblock_outline", "js/views/utils/view_
},
createNewItemViewState: function(locator, scrollOffset) {
this.expandedLocators.add(locator);
return {
locator_to_show: locator,
edit_display_name: true,
expanded_locators: [ locator ],
scroll_offset: scrollOffset || 0
};
},
......@@ -168,7 +167,7 @@ define(["jquery", "underscore", "js/views/xblock_outline", "js/views/utils/view_
handleClass: '.section-drag-handle',
droppableClass: 'ol.list-sections',
parentLocationSelector: 'article.outline',
refresh: this.refresh.bind(this)
refresh: this.refreshWithCollapsedState.bind(this)
});
}
else if ($(element).hasClass("outline-subsection")) {
......@@ -177,7 +176,7 @@ define(["jquery", "underscore", "js/views/xblock_outline", "js/views/utils/view_
handleClass: '.subsection-drag-handle',
droppableClass: 'ol.list-subsections',
parentLocationSelector: 'li.outline-section',
refresh: this.refresh.bind(this)
refresh: this.refreshWithCollapsedState.bind(this)
});
}
else if ($(element).hasClass("outline-unit")) {
......@@ -186,7 +185,7 @@ define(["jquery", "underscore", "js/views/xblock_outline", "js/views/utils/view_
handleClass: '.unit-drag-handle',
droppableClass: 'ol.list-units',
parentLocationSelector: 'li.outline-subsection',
refresh: this.refresh.bind(this)
refresh: this.refreshWithCollapsedState.bind(this)
});
}
}
......
......@@ -4,7 +4,9 @@
define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views/utils/xblock_utils",
"js/views/course_outline"],
function ($, _, gettext, BasePage, XBlockViewUtils, CourseOutlineView) {
var CourseOutlinePage = BasePage.extend({
var expandedLocators, CourseOutlinePage;
CourseOutlinePage = BasePage.extend({
// takes XBlockInfo as a model
events: {
......@@ -36,12 +38,32 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
},
renderPage: function() {
var setInitialExpandState = function (xblockInfo, expandedLocators) {
if (xblockInfo.isCourse() || xblockInfo.isChapter()) {
expandedLocators.add(xblockInfo.get('id'));
}
};
this.setCollapseExpandVisibility();
this.expandedLocators = expandedLocators;
this.expandedLocators.clear();
if (this.model.get('child_info')) {
_.each(this.model.get('child_info').children, function (childXBlockInfo) {
setInitialExpandState(childXBlockInfo, this.expandedLocators);
}, this);
}
setInitialExpandState(this.model, this.expandedLocators);
if (this.initialState && this.initialState.expanded_locators) {
this.expandedLocators.addAll(this.initialState.expanded_locators);
}
this.outlineView = new CourseOutlineView({
el: this.$('.outline'),
model: this.model,
isRoot: true,
initialState: this.initialState
initialState: this.initialState,
expandedLocators: this.expandedLocators
});
this.outlineView.render();
this.outlineView.setViewState(this.initialState || {});
......@@ -65,8 +87,67 @@ define(["jquery", "underscore", "gettext", "js/views/pages/base_page", "js/views
element.removeClass('is-collapsed');
}
});
if (this.model.get('child_info')) {
_.each(this.model.get('child_info').children, function (childXBlockInfo) {
if (collapse) {
this.expandedLocators.remove(childXBlockInfo.get('id'));
}
else {
this.expandedLocators.add(childXBlockInfo.get('id'));
}
}, this);
}
}
});
/**
* Represents the set of locators that should be expanded for the page.
*/
expandedLocators = {
locators: [],
/**
* Add the locator to the set if it is not already present.
*/
add: function (locator) {
if (!this.contains(locator)) {
this.locators.push(locator);
}
},
/**
* Accepts an array of locators and adds them all to the set if not already present.
*/
addAll: function(locators) {
_.each(locators, function(locator) {
this.add(locator);
}, this);
},
/**
* Remove the locator from the set if it is present.
*/
remove: function (locator) {
var index = this.locators.indexOf(locator);
if (index >= 0) {
this.locators.splice(index, 1);
}
},
/**
* Returns true iff the locator is present in the set.
*/
contains: function (locator) {
return this.locators.indexOf(locator) >= 0;
},
/**
* Clears all expanded locators from the set.
*/
clear: function () {
this.locators = [];
}
};
return CourseOutlinePage;
}); // end define();
......@@ -9,7 +9,6 @@
*
* The view can be constructed with an initialState option which is a JSON structure representing
* the desired initial state. The parameters are as follows:
* - expanded_locators - the locators that should be shown as expanded in addition to the defaults
* - locator_to_show - the locator for the xblock which is the one being explicitly shown
* - scroll_offset - the scroll offset to use for the locator being shown
* - edit_display_name - true if the shown xblock's display name should be in inline edit mode
......@@ -30,6 +29,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/utils/
initialize: function() {
BaseView.prototype.initialize.call(this);
this.initialState = this.options.initialState;
this.expandedLocators = this.options.expandedLocators;
this.template = this.options.template;
if (!this.template) {
this.template = this.loadTemplate(this.templateName);
......@@ -37,7 +37,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/utils/
this.parentInfo = this.options.parentInfo;
this.parentView = this.options.parentView;
this.renderedChildren = false;
this.model.on('sync', this.onXBlockChange, this);
this.model.on('sync', this.onSync, this);
},
render: function() {
......@@ -47,6 +47,9 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/utils/
if (this.shouldRenderChildren() && this.shouldExpandChildren()) {
this.renderChildren();
}
else {
this.renderedChildren = false;
}
return this;
},
......@@ -132,6 +135,17 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/utils/
},
toggleExpandCollapse: function(event) {
// The course outline page tracks expanded locators. The unit location sidebar does not.
if (this.expandedLocators) {
var locator = this.model.get('id');
var wasExpanded = this.expandedLocators.contains(locator);
if (wasExpanded) {
this.expandedLocators.remove(locator);
}
else {
this.expandedLocators.add(locator);
}
}
// Ensure that the children have been rendered before expanding
if (this.shouldRenderChildren() && !this.renderedChildren) {
this.renderChildren();
......@@ -164,6 +178,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/utils/
model: xblockInfo,
parentInfo: parentInfo,
initialState: this.initialState,
expandedLocators: this.expandedLocators,
template: this.template,
parentView: parentView || this
});
......@@ -181,6 +196,12 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/utils/
return xblockType;
},
onSync: function(event) {
if (ViewUtils.hasChangedAttributes(this.model, ['visibility_state', 'child_info', 'display_name'])) {
this.onXBlockChange();
}
},
onXBlockChange: function() {
var oldElement = this.$el,
viewState = this.initialState;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment