//---------------------------------------------------------------------------- // Copyright (C) 2013 The IPython Development Team // // Distributed under the terms of the BSD License. The full license is in // the file COPYING, distributed as part of this software. //---------------------------------------------------------------------------- //============================================================================ // SelectionContainerWidget //============================================================================ /** * @module IPython * @namespace IPython **/ define(["notebook/js/widgets/widget"], function(WidgetManager){ var AccordionView = IPython.DOMWidgetView.extend({ render: function(){ // Called when view is rendered. var guid = 'accordion' + IPython.utils.uuid(); this.$el .attr('id', guid) .addClass('accordion'); this.containers = []; this.model_containers = {}; this.update_children([], this.model.get('_children')); this.model.on('change:_children', function(model, value, options) { this.update_children(model.previous('_children'), value); }, this); }, update: function(options) { // Update the contents of this view // // Called when the model is changed. The model may have been // changed by another view or by a state update from the back-end. if (options === undefined || options.updated_view != this) { // Set tab titles var titles = this.model.get('_titles'); var that = this; _.each(titles, function(title, page_index) { var accordian = that.containers[page_index]; if (accordian !== undefined) { accordian .find('.accordion-heading') .find('.accordion-toggle') .text(title); } }); // Set selected page var selected_index = this.model.get("selected_index"); if (0 <= selected_index && selected_index < this.containers.length) { _.each(this.containers, function(container, index) { if (index==selected_index) { container.find('.accordion-body').collapse('show'); } else { container.find('.accordion-body').collapse('hide'); } }); } } return AccordionView.__super__.update.apply(this); }, update_children: function(old_list, new_list) { // Called when the children list is modified. this.do_diff(old_list, new_list, $.proxy(this.remove_child_model, this), $.proxy(this.add_child_model, this)); }, remove_child_model: function(model) { // Called when a child is removed from children list. var accordion_group = this.model_containers[model.id]; this.containers.splice(accordion_group.container_index, 1); delete this.model_containers[model.id]; accordion_group.remove(); this.delete_child_view(model); }, add_child_model: function(model) { // Called when a child is added to children list. var view = this.create_child_view(model); var index = this.containers.length; var uuid = IPython.utils.uuid(); var accordion_group = $('
') .addClass('accordion-group') .appendTo(this.$el); var accordion_heading = $('') .addClass('accordion-heading') .appendTo(accordion_group); var that = this; var accordion_toggle = $('') .addClass('accordion-toggle') .attr('data-toggle', 'collapse') .attr('data-parent', '#' + this.$el.attr('id')) .attr('href', '#' + uuid) .click(function(evt){ // Calling model.set will trigger all of the other views of the // model to update. that.model.set("selected_index", index, {updated_view: this}); that.touch(); }) .text('Page ' + index) .appendTo(accordion_heading); var accordion_body = $('', {id: uuid}) .addClass('accordion-body collapse') .appendTo(accordion_group); var accordion_inner = $('') .addClass('accordion-inner') .appendTo(accordion_body); var container_index = this.containers.push(accordion_group) - 1; accordion_group.container_index = container_index; this.model_containers[model.id] = accordion_group; accordion_inner.append(view.$el); this.update(); // Stupid workaround to close the bootstrap accordion tabs which // open by default even though they don't have the `in` class // attached to them. For some reason a delay is required. // TODO: Better fix. setTimeout(function(){ that.update(); }, 500); }, }); WidgetManager.register_widget_view('AccordionView', AccordionView); var TabView = IPython.DOMWidgetView.extend({ initialize: function() { // Public constructor. this.containers = []; TabView.__super__.initialize.apply(this, arguments); }, render: function(){ // Called when view is rendered. var uuid = 'tabs'+IPython.utils.uuid(); var that = this; this.$tabs = $('', {id: uuid}) .addClass('nav') .addClass('nav-tabs') .appendTo(this.$el); this.$tab_contents = $('', {id: uuid + 'Content'}) .addClass('tab-content') .appendTo(this.$el); this.containers = []; this.update_children([], this.model.get('_children')); this.model.on('change:_children', function(model, value, options) { this.update_children(model.previous('_children'), value); }, this); }, update_children: function(old_list, new_list) { // Called when the children list is modified. this.do_diff(old_list, new_list, $.proxy(this.remove_child_model, this), $.proxy(this.add_child_model, this)); }, remove_child_model: function(model) { // Called when a child is removed from children list. var view = this.child_views[model.id]; this.containers.splice(view.parent_tab.tab_text_index, 1); view.parent_tab.remove(); view.parent_container.remove(); view.remove(); this.delete_child_view(model); }, add_child_model: function(model) { // Called when a child is added to children list. var view = this.create_child_view(model); var index = this.containers.length; var uuid = IPython.utils.uuid(); var that = this; var tab = $('') .css('list-style-type', 'none') .appendTo(this.$tabs); view.parent_tab = tab; var tab_text = $('') .attr('href', '#' + uuid) .attr('data-toggle', 'tab') .text('Page ' + index) .appendTo(tab) .click(function (e) { // Calling model.set will trigger all of the other views of the // model to update. that.model.set("selected_index", index, {updated_view: this}); that.touch(); that.select_page(index); }); tab.tab_text_index = this.containers.push(tab_text) - 1; var contents_div = $('', {id: uuid}) .addClass('tab-pane') .addClass('fade') .append(view.$el) .appendTo(this.$tab_contents); view.parent_container = contents_div; }, update: function(options) { // Update the contents of this view // // Called when the model is changed. The model may have been // changed by another view or by a state update from the back-end. if (options === undefined || options.updated_view != this) { // Set tab titles var titles = this.model.get('_titles'); var that = this; _.each(titles, function(title, page_index) { var tab_text = that.containers[page_index]; if (tab_text !== undefined) { tab_text.text(title); } }); var selected_index = this.model.get('selected_index'); if (0 <= selected_index && selected_index < this.containers.length) { this.select_page(selected_index); } } return TabView.__super__.update.apply(this); }, select_page: function(index) { // Select a page. this.$tabs.find('li') .removeClass('active'); this.containers[index].tab('show'); }, }); WidgetManager.register_widget_view('TabView', TabView); });