-
Notifications
You must be signed in to change notification settings - Fork 0
/
tabs.js
197 lines (177 loc) · 5.06 KB
/
tabs.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/**
* Tab Manager Class
*
* Usage: var tm = new TabManager('#tabs-go-here-in-html');
* tm.addTab( {id: 'tab 1'});
* tm.addTab( {id: 'tab 2'});
* tm.render('tab 1');
*
* Other things to pass in for options:
* - order: the order the tab should show up (left to right)
* - selectCallback: function to execute when tab is clicked. the this variable will be the tab view (marionette ItemView)
* - unselectCallback: same as above but when unclicked
* - tagName: the HTML tag that the tab should render as. defaults to span
* - className / selectedClassName: the default & selected HTML class to be
*
* @author http://github.com/nickfun
* @since 2013-03-18
*/
function TabManager( target ) {
// Private Functions, Properties
// -----------------------------
var _tabTemplate = _.template('<%= id %>');
var that = this;
var TabModel = Backbone.Model.extend({
defaults: {
id: '_tab',
order: 1,
tagName: 'span',
className: '_tab_manager tab-normal',
selectedClassName: '_tab_manager tab-selected'
},
idAttribute: 'id'
});
// collection of tabs to display
var _TabCollection = Backbone.Collection.extend({
model: TabModel
});
var _tabs = new _TabCollection();
// how our tabs should be sorted
_tabs.comparator = function( oTab) {
return oTab.get('order');
};
// the tab that is currently selected
var _currentTabView = false;
// view that displays one tab
var TabView = Backbone.Marionette.ItemView.extend({
className: function() {
return this.model.get('className');
},
tagName: function() {
return this.model.get('tagName');
},
getTemplate: function() {
return _tabTemplate;
},
attributes: function() {
return { 'data-tabViewCid': this.cid };
},
events: {
'click': 'clickHandler'
},
clickHandler: function( oEvent ) {
this.select();
},
select: function() {
// was something already clicked?
if( _currentTabView === false ) {
// no, this is a new selection
that.selectCallback( this );
// remember new selection
_currentTabView = this;
return;
}
// do nothing if we are selecting ourself
if( _currentTabView.cid === this.cid ) {
return;
}
// unselect old, select new
that.unselectCallback( _currentTabView );
that.selectCallback( this );
// remember new selection
_currentTabView = this;
}
});
// view that displays all tabs
var AllTabs = new Backbone.Marionette.CollectionView({
el: $(target),
itemView: TabView,
collection: _tabs
});
// public functions
// ----------------
// Set the template
this.setTemplate = function( sTemplate ) {
_tabTemplate = _.template( sTemplate );
};
// add a tab
this.addTab = function( oTabModel ) {
_tabs.add( oTabModel, {merge: true} );
};
// remove a tab
this.removeTab = function( sTabName ) {
// get the model
var oModel = _tabs.get( sTabName );
// is it the selected on?
if( _currentTabView !== false && _currentTabView.model.id == oModel.id ) {
// unselect it
this.unselectCallback( AllTabs.children.findByModel(oModel) );
// select nothing
_currentTabView = false;
}
_tabs.remove( sTabName );
};
// select a tab
this.selectTab = function( sSelectedName ) {
// get the model for it
var oModel = _tabs.get( sSelectedName );
// valid?
if( typeof oModel === 'undefined' ) {
throw new Error("TabManager: cant find tab " + sSelectedName);
}
// get the view
var oView = AllTabs.children.findByModel( oModel );
// select it
oView.select();
};
// render
// pass in the name of the tab to be default selection
this.render = function( sSelectedName ) {
_tabs.sort();
AllTabs.render();
var oView;
var oModel;
oModel = _tabs.get( sSelectedName );
if( typeof oModel === 'undefined' ) {
// model not found. use first.
oModel = _tabs.first();
}
oView = AllTabs.children.findByModel( oModel );
oView.select();
};
// get tabs collection for whatever reason
this.getTabs = function() {
return _tabs;
};
// get the big CollectionView that is showing everything
this.getView = function() {
return AllTabs;
};
// Making these public in case they need to be over-ridden
// but you should just specify a callback for each tab
// What to do when a tab is selected
this.selectCallback = function( oView ) {
oView.$el.toggleClass( oView.model.get('className') );
oView.$el.toggleClass( oView.model.get('selectedClassName') );
// does this model have a callback for selection?
if( oView.model.has('selectCallback')) {
var callback = oView.model.get('selectCallback');
if( typeof callback !== 'function' ) {
throw new Error("TabManager: invalid callback");
}
callback.apply( oView );
}
};
// what to do when a tab is unselected
this.unselectCallback = function( oView ) {
oView.$el.toggleClass( oView.model.get('className') );
oView.$el.toggleClass( oView.model.get('selectedClassName') );
if( oView.model.has('unselectCallback')) {
var callback = oView.model.get('unselectCallback');
if( typeof callback !== 'function' ) {
throw new Error("TabManager: invalid callback");
}
callback.apply( oView );
}
};
}