mirror of
https://github.com/kamranahmedse/driver.js.git
synced 2026-10-31 12:04:55 +08:00
WIP - Remove canvas and use HTML/CSS
This commit is contained in:
@@ -320,9 +320,6 @@ activeElement.getNode(); // Gets the DOM Element behind this element
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="driver-page-overlay"></div>
|
||||
<div id="driver-highlighted-element-stage"></div>
|
||||
|
||||
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
<script async defer src="//buttons.github.io/buttons.js"></script>
|
||||
<script src="//twemoji.maxcdn.com/2/twemoji.min.js?2.5"></script>
|
||||
|
||||
@@ -7,9 +7,10 @@ export const ESC_KEY_CODE = 27;
|
||||
export const LEFT_KEY_CODE = 37;
|
||||
export const RIGHT_KEY_CODE = 39;
|
||||
|
||||
export const ID_OVERLAY = 'driver-canvas-overlay';
|
||||
|
||||
export const ID_OVERLAY = 'driver-page-overlay';
|
||||
export const ID_STAGE = 'driver-highlighted-element-stage';
|
||||
export const ID_POPOVER = 'driver-popover-item';
|
||||
|
||||
export const CLASS_POPOVER_TIP = 'driver-popover-tip';
|
||||
export const CLASS_POPOVER_TITLE = 'driver-popover-title';
|
||||
export const CLASS_POPOVER_DESCRIPTION = 'driver-popover-description';
|
||||
@@ -33,3 +34,6 @@ export const POPOVER_HTML = `
|
||||
</span>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
export const OVERLAY_HTML = `<div id="${ID_OVERLAY}"></div>`;
|
||||
export const STAGE_HTML = `<div id="${ID_STAGE}"></div>`;
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Turn a string into a node
|
||||
* @param {String} htmlString to convert
|
||||
* @return {Node} Converted node element
|
||||
*/
|
||||
// eslint-disable-next-line
|
||||
export const createNodeFromString = (htmlString) => {
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = htmlString.trim();
|
||||
|
||||
// Change this to div.childNodes to support multiple top-level nodes
|
||||
return div.firstChild;
|
||||
};
|
||||
+11
-8
@@ -148,14 +148,6 @@ export default class Element {
|
||||
}
|
||||
}
|
||||
|
||||
getSize() {
|
||||
const boundingRect = this.node.getBoundingClientRect();
|
||||
return {
|
||||
width: boundingRect.width,
|
||||
height: boundingRect.height
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Is called when the element is about to be highlighted
|
||||
* i.e. either if overlay has started moving the highlight towards
|
||||
@@ -249,4 +241,15 @@ export default class Element {
|
||||
width: Math.max(body.scrollWidth, body.offsetWidth, html.scrollWidth, html.offsetWidth),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size for popover
|
||||
* @returns {{height: number, width: number}}
|
||||
*/
|
||||
getSize() {
|
||||
return {
|
||||
height: Math.max(this.node.scrollHeight, this.node.offsetHeight),
|
||||
width: Math.max(this.node.scrollWidth, this.node.offsetWidth),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+17
-21
@@ -1,4 +1,6 @@
|
||||
import Position from './position';
|
||||
import { ID_OVERLAY, OVERLAY_HTML, POPOVER_HTML } from "../common/constants";
|
||||
import { createNodeFromString } from "../common/utils";
|
||||
|
||||
/**
|
||||
* Responsible for overlay creation and manipulation i.e.
|
||||
@@ -8,9 +10,10 @@ export default class Overlay {
|
||||
/**
|
||||
* @param {Object} options
|
||||
* @param {Window} window
|
||||
* @param {Stage} stage
|
||||
* @param {Document} document
|
||||
*/
|
||||
constructor(options, window, document) {
|
||||
constructor(options, stage, window, document) {
|
||||
this.options = options;
|
||||
|
||||
this.positionToHighlight = new Position({}); // position at which layover is to be patched at
|
||||
@@ -22,18 +25,22 @@ export default class Overlay {
|
||||
|
||||
this.window = window;
|
||||
this.document = document;
|
||||
this.stage = stage;
|
||||
|
||||
this.resetOverlay();
|
||||
this.makeNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the overlay
|
||||
*/
|
||||
resetOverlay() {
|
||||
// @todo: append the elements if not there already
|
||||
makeNode() {
|
||||
let pageOverlay = this.document.getElementById(ID_OVERLAY);
|
||||
if (!pageOverlay) {
|
||||
pageOverlay = createNodeFromString(OVERLAY_HTML);
|
||||
document.body.appendChild(pageOverlay);
|
||||
}
|
||||
|
||||
this.pageOverlay = this.document.getElementById('driver-page-overlay');
|
||||
this.highlightStage = this.document.getElementById('driver-highlighted-element-stage');
|
||||
this.node = pageOverlay;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,8 +109,8 @@ export default class Overlay {
|
||||
this.highlightedElement = null;
|
||||
this.lastHighlightedElement = null;
|
||||
|
||||
this.pageOverlay.style.opacity = '0';
|
||||
this.highlightStage.style.display = 'none';
|
||||
this.node.style.opacity = '0';
|
||||
this.stage.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,22 +123,11 @@ export default class Overlay {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make it two times the padding because, half will be given on left and half on right
|
||||
const requiredPadding = this.options.padding * 2;
|
||||
|
||||
// Show the overlay
|
||||
this.pageOverlay.style.opacity = `${this.options.opacity}`;
|
||||
|
||||
const width = (this.positionToHighlight.right - this.positionToHighlight.left) + (requiredPadding);
|
||||
const height = (this.positionToHighlight.bottom - this.positionToHighlight.top) + (requiredPadding);
|
||||
this.node.style.opacity = `${this.options.opacity}`;
|
||||
|
||||
// Show the stage
|
||||
this.highlightStage.style.display = 'block';
|
||||
this.highlightStage.style.position = 'absolute';
|
||||
this.highlightStage.style.width = `${width}px`;
|
||||
this.highlightStage.style.height = `${height}px`;
|
||||
this.highlightStage.style.top = `${this.positionToHighlight.top - (requiredPadding / 2)}px`;
|
||||
this.highlightStage.style.left = `${this.positionToHighlight.left - (requiredPadding / 2)}px`;
|
||||
this.stage.show(this.positionToHighlight);
|
||||
|
||||
// Element has been highlighted
|
||||
this.highlightedElement.onHighlighted();
|
||||
|
||||
+3
-25
@@ -9,6 +9,7 @@ import {
|
||||
ID_POPOVER,
|
||||
POPOVER_HTML,
|
||||
} from '../common/constants';
|
||||
import { createNodeFromString } from '../common/utils';
|
||||
|
||||
/**
|
||||
* Popover that is displayed on top of the highlighted element
|
||||
@@ -48,10 +49,11 @@ export default class Popover extends Element {
|
||||
makeNode() {
|
||||
let popover = this.document.getElementById(ID_POPOVER);
|
||||
if (!popover) {
|
||||
popover = Popover.createFromString(POPOVER_HTML);
|
||||
popover = createNodeFromString(POPOVER_HTML);
|
||||
document.body.appendChild(popover);
|
||||
}
|
||||
|
||||
|
||||
this.node = popover;
|
||||
this.tipNode = popover.querySelector(`.${CLASS_POPOVER_TIP}`);
|
||||
this.titleNode = popover.querySelector(`.${CLASS_POPOVER_TITLE}`);
|
||||
@@ -62,30 +64,6 @@ export default class Popover extends Element {
|
||||
this.closeBtnNode = popover.querySelector(`.${CLASS_CLOSE_BTN}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a string into a node
|
||||
* @param {String} htmlString to convert
|
||||
* @return {Node} Converted node element
|
||||
*/
|
||||
static createFromString(htmlString) {
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = htmlString.trim();
|
||||
|
||||
// Change this to div.childNodes to support multiple top-level nodes
|
||||
return div.firstChild;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size for popover
|
||||
* @returns {{height: number, width: number}}
|
||||
*/
|
||||
getSize() {
|
||||
return {
|
||||
height: Math.max(this.node.scrollHeight, this.node.offsetHeight),
|
||||
width: Math.max(this.node.scrollWidth, this.node.offsetWidth),
|
||||
};
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.node.style.display = 'none';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import { ID_STAGE, POPOVER_HTML, STAGE_HTML } from '../common/constants';
|
||||
import { createNodeFromString } from '../common/utils';
|
||||
import Element from './element';
|
||||
|
||||
/**
|
||||
* Stage behind the highlighted element to give it a little
|
||||
* highlight from rest of the page
|
||||
*/
|
||||
export default class Stage extends Element {
|
||||
/**
|
||||
* @param {Object} options
|
||||
* @param {Window} window
|
||||
* @param {Document} document
|
||||
*/
|
||||
constructor(options, window, document) {
|
||||
super();
|
||||
|
||||
this.options = options;
|
||||
this.window = window;
|
||||
this.document = document;
|
||||
|
||||
this.makeNode();
|
||||
this.hide();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the DOM element if not already there
|
||||
*/
|
||||
makeNode() {
|
||||
let stage = this.document.getElementById(ID_STAGE);
|
||||
if (!stage) {
|
||||
stage = createNodeFromString(STAGE_HTML);
|
||||
document.body.appendChild(stage);
|
||||
}
|
||||
|
||||
this.node = stage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply hides the stage
|
||||
*/
|
||||
hide() {
|
||||
this.node.style.display = 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes it visible and sets the default properties
|
||||
*/
|
||||
reset() {
|
||||
this.node.style.display = 'block';
|
||||
this.node.style.left = '0';
|
||||
this.node.style.top = '0';
|
||||
this.node.style.bottom = '';
|
||||
this.node.style.right = '';
|
||||
}
|
||||
|
||||
show(position) {
|
||||
this.reset();
|
||||
|
||||
// Make it two times the padding because, half will be given on left and half on right
|
||||
const requiredPadding = this.options.padding * 2;
|
||||
|
||||
const width = (position.right - position.left) + (requiredPadding);
|
||||
const height = (position.bottom - position.top) + (requiredPadding);
|
||||
|
||||
// Show the stage
|
||||
this.node.style.display = 'block';
|
||||
this.node.style.position = 'absolute';
|
||||
this.node.style.width = `${width}px`;
|
||||
this.node.style.height = `${height}px`;
|
||||
this.node.style.top = `${position.top - (requiredPadding / 2)}px`;
|
||||
this.node.style.left = `${position.left - (requiredPadding / 2)}px`;
|
||||
}
|
||||
}
|
||||
|
||||
+12
-5
@@ -14,6 +14,7 @@ import {
|
||||
OVERLAY_PADDING,
|
||||
RIGHT_KEY_CODE,
|
||||
} from './common/constants';
|
||||
import Stage from './core/stage';
|
||||
|
||||
/**
|
||||
* Plugin class that drives the plugin
|
||||
@@ -38,13 +39,13 @@ export default class Driver {
|
||||
|
||||
this.document = document;
|
||||
this.window = window;
|
||||
|
||||
this.isActivated = false;
|
||||
this.overlay = new Overlay(this.options, this.window, this.document);
|
||||
|
||||
this.steps = []; // steps to be presented if any
|
||||
this.currentStep = 0; // index for the currently highlighted step
|
||||
|
||||
const stage = new Stage(this.options, window, document);
|
||||
this.overlay = new Overlay(this.options, stage, window, document);
|
||||
|
||||
this.onResize = this.onResize.bind(this);
|
||||
this.onKeyUp = this.onKeyUp.bind(this);
|
||||
this.onClick = this.onClick.bind(this);
|
||||
@@ -242,11 +243,16 @@ export default class Driver {
|
||||
let querySelector = '';
|
||||
let elementOptions = {};
|
||||
|
||||
// If it is just a query selector string
|
||||
if (typeof currentStep === 'string') {
|
||||
querySelector = currentStep;
|
||||
} else {
|
||||
querySelector = currentStep.element;
|
||||
elementOptions = Object.assign({}, this.options, currentStep);
|
||||
elementOptions = Object.assign(
|
||||
{},
|
||||
this.options,
|
||||
currentStep,
|
||||
);
|
||||
}
|
||||
|
||||
const domElement = this.document.querySelector(querySelector);
|
||||
@@ -260,7 +266,8 @@ export default class Driver {
|
||||
const popoverOptions = Object.assign(
|
||||
{},
|
||||
this.options,
|
||||
elementOptions.popover, {
|
||||
elementOptions.popover,
|
||||
{
|
||||
totalCount: allSteps.length,
|
||||
currentIndex: index,
|
||||
isFirst: index === 0,
|
||||
|
||||
Reference in New Issue
Block a user