Skip to content

Commit

Permalink
support config.checkSelectionRanges & features.{selectionSupportsMult…
Browse files Browse the repository at this point in the history
…ipleRanges, collapsedNonEditableSelectionsSupported}
  • Loading branch information
giabao committed Apr 20, 2019
1 parent c7ca257 commit 4fd64b4
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 17 deletions.
9 changes: 5 additions & 4 deletions src/core/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ export interface Features {
selectionHasAnchorAndFocus?: boolean;
selectionHasExtend?: boolean;
selectionHasRangeCount?: boolean;
selectionSupportsMultipleRanges: false;
selectionSupportsMultipleRanges: boolean;
implementsControlRange: false;
collapsedNonEditableSelectionsSupported: boolean;
}
export const features: Features = {
implementsDomRange: true,
Expand All @@ -35,13 +36,13 @@ export const features: Features = {
implementsDocSelection: false,
selectionSupportsMultipleRanges: false,
implementsControlRange: false,
collapsedNonEditableSelectionsSupported: true,
};
/** @deprecated all configs is const! */
export interface Config {
/** @deprecated range2 don't have TextRange */
preferTextRange: false;
checkSelectionRanges: true;
checkSelectionRanges: boolean;
}
/** @deprecated all configs is const! */
export const config: Config = {
preferTextRange: false,
checkSelectionRanges: true,
Expand Down
2 changes: 1 addition & 1 deletion src/core/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ export function isWindow(obj): obj is Window {
function isIframe(o): o is HTMLIFrameElement {
return o.nodeType == 1 && o.tagName.toLowerCase() == "iframe"
}
export function getContentDocument(obj: Document | HTMLIFrameElement| Window, module: Module, methodName: string): Document {
export function getContentDocument(obj: Window | Node, module: Module, methodName: string): Document {
var doc;

if (!obj) {
Expand Down
4 changes: 4 additions & 0 deletions src/core/internal/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ export {
WrappedRange,
createNativeRange,
createRange,
// /** @deprecated */
// createRange as createIframeRange,
shimCreateRange,
// from ./wrappedselection
getNativeSelection,
isSelectionValid,
getSelection,
// /** @deprecated */
// getSelection as getIframeSelection,
WrappedSelection,
WrappedSelection as Selection, //alias
RangeIterator,
Expand Down
90 changes: 84 additions & 6 deletions src/core/internal/wrappedselection.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {Module} from "../module";
import {config, features} from "../api";
import {config, features, onDocReady} from "../api";
import {DOMException} from "../DOMException";

import * as util from "../util";
import {Constructor, isHostMethod} from "../util";
import {areHostMethods, isHostMethod} from "../util";

import * as dom from "../dom";
import {DomPosition, getDocument} from "../dom";
Expand Down Expand Up @@ -61,15 +61,15 @@ export function isSelectionValid() {
return true;
}

var testSelection = getNativeSelection();
const testSelection = getNativeSelection();

// In Firefox, the selection is null in an iframe with display: none. See issue #138.
if (!testSelection) {
module.fail("Native selection was null (possibly issue 138?)");
// return false;
}

var testRange = createNativeRange(document);
const testRange = createNativeRange(document);

// Obtaining a range from a selection
const selectionHasAnchorAndFocus =
Expand Down Expand Up @@ -210,7 +210,7 @@ let selectionIsCollapsed =
return null;
}

export function getSelection(win?: Window | WrappedSelection | Document): WrappedSelection {
export function getSelection(win?: Window | Node | WrappedSelection): WrappedSelection {
// Check if the parameter is a Rangy Selection object
if (win && win instanceof WrappedSelection) {
win.refresh();
Expand Down Expand Up @@ -411,7 +411,7 @@ let selectionIsCollapsed =
empty = this.removeAllRanges;

//if (selectionHasRangeCount) {
addRange = addRange;
addRange = addRange.bind(this);

setRanges(ranges: WrappedRange[]): void {
this.removeAllRanges();
Expand Down Expand Up @@ -676,3 +676,81 @@ export function shimGetSelection(win?) {
};
}
};

function docReadyHandler(): void {
const isSupport = areHostMethods(testSelection, ["addRange", "getRangeAt", "removeAllRanges"]) &&
typeof testSelection.rangeCount == NUMBER && features.implementsDomRange;
if (!isSupport) return;

// Previously an iframe was used but this caused problems in some circumstances in IE, so tests are
// performed on the current document's selection. See issue 109.

// Note also that if a selection previously existed, it is wiped and later restored by these tests. This
// will result in the selection direction begin reversed if the original selection was backwards and the
// browser does not support setting backwards selections (Internet Explorer, I'm looking at you).
const sel = window.getSelection();
// Store the current selection
const originalSelectionRangeCount = sel.rangeCount;
const selectionHasMultipleRanges = (originalSelectionRangeCount > 1);
const originalSelectionRanges = [];
const originalSelectionBackward = winSelectionIsBackward(sel);
for (let i = 0; i < originalSelectionRangeCount; ++i) {
originalSelectionRanges[i] = sel.getRangeAt(i);
}

// Create some test elements
const testEl = dom.createTestElement(document, "", false);
const textNode = testEl.appendChild( document.createTextNode("\u00a0\u00a0\u00a0") );

// Test whether the native selection will allow a collapsed selection within a non-editable element
const r1 = document.createRange();

r1.setStart(textNode, 1);
r1.collapse(true);
sel.removeAllRanges();
sel.addRange(r1);
features.collapsedNonEditableSelectionsSupported = (sel.rangeCount == 1);
sel.removeAllRanges();

// Test whether the native selection is capable of supporting multiple ranges.
if (selectionHasMultipleRanges) {
features.selectionSupportsMultipleRanges = true;
} else {
// Doing the original feature test here in Chrome 36 (and presumably later versions) prints a
// console error of "Discontiguous selection is not supported." that cannot be suppressed. There's
// nothing we can do about this while retaining the feature test so we have to resort to a browser
// sniff. I'm not happy about it. See
// https://code.google.com/p/chromium/issues/detail?id=399791
const chromeMatch = window.navigator.appVersion.match(/Chrome\/(.*?) /);
if (chromeMatch && parseInt(chromeMatch[1]) >= 36) {
features.selectionSupportsMultipleRanges = false;
} else {
const r2 = r1.cloneRange();
r1.setStart(textNode, 0);
r2.setEnd(textNode, 3);
r2.setStart(textNode, 2);
sel.addRange(r1);
sel.addRange(r2);
features.selectionSupportsMultipleRanges = (sel.rangeCount == 2);
}
}

// Clean up
dom.removeNode(testEl);
sel.removeAllRanges();

for (let i = 0; i < originalSelectionRangeCount; ++i) {
if (i == 0 && originalSelectionBackward) {
if (addRangeBackwardToNative) {
addRangeBackwardToNative(sel, originalSelectionRanges[i]);
} else {
module.warn("Rangy initialization: original selection was backwards but selection has been restored forwards because the browser does not support Selection.extend");
sel.addRange(originalSelectionRanges[i]);
}
} else {
sel.addRange(originalSelectionRanges[i]);
}
}
}

onDocReady(docReadyHandler);
15 changes: 9 additions & 6 deletions src/util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
import * as api from "rangy2";
import {
WrappedSelection as SelProto,
DomRange as RangeProto
DomRange as RangeProto,
getNativeSelection
} from "rangy2";

// const module = new Module("Util", ["WrappedSelection"]);
Expand All @@ -31,9 +32,9 @@ export class WrappedSelection extends SelProto {

pasteHtml(html) {
this.deleteFromDocument();
var range = this.getRangeAt(0);
var frag = this.createContextualFragment(html);
var lastNode = frag.lastChild;
const range = this.getRangeAt(0);
const frag = range.createContextualFragment(html);
const lastNode = frag.lastChild;
range.insertNode(frag);
if (lastNode) {
range.setStartAfter(lastNode)
Expand Down Expand Up @@ -105,7 +106,9 @@ export function createRangeFromNodeContents(node) {
};

export function selectNodeContents(node) {
api.getSelection().selectNodeContents(node);
};
const nativeSel = getNativeSelection();
const sel = new WrappedSelection(nativeSel, window)
sel.selectNodeContents(node);
}

// TODO: simple selection save/restore

0 comments on commit 4fd64b4

Please sign in to comment.