##// END OF EJS Templates
- ModalView can now be docked and undocked...
Jonathan Frederic -
Show More
@@ -1,193 +1,259
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2013 The IPython Development Team
2 // Copyright (C) 2013 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // ContainerWidget
9 // ContainerWidget
10 //============================================================================
10 //============================================================================
11
11
12 /**
12 /**
13 * @module IPython
13 * @module IPython
14 * @namespace IPython
14 * @namespace IPython
15 **/
15 **/
16
16
17 define(["notebook/js/widget"], function(widget_manager) {
17 define(["notebook/js/widget"], function(widget_manager) {
18
18
19 var set_flex_property = function(element, property_name, enabled) {
19 var set_flex_property = function(element, property_name, enabled) {
20 if (enabled) {
20 if (enabled) {
21 element.addClass(property_name);
21 element.addClass(property_name);
22 } else {
22 } else {
23 element.removeClass(property_name);
23 element.removeClass(property_name);
24 }
24 }
25 };
25 };
26
26
27 var set_flex_properties = function(context, element) {
27 var set_flex_properties = function(context, element) {
28
28
29 // Apply flexible box model properties by adding and removing
29 // Apply flexible box model properties by adding and removing
30 // corrosponding CSS classes.
30 // corrosponding CSS classes.
31 // Defined in IPython/html/static/base/less/flexbox.less
31 // Defined in IPython/html/static/base/less/flexbox.less
32 set_flex_property(element, 'vbox', context.model.get('_vbox'));
32 set_flex_property(element, 'vbox', context.model.get('_vbox'));
33 set_flex_property(element, 'hbox', context.model.get('_hbox'));
33 set_flex_property(element, 'hbox', context.model.get('_hbox'));
34 set_flex_property(element, 'start', context.model.get('_pack_start'));
34 set_flex_property(element, 'start', context.model.get('_pack_start'));
35 set_flex_property(element, 'center', context.model.get('_pack_center'));
35 set_flex_property(element, 'center', context.model.get('_pack_center'));
36 set_flex_property(element, 'end', context.model.get('_pack_end'));
36 set_flex_property(element, 'end', context.model.get('_pack_end'));
37 set_flex_property(element, 'align-start', context.model.get('_align_start'));
37 set_flex_property(element, 'align-start', context.model.get('_align_start'));
38 set_flex_property(element, 'align-center', context.model.get('_align_center'));
38 set_flex_property(element, 'align-center', context.model.get('_align_center'));
39 set_flex_property(element, 'align-end', context.model.get('_align_end'));
39 set_flex_property(element, 'align-end', context.model.get('_align_end'));
40 set_flex_property(element, 'box-flex0', context.model.get('_flex0'));
40 set_flex_property(element, 'box-flex0', context.model.get('_flex0'));
41 set_flex_property(element, 'box-flex1', context.model.get('_flex1'));
41 set_flex_property(element, 'box-flex1', context.model.get('_flex1'));
42 set_flex_property(element, 'box-flex2', context.model.get('_flex2'));
42 set_flex_property(element, 'box-flex2', context.model.get('_flex2'));
43 };
43 };
44
44
45
45
46
46
47 var ContainerModel = IPython.WidgetModel.extend({});
47 var ContainerModel = IPython.WidgetModel.extend({});
48 widget_manager.register_widget_model('ContainerWidgetModel', ContainerModel);
48 widget_manager.register_widget_model('ContainerWidgetModel', ContainerModel);
49
49
50 var ContainerView = IPython.WidgetView.extend({
50 var ContainerView = IPython.WidgetView.extend({
51
51
52 render: function(){
52 render: function(){
53 this.$el
53 this.$el
54 .addClass('widget-container');
54 .addClass('widget-container');
55 },
55 },
56
56
57 update: function(){
57 update: function(){
58 set_flex_properties(this, this.$el);
58 set_flex_properties(this, this.$el);
59 return IPython.WidgetView.prototype.update.call(this);
59 return IPython.WidgetView.prototype.update.call(this);
60 },
60 },
61
61
62 display_child: function(view) {
62 display_child: function(view) {
63 this.$el.append(view.$el);
63 this.$el.append(view.$el);
64 },
64 },
65 });
65 });
66
66
67 widget_manager.register_widget_view('ContainerView', ContainerView);
67 widget_manager.register_widget_view('ContainerView', ContainerView);
68
68
69
69
70 var ModalView = IPython.WidgetView.extend({
70 var ModalView = IPython.WidgetView.extend({
71
71
72 render: function(){
72 render: function(){
73 var that = this;
73 var that = this;
74 this.$el
74 this.$el
75 .html('')
75 .html('')
76 .on("remove", function(){
76 .on("remove", function(){
77 that.$window.remove();
77 that.$window.remove();
78 });
78 });
79 this.$window = $('<div />')
79 this.$window = $('<div />')
80 .addClass('modal widget-modal')
80 .addClass('modal widget-modal')
81 .appendTo($('#notebook-container'));
81 .appendTo($('#notebook-container'))
82 .mousedown(function(){
83 that.bring_to_front();
84 });
82 this.$title_bar = $('<div />')
85 this.$title_bar = $('<div />')
83 .addClass('popover-title')
86 .addClass('popover-title')
84 .appendTo(this.$window);
87 .appendTo(this.$window)
85 var that = this;
88 .mousedown(function(){
86 $('<button />')
89 that.bring_to_front();
87 .addClass('close')
90 });;
88 .html('&times;')
91 this.$close = $('<button />')
92 .addClass('close icon-remove')
93 .css('margin-left', '5px')
89 .appendTo(this.$title_bar)
94 .appendTo(this.$title_bar)
90 .click(function(){
95 .click(function(){
91 that.hide();
96 that.hide();
92 event.stopPropagation();
97 event.stopPropagation();
93 });
98 });
99 this.$minimize = $('<button />')
100 .addClass('close icon-arrow-down')
101 .appendTo(this.$title_bar)
102 .click(function(){
103 that.popped_out = !that.popped_out;
104 if (!that.popped_out) {
105 that.$minimize
106 .removeClass('icon-arrow-down')
107 .addClass('icon-arrow-up');
108
109 that.$window
110 .draggable('destroy')
111 .resizable('destroy')
112 .removeClass('widget-modal modal')
113 .addClass('docked-widget-modal')
114 .detach()
115 .insertBefore(that.$show_button);
116 that.$show_button.hide();
117 that.$close.hide();
118 } else {
119 that.$minimize
120 .addClass('icon-arrow-down')
121 .removeClass('icon-arrow-up');
122
123 that.$window
124 .removeClass('docked-widget-modal')
125 .addClass('widget-modal modal')
126 .detach()
127 .appendTo($('#notebook-container'))
128 .draggable({handle: '.popover-title', snap: '#notebook, .modal', snapMode: 'both'})
129 .resizable()
130 .children('.ui-resizable-handle').show();
131 that.show();
132 that.$show_button.show();
133 that.$close.show();
134 }
135 event.stopPropagation();
136 });
94 this.$title = $('<div />')
137 this.$title = $('<div />')
95 .addClass('widget-modal-title')
138 .addClass('widget-modal-title')
96 .html('&nbsp;')
139 .html('&nbsp;')
97 .appendTo(this.$title_bar);
140 .appendTo(this.$title_bar);
98 this.$body = $('<div />')
141 this.$body = $('<div />')
99 .addClass('modal-body')
142 .addClass('modal-body')
100 .addClass('widget-modal-body')
143 .addClass('widget-modal-body')
101 .addClass('widget-container')
144 .addClass('widget-container')
102 .appendTo(this.$window);
145 .appendTo(this.$window);
103
146
104 this.$show_button = $('<button />')
147 this.$show_button = $('<button />')
105 .html('&nbsp;')
148 .html('&nbsp;')
106 .addClass('btn btn-info widget-modal-show')
149 .addClass('btn btn-info widget-modal-show')
107 .appendTo(this.$el)
150 .appendTo(this.$el)
108 .click(function(){
151 .click(function(){
109 that.show();
152 that.show();
110 });
153 });
111
154
112 this.$window.draggable({handle: '.popover-title', snap: '#notebook, .modal', snapMode: 'both'});
155 this.$window.draggable({handle: '.popover-title', snap: '#notebook, .modal', snapMode: 'both'});
113 this.$window.resizable();
156 this.$window.resizable();
114 this.$window.on('resize', function(){
157 this.$window.on('resize', function(){
115 that.$body.outerHeight(that.$window.innerHeight() - that.$title_bar.outerHeight());
158 that.$body.outerHeight(that.$window.innerHeight() - that.$title_bar.outerHeight());
116 })
159 })
117
160
118 this.$el_to_style = this.$body;
161 this.$el_to_style = this.$body;
119 this._shown_once = false;
162 this._shown_once = false;
163 this.popped_out = true;
120 },
164 },
121
165
122 hide: function() {
166 hide: function() {
123 this.$window.hide();
167 this.$window.hide();
124 this.$show_button.removeClass('btn-info');
168 this.$show_button.removeClass('btn-info');
125 },
169 },
126
170
127 show: function() {
171 show: function() {
128 this.$show_button.addClass('btn-info');
172 this.$show_button.addClass('btn-info');
129
173
130 this.$window.show();
174 this.$window.show();
131 this.$window.css("positon", "absolute")
175 if (this.popped_out) {
132 this.$window.css("top", "0px");
176 this.$window.css("positon", "absolute")
133 this.$window.css("left", Math.max(0, (($('body').outerWidth() - this.$window.outerWidth()) / 2) +
177 this.$window.css("top", "0px");
134 $(window).scrollLeft()) + "px");
178 this.$window.css("left", Math.max(0, (($('body').outerWidth() - this.$window.outerWidth()) / 2) +
179 $(window).scrollLeft()) + "px");
180 this.bring_to_front();
181 }
182 },
183
184 bring_to_front: function() {
185 var $widget_modals = $(".widget-modal");
186 var max_zindex = 0;
187 $widget_modals.each(function (index, el){
188 max_zindex = Math.max(max_zindex, parseInt($(el).css('z-index')));
189 });
190
191 // Start z-index of widget modals at 2000
192 max_zindex = Math.max(max_zindex, 2000);
193
194 $widget_modals.each(function (index, el){
195 $el = $(el)
196 if (max_zindex == parseInt($el.css('z-index'))) {
197 $el.css('z-index', max_zindex - 1);
198 }
199 });
200 this.$window.css('z-index', max_zindex);
135 },
201 },
136
202
137 update: function(){
203 update: function(){
138 set_flex_properties(this, this.$body);
204 set_flex_properties(this, this.$body);
139
205
140 var description = this.model.get('description');
206 var description = this.model.get('description');
141 description = description.replace(/ /g, '&nbsp;', 'm');
207 description = description.replace(/ /g, '&nbsp;', 'm');
142 description = description.replace(/\n/g, '<br>\n', 'm');
208 description = description.replace(/\n/g, '<br>\n', 'm');
143 if (description.length == 0) {
209 if (description.length == 0) {
144 this.$title.html('&nbsp;'); // Preserve title height
210 this.$title.html('&nbsp;'); // Preserve title height
145 } else {
211 } else {
146 this.$title.html(description);
212 this.$title.html(description);
147 }
213 }
148
214
149 var button_text = this.model.get('button_text');
215 var button_text = this.model.get('button_text');
150 button_text = button_text.replace(/ /g, '&nbsp;', 'm');
216 button_text = button_text.replace(/ /g, '&nbsp;', 'm');
151 button_text = button_text.replace(/\n/g, '<br>\n', 'm');
217 button_text = button_text.replace(/\n/g, '<br>\n', 'm');
152 if (button_text.length == 0) {
218 if (button_text.length == 0) {
153 this.$show_button.html('&nbsp;'); // Preserve button height
219 this.$show_button.html('&nbsp;'); // Preserve button height
154 } else {
220 } else {
155 this.$show_button.html(button_text);
221 this.$show_button.html(button_text);
156 }
222 }
157
223
158 if (!this._shown_once) {
224 if (!this._shown_once) {
159 this._shown_once = true;
225 this._shown_once = true;
160 this.show();
226 this.show();
161 }
227 }
162
228
163 return IPython.WidgetView.prototype.update.call(this);
229 return IPython.WidgetView.prototype.update.call(this);
164 },
230 },
165
231
166 display_child: function(view) {
232 display_child: function(view) {
167 this.$body.append(view.$el);
233 this.$body.append(view.$el);
168 },
234 },
169
235
170 _get_selector_element: function(selector) {
236 _get_selector_element: function(selector) {
171
237
172 // Since the modal actually isn't within the $el in the DOM, we need to extend
238 // Since the modal actually isn't within the $el in the DOM, we need to extend
173 // the selector logic to allow the user to set css on the modal if need be.
239 // the selector logic to allow the user to set css on the modal if need be.
174 // The convention used is:
240 // The convention used is:
175 // "modal" - select the modal div
241 // "modal" - select the modal div
176 // "modal [selector]" - select element(s) within the modal div.
242 // "modal [selector]" - select element(s) within the modal div.
177 // "[selector]" - select elements within $el
243 // "[selector]" - select elements within $el
178 // "" - select the $el_to_style
244 // "" - select the $el_to_style
179 if (selector.substring(0, 5) == 'modal') {
245 if (selector.substring(0, 5) == 'modal') {
180 if (selector == 'modal') {
246 if (selector == 'modal') {
181 return this.$window;
247 return this.$window;
182 } else {
248 } else {
183 return this.$window.find(selector.substring(6));
249 return this.$window.find(selector.substring(6));
184 }
250 }
185 } else {
251 } else {
186 return IPython.WidgetView.prototype._get_selector_element.call(this, selector);
252 return IPython.WidgetView.prototype._get_selector_element.call(this, selector);
187 }
253 }
188 },
254 },
189
255
190 });
256 });
191
257
192 widget_manager.register_widget_view('ModalView', ModalView);
258 widget_manager.register_widget_view('ModalView', ModalView);
193 });
259 });
General Comments 0
You need to be logged in to leave comments. Login now