Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modal UI #3605

Merged
merged 57 commits into from
Jan 11, 2014
Merged
Show file tree
Hide file tree
Changes from 52 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
7d0f415
Starting work on select/focus logic.
ellisonbg Jun 30, 2013
a11c3df
Adding new logic to cells.
ellisonbg Jul 3, 2013
2dd3d63
More work on the dual mode UX.
ellisonbg Jul 8, 2013
b2c174f
Semi working version of basic dual mode UX.
ellisonbg Jul 11, 2013
0e882fd
Don't bind notebook keyboard events to $(document).
ellisonbg Jul 20, 2013
fef08d9
Binding to notebook div not document.
ellisonbg Sep 26, 2013
b0aa243
Removing manual focusing of notebook div.
ellisonbg Oct 24, 2013
9ba9496
Adding keyboard manager logic.
ellisonbg Dec 5, 2013
acac37b
Lots of updates and changes.
ellisonbg Dec 6, 2013
acf3710
Code comments and minor fixes.
ellisonbg Dec 6, 2013
0135ad2
Removing KBN null mode and replacing with enable/disable.
ellisonbg Dec 6, 2013
7fc210d
Adding missing enable/disable methods.
ellisonbg Dec 6, 2013
1283ebb
Moving a cell focuses it after the move.
ellisonbg Dec 7, 2013
b51276b
Split cell keyboard shortcut wired up. Merge markdown adds 2nd \n.
ellisonbg Dec 7, 2013
71eb69b
Add + for merge cell below and carefully manage split cell state.
ellisonbg Dec 7, 2013
ef87614
Carefully manage rendered state in merge cell.
ellisonbg Dec 7, 2013
e25c9e4
Fixing select when inserting cell using menu.
ellisonbg Dec 7, 2013
619528c
Fixing bug in KeyboardManager.enable/disable.
ellisonbg Dec 7, 2013
d5e4ce5
Changing a heading cell level should enter edit mode and set dirty
ellisonbg Dec 7, 2013
0f4213e
Fixing delete/undelete logic.
ellisonbg Dec 7, 2013
aeffe3b
Using a more specific approach for managing CM focus.
ellisonbg Dec 8, 2013
6481cb5
Delete cell only if you press "d" twice in 1 second.
ellisonbg Dec 8, 2013
89eac9e
HTML and JavaScript output KBM event handling.
ellisonbg Dec 10, 2013
d6a3ec7
Like, OMG, keyboardmanager.js is a beast.
ellisonbg Dec 10, 2013
c4fda88
Fixing bugs and adding automatic KB shortcut help.
ellisonbg Dec 10, 2013
9d44616
Adding j/k for select next/prev. Faster than up/down.
ellisonbg Dec 10, 2013
bfc1794
Updating help string for ctrl-enter and alt-enter.
ellisonbg Dec 13, 2013
c2b3a2b
Pressing d twice now deletes cell on first try.
ellisonbg Jan 7, 2014
e228b93
Fix raw_input.
ellisonbg Jan 7, 2014
20c436e
shift-enter should doesn't create a new cell at the bottom.
ellisonbg Jan 7, 2014
5233b21
Fixing css class on cell related to selected, rendered, mode.
ellisonbg Jan 8, 2014
bdb4c53
Ongoing work on cell splitting.
ellisonbg Jan 8, 2014
cc09699
TextCell.unrender should not focus CM/select.
ellisonbg Jan 8, 2014
ad1a6ed
Cleanup of cell splitting.
ellisonbg Jan 8, 2014
f1ffb2b
Cell splitting merging works with RawCell now.
ellisonbg Jan 8, 2014
0d3e611
Special handling for CM's vim keyboard mapping.
ellisonbg Jan 8, 2014
0202e66
Adding back doc in Keyboard Shortcut.
ellisonbg Jan 8, 2014
54b48d9
Don't always call focus_cell in Cell.command_mode.
ellisonbg Jan 9, 2014
627a797
select next cell in insert cell below in menubar to match kb.
ellisonbg Jan 9, 2014
538a39b
Focus cells after they are inserted.
ellisonbg Jan 9, 2014
33dd5d6
Fixing a few keyboard codes and shortcuts.
ellisonbg Jan 9, 2014
ab3a1dd
Adding missig altKey test to CodeCell.
ellisonbg Jan 9, 2014
9448c01
Removing old method on RawCell - just use the base class.
ellisonbg Jan 9, 2014
dd345f4
Fixing JS tests.
ellisonbg Jan 9, 2014
ff51227
Fixing more JS tests.
ellisonbg Jan 9, 2014
b696039
Renaming execute methods.
ellisonbg Jan 9, 2014
6996d42
Reordering conditional.
ellisonbg Jan 9, 2014
3088dda
Fixing delete_count logic.
ellisonbg Jan 9, 2014
a8751bb
Cleaning up console log messages.
ellisonbg Jan 9, 2014
dca69cb
canonicalize -> normalize in keyboard manager.
ellisonbg Jan 9, 2014
5b066a2
Semicolon cleanup.
ellisonbg Jan 9, 2014
2259a24
Adding sorting and better layout to the KB shortcuts.
ellisonbg Jan 10, 2014
3be8af8
Fixing design of quickhelp.
ellisonbg Jan 10, 2014
6573c62
Adding basic examples notebook about modal editing.
ellisonbg Jan 10, 2014
ab7fc46
Fixing links and text of User Experience notebook.
ellisonbg Jan 10, 2014
66589e1
Minor changes to KB handling.
ellisonbg Jan 10, 2014
a6562f1
Work on shortcuts and examples notebook.
ellisonbg Jan 10, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 11 additions & 7 deletions IPython/html/static/base/js/dialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,17 @@ IPython.dialog = (function (IPython) {
dialog.remove();
});
}
if (options.reselect_cell !== false) {
dialog.on("hidden", function () {
if (IPython.notebook) {
var cell = IPython.notebook.get_selected_cell();
if (cell) cell.select();
}
});
dialog.on("hidden", function () {
if (IPython.notebook) {
var cell = IPython.notebook.get_selected_cell();
if (cell) cell.select();
IPython.keyboard_manager.enable();
IPython.keyboard_manager.command_mode();
}
});

if (IPython.keyboard_manager) {
IPython.keyboard_manager.disable();
}

return dialog.modal(options);
Expand Down
24 changes: 23 additions & 1 deletion IPython/html/static/base/js/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,26 @@ IPython.utils = (function (IPython) {
return M;
})();

var is_or_has = function (a, b) {
// Is b a child of a or a itself?
return a.has(b).length !==0 || a.is(b);
}

var is_focused = function (e) {
// Is element e, or one of its children focused?
e = $(e);
var target = $(document.activeElement);
if (target.length > 0) {
if (is_or_has(e, target)) {
return true;
} else {
return false;
}
} else {
return false;
}
}


return {
regex_split : regex_split,
Expand All @@ -475,7 +495,9 @@ IPython.utils = (function (IPython) {
encode_uri_components : encode_uri_components,
splitext : splitext,
always_new : always_new,
browser : browser
browser : browser,
is_or_has : is_or_has,
is_focused : is_focused
};

}(IPython));
Expand Down
176 changes: 149 additions & 27 deletions IPython/html/static/notebook/js/cell.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ var IPython = (function (IPython) {
this.placeholder = options.placeholder || '';
this.read_only = options.cm_config.readOnly;
this.selected = false;
this.rendered = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see indentation with tabs here while trying to resolve conflict to test the branch.

this.mode = 'command';
this.metadata = {};
// load this from metadata later ?
this.user_highlight = 'auto';
Expand All @@ -60,6 +62,7 @@ var IPython = (function (IPython) {
if (this.element !== null) {
this.element.data("cell", this);
this.bind_events();
this.init_classes();
}
};

Expand Down Expand Up @@ -97,6 +100,26 @@ var IPython = (function (IPython) {
Cell.prototype.create_element = function () {
};

Cell.prototype.init_classes = function () {
// Call after this.element exists to initialize the css classes
// related to selected, rendered and mode.
if (this.selected) {
this.element.addClass('selected');
} else {
this.element.addClass('unselected');
}
if (this.rendered) {
this.element.addClass('rendered');
} else {
this.element.addClass('unrendered');
}
if (this.mode === 'edit') {
this.element.addClass('edit_mode');
} else {
this.element.addClass('command_mode');
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

semicolon



/**
* Subclasses can implement override bind_events.
Expand All @@ -108,67 +131,167 @@ var IPython = (function (IPython) {
var that = this;
// We trigger events so that Cell doesn't have to depend on Notebook.
that.element.click(function (event) {
if (that.selected === false) {
if (!that.selected) {
$([IPython.events]).trigger('select.Cell', {'cell':that});
}
};
});
that.element.focusin(function (event) {
if (that.selected === false) {
if (!that.selected) {
$([IPython.events]).trigger('select.Cell', {'cell':that});
}
};
});
if (this.code_mirror) {
this.code_mirror.on("change", function(cm, change) {
$([IPython.events]).trigger("set_dirty.Notebook", {value: true});
});
}
if (this.code_mirror) {
this.code_mirror.on('focus', function(cm, change) {
$([IPython.events]).trigger('edit_mode.Cell', {cell: that});
});
}
if (this.code_mirror) {
this.code_mirror.on('blur', function(cm, change) {
if (that.mode === 'edit') {
setTimeout(function () {
var isf = IPython.utils.is_focused;
var trigger = true;
if (isf('div#tooltip') || isf('div.completions')) {
trigger = false;
}
if (trigger) {
$([IPython.events]).trigger('command_mode.Cell', {cell: that});
}
}, 1);
}
});
}
};

/**
* Triger typsetting of math by mathjax on current cell element
* @method typeset
*/
Cell.prototype.typeset = function () {
if (window.MathJax){
if (window.MathJax) {
var cell_math = this.element.get(0);
MathJax.Hub.Queue(["Typeset", MathJax.Hub, cell_math]);
}
};

/**
* should be triggerd when cell is selected
* handle cell level logic when a cell is selected
* @method select
* @return is the action being taken
*/
Cell.prototype.select = function () {
this.element.addClass('selected');
this.selected = true;
if (!this.selected) {
this.element.addClass('selected');
this.element.removeClass('unselected');
this.selected = true;
return true;
} else {
return false;
}
};


/**
* should be triggerd when cell is unselected
* handle cell level logic when a cell is unselected
* @method unselect
* @return is the action being taken
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this statement.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you actually have "@return is the action being taken" in lots of places.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's like an event handler, return true if an action is taken, false if nothing happend

*/
Cell.prototype.unselect = function () {
this.element.removeClass('selected');
this.selected = false;
if (this.selected) {
this.element.addClass('unselected');
this.element.removeClass('selected');
this.selected = false;
return true;
} else {
return false;
}
};

/**
* should be overritten by subclass
* @method get_text
* handle cell level logic when a cell is rendered
* @method render
* @return is the action being taken
*/
Cell.prototype.get_text = function () {
Cell.prototype.render = function () {
if (!this.rendered) {
this.element.addClass('rendered');
this.element.removeClass('unrendered');
this.rendered = true;
return true;
} else {
return false;
}
};

/**
* should be overritten by subclass
* @method set_text
* @param {string} text
* handle cell level logic when a cell is unrendered
* @method unrender
* @return is the action being taken
*/
Cell.prototype.set_text = function (text) {
Cell.prototype.unrender = function () {
if (this.rendered) {
this.element.addClass('unrendered');
this.element.removeClass('rendered');
this.rendered = false;
return true;
} else {
return false;
}
};

/**
* enter the command mode for the cell
* @method command_mode
* @return is the action being taken
*/
Cell.prototype.command_mode = function () {
if (this.mode !== 'command') {
this.element.addClass('command_mode');
this.element.removeClass('edit_mode');
this.mode = 'command';
return true;
} else {
return false;
}
};

/**
* enter the edit mode for the cell
* @method command_mode
* @return is the action being taken
*/
Cell.prototype.edit_mode = function () {
if (this.mode !== 'edit') {
this.element.addClass('edit_mode');
this.element.removeClass('command_mode');
this.mode = 'edit';
return true;
} else {
return false;
}
}

/**
* Focus the cell in the DOM sense
* @method focus_cell
*/
Cell.prototype.focus_cell = function () {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why the _cell sufix ? mycodecell.focus() seem more natural to me than myceodecell.focus_cell() because I know it is a cell.

this.element.focus();
}

/**
* Focus the editor area so a user can type
* @method focus_editor
*/
Cell.prototype.focus_editor = function () {
this.refresh();
this.code_mirror.focus();
}

/**
* Refresh codemirror instance
* @method refresh
Expand All @@ -177,20 +300,19 @@ var IPython = (function (IPython) {
this.code_mirror.refresh();
};


/**
* should be overritten by subclass
* @method edit
**/
Cell.prototype.edit = function () {
* @method get_text
*/
Cell.prototype.get_text = function () {
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty method., but I guess you know that.



/**
* should be overritten by subclass
* @method render
**/
Cell.prototype.render = function () {
* @method set_text
* @param {string} text
*/
Cell.prototype.set_text = function (text) {
};

/**
Expand Down