upfront-editable
Version:
Friendly contenteditable API
181 lines (143 loc) • 5.61 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _rangy = require('rangy');
var _rangy2 = _interopRequireDefault(_rangy);
var _parser = require('./parser');
var parser = _interopRequireWildcard(_parser);
var _rangeContainer = require('./range-container');
var _rangeContainer2 = _interopRequireDefault(_rangeContainer);
var _cursor = require('./cursor');
var _cursor2 = _interopRequireDefault(_cursor);
var _selection = require('./selection');
var _selection2 = _interopRequireDefault(_selection);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* The SelectionWatcher module watches for selection changes inside
* of editable blocks.
*
* @module core
* @submodule selectionWatcher
*/
var SelectionWatcher = function () {
function SelectionWatcher(dispatcher, win) {
(0, _classCallCheck3.default)(this, SelectionWatcher);
this.dispatcher = dispatcher;
this.win = win || window;
this.rangySelection = undefined;
this.currentSelection = undefined;
this.currentRange = undefined;
}
/**
* Updates the internal selection pointer to the current rangy selection.
* Returns true if no exception occured.
*/
(0, _createClass3.default)(SelectionWatcher, [{
key: 'syncSelection',
value: function syncSelection() {
// it is possible that rangy has a problem with the nativeSelection
try {
this.rangySelection = _rangy2.default.getSelection(this.win);
} catch (err) {
return false;
}
return true;
}
/**
* Return a RangeContainer if the current selection is within an editable
* otherwise return an empty RangeContainer
*/
}, {
key: 'getRangeContainer',
value: function getRangeContainer() {
var successfulSync = this.syncSelection();
// rangeCount is 0 or 1 in all browsers except firefox
// firefox can work with multiple ranges
// (on a mac hold down the command key to select multiple ranges)
if (this.rangySelection.rangeCount && successfulSync) {
var range = this.rangySelection.getRangeAt(0);
var hostNode = parser.getHost(range.commonAncestorContainer);
if (hostNode) return new _rangeContainer2.default(hostNode, range);
}
// return an empty range container
return new _rangeContainer2.default();
}
/**
* Gets a fresh RangeContainer with the current selection or cursor.
*
* @return RangeContainer instance
*/
}, {
key: 'getFreshRange',
value: function getFreshRange() {
return this.getRangeContainer();
}
/**
* Gets a fresh RangeContainer with the current selection or cursor.
*
* @return Either a Cursor or Selection instance or undefined if
* there is neither a selection or cursor.
*/
}, {
key: 'getFreshSelection',
value: function getFreshSelection() {
var range = this.getRangeContainer();
return range.isCursor ? range.getCursor(this.win) : range.getSelection(this.win);
}
/**
* Get the selection set by the last selectionChanged event.
* Sometimes the event does not fire fast enough and the seleciton
* you get is not the one the user sees.
* In those cases use #getFreshSelection()
*
* @return Either a Cursor or Selection instance or undefined if
* there is neither a selection or cursor.
*/
}, {
key: 'getSelection',
value: function getSelection() {
return this.currentSelection;
}
}, {
key: 'forceCursor',
value: function forceCursor() {
var range = this.getRangeContainer();
return range.forceCursor();
}
}, {
key: 'selectionChanged',
value: function selectionChanged() {
var newRange = this.getRangeContainer();
if (newRange.isDifferentFrom(this.currentRange)) {
var lastSelection = this.currentSelection;
this.currentRange = newRange;
// empty selection or cursor
if (lastSelection) {
if (lastSelection.isCursor && !this.currentRange.isCursor) {
this.dispatcher.notify('cursor', lastSelection.host);
} else if (lastSelection.isSelection && !this.currentRange.isSelection) {
this.dispatcher.notify('selection', lastSelection.host);
}
}
// set new selection or cursor and fire event
if (this.currentRange.isCursor) {
this.currentSelection = new _cursor2.default(this.currentRange.host, this.currentRange.range);
this.dispatcher.notify('cursor', this.currentSelection.host, this.currentSelection);
} else if (this.currentRange.isSelection) {
this.currentSelection = new _selection2.default(this.currentRange.host, this.currentRange.range);
this.dispatcher.notify('selection', this.currentSelection.host, this.currentSelection);
} else {
this.currentSelection = undefined;
}
}
}
}]);
return SelectionWatcher;
}();
exports.default = SelectionWatcher;