Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handsontable should work properly in <iframe> #5723

Merged
merged 12 commits into from Jan 25, 2019
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions .eslintrc.js
Expand Up @@ -57,6 +57,8 @@ module.exports = {
"no-restricted-globals": [
"error",
"Handsontable",
"window",
"document",
{
"name": "console",
"message": "Using the `console` object is not allowed within Handsontable. Please use one of the helpers from the `console.js` file instead."
Expand Down
47 changes: 38 additions & 9 deletions handsontable.d.ts
Expand Up @@ -281,6 +281,7 @@ declare namespace Handsontable {
editor: HTMLElement;
editorStyle: CSSStyleDeclaration;
hidden: boolean;
rootDocument: Document;

setPosition(x: number, y: number): void;
setSize(width: number, height: number): void;
Expand Down Expand Up @@ -466,6 +467,7 @@ declare namespace Handsontable {
cellWidth: number;
left: number;
leftRelative: number;
rootWindow: Window;
scrollLeft: number;
scrollTop: number;
top: number;
Expand Down Expand Up @@ -764,9 +766,10 @@ declare namespace Handsontable {
}

interface FocusableWrapper {
mainElement: HTMLElement;
eventManager: EventManager;
listenersCount: WeakSet<HTMLElement>;
mainElement: HTMLElement;
rootDocument: Document;

useSecondaryElement(): void;
setFocusableElement(element: HTMLElement): void;
Expand Down Expand Up @@ -1378,6 +1381,27 @@ declare namespace Handsontable {
untrimRow(row: number): void;
untrimRows(rows: number[]): void;
}

interface Storage {
prefix: string;
rootWindow: Window;
savedKeys: string[];

clearSavedKeys(): void;
loadSavedKeys(): void;
loadValue(key: string, defaultValue: object): any;
resetAll(): void;
saveSavedKeys(): void;
saveValue(key: string, value: any): void;
}

interface PersistenState extends Base {
storage: Storage;

loadValue(key: string, saveTo: object): void;
saveValue(key: string, value: any): void;
resetValue(key: string): void;
}

interface Search extends Base {
callback: () => void;
Expand Down Expand Up @@ -1830,11 +1854,13 @@ declare namespace Handsontable {
hasCaptionProblem(): boolean | void,
inherit(Child: object, Parent: object): object,
isChrome(): boolean,
isClassListSupported(): boolean;
isCtrlKey(keyCode: number): boolean,
isDefined(variable: any): boolean,
isEdge(): boolean,
isEmpty(variable: any): boolean,
isFunction(func: any): boolean,
isGetComputedStyleSupported(): boolean,
isIE(): boolean,
isIE8(): boolean,
isIE9(): boolean,
Expand All @@ -1848,6 +1874,7 @@ declare namespace Handsontable {
isPercentValue(value: string): boolean,
isPrintableChar(keyCode: number): boolean,
isSafari(): boolean,
isTextContentSupported(): boolean,
isTouchSupported(): boolean,
isUndefined(variable: any): boolean,
isWebComponentSupportedNatively(): boolean,
Expand Down Expand Up @@ -1879,25 +1906,26 @@ declare namespace Handsontable {
HTML_CHARACTERS: RegExp,
addClass: (element: HTMLElement, className: string | any[]) => void;
addEvent: (element: HTMLElement, event: string, callback: () => void) => void;
clearTextSelection: (rootWindow?: Window) => void;
closest: (element: HTMLElement, nodes: any[], until?: HTMLElement) => HTMLElement | void;
closestDown: (element: HTMLElement, nodes: any[], until?: HTMLElement) => HTMLElement | void;
empty: (element: HTMLElement) => void;
fastInnerHTML: (element: HTMLElement, content: string) => void;
fastInnerText: (element: HTMLElement, content: string) => void;
getCaretPosition: (el: HTMLElement) => number;
getComputedStyle: (element: HTMLElement) => CSSStyleDeclaration | object;
getComputedStyle: (element: HTMLElement, rootWindow?: Window) => CSSStyleDeclaration | object;
getCssTransform: (element: HTMLElement) => number | void;
getParent: (element: HTMLElement, level?: number) => HTMLElement | void;
getScrollLeft: (element: HTMLElement) => number;
getScrollTop: (element: HTMLElement) => number;
getScrollLeft: (element: HTMLElement, rootWindow?: Window) => number;
getScrollTop: (element: HTMLElement, rootWindow?: Window) => number;
getScrollableElement: (element: HTMLElement) => HTMLElement;
getScrollbarWidth: () => number;
getScrollbarWidth: (rootDocument?: Document) => number;
getSelectionEndPosition: (el: HTMLElement) => number;
getSelectionText: () => string;
getStyle: (element: HTMLElement, prop: string) => string;
getSelectionText: (rootWindow?: Window) => string;
getStyle: (element: HTMLElement, prop: string, rootWindow?: Window) => string;
getTrimmingContainer: (base: HTMLElement) => HTMLElement;
getWindowScrollLeft: () => number;
getWindowScrollTop: () => number;
getWindowScrollLeft: (rootWindow?: Window) => number;
getWindowScrollTop: (rootWindow?: Window) => number;
hasClass: (element: HTMLElement, className: string) => boolean;
hasHorizontalScrollbar: (element: HTMLElement) => boolean;
hasVerticalScrollbar: (element: HTMLElement) => boolean;
Expand Down Expand Up @@ -2000,6 +2028,7 @@ declare namespace Handsontable {
nestedHeaders: plugins.NestedHeaders,
nestedRows: plugins.NestedRows,
observeChanges: plugins.ObserveChanges,
persistentState: plugins.PersistenState,
search: plugins.Search,
touchScroll: plugins.TouchScroll,
trimRows: plugins.TrimRows,
Expand Down
69 changes: 39 additions & 30 deletions src/3rdparty/walkontable/src/border.js
Expand Up @@ -63,8 +63,10 @@ class Border {
* Register all necessary events
*/
registerListeners() {
this.eventManager.addEventListener(document.body, 'mousedown', () => this.onMouseDown());
this.eventManager.addEventListener(document.body, 'mouseup', () => this.onMouseUp());
const documentBody = this.wot.rootDocument.body;

this.eventManager.addEventListener(documentBody, 'mousedown', () => this.onMouseDown());
this.eventManager.addEventListener(documentBody, 'mouseup', () => this.onMouseUp());

for (let c = 0, len = this.main.childNodes.length; c < len; c++) {
this.eventManager.addEventListener(this.main.childNodes[c], 'mouseenter', event => this.onMouseEnter(event, this.main.childNodes[c]));
Expand Down Expand Up @@ -104,6 +106,7 @@ class Border {
stopImmediatePropagation(event);

const _this = this;
const documentBody = this.wot.rootDocument.body;
const bounds = parentElement.getBoundingClientRect();
// Hide border to prevents selection jumping when fragmentSelection is enabled.
parentElement.style.display = 'none';
Expand All @@ -125,12 +128,12 @@ class Border {

function handler(handlerEvent) {
if (isOutside(handlerEvent)) {
_this.eventManager.removeEventListener(document.body, 'mousemove', handler);
_this.eventManager.removeEventListener(documentBody, 'mousemove', handler);
parentElement.style.display = 'block';
}
}

this.eventManager.addEventListener(document.body, 'mousemove', handler);
this.eventManager.addEventListener(documentBody, 'mousemove', handler);
}

/**
Expand All @@ -139,7 +142,8 @@ class Border {
* @param {Object} settings
*/
createBorders(settings) {
this.main = document.createElement('div');
const { rootDocument } = this.wot;
this.main = rootDocument.createElement('div');

const borderDivs = ['top', 'left', 'bottom', 'right', 'corner'];
let style = this.main.style;
Expand All @@ -149,7 +153,7 @@ class Border {

for (let i = 0; i < 5; i++) {
const position = borderDivs[i];
const div = document.createElement('div');
const div = rootDocument.createElement('div');

div.className = `wtBorder ${this.settings.className || ''}`; // + borderDivs[i];

Expand Down Expand Up @@ -189,13 +193,14 @@ class Border {
}
this.disappear();

let bordersHolder = this.wot.wtTable.bordersHolder;
const { wtTable } = this.wot;
let bordersHolder = wtTable.bordersHolder;

if (!bordersHolder) {
bordersHolder = document.createElement('div');
bordersHolder = rootDocument.createElement('div');
bordersHolder.className = 'htBorders';
this.wot.wtTable.bordersHolder = bordersHolder;
this.wot.wtTable.spreader.appendChild(bordersHolder);
wtTable.bordersHolder = bordersHolder;
wtTable.spreader.appendChild(bordersHolder);
}
bordersHolder.appendChild(this.main);
}
Expand All @@ -204,11 +209,13 @@ class Border {
* Create multiple selector handler for mobile devices
*/
createMultipleSelectorHandles() {
const { rootDocument } = this.wot;

this.selectionHandles = {
topLeft: document.createElement('DIV'),
topLeftHitArea: document.createElement('DIV'),
bottomRight: document.createElement('DIV'),
bottomRightHitArea: document.createElement('DIV')
topLeft: rootDocument.createElement('DIV'),
topLeftHitArea: rootDocument.createElement('DIV'),
bottomRight: rootDocument.createElement('DIV'),
bottomRightHitArea: rootDocument.createElement('DIV')
};
const width = 10;
const hitAreaWidth = 40;
Expand Down Expand Up @@ -322,15 +329,16 @@ class Border {
return;
}

const { wtTable, rootDocument, rootWindow } = this.wot;
let fromRow;
let toRow;
let fromColumn;
let toColumn;

const rowsCount = this.wot.wtTable.getRenderedRowsCount();
const rowsCount = wtTable.getRenderedRowsCount();

for (let i = 0; i < rowsCount; i += 1) {
const s = this.wot.wtTable.rowFilter.renderedToSource(i);
const s = wtTable.rowFilter.renderedToSource(i);

if (s >= corners[0] && s <= corners[2]) {
fromRow = s;
Expand All @@ -339,18 +347,18 @@ class Border {
}

for (let i = rowsCount - 1; i >= 0; i -= 1) {
const s = this.wot.wtTable.rowFilter.renderedToSource(i);
const s = wtTable.rowFilter.renderedToSource(i);

if (s >= corners[0] && s <= corners[2]) {
toRow = s;
break;
}
}

const columnsCount = this.wot.wtTable.getRenderedColumnsCount();
const columnsCount = wtTable.getRenderedColumnsCount();

for (let i = 0; i < columnsCount; i += 1) {
const s = this.wot.wtTable.columnFilter.renderedToSource(i);
const s = wtTable.columnFilter.renderedToSource(i);

if (s >= corners[1] && s <= corners[3]) {
fromColumn = s;
Expand All @@ -359,7 +367,7 @@ class Border {
}

for (let i = columnsCount - 1; i >= 0; i -= 1) {
const s = this.wot.wtTable.columnFilter.renderedToSource(i);
const s = wtTable.columnFilter.renderedToSource(i);

if (s >= corners[1] && s <= corners[3]) {
toColumn = s;
Expand All @@ -371,12 +379,12 @@ class Border {

return;
}
let fromTD = this.wot.wtTable.getCell(new CellCoords(fromRow, fromColumn));
let fromTD = wtTable.getCell(new CellCoords(fromRow, fromColumn));
const isMultiple = (fromRow !== toRow || fromColumn !== toColumn);
const toTD = isMultiple ? this.wot.wtTable.getCell(new CellCoords(toRow, toColumn)) : fromTD;
const toTD = isMultiple ? wtTable.getCell(new CellCoords(toRow, toColumn)) : fromTD;
const fromOffset = offset(fromTD);
const toOffset = isMultiple ? offset(toTD) : fromOffset;
const containerOffset = offset(this.wot.wtTable.TABLE);
const containerOffset = offset(wtTable.TABLE);
const minTop = fromOffset.top;
const minLeft = fromOffset.left;

Expand Down Expand Up @@ -412,7 +420,7 @@ class Border {
}
}

const style = getComputedStyle(fromTD);
const style = getComputedStyle(fromTD, rootWindow);

if (parseInt(style.borderTopWidth, 10) > 0) {
top += 1;
Expand Down Expand Up @@ -467,11 +475,11 @@ class Border {
// Hide the fill handle, so the possible further adjustments won't force unneeded scrollbars.
this.cornerStyle.display = 'none';

let trimmingContainer = getTrimmingContainer(this.wot.wtTable.TABLE);
const trimToWindow = trimmingContainer === window;
let trimmingContainer = getTrimmingContainer(wtTable.TABLE);
const trimToWindow = trimmingContainer === rootWindow;

if (trimToWindow) {
trimmingContainer = document.documentElement;
trimmingContainer = rootDocument.documentElement;
}

if (toColumn === this.wot.getSetting('totalColumns') - 1) {
Expand Down Expand Up @@ -537,7 +545,8 @@ class Border {
* @return {Array|Boolean} Returns an array of [headerElement, left, width] or [headerElement, top, height], depending on `direction` (`false` in case of an error getting the headers).
*/
getDimensionsFromHeader(direction, fromIndex, toIndex, containerOffset) {
const rootHotElement = this.wot.wtTable.wtRootElement.parentNode;
const { wtTable } = this.wot;
const rootHotElement = wtTable.wtRootElement.parentNode;
let getHeaderFn = null;
let dimensionFn = null;
let entireSelectionClassname = null;
Expand All @@ -549,15 +558,15 @@ class Border {

switch (direction) {
case 'rows':
getHeaderFn = (...args) => this.wot.wtTable.getRowHeader(...args);
getHeaderFn = (...args) => wtTable.getRowHeader(...args);
dimensionFn = (...args) => outerHeight(...args);
entireSelectionClassname = 'ht__selection--rows';
dimensionProperty = 'top';

break;

case 'columns':
getHeaderFn = (...args) => this.wot.wtTable.getColumnHeader(...args);
getHeaderFn = (...args) => wtTable.getColumnHeader(...args);
dimensionFn = (...args) => outerWidth(...args);
entireSelectionClassname = 'ht__selection--columns';
dimensionProperty = 'left';
Expand Down
2 changes: 2 additions & 0 deletions src/3rdparty/walkontable/src/core.js
Expand Up @@ -25,6 +25,8 @@ class Walkontable {

// this is the namespace for global events
this.guid = `wt_${randomString()}`;
this.rootDocument = settings.table.ownerDocument;
this.rootWindow = this.rootDocument.defaultView;

// bootstrap from settings
if (settings.cloneSource) {
Expand Down
4 changes: 2 additions & 2 deletions src/3rdparty/walkontable/src/event.js
Expand Up @@ -94,7 +94,7 @@ class Event {
initMouseEvents();
}

this.eventManager.addEventListener(window, 'resize', () => {
this.eventManager.addEventListener(this.instance.rootWindow, 'resize', () => {
if (this.instance.getSetting('stretchH') !== 'none') {
this.instance.draw();
}
Expand Down Expand Up @@ -161,7 +161,7 @@ class Event {
*/
onMouseDown(event) {
const priv = privatePool.get(this);
const activeElement = document.activeElement;
const activeElement = this.instance.rootDocument.activeElement;
const getParentNode = partial(getParent, event.realTarget);
const realTarget = event.realTarget;

Expand Down