1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-08-17 14:37:58 +00:00
seahub/media/aloha-0.22.7/plugins/common/table/lib/table-cell.js
llj 720ac28c22 [aloha] upgraded to 0.22.7 and added textcolor plugin
* textcolor: fixed plugin bugs, added translation for zh
* image: fixed default.jpg src bug
* added 'ru' support for seaf edit
* rm aloha-0.22.3 and ununsed files in aloha-0.22.7
2013-01-15 14:48:04 +08:00

536 lines
14 KiB
JavaScript

define(
['jquery', 'table/table-plugin-utils'],
function (jQuery, Utils) {
/**
* Constructs a TableCell.
*
* @param {DomNode} cell
* A td/th which will be represente by this TableCell.
* @param {Table} tableObj
* The Table which contains the cell. The cell will be
* activated/dactivated with the table.
*/
var TableCell = function (originalTd, tableObj) {
if (null == originalTd) {
originalTd = '<td>&nbsp;</td>';
}
//original Td must be a DOM node so that the this.obj.context property is available
//this transformation will properly handle jQuery objects as well as DOM nodes
originalTd = jQuery(originalTd).get(0);
this.obj = jQuery(originalTd);
this.tableObj = tableObj;
tableObj.cells.push(this);
};
/**
* Reference to the jQuery-representation of the wrapping table
*
* @see TableCell.table
*/
TableCell.prototype.tableObj = undefined;
/**
* Reference to the jQuery td-Object of the cell
*/
TableCell.prototype.obj = undefined;
/**
* The jQuery wrapper of the cell
*/
TableCell.prototype.wrapper = undefined;
/**
* Flag if the cell has focus
*/
TableCell.prototype.hasFocus = false;
TableCell.prototype.activate = function () {
var cell = this;
var $elem = cell.obj;
// wrap the created div into the contents of the cell
$elem.wrapInner('<div/>');
// create the editable wrapper for the cells
var $wrapper = $elem.children('div').eq(0);
$wrapper.contentEditable(true);
$wrapper.addClass('aloha-table-cell-editable');
// attach events to the editable div-object
$wrapper.bind('focus', function ($event) {
// ugly workaround for ext-js-adapter problem in
// ext-jquery-adapter-debug.js:1020
if ($event.currentTarget) {
$event.currentTarget.indexOf = function () {
return -1;
};
}
cell._editableFocus($event);
});
$wrapper.bind('mousedown', function ($event) {
// ugly workaround for ext-js-adapter problem in ext-jquery-adapter-debug.js:1020
if ($event.currentTarget) {
$event.currentTarget.indexOf = function () {
return -1;
};
}
cell._editableMouseDown($event);
cell.tableObj.selection.baseCellPosition = [cell._virtualY(), cell._virtualX()];
if ($event.shiftKey) {
// shift-click to select a coherent cell range
//
// in IE it's not possible to select multiple cells when you "select+drag" over other cells
// click into the first cell and then "shift-click" into the last cell of the coherent cell range you want to select
var right = cell.tableObj.selection.lastBaseCellPosition[1];
var bottom = cell.tableObj.selection.lastBaseCellPosition[0];
var topLeft = cell.tableObj.selection.baseCellPosition;
var left = topLeft[1];
if (left > right) {
left = right;
right = topLeft[1];
}
var top = topLeft[0];
if (top > bottom) {
top = bottom;
bottom = topLeft[0];
}
var rect = {
"top": top,
"right": right,
"bottom": bottom,
"left": left
};
var table = cell.tableObj;
var $rows = table.obj.children().children('tr');
var grid = Utils.makeGrid($rows);
table.selection.selectedCells = [];
var selectClass = table.get('classCellSelected');
Utils.walkGrid(grid, function (cellInfo, j, i) {
if (Utils.containsDomCell(cellInfo)) {
if (i >= rect.top && i <= rect.bottom && j >= rect.left && j <= rect.right) {
jQuery(cellInfo.cell).addClass(selectClass);
table.selection.selectedCells.push(cellInfo.cell);
} else {
jQuery(cellInfo.cell).removeClass(selectClass);
}
}
});
table.selection.notifyCellsSelected();
} else {
cell.tableObj.selection.lastBaseCellPosition = cell.tableObj.selection.baseCellPosition;
cell._editableMouseDown($event);
cell._startCellSelection();
}
});
$wrapper.bind('blur', function ($event) {
cell._editableBlur($event);
});
$wrapper.bind('keyup', function ($event) {
cell._editableKeyUp($event);
});
$wrapper.bind('keydown', function ($event) {
cell._editableKeyDown($event);
});
$wrapper.bind('mouseover', function ($event) {
cell._selectCellRange();
});
// we will treat the wrapper just like an editable
$wrapper.contentEditableSelectionChange(function ($event) {
Aloha.Selection.onChange($wrapper, $event);
return $wrapper;
});
$elem.bind('mousedown', function ($event) {
window.setTimeout(function () {
// Select the entire cell's content.
cell.wrapper.trigger('focus');
cell._selectAll($wrapper);
}, 1);
if (!$event.shiftKey) {
cell.tableObj.selection.unselectCells();
cell._startCellSelection();
}
$event.stopPropagation();
});
if ($elem.get(0)) {
$elem.get(0).onselectstart = function () {
return false;
};
}
// set contenteditable wrapper div
this.wrapper = $elem.children();
if (this.wrapper.get(0)) {
this.wrapper.get(0).onselectstart = function () {
window.event.cancelBubble = true;
};
// Disabled the dragging of content, since it makes cell selection
// difficult.
this.wrapper.get(0).ondragstart = function () {
return false
};
}
return this;
};
/**
* The deactivate method removes the contenteditable helper div within the
* table-data field and wraps the innerHtml to the outerHTML
*
* @return void
*/
TableCell.prototype.deactivate = function () {
var wrapper = jQuery(this.obj.children('.aloha-table-cell-editable'));
if (wrapper.length) {
// unwrap cell contents without re-creating dom nodes
wrapper.parent().append(
wrapper.contents()
);
// remove the contenteditable div and its attached events
wrapper.remove();
// remove the click event of the
this.obj.unbind('click');
this.obj.unbind('mousedown');
if (jQuery.trim(this.obj.attr('class')) == '') {
this.obj.removeAttr('class');
}
}
}
/**
* Native toString-method
*
* @return string name of the namespace
*/
TableCell.prototype.toString = function () {
return 'TableCell';
};
/**
* Focus method for the contentediable div within a table data-field. The method
* requires the event-property Cell as a Cell object. If the
* Cell wasn't activated yet it does all relevant actions to activate the cell.
*
* @param e
* the jquery event object
* @return void
*/
TableCell.prototype._editableFocus = function (e) {
// only do activation stuff if the cell don't has the focus
if (!this.hasFocus) {
// set an internal flag to focus the table
this.tableObj.focus();
// add an active-class
this.obj.addClass('aloha-table-cell_active');
// set the focus flag
this.hasFocus = true;
// unset the selection type
this.tableObj.selection.selectionType = 'cell';
}
};
/**
* Blur event for the contenteditable div within a table-data field. The method
* requires the event-property TableCell as a TableCell object. It
* sets the hasFocus flag of the cell to false and removes the "active"
* css-class.
*
* @param jqEvent
* the jquery event object
* @return void
*/
TableCell.prototype._editableBlur = function (jqEvent) {
// reset the focus of the cell
this.hasFocus = false;
// remove "active class"
this.obj.removeClass('aloha-table-cell_active');
};
/**
* Gives the X (column no) for a cell, after adding colspans
*/
TableCell.prototype._virtualX = function () {
var $rows = this.tableObj.obj.children().children('tr');
var rowIdx = this.obj.parent().index();
var colIdx = this.obj.index();
return Utils.cellIndexToGridColumn($rows, rowIdx, colIdx);
};
/**
* Gives the Y (row no) for a cell, after adding colspans
*/
TableCell.prototype._virtualY = function () {
return this.obj.parent('tr').index();
};
/**
* Starts the cell selection mode
*/
TableCell.prototype._startCellSelection = function () {
if(!this.tableObj.selection.cellSelectionMode) {
//unselect currently selected cells
this.tableObj.selection.unselectCells();
// activate cell selection mode
this.tableObj.selection.cellSelectionMode = true;
//bind a global mouseup event handler to stop cell selection
var that = this;
jQuery('body').bind('mouseup.cellselection', function () {
that._endCellSelection();
});
this.tableObj.selection.baseCellPosition = [this._virtualY(), this._virtualX()];
}
};
/**
* Ends the cell selection mode
*/
TableCell.prototype._endCellSelection = function() {
if(this.tableObj.selection.cellSelectionMode) {
this.tableObj.selection.cellSelectionMode = false;
this.tableObj.selection.baseCellPosition = null;
this.tableObj.selection.lastSelectionRange = null;
this.tableObj.selection.selectionType = 'cell';
//unbind the global cell selection event
jQuery('body').unbind('mouseup.cellselection');
}
};
TableCell.prototype._getSelectedRect = function () {
var right = this._virtualX();
var bottom = this._virtualY();
var topLeft = this.tableObj.selection.baseCellPosition;
var left = topLeft[1];
if (left > right) {
left = right;
right = topLeft[1];
}
var top = topLeft[0];
if (top > bottom) {
top = bottom;
bottom = topLeft[0];
}
return {
"top": top,
"right": right,
"bottom": bottom,
"left": left
};
};
/**
* Toggles selection of cell.
* This works only when cell selection mode is active.
*/
TableCell.prototype._selectCellRange = function() {
if(this.tableObj.selection.resizeMode || !this.tableObj.selection.cellSelectionMode) {
return;
}
var rect = this._getSelectedRect();
var table = this.tableObj;
var $rows = table.obj.children().children('tr');
var grid = Utils.makeGrid($rows);
table.selection.selectedCells = [];
var selectClass = table.get('classCellSelected');
Utils.walkGrid(grid, function (cellInfo, j, i) {
if (Utils.containsDomCell(cellInfo)) {
if (i >= rect.top && i <= rect.bottom && j >= rect.left && j <= rect.right) {
jQuery(cellInfo.cell).addClass(selectClass);
table.selection.selectedCells.push(cellInfo.cell);
} else {
jQuery(cellInfo.cell).removeClass(selectClass);
}
}
});
table.selection.notifyCellsSelected();
};
/**
* Selects all inner-contens of an contentEditable-object
*
* @param editableNode dom-representation of the editable node (div-element)
* @return void
*/
TableCell.prototype._selectAll = function (editableNode) {
var e = (editableNode.jquery) ? editableNode.get(0) : editableNode;
// Not IE
if (!jQuery.browser.msie) {
var s = window.getSelection();
// WebKit
if (s.setBaseAndExtent /*&& e> 0 */ ) {
s.setBaseAndExtent(e, 0, e, Math.max(0, e.innerText.length - 1));
}
// Firefox and Opera
else {
// workaround for bug # 42885
if (window.opera && e.innerHTML.substring(e.innerHTML.length - 4) == '<BR>') {
e.innerHTML = e.innerHTML + '&#160;';
}
var r = document.createRange();
r.selectNodeContents(e);
s.removeAllRanges();
s.addRange(r);
}
}
// Some older browsers
else if (document.getSelection) {
var s = document.getSelection();
var r = document.createRange();
r.selectNodeContents(e);
s.removeAllRanges();
s.addRange(r);
}
// IE
else if (document.selection) {
var r = document.body.createTextRange();
r.moveToElementText(e);
r.select();
}
};
/**
* The mouse-down event for the editable-div in the thd-field. Unselect all
* cells when clicking on the editable-div.
*
* @param jqEvent
* the jquery-event object
* @return void
*/
TableCell.prototype._editableMouseDown = function (jqEvent) {
// deselect all highlighted cells registered in the this.tableObj.selection object
this.tableObj.selection.unselectCells();
if (this.tableObj.hasFocus) {
jqEvent.stopPropagation();
}
};
/**
* The key-up event for the editable-div in the td-field. Just check if the div
* is empty and insert an &nbsp;
*
* @param jqEvent
* the jquery-event object
* @return void
*/
TableCell.prototype._editableKeyUp = function (jqEvent) {
//TODO do we need to check for empty cells and insert a space?
//this._checkForEmptyEvent(jqEvent);
};
/**
* The key-down event for the ediable-div in the td-field. Check if the the div
* is empty and insert an &nbsp. Furthermore if cells are selected, unselect
* them.
*
* @param jqEvent
* the jquery-event object
* @return void
*/
TableCell.prototype._editableKeyDown = function (jqEvent) {
var KEYCODE_TAB = 9;
this._checkForEmptyEvent(jqEvent);
if ( this.obj[0] === this.tableObj.obj.find('tr:last td:last')[0] ) {
// only add a row on a single key-press of tab (so check
// that alt-, shift- or ctrl-key are NOT pressed)
if (KEYCODE_TAB == jqEvent.keyCode && !jqEvent.altKey && !jqEvent.shiftKey && !jqEvent.ctrlKey) {
// add a row after the current row
this.tableObj.addRow(this.obj.parent().index() + 1);
// firefox needs this for the first cell of the new row
// to be selected (.focus() doesn't work reliably in
// IE7)
this.tableObj.cells[this.tableObj.cells.length - 1]._selectAll(this.wrapper.get(0));
jqEvent.stopPropagation();
return;
}
}
};
/**
* The custom keyup event for a table-cell Checks if the cell is empty and
* inserts a space (\u00a0)
*
* @param e
* the event object which is given by jquery
* @return void
*/
TableCell.prototype._checkForEmptyEvent = function (jqEvent) {
var $wrapper = jQuery(this.wrapper),
text = $wrapper.text();
if ($wrapper.children().length > 0) {
return;
}
// if empty insert a blank space and blur and focus the wrapper
if (text === '') {
this.wrapper.text('\u00a0');
this.wrapper.get(0).blur();
this.wrapper.get(0).focus();
}
};
/**
* Given a cell, will return the container element of the contents
* of the cell. The container element may be the given cell itself,
* or a wrapper element, in the case of activated cells.
*
* @param {DomNode} cell
* the TH/TD of a TableCell that may or may not be actived.
* @return {DomNode}
* the element that contains the contents of the given cell.
*/
TableCell.getContainer = function (cell) {
if (jQuery(cell.firstChild).hasClass("aloha-table-cell-editable")) {
return cell.firstChild;
} else {
return cell;
}
};
return TableCell;
});