mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 22:08:20 +01:00
MDL-44067 Atto: Improve table editing controls.
Remove flaky inline menu icons - instead clicking on the table button, when you are in a table shows the context menu for the current cell. I removed all the special code for 'atto_control' - because it did not work very well. Having non-contenteditable nodes inside a contenteditable region seems in expose bugs in different browsers.
This commit is contained in:
parent
5ec54dd125
commit
05843fd3ee
@ -137,7 +137,7 @@ M.atto_table = M.atto_table || {
|
||||
});
|
||||
}
|
||||
// We store the cell of the last click (the control node is transient).
|
||||
this.lasttarget = e.target.ancestor('td, th');
|
||||
this.lasttarget = e.target.ancestor('.editor_atto_content td, .editor_atto_content th', true);
|
||||
this.controlmenu.show();
|
||||
this.controlmenu.align(e.target, [Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.BL]);
|
||||
var bodynode = this.controlmenu.get('boundingBox');
|
||||
@ -417,6 +417,36 @@ M.atto_table = M.atto_table || {
|
||||
M.editor_atto.text_updated(elementid);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle a button click - this will either open the new table dialogue,
|
||||
* or the edit table context menu.
|
||||
*
|
||||
* @method handle_button
|
||||
* @param Y.Event event
|
||||
* @param string elementid
|
||||
*/
|
||||
handle_button : function(event, elementid) {
|
||||
var selection = M.editor_atto.get_selection_parent_node();
|
||||
var editable = M.editor_atto.get_editable_node(elementid);
|
||||
var cell;
|
||||
|
||||
if (!selection) {
|
||||
return M.atto_table.display_chooser(event, elementid);
|
||||
}
|
||||
Y.one(selection).ancestors('th, td', true).each(function(node) {
|
||||
if (editable.contains(node)) {
|
||||
cell = node;
|
||||
}
|
||||
});
|
||||
|
||||
if (cell) {
|
||||
event.target = cell;
|
||||
return M.atto_table.show_menu(event, elementid);
|
||||
}
|
||||
return M.atto_table.display_chooser(event, elementid);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Handle a selection from the table control menu.
|
||||
*
|
||||
@ -481,45 +511,14 @@ M.atto_table = M.atto_table || {
|
||||
}
|
||||
|
||||
var iconurl = M.util.image_url('e/table', 'core');
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'table', iconurl, params.group, this.display_chooser);
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'table', iconurl, params.group, this.handle_button);
|
||||
|
||||
var contenteditable = M.editor_atto.get_editable_node(params.elementid);
|
||||
contenteditable.delegate('click', this.show_menu, 'td > .atto_control, th > .atto_control', this, params.elementid);
|
||||
contenteditable.delegate('key', this.show_menu, 'down:enter,space', 'td > .atto_control, th > .atto_control', this, params.elementid);
|
||||
// Disable mozilla table controls.
|
||||
if (Y.UA.gecko) {
|
||||
document.execCommand("enableInlineTableEditing", false, "false");
|
||||
document.execCommand("enableInlineTableEditing", false, false);
|
||||
document.execCommand("enableObjectResizing", false, false);
|
||||
}
|
||||
|
||||
this.insert_table_controls(params.elementid);
|
||||
|
||||
// Re-add the table controls whenever the content is updated.
|
||||
M.editor_atto.add_text_updated_handler(params.elementid, this.insert_table_controls);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the table editing controls to the content area.
|
||||
*
|
||||
* @method insert_table_controls
|
||||
* @param String elementid - The id of the text area backed by the content editable field.
|
||||
*/
|
||||
insert_table_controls : function(elementid) {
|
||||
var contenteditable = M.editor_atto.get_editable_node(elementid),
|
||||
allcells = contenteditable.all('td .atto_control,th .atto_control'),
|
||||
cells = contenteditable.all('td:last-child,th:last-child,tbody tr:last-child > td, tbody tr:last-child > th');
|
||||
|
||||
allcells.each(function(node) {
|
||||
if (cells.indexOf(node) === -1) {
|
||||
node.remove(true);
|
||||
}
|
||||
});
|
||||
|
||||
cells.each(function(node) {
|
||||
if (!node.one('.atto_control')) {
|
||||
node.append(M.atto_table.menunode.cloneNode(true));
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
|
File diff suppressed because one or more lines are too long
@ -137,7 +137,7 @@ M.atto_table = M.atto_table || {
|
||||
});
|
||||
}
|
||||
// We store the cell of the last click (the control node is transient).
|
||||
this.lasttarget = e.target.ancestor('td, th');
|
||||
this.lasttarget = e.target.ancestor('.editor_atto_content td, .editor_atto_content th', true);
|
||||
this.controlmenu.show();
|
||||
this.controlmenu.align(e.target, [Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.BL]);
|
||||
var bodynode = this.controlmenu.get('boundingBox');
|
||||
@ -417,6 +417,36 @@ M.atto_table = M.atto_table || {
|
||||
M.editor_atto.text_updated(elementid);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle a button click - this will either open the new table dialogue,
|
||||
* or the edit table context menu.
|
||||
*
|
||||
* @method handle_button
|
||||
* @param Y.Event event
|
||||
* @param string elementid
|
||||
*/
|
||||
handle_button : function(event, elementid) {
|
||||
var selection = M.editor_atto.get_selection_parent_node();
|
||||
var editable = M.editor_atto.get_editable_node(elementid);
|
||||
var cell;
|
||||
|
||||
if (!selection) {
|
||||
return M.atto_table.display_chooser(event, elementid);
|
||||
}
|
||||
Y.one(selection).ancestors('th, td', true).each(function(node) {
|
||||
if (editable.contains(node)) {
|
||||
cell = node;
|
||||
}
|
||||
});
|
||||
|
||||
if (cell) {
|
||||
event.target = cell;
|
||||
return M.atto_table.show_menu(event, elementid);
|
||||
}
|
||||
return M.atto_table.display_chooser(event, elementid);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Handle a selection from the table control menu.
|
||||
*
|
||||
@ -481,45 +511,14 @@ M.atto_table = M.atto_table || {
|
||||
}
|
||||
|
||||
var iconurl = M.util.image_url('e/table', 'core');
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'table', iconurl, params.group, this.display_chooser);
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'table', iconurl, params.group, this.handle_button);
|
||||
|
||||
var contenteditable = M.editor_atto.get_editable_node(params.elementid);
|
||||
contenteditable.delegate('click', this.show_menu, 'td > .atto_control, th > .atto_control', this, params.elementid);
|
||||
contenteditable.delegate('key', this.show_menu, 'down:enter,space', 'td > .atto_control, th > .atto_control', this, params.elementid);
|
||||
// Disable mozilla table controls.
|
||||
if (Y.UA.gecko) {
|
||||
document.execCommand("enableInlineTableEditing", false, "false");
|
||||
document.execCommand("enableInlineTableEditing", false, false);
|
||||
document.execCommand("enableObjectResizing", false, false);
|
||||
}
|
||||
|
||||
this.insert_table_controls(params.elementid);
|
||||
|
||||
// Re-add the table controls whenever the content is updated.
|
||||
M.editor_atto.add_text_updated_handler(params.elementid, this.insert_table_controls);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the table editing controls to the content area.
|
||||
*
|
||||
* @method insert_table_controls
|
||||
* @param String elementid - The id of the text area backed by the content editable field.
|
||||
*/
|
||||
insert_table_controls : function(elementid) {
|
||||
var contenteditable = M.editor_atto.get_editable_node(elementid),
|
||||
allcells = contenteditable.all('td .atto_control,th .atto_control'),
|
||||
cells = contenteditable.all('td:last-child,th:last-child,tbody tr:last-child > td, tbody tr:last-child > th');
|
||||
|
||||
allcells.each(function(node) {
|
||||
if (cells.indexOf(node) === -1) {
|
||||
node.remove(true);
|
||||
}
|
||||
});
|
||||
|
||||
cells.each(function(node) {
|
||||
if (!node.one('.atto_control')) {
|
||||
node.append(M.atto_table.menunode.cloneNode(true));
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -135,7 +135,7 @@ M.atto_table = M.atto_table || {
|
||||
});
|
||||
}
|
||||
// We store the cell of the last click (the control node is transient).
|
||||
this.lasttarget = e.target.ancestor('td, th');
|
||||
this.lasttarget = e.target.ancestor('.editor_atto_content td, .editor_atto_content th', true);
|
||||
this.controlmenu.show();
|
||||
this.controlmenu.align(e.target, [Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.BL]);
|
||||
var bodynode = this.controlmenu.get('boundingBox');
|
||||
@ -415,6 +415,36 @@ M.atto_table = M.atto_table || {
|
||||
M.editor_atto.text_updated(elementid);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle a button click - this will either open the new table dialogue,
|
||||
* or the edit table context menu.
|
||||
*
|
||||
* @method handle_button
|
||||
* @param Y.Event event
|
||||
* @param string elementid
|
||||
*/
|
||||
handle_button : function(event, elementid) {
|
||||
var selection = M.editor_atto.get_selection_parent_node();
|
||||
var editable = M.editor_atto.get_editable_node(elementid);
|
||||
var cell;
|
||||
|
||||
if (!selection) {
|
||||
return M.atto_table.display_chooser(event, elementid);
|
||||
}
|
||||
Y.one(selection).ancestors('th, td', true).each(function(node) {
|
||||
if (editable.contains(node)) {
|
||||
cell = node;
|
||||
}
|
||||
});
|
||||
|
||||
if (cell) {
|
||||
event.target = cell;
|
||||
return M.atto_table.show_menu(event, elementid);
|
||||
}
|
||||
return M.atto_table.display_chooser(event, elementid);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Handle a selection from the table control menu.
|
||||
*
|
||||
@ -479,45 +509,14 @@ M.atto_table = M.atto_table || {
|
||||
}
|
||||
|
||||
var iconurl = M.util.image_url('e/table', 'core');
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'table', iconurl, params.group, this.display_chooser);
|
||||
M.editor_atto.add_toolbar_button(params.elementid, 'table', iconurl, params.group, this.handle_button);
|
||||
|
||||
var contenteditable = M.editor_atto.get_editable_node(params.elementid);
|
||||
contenteditable.delegate('click', this.show_menu, 'td > .atto_control, th > .atto_control', this, params.elementid);
|
||||
contenteditable.delegate('key', this.show_menu, 'down:enter,space', 'td > .atto_control, th > .atto_control', this, params.elementid);
|
||||
// Disable mozilla table controls.
|
||||
if (Y.UA.gecko) {
|
||||
document.execCommand("enableInlineTableEditing", false, "false");
|
||||
document.execCommand("enableInlineTableEditing", false, false);
|
||||
document.execCommand("enableObjectResizing", false, false);
|
||||
}
|
||||
|
||||
this.insert_table_controls(params.elementid);
|
||||
|
||||
// Re-add the table controls whenever the content is updated.
|
||||
M.editor_atto.add_text_updated_handler(params.elementid, this.insert_table_controls);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the table editing controls to the content area.
|
||||
*
|
||||
* @method insert_table_controls
|
||||
* @param String elementid - The id of the text area backed by the content editable field.
|
||||
*/
|
||||
insert_table_controls : function(elementid) {
|
||||
var contenteditable = M.editor_atto.get_editable_node(elementid),
|
||||
allcells = contenteditable.all('td .atto_control,th .atto_control'),
|
||||
cells = contenteditable.all('td:last-child,th:last-child,tbody tr:last-child > td, tbody tr:last-child > th');
|
||||
|
||||
allcells.each(function(node) {
|
||||
if (cells.indexOf(node) === -1) {
|
||||
node.remove(true);
|
||||
}
|
||||
});
|
||||
|
||||
cells.each(function(node) {
|
||||
if (!node.one('.atto_control')) {
|
||||
node.append(M.atto_table.menunode.cloneNode(true));
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -90,7 +90,7 @@ M.editor_atto = M.editor_atto || {
|
||||
buttonhandlers : {},
|
||||
|
||||
/**
|
||||
* List of attached handlers to add inline editing controls to content.
|
||||
* List of attached handlers.
|
||||
*/
|
||||
textupdatedhandlers : {},
|
||||
|
||||
@ -288,7 +288,6 @@ M.editor_atto = M.editor_atto || {
|
||||
|
||||
/**
|
||||
* Add a content update handler to be called whenever the content is updated.
|
||||
* This is used to add inline editing controls to the content that are cleaned on submission.
|
||||
*
|
||||
* @param string elementid - the id of the textarea we created this editor from.
|
||||
* @handler function callback - The function to do the cleaning.
|
||||
@ -659,10 +658,6 @@ M.editor_atto = M.editor_atto || {
|
||||
}
|
||||
});
|
||||
|
||||
Y.each(atto.all('.atto_control'), function(node) {
|
||||
node.remove(true);
|
||||
});
|
||||
|
||||
// Remove any and all nasties from source.
|
||||
atto.cleanHTML();
|
||||
|
||||
@ -1012,6 +1007,8 @@ CONTROLMENU = function(config) {
|
||||
config.width = 'auto';
|
||||
config.lightbox = false;
|
||||
config.footerContent = '';
|
||||
config.hideOn = [ { eventName: 'clickoutside' } ];
|
||||
|
||||
CONTROLMENU.superclass.constructor.apply(this, [config]);
|
||||
};
|
||||
|
||||
@ -1037,16 +1034,6 @@ Y.extend(CONTROLMENU, M.core.dialogue, {
|
||||
headertext.addClass('accesshide');
|
||||
headertext.setHTML(this.get('headerText'));
|
||||
body.prepend(headertext);
|
||||
|
||||
body.on('clickoutside', function(e) {
|
||||
if (this.get('visible')) {
|
||||
// Note: we need to compare ids because for some reason - sometimes button is an Object, not a Y.Node.
|
||||
if (!e.target.ancestor('.atto_control')) {
|
||||
e.preventDefault();
|
||||
this.hide();
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
|
||||
}, {
|
||||
|
File diff suppressed because one or more lines are too long
@ -90,7 +90,7 @@ M.editor_atto = M.editor_atto || {
|
||||
buttonhandlers : {},
|
||||
|
||||
/**
|
||||
* List of attached handlers to add inline editing controls to content.
|
||||
* List of attached handlers.
|
||||
*/
|
||||
textupdatedhandlers : {},
|
||||
|
||||
@ -288,7 +288,6 @@ M.editor_atto = M.editor_atto || {
|
||||
|
||||
/**
|
||||
* Add a content update handler to be called whenever the content is updated.
|
||||
* This is used to add inline editing controls to the content that are cleaned on submission.
|
||||
*
|
||||
* @param string elementid - the id of the textarea we created this editor from.
|
||||
* @handler function callback - The function to do the cleaning.
|
||||
@ -659,10 +658,6 @@ M.editor_atto = M.editor_atto || {
|
||||
}
|
||||
});
|
||||
|
||||
Y.each(atto.all('.atto_control'), function(node) {
|
||||
node.remove(true);
|
||||
});
|
||||
|
||||
// Remove any and all nasties from source.
|
||||
atto.cleanHTML();
|
||||
|
||||
@ -1012,6 +1007,8 @@ CONTROLMENU = function(config) {
|
||||
config.width = 'auto';
|
||||
config.lightbox = false;
|
||||
config.footerContent = '';
|
||||
config.hideOn = [ { eventName: 'clickoutside' } ];
|
||||
|
||||
CONTROLMENU.superclass.constructor.apply(this, [config]);
|
||||
};
|
||||
|
||||
@ -1037,16 +1034,6 @@ Y.extend(CONTROLMENU, M.core.dialogue, {
|
||||
headertext.addClass('accesshide');
|
||||
headertext.setHTML(this.get('headerText'));
|
||||
body.prepend(headertext);
|
||||
|
||||
body.on('clickoutside', function(e) {
|
||||
if (this.get('visible')) {
|
||||
// Note: we need to compare ids because for some reason - sometimes button is an Object, not a Y.Node.
|
||||
if (!e.target.ancestor('.atto_control')) {
|
||||
e.preventDefault();
|
||||
this.hide();
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
|
||||
}, {
|
||||
|
12
lib/editor/atto/yui/src/editor/js/controlmenu.js
vendored
12
lib/editor/atto/yui/src/editor/js/controlmenu.js
vendored
@ -16,6 +16,8 @@ CONTROLMENU = function(config) {
|
||||
config.width = 'auto';
|
||||
config.lightbox = false;
|
||||
config.footerContent = '';
|
||||
config.hideOn = [ { eventName: 'clickoutside' } ];
|
||||
|
||||
CONTROLMENU.superclass.constructor.apply(this, [config]);
|
||||
};
|
||||
|
||||
@ -41,16 +43,6 @@ Y.extend(CONTROLMENU, M.core.dialogue, {
|
||||
headertext.addClass('accesshide');
|
||||
headertext.setHTML(this.get('headerText'));
|
||||
body.prepend(headertext);
|
||||
|
||||
body.on('clickoutside', function(e) {
|
||||
if (this.get('visible')) {
|
||||
// Note: we need to compare ids because for some reason - sometimes button is an Object, not a Y.Node.
|
||||
if (!e.target.ancestor('.atto_control')) {
|
||||
e.preventDefault();
|
||||
this.hide();
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
|
||||
}, {
|
||||
|
7
lib/editor/atto/yui/src/editor/js/editor.js
vendored
7
lib/editor/atto/yui/src/editor/js/editor.js
vendored
@ -88,7 +88,7 @@ M.editor_atto = M.editor_atto || {
|
||||
buttonhandlers : {},
|
||||
|
||||
/**
|
||||
* List of attached handlers to add inline editing controls to content.
|
||||
* List of attached handlers.
|
||||
*/
|
||||
textupdatedhandlers : {},
|
||||
|
||||
@ -286,7 +286,6 @@ M.editor_atto = M.editor_atto || {
|
||||
|
||||
/**
|
||||
* Add a content update handler to be called whenever the content is updated.
|
||||
* This is used to add inline editing controls to the content that are cleaned on submission.
|
||||
*
|
||||
* @param string elementid - the id of the textarea we created this editor from.
|
||||
* @handler function callback - The function to do the cleaning.
|
||||
@ -657,10 +656,6 @@ M.editor_atto = M.editor_atto || {
|
||||
}
|
||||
});
|
||||
|
||||
Y.each(atto.all('.atto_control'), function(node) {
|
||||
node.remove(true);
|
||||
});
|
||||
|
||||
// Remove any and all nasties from source.
|
||||
atto.cleanHTML();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user