[#88,view,state][s]: support for setting and getting currentView.
* Also refactor so that dataset view switcher in DataExplorer runs via direct JS rather than routing (as have meant to do for a while). this is important because a) routing stuff is partly going away b) it's cleaner this way.
This commit is contained in:
41
src/view.js
41
src/view.js
@@ -154,7 +154,7 @@ my.DataExplorer = Backbone.View.extend({
|
|||||||
<div class="header"> \
|
<div class="header"> \
|
||||||
<ul class="navigation"> \
|
<ul class="navigation"> \
|
||||||
{{#views}} \
|
{{#views}} \
|
||||||
<li><a href="#{{id}}" class="btn">{{label}}</a> \
|
<li><a href="#{{id}}" data-view="{{id}}" class="btn">{{label}}</a> \
|
||||||
{{/views}} \
|
{{/views}} \
|
||||||
</ul> \
|
</ul> \
|
||||||
<div class="recline-results-info"> \
|
<div class="recline-results-info"> \
|
||||||
@@ -177,7 +177,8 @@ my.DataExplorer = Backbone.View.extend({
|
|||||||
</div> \
|
</div> \
|
||||||
',
|
',
|
||||||
events: {
|
events: {
|
||||||
'click .menu-right a': 'onMenuClick'
|
'click .menu-right a': '_onMenuClick',
|
||||||
|
'click .navigation a': '_onSwitchView'
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize: function(options) {
|
initialize: function(options) {
|
||||||
@@ -207,10 +208,10 @@ my.DataExplorer = Backbone.View.extend({
|
|||||||
})
|
})
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
this.state = new recline.Model.ObjectState();
|
|
||||||
// these must be called after pageViews are created
|
// these must be called after pageViews are created
|
||||||
this._setupState(options.state);
|
|
||||||
this.render();
|
this.render();
|
||||||
|
// should come after render as may need to interact with elements in the view
|
||||||
|
this._setupState(options.state);
|
||||||
|
|
||||||
this.router = new Backbone.Router();
|
this.router = new Backbone.Router();
|
||||||
this.setupRouting();
|
this.setupRouting();
|
||||||
@@ -299,10 +300,10 @@ my.DataExplorer = Backbone.View.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
updateNav: function(pageName, queryString) {
|
updateNav: function(pageName) {
|
||||||
this.el.find('.navigation li').removeClass('active');
|
this.el.find('.navigation li').removeClass('active');
|
||||||
this.el.find('.navigation li a').removeClass('disabled');
|
this.el.find('.navigation li a').removeClass('disabled');
|
||||||
var $el = this.el.find('.navigation li a[href=#' + pageName + ']');
|
var $el = this.el.find('.navigation li a[data-view="' + pageName + '"]');
|
||||||
$el.parent().addClass('active');
|
$el.parent().addClass('active');
|
||||||
$el.addClass('disabled');
|
$el.addClass('disabled');
|
||||||
// show the specific page
|
// show the specific page
|
||||||
@@ -317,7 +318,7 @@ my.DataExplorer = Backbone.View.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onMenuClick: function(e) {
|
_onMenuClick: function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var action = $(e.target).attr('data-action');
|
var action = $(e.target).attr('data-action');
|
||||||
if (action === 'filters') {
|
if (action === 'filters') {
|
||||||
@@ -327,29 +328,47 @@ my.DataExplorer = Backbone.View.extend({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onSwitchView: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var viewName = $(e.target).attr('data-view');
|
||||||
|
this.updateNav(viewName);
|
||||||
|
this.state.set({currentView: viewName});
|
||||||
|
},
|
||||||
|
|
||||||
|
// create a state object for this view and do the job of
|
||||||
|
//
|
||||||
|
// a) initializing it from both data passed in and other sources (e.g. hash url)
|
||||||
|
//
|
||||||
|
// b) ensure the state object is updated in responese to changes in subviews, query etc.
|
||||||
_setupState: function(initialState) {
|
_setupState: function(initialState) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
// get data from the query string / hash url plus some defaults
|
||||||
var qs = my.parseHashQueryString();
|
var qs = my.parseHashQueryString();
|
||||||
var query = qs.reclineQuery;
|
var query = qs.reclineQuery;
|
||||||
query = query ? JSON.parse(query) : self.model.queryState.toJSON();
|
query = query ? JSON.parse(query) : self.model.queryState.toJSON();
|
||||||
// backwards compatability (now named view-graph but was named graph)
|
// backwards compatability (now named view-graph but was named graph)
|
||||||
var graphState = qs['view-graph'] || qs.graph;
|
var graphState = qs['view-graph'] || qs.graph;
|
||||||
graphState = graphState ? JSON.parse(graphState) : {};
|
graphState = graphState ? JSON.parse(graphState) : {};
|
||||||
|
|
||||||
|
// now get default data + hash url plus initial state and initial our state object with it
|
||||||
var stateData = _.extend({
|
var stateData = _.extend({
|
||||||
query: query,
|
query: query,
|
||||||
'view-graph': graphState,
|
'view-graph': graphState,
|
||||||
backend: this.model.backend.__type__,
|
backend: this.model.backend.__type__,
|
||||||
dataset: this.model.toJSON(),
|
dataset: this.model.toJSON(),
|
||||||
currentView: null,
|
currentView: this.pageViews[0].id,
|
||||||
readOnly: false
|
readOnly: false
|
||||||
},
|
},
|
||||||
initialState);
|
initialState);
|
||||||
this.state.set(stateData);
|
this.state = new recline.Model.ObjectState(stateData);
|
||||||
|
|
||||||
// now do updates based on state
|
// now do updates based on state
|
||||||
if (this.state.get('readOnly')) {
|
if (this.state.get('readOnly')) {
|
||||||
this.setReadOnly();
|
this.setReadOnly();
|
||||||
}
|
}
|
||||||
|
if (this.state.get('currentView')) {
|
||||||
|
this.updateNav(this.state.get('currentView'));
|
||||||
|
}
|
||||||
_.each(this.pageViews, function(pageView) {
|
_.each(this.pageViews, function(pageView) {
|
||||||
var viewId = 'view-' + pageView.id;
|
var viewId = 'view-' + pageView.id;
|
||||||
if (viewId in self.state.attributes) {
|
if (viewId in self.state.attributes) {
|
||||||
@@ -357,7 +376,7 @@ my.DataExplorer = Backbone.View.extend({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// bind for changes state in associated objects
|
// finally ensure we update our state object when state of sub-object changes so that state is always up to date
|
||||||
this.model.queryState.bind('change', function() {
|
this.model.queryState.bind('change', function() {
|
||||||
self.state.set({queryState: self.model.queryState.toJSON()});
|
self.state.set({queryState: self.model.queryState.toJSON()});
|
||||||
});
|
});
|
||||||
@@ -376,7 +395,7 @@ my.DataExplorer = Backbone.View.extend({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ## restore
|
// ### DataExplorer.restore
|
||||||
//
|
//
|
||||||
// Restore a DataExplorer instance from a serialized state including the associated dataset
|
// Restore a DataExplorer instance from a serialized state including the associated dataset
|
||||||
my.DataExplorer.restore = function(state) {
|
my.DataExplorer.restore = function(state) {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ test('get State', function () {
|
|||||||
var state = explorer.state;
|
var state = explorer.state;
|
||||||
ok(state.get('query'));
|
ok(state.get('query'));
|
||||||
equal(state.get('readOnly'), false);
|
equal(state.get('readOnly'), false);
|
||||||
|
equal(state.get('currentView'), 'grid');
|
||||||
equal(state.get('query').size, 100);
|
equal(state.get('query').size, 100);
|
||||||
deepEqual(state.get('view-grid').hiddenFields, []);
|
deepEqual(state.get('view-grid').hiddenFields, []);
|
||||||
equal(state.get('backend'), 'memory');
|
equal(state.get('backend'), 'memory');
|
||||||
@@ -34,17 +35,29 @@ test('get State', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('initialize state', function () {
|
test('initialize state', function () {
|
||||||
|
var $el = $('<div class="test-view-explorer-init-state" />');
|
||||||
|
$('.fixtures .data-explorer-here').append($el);
|
||||||
var dataset = Fixture.getDataset();
|
var dataset = Fixture.getDataset();
|
||||||
var explorer = new recline.View.DataExplorer({
|
var explorer = new recline.View.DataExplorer({
|
||||||
model: dataset,
|
model: dataset,
|
||||||
|
el: $el,
|
||||||
state: {
|
state: {
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
|
currentView: 'graph',
|
||||||
'view-grid': {
|
'view-grid': {
|
||||||
hiddenFields: ['x']
|
hiddenFields: ['x']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ok(explorer.state.get('readOnly'));
|
ok(explorer.state.get('readOnly'));
|
||||||
|
ok(explorer.state.get('currentView'), 'graph');
|
||||||
|
// check the correct view is visible
|
||||||
|
var css = explorer.el.find('.navigation a[data-view="graph"]').attr('class').split(' ');
|
||||||
|
ok(_.contains(css, 'disabled'), css);
|
||||||
|
|
||||||
|
var css = explorer.el.find('.navigation a[data-view="grid"]').attr('class').split(' ');
|
||||||
|
ok(!(_.contains(css, 'disabled')), css);
|
||||||
|
$el.remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('restore (from serialized state)', function() {
|
test('restore (from serialized state)', function() {
|
||||||
|
|||||||
Reference in New Issue
Block a user