Fixed lots of bugs

Half overhaul of notebook focus events...
pull/37/head
Jonathan Frederic 12 years ago
parent 206d35a89e
commit 6f7c502157

@ -118,7 +118,7 @@ var IPython = (function (IPython) {
} else {
this.element.addClass('command_mode');
}
}
};
/**
@ -133,12 +133,12 @@ var IPython = (function (IPython) {
that.element.click(function (event) {
if (!that.selected) {
$([IPython.events]).trigger('select.Cell', {'cell':that});
};
}
});
that.element.focusin(function (event) {
if (!that.selected) {
$([IPython.events]).trigger('select.Cell', {'cell':that});
};
}
});
if (this.code_mirror) {
this.code_mirror.on("change", function(cm, change) {
@ -147,31 +147,12 @@ var IPython = (function (IPython) {
}
if (this.code_mirror) {
this.code_mirror.on('focus', function(cm, change) {
console.log('cell focused');
if (that._continue_blur) {
that._continue_blur = false;
} else {
if (that.mode === 'command') {
$([IPython.events]).trigger('edit_mode.Cell', {cell: that});
}
}
$([IPython.events]).trigger('focus_text.Cell', {cell: that});
});
}
if (this.code_mirror) {
this.code_mirror.on('blur', function(cm, change) {
console.log('cell blur');
that._continue_blur = true;
setTimeout($.proxy(function () {
if (that._continue_blur) {
console.log('cell blur> edit true> callback');
var isf = IPython.utils.is_focused;
if (! (isf('div#tooltip') || isf('div.completions'))) {
if (that.mode === 'edit') {
$([IPython.events]).trigger('command_mode.Cell', {cell: that});
}
}
}
}, that), 1);
$([IPython.events]).trigger('blur_text.Cell', {cell: that});
});
}
};
@ -281,7 +262,7 @@ var IPython = (function (IPython) {
} else {
return false;
}
}
};
/**
* Focus the cell in the DOM sense
@ -289,24 +270,7 @@ var IPython = (function (IPython) {
*/
Cell.prototype.focus_cell = function () {
this.element.focus();
}
/**
* Focus the editor area so a user can type
* @method focus_editor
*/
Cell.prototype.focus_editor = function () {
var that = this;
this.refresh();
// Only focus the CM editor if it is not focused already. This prevents jumps
// related to the previous prompt position.
setTimeout(function () {
var isf = IPython.utils.is_focused;
if (!isf(that.element.find('div.CodeMirror'))) {
that.code_mirror.focus();
}
}, 1);
}
};
/**
* Refresh codemirror instance

@ -391,6 +391,14 @@ var IPython = (function (IPython) {
return cont;
};
CodeCell.prototype.unselect = function () {
var cont = IPython.Cell.prototype.unselect.apply(this);
if (cont) {
this.code_mirror.getInputField().blur();
}
return cont;
};
CodeCell.prototype.render = function () {
var cont = IPython.Cell.prototype.render.apply(this);
// Always execute, even if we are already in the rendered state
@ -404,11 +412,27 @@ var IPython = (function (IPython) {
CodeCell.prototype.edit_mode = function () {
var cont = IPython.Cell.prototype.edit_mode.apply(this);
if (cont) {
if (this.mode === 'edit') {
this.focus_editor();
}
return cont;
}
};
/**
* Focus the editor area so a user can type
* @method focus_editor
*/
CodeCell.prototype.focus_editor = function () {
// Only focus the CM editor if it is not focused already. This prevents
// jumps related to the previous prompt position. Here we can't use
// IPython.utils.is_focused since it uses document.activeElement which
// may not be set by the time this is called. Instead look at the input
// element of codemirror directly to see if it is focused. Use the
// jQuery :focus pseudo selector (http://api.jquery.com/focus-selector/)
if (!$(this.code_mirror.win).is(':focus')) {
this.code_mirror.focus();
}
};
CodeCell.prototype.select_all = function () {
var start = {line: 0, ch: 0};

@ -73,6 +73,7 @@ var IPython = (function (IPython) {
var Completer = function (cell) {
this._visible = false;
this.cell = cell;
this.editor = cell.code_mirror;
var that = this;
@ -84,6 +85,10 @@ var IPython = (function (IPython) {
});
};
Completer.prototype.is_visible = function () {
// Return whether or not the completer is visible.
return this._visible;
};
Completer.prototype.startCompletion = function () {
// call for a 'first' completion, that will set the editor and do some
@ -225,6 +230,7 @@ var IPython = (function (IPython) {
.attr('multiple', 'true')
.attr('size', Math.min(10, this.raw_result.length));
this.complete.append(this.sel);
this._visible = true;
$('body').append(this.complete);
// After everything is on the page, compute the postion.
@ -282,6 +288,7 @@ var IPython = (function (IPython) {
};
Completer.prototype.close = function () {
this._visible = false;
if (this.done) return;
this.done = true;
$('.completions').remove();

@ -115,20 +115,12 @@ var IPython = (function (IPython) {
that.select(index);
});
$([IPython.events]).on('edit_mode.Cell', function (event, data) {
console.log('edit mode cell');
var index = that.find_cell_index(data.cell);
that.select(index);
that.edit_mode();
$([IPython.events]).on('focus_text.Cell', function (event, data) {
that.handle_cell_text_focus(that.find_cell_index(data.cell));
});
$([IPython.events]).on('command_mode.Cell', function (event, data) {
console.log('command mode cell');
// In Firefox the focus event is called before the blur event. In
// other words, two cells elements may be focused at any given time.
// Here we verify that no cells are currently in edit mode before
// putting the entire notebook in command mode.
that.command_mode();
$([IPython.events]).on('blur_text.Cell', function (event, data) {
that.handle_cell_text_blur(that.find_cell_index(data.cell));
});
$([IPython.events]).on('status_autorestarting.Kernel', function () {
@ -465,6 +457,8 @@ var IPython = (function (IPython) {
if (this.is_valid_cell_index(index)) {
var sindex = this.get_selected_index();
if (sindex !== null && index !== sindex) {
// Put the cell in command mode and unselect it.
this.get_cell(sindex).command_mode();
this.get_cell(sindex).unselect();
}
var cell = this.get_cell(index);
@ -509,41 +503,67 @@ var IPython = (function (IPython) {
// Edit/Command mode
Notebook.prototype.get_edit_index = function () {
Notebook.prototype.get_edit_index = function (ignore_index) {
var result = null;
this.get_cell_elements().filter(function (index) {
if ($(this).data("cell").mode === 'edit') {
result = index;
if (ignore_index===undefined || ignore_index!==index) {
result = index;
}
}
});
return result;
};
Notebook.prototype.command_mode = function () {
console.log('cell.command_mode');
console.log('notebook command_mode()');
// Make sure there isn't an edit mode cell lingering around.
var cell = this.get_cell(this.get_edit_index());
if (cell) {
cell.command_mode();
}
// Notify the keyboard manager if this is a change of mode for the
// notebook as a whole.
if (this.mode !== 'command') {
$([IPython.events]).trigger('command_mode.Notebook');
var index = this.get_edit_index();
var cell = this.get_cell(index);
if (cell) {
cell.command_mode();
}
this.mode = 'command';
$([IPython.events]).trigger('command_mode.Notebook');
IPython.keyboard_manager.command_mode();
}
};
Notebook.prototype.edit_mode = function () {
console.log('cell.edit_mode');
Notebook.prototype.edit_mode = function (index) {
console.log('notebook edit_mode()');
// Either use specified index or selected cell's index.
// Must explictly check for undefined CBool(0) = false.
if (index===undefined) {
index = this.get_selected_index();
}
var cell = this.get_cell(index);
// Make sure the cell exists.
if (cell === null) { return; }
// If another cell is currently in edit mode set it to command mode.
var edit_index = this.get_edit_index(index);
if (edit_index !== null) { // Must explictly check for null CBool(0) = false.
var edit_cell = this.get_cell(edit_index);
if (edit_cell) {
edit_cell.command_mode();
}
}
// Set the cell to edit mode and notify the keyboard manager if this
// is a change of mode for the notebook as a whole.
if (this.get_selected_index()!==index) {
this.select(index);
}
cell.edit_mode();
if (this.mode !== 'edit') {
$([IPython.events]).trigger('edit_mode.Notebook');
var cell = this.get_selected_cell();
if (cell === null) {return;} // No cell is selected
// We need to set the mode to edit to prevent reentering this method
// when cell.edit_mode() is called below.
this.mode = 'edit';
$([IPython.events]).trigger('edit_mode.Notebook');
IPython.keyboard_manager.edit_mode();
cell.edit_mode();
}
};
@ -553,6 +573,36 @@ var IPython = (function (IPython) {
cell.focus_cell();
};
Notebook.prototype.handle_cell_text_focus = function (index) {
this.edit_mode(index);
};
Notebook.prototype.handle_cell_text_blur = function (index) {
var cell = this.get_cell(index);
if (!cell) {return;}
// Only respect the blur event if the tooltip and autocompleter are
// not visible.
var tooltip_visible = IPython.tooltip && IPython.tooltip.is_visible();
var completer_visible = cell.completer && cell.completer.is_visible();
if (!tooltip_visible && !completer_visible) {
// In Firefox the focus event is called before the blur event. In
// other words, two cells elements may be focused at any given time.
// This has been witnessed on Win7 x64 w/ FF 25. Here we only put the
// entire notebook in command mode iff the cell textbox being blured is
// the one that is currently in edit mode. Otherwise, we assume the
// event order has been reversed and we just put this particular cell
// in command mode.
if (index===this.get_edit_index(index)) {
console.log('full command_mode');
this.command_mode();
} else {
console.log('cell command_mode');
cell.command_mode();
}
}
};
// Cell movement
/**
@ -1411,8 +1461,8 @@ var IPython = (function (IPython) {
console.log('execute cell command_mode');
cell.execute();
this.command_mode();
cell.focus_cell();
this.command_mode();
this.set_dirty(true);
};
@ -1467,6 +1517,7 @@ var IPython = (function (IPython) {
this.select(cell_index+1);
this.get_cell(cell_index+1).focus_cell();
this.command_mode();
this.set_dirty(true);
};

@ -52,7 +52,7 @@ var IPython = (function (IPython) {
// expand the tooltip to see more
var expandlink = $('<a/>').attr('href', "#").addClass("ui-corner-all") //rounded corner
.attr('role', "button").attr('id', 'expanbutton').attr('title', 'Grow the tooltip vertically (press tab 2 times)').click(function () {
that.expand()
that.expand();
}).append(
$('<span/>').text('Expand').addClass('ui-icon').addClass('ui-icon-plus'));
@ -121,9 +121,13 @@ var IPython = (function (IPython) {
this._old_cell = (cell) ? cell : null;
this._old_request = (text) ? text : null;
this._consecutive_counter = 0;
}
};
};
Tooltip.prototype.is_visible = function () {
return !this._hidden;
};
Tooltip.prototype.showInPager = function (cell) {
// reexecute last call in pager by appending ? to show back in pager
var that = this;
@ -139,27 +143,27 @@ var IPython = (function (IPython) {
'store_history': true
});
this.remove_and_cancel_tooltip();
}
};
// grow the tooltip verticaly
Tooltip.prototype.expand = function () {
this.text.removeClass('smalltooltip');
this.text.addClass('bigtooltip');
$('#expanbutton').hide('slow');
}
};
// deal with all the logic of hiding the tooltip
// and reset it's status
Tooltip.prototype._hide = function () {
this._hidden = true;
this.tooltip.fadeOut('fast');
$('#expanbutton').show('slow');
this.text.removeClass('bigtooltip');
this.text.addClass('smalltooltip');
// keep scroll top to be sure to always see the first line
this.text.scrollTop(0);
this._hidden = true;
this.code_mirror = null;
}
};
// return true on successfully removing a visible tooltip; otherwise return
// false.
@ -178,23 +182,23 @@ var IPython = (function (IPython) {
} else {
return false;
}
}
};
// cancel autocall done after '(' for example.
Tooltip.prototype.cancel_pending = function () {
if (this._tooltip_timeout != null) {
if (this._tooltip_timeout !== null) {
clearTimeout(this._tooltip_timeout);
this._tooltip_timeout = null;
}
}
};
// will trigger tooltip after timeout
Tooltip.prototype.pending = function (cell, hide_if_no_docstring) {
var that = this;
this._tooltip_timeout = setTimeout(function () {
that.request(cell, hide_if_no_docstring)
that.request(cell, hide_if_no_docstring);
}, that.time_before_tooltip);
}
};
// easy access for julia monkey patching.
Tooltip.last_token_re = /[a-z_][0-9a-z._]*$/gi;
@ -219,7 +223,7 @@ var IPython = (function (IPython) {
line = line.replace(endBracket, "");
// reset the regex object
Tooltip.last_token_re.lastIndex = 0;
return Tooltip.last_token_re.exec(line)
return Tooltip.last_token_re.exec(line);
};
Tooltip.prototype._request_tooltip = function (cell, line) {
@ -252,7 +256,7 @@ var IPython = (function (IPython) {
// now we treat the different number of keypress
// first if same cell, same text, increment counter by 1
if (this._old_cell == cell && this._old_request == text && this._hidden == false) {
if (this._old_cell == cell && this._old_request == text && this._hidden === false) {
this._consecutive_counter++;
} else {
// else reset
@ -273,7 +277,7 @@ var IPython = (function (IPython) {
}
return;
}
};
// cancel the option of having the tooltip to stick
Tooltip.prototype.cancel_stick = function () {
@ -281,14 +285,14 @@ var IPython = (function (IPython) {
this._stick_timeout = null;
this._clocklink.hide('slow');
this._sticky = false;
}
};
// put the tooltip in a sicky state for 10 seconds
// it won't be removed by remove_and_cancell() unless you called with
// the first parameter set to true.
// remove_and_cancell_tooltip(true)
Tooltip.prototype.stick = function (time) {
time = (time != undefined) ? time : 10;
time = (time !== undefined) ? time : 10;
var that = this;
this._sticky = true;
this._clocklink.show('slow');
@ -296,7 +300,7 @@ var IPython = (function (IPython) {
that._sticky = false;
that._clocklink.hide('slow');
}, time * 1000);
}
};
// should be called with the kernel reply to actually show the tooltip
Tooltip.prototype._show = function (reply) {
@ -322,7 +326,7 @@ var IPython = (function (IPython) {
var xinter = o.left + (xinit - o.left) / w * (w - 450);
var posarrowleft = xinit - xinter;
if (this._hidden == false) {
if (this._hidden === false) {
this.tooltip.animate({
'left': xinter - 30 + 'px',
'top': (head.bottom + 10) + 'px'
@ -365,8 +369,8 @@ var IPython = (function (IPython) {
}
}
this.tooltip.fadeIn('fast');
this._hidden = false;
this.tooltip.fadeIn('fast');
this.text.children().remove();
var pre = $('<pre/>').html(utils.fixConsole(docstring));
@ -377,8 +381,7 @@ var IPython = (function (IPython) {
this.text.append(pre);
// keep scroll top to be sure to always see the first line
this.text.scrollTop(0);
}
};
IPython.Tooltip = Tooltip;

Loading…
Cancel
Save