/**
* CellSelection.js
*
* Released under LGPL License.
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
*
* License: http://www.tinymce.com/license
* Contributing: http://www.tinymce.com/contributing
*/
/*eslint no-bitwise:0 */
define(
'tinymce.plugins.table.selection.CellSelection',
[
'ephox.darwin.api.InputHandlers',
'ephox.darwin.api.SelectionAnnotation',
'ephox.darwin.api.SelectionKeys',
'ephox.katamari.api.Fun',
'ephox.katamari.api.Option',
'ephox.katamari.api.Struct',
'ephox.snooker.api.TableLookup',
'ephox.sugar.api.dom.Compare',
'ephox.sugar.api.node.Element',
'ephox.sugar.api.node.Node',
'ephox.sugar.api.node.Text',
'ephox.sugar.api.properties.Attr',
'ephox.sugar.api.search.Traverse',
'ephox.sugar.api.selection.Selection',
'ephox.sugar.selection.core.SelectionDirection',
'tinymce.plugins.table.alien.Util',
'tinymce.plugins.table.queries.Direction',
'tinymce.plugins.table.selection.Ephemera'
],
function (InputHandlers, SelectionAnnotation, SelectionKeys, Fun, Option, Struct, TableLookup, Compare, Element, Node, Text, Attr, Traverse, Selection, SelectionDirection, Util, Direction, Ephemera) {
return function (editor, lazyResize) {
var handlerStruct = Struct.immutableBag(['mousedown', 'mouseover', 'mouseup', 'keyup', 'keydown'], []);
var handlers = Option.none();
var annotations = SelectionAnnotation.byAttr(Ephemera);
editor.on('init', function (e) {
var win = editor.getWin();
var body = Util.getBody(editor);
var isRoot = Util.getIsRoot(editor);
var syncSelection = function () {
var sel = editor.selection;
var start = Element.fromDom(sel.getStart());
var end = Element.fromDom(sel.getEnd());
var startTable = TableLookup.table(start);
var endTable = TableLookup.table(end);
var sameTable = startTable.bind(function (tableStart) {
return endTable.bind(function (tableEnd) {
return Compare.eq(tableStart, tableEnd) ? Option.some(true) : Option.none();
});
});
sameTable.fold(function () {
annotations.clear(body);
}, Fun.noop);
};
var mouseHandlers = InputHandlers.mouse(win, body, isRoot, annotations);
var keyHandlers = InputHandlers.keyboard(win, body, isRoot, annotations);
var handleResponse = function (event, response) {
if (response.kill()) {
event.kill();
}
response.selection().each(function (ns) {
var relative = Selection.relative(ns.start(), ns.finish());
var rng = SelectionDirection.asLtrRange(win, relative);
editor.selection.setRng(rng);
});
};
var keyup = function (event) {
var wrappedEvent = wrapEvent(event);
// Note, this is an optimisation.
if (wrappedEvent.raw().shiftKey && SelectionKeys.isNavigation(wrappedEvent.raw().which)) {
var rng = editor.selection.getRng();
var start = Element.fromDom(rng.startContainer);
var end = Element.fromDom(rng.endContainer);
keyHandlers.keyup(wrappedEvent, start, rng.startOffset, end, rng.endOffset).each(function (response) {
handleResponse(wrappedEvent, response);
});
}
};
var checkLast = function (last) {
return !Attr.has(last, 'data-mce-bogus') && Node.name(last) !== 'br' && !(Node.isText(last) && Text.get(last).length === 0);
};
var getLast = function () {
var body = Element.fromDom(editor.getBody());
var lastChild = Traverse.lastChild(body);
var getPrevLast = function (last) {
return Traverse.prevSibling(last).bind(function (prevLast) {
return checkLast(prevLast) ? Option.some(prevLast) : getPrevLast(prevLast);
});
};
return lastChild.bind(function (last) {
return checkLast(last) ? Option.some(last) : getPrevLast(last);
});
};
var keydown = function (event) {
var wrappedEvent = wrapEvent(event);
lazyResize().each(function (resize) {
resize.hideBars();
});
if (event.which === 40) {
getLast().each(function (last) {
if (Node.name(last) === 'table') {
if (editor.settings.forced_root_block) {
editor.dom.add(
editor.getBody(),
editor.settings.forced_root_block,
editor.settings.forced_root_block_attrs,
'<br/>'
);
} else {
editor.dom.add(editor.getBody(), 'br');
}
}
});
}
var rng = editor.selection.getRng();
var startContainer = Element.fromDom(editor.selection.getStart());
var start = Element.fromDom(rng.startContainer);
var end = Element.fromDom(rng.endContainer);
var direction = Direction.directionAt(startContainer).isRtl() ? SelectionKeys.rtl : SelectionKeys.ltr;
keyHandlers.keydown(wrappedEvent, start, rng.startOffset, end, rng.endOffset, direction).each(function (response) {
handleResponse(wrappedEvent, response);
});
lazyResize().each(function (resize) {
resize.showBars();
});
};
var wrapEvent = function (event) {
// IE9 minimum
var target = Element.fromDom(event.target);
var stop = function () {
event.stopPropagation();
};
var prevent = function () {
event.preventDefault();
};
var kill = Fun.compose(prevent, stop); // more of a sequence than a compose, but same effect
// FIX: Don't just expose the raw event. Need to identify what needs standardisation.
return {
'target': Fun.constant(target),
'x': Fun.constant(event.x),
'y': Fun.constant(event.y),
'stop': stop,
'prevent': prevent,
'kill': kill,
'raw': Fun.constant(event)
};
};
var isLeftMouse = function (raw) {
return raw.button === 0;
};
// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons
var isLeftButtonPressed = function (raw) {
// Only added by Chrome/Firefox in June 2015.
// This is only to fix a 1px bug (TBIO-2836) so return true if we're on an older browser
if (raw.buttons === undefined) {
return true;
}
// use bitwise & for optimal comparison
return (raw.buttons & 1) !== 0;
};
var mouseDown = function (e) {
if (isLeftMouse(e)) {
mouseHandlers.mousedown(wrapEvent(e));
}
};
var mouseOver = function (e) {
if (isLeftButtonPressed(e)) {
mouseHandlers.mouseover(wrapEvent(e));
}
};
var mouseUp = function (e) {
if (isLeftMouse) {
mouseHandlers.mouseup(wrapEvent(e));
}
};
editor.on('mousedown', mouseDown);
editor.on('mouseover', mouseOver);
editor.on('mouseup', mouseUp);
editor.on('keyup', keyup);
editor.on('keydown', keydown);
editor.on('nodechange', syncSelection);
handlers = Option.some(handlerStruct({
mousedown: mouseDown,
mouseover: mouseOver,
mouseup: mouseUp,
keyup: keyup,
keydown: keydown
}));
});
var destroy = function () {
handlers.each(function (handlers) {
// editor.off('mousedown', handlers.mousedown());
// editor.off('mouseover', handlers.mouseover());
// editor.off('mouseup', handlers.mouseup());
// editor.off('keyup', handlers.keyup());
// editor.off('keydown', handlers.keydown());
});
};
return {
clear: annotations.clear,
destroy: destroy
};
};
}
);
|