WIP - Remove canvas and use HTML/CSS
Browse files- index.html +0 -3
- src/common/constants.js +6 -2
- src/common/utils.js +13 -0
- src/core/element.js +11 -8
- src/core/overlay.js +17 -21
- src/core/popover.js +3 -25
- src/core/stage.js +75 -0
- src/index.js +12 -5
index.html
CHANGED
@@ -320,9 +320,6 @@ activeElement.getNode(); // Gets the DOM Element behind this element
|
|
320 |
</div>
|
321 |
</div>
|
322 |
|
323 |
-
<div id="driver-page-overlay"></div>
|
324 |
-
<div id="driver-highlighted-element-stage"></div>
|
325 |
-
|
326 |
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
|
327 |
<script async defer src="//buttons.github.io/buttons.js"></script>
|
328 |
<script src="//twemoji.maxcdn.com/2/twemoji.min.js?2.5"></script>
|
|
|
320 |
</div>
|
321 |
</div>
|
322 |
|
|
|
|
|
|
|
323 |
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
|
324 |
<script async defer src="//buttons.github.io/buttons.js"></script>
|
325 |
<script src="//twemoji.maxcdn.com/2/twemoji.min.js?2.5"></script>
|
src/common/constants.js
CHANGED
@@ -7,9 +7,10 @@ export const ESC_KEY_CODE = 27;
|
|
7 |
export const LEFT_KEY_CODE = 37;
|
8 |
export const RIGHT_KEY_CODE = 39;
|
9 |
|
10 |
-
export const ID_OVERLAY = 'driver-
|
11 |
-
|
12 |
export const ID_POPOVER = 'driver-popover-item';
|
|
|
13 |
export const CLASS_POPOVER_TIP = 'driver-popover-tip';
|
14 |
export const CLASS_POPOVER_TITLE = 'driver-popover-title';
|
15 |
export const CLASS_POPOVER_DESCRIPTION = 'driver-popover-description';
|
@@ -33,3 +34,6 @@ export const POPOVER_HTML = `
|
|
33 |
</span>
|
34 |
</div>
|
35 |
</div>`;
|
|
|
|
|
|
|
|
7 |
export const LEFT_KEY_CODE = 37;
|
8 |
export const RIGHT_KEY_CODE = 39;
|
9 |
|
10 |
+
export const ID_OVERLAY = 'driver-page-overlay';
|
11 |
+
export const ID_STAGE = 'driver-highlighted-element-stage';
|
12 |
export const ID_POPOVER = 'driver-popover-item';
|
13 |
+
|
14 |
export const CLASS_POPOVER_TIP = 'driver-popover-tip';
|
15 |
export const CLASS_POPOVER_TITLE = 'driver-popover-title';
|
16 |
export const CLASS_POPOVER_DESCRIPTION = 'driver-popover-description';
|
|
|
34 |
</span>
|
35 |
</div>
|
36 |
</div>`;
|
37 |
+
|
38 |
+
export const OVERLAY_HTML = `<div id="${ID_OVERLAY}"></div>`;
|
39 |
+
export const STAGE_HTML = `<div id="${ID_STAGE}"></div>`;
|
src/common/utils.js
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Turn a string into a node
|
3 |
+
* @param {String} htmlString to convert
|
4 |
+
* @return {Node} Converted node element
|
5 |
+
*/
|
6 |
+
// eslint-disable-next-line
|
7 |
+
export const createNodeFromString = (htmlString) => {
|
8 |
+
const div = document.createElement('div');
|
9 |
+
div.innerHTML = htmlString.trim();
|
10 |
+
|
11 |
+
// Change this to div.childNodes to support multiple top-level nodes
|
12 |
+
return div.firstChild;
|
13 |
+
};
|
src/core/element.js
CHANGED
@@ -148,14 +148,6 @@ export default class Element {
|
|
148 |
}
|
149 |
}
|
150 |
|
151 |
-
getSize() {
|
152 |
-
const boundingRect = this.node.getBoundingClientRect();
|
153 |
-
return {
|
154 |
-
width: boundingRect.width,
|
155 |
-
height: boundingRect.height
|
156 |
-
};
|
157 |
-
}
|
158 |
-
|
159 |
/**
|
160 |
* Is called when the element is about to be highlighted
|
161 |
* i.e. either if overlay has started moving the highlight towards
|
@@ -249,4 +241,15 @@ export default class Element {
|
|
249 |
width: Math.max(body.scrollWidth, body.offsetWidth, html.scrollWidth, html.offsetWidth),
|
250 |
};
|
251 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
252 |
}
|
|
|
148 |
}
|
149 |
}
|
150 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
151 |
/**
|
152 |
* Is called when the element is about to be highlighted
|
153 |
* i.e. either if overlay has started moving the highlight towards
|
|
|
241 |
width: Math.max(body.scrollWidth, body.offsetWidth, html.scrollWidth, html.offsetWidth),
|
242 |
};
|
243 |
}
|
244 |
+
|
245 |
+
/**
|
246 |
+
* Gets the size for popover
|
247 |
+
* @returns {{height: number, width: number}}
|
248 |
+
*/
|
249 |
+
getSize() {
|
250 |
+
return {
|
251 |
+
height: Math.max(this.node.scrollHeight, this.node.offsetHeight),
|
252 |
+
width: Math.max(this.node.scrollWidth, this.node.offsetWidth),
|
253 |
+
};
|
254 |
+
}
|
255 |
}
|
src/core/overlay.js
CHANGED
@@ -1,4 +1,6 @@
|
|
1 |
import Position from './position';
|
|
|
|
|
2 |
|
3 |
/**
|
4 |
* Responsible for overlay creation and manipulation i.e.
|
@@ -8,9 +10,10 @@ export default class Overlay {
|
|
8 |
/**
|
9 |
* @param {Object} options
|
10 |
* @param {Window} window
|
|
|
11 |
* @param {Document} document
|
12 |
*/
|
13 |
-
constructor(options, window, document) {
|
14 |
this.options = options;
|
15 |
|
16 |
this.positionToHighlight = new Position({}); // position at which layover is to be patched at
|
@@ -22,18 +25,22 @@ export default class Overlay {
|
|
22 |
|
23 |
this.window = window;
|
24 |
this.document = document;
|
|
|
25 |
|
26 |
-
this.
|
27 |
}
|
28 |
|
29 |
/**
|
30 |
* Prepares the overlay
|
31 |
*/
|
32 |
-
|
33 |
-
|
|
|
|
|
|
|
|
|
34 |
|
35 |
-
this.
|
36 |
-
this.highlightStage = this.document.getElementById('driver-highlighted-element-stage');
|
37 |
}
|
38 |
|
39 |
/**
|
@@ -102,8 +109,8 @@ export default class Overlay {
|
|
102 |
this.highlightedElement = null;
|
103 |
this.lastHighlightedElement = null;
|
104 |
|
105 |
-
this.
|
106 |
-
this.
|
107 |
}
|
108 |
|
109 |
/**
|
@@ -116,22 +123,11 @@ export default class Overlay {
|
|
116 |
return;
|
117 |
}
|
118 |
|
119 |
-
// Make it two times the padding because, half will be given on left and half on right
|
120 |
-
const requiredPadding = this.options.padding * 2;
|
121 |
-
|
122 |
// Show the overlay
|
123 |
-
this.
|
124 |
-
|
125 |
-
const width = (this.positionToHighlight.right - this.positionToHighlight.left) + (requiredPadding);
|
126 |
-
const height = (this.positionToHighlight.bottom - this.positionToHighlight.top) + (requiredPadding);
|
127 |
|
128 |
// Show the stage
|
129 |
-
this.
|
130 |
-
this.highlightStage.style.position = 'absolute';
|
131 |
-
this.highlightStage.style.width = `${width}px`;
|
132 |
-
this.highlightStage.style.height = `${height}px`;
|
133 |
-
this.highlightStage.style.top = `${this.positionToHighlight.top - (requiredPadding / 2)}px`;
|
134 |
-
this.highlightStage.style.left = `${this.positionToHighlight.left - (requiredPadding / 2)}px`;
|
135 |
|
136 |
// Element has been highlighted
|
137 |
this.highlightedElement.onHighlighted();
|
|
|
1 |
import Position from './position';
|
2 |
+
import { ID_OVERLAY, OVERLAY_HTML, POPOVER_HTML } from "../common/constants";
|
3 |
+
import { createNodeFromString } from "../common/utils";
|
4 |
|
5 |
/**
|
6 |
* Responsible for overlay creation and manipulation i.e.
|
|
|
10 |
/**
|
11 |
* @param {Object} options
|
12 |
* @param {Window} window
|
13 |
+
* @param {Stage} stage
|
14 |
* @param {Document} document
|
15 |
*/
|
16 |
+
constructor(options, stage, window, document) {
|
17 |
this.options = options;
|
18 |
|
19 |
this.positionToHighlight = new Position({}); // position at which layover is to be patched at
|
|
|
25 |
|
26 |
this.window = window;
|
27 |
this.document = document;
|
28 |
+
this.stage = stage;
|
29 |
|
30 |
+
this.makeNode();
|
31 |
}
|
32 |
|
33 |
/**
|
34 |
* Prepares the overlay
|
35 |
*/
|
36 |
+
makeNode() {
|
37 |
+
let pageOverlay = this.document.getElementById(ID_OVERLAY);
|
38 |
+
if (!pageOverlay) {
|
39 |
+
pageOverlay = createNodeFromString(OVERLAY_HTML);
|
40 |
+
document.body.appendChild(pageOverlay);
|
41 |
+
}
|
42 |
|
43 |
+
this.node = pageOverlay;
|
|
|
44 |
}
|
45 |
|
46 |
/**
|
|
|
109 |
this.highlightedElement = null;
|
110 |
this.lastHighlightedElement = null;
|
111 |
|
112 |
+
this.node.style.opacity = '0';
|
113 |
+
this.stage.hide();
|
114 |
}
|
115 |
|
116 |
/**
|
|
|
123 |
return;
|
124 |
}
|
125 |
|
|
|
|
|
|
|
126 |
// Show the overlay
|
127 |
+
this.node.style.opacity = `${this.options.opacity}`;
|
|
|
|
|
|
|
128 |
|
129 |
// Show the stage
|
130 |
+
this.stage.show(this.positionToHighlight);
|
|
|
|
|
|
|
|
|
|
|
131 |
|
132 |
// Element has been highlighted
|
133 |
this.highlightedElement.onHighlighted();
|
src/core/popover.js
CHANGED
@@ -9,6 +9,7 @@ import {
|
|
9 |
ID_POPOVER,
|
10 |
POPOVER_HTML,
|
11 |
} from '../common/constants';
|
|
|
12 |
|
13 |
/**
|
14 |
* Popover that is displayed on top of the highlighted element
|
@@ -48,10 +49,11 @@ export default class Popover extends Element {
|
|
48 |
makeNode() {
|
49 |
let popover = this.document.getElementById(ID_POPOVER);
|
50 |
if (!popover) {
|
51 |
-
popover =
|
52 |
document.body.appendChild(popover);
|
53 |
}
|
54 |
|
|
|
55 |
this.node = popover;
|
56 |
this.tipNode = popover.querySelector(`.${CLASS_POPOVER_TIP}`);
|
57 |
this.titleNode = popover.querySelector(`.${CLASS_POPOVER_TITLE}`);
|
@@ -62,30 +64,6 @@ export default class Popover extends Element {
|
|
62 |
this.closeBtnNode = popover.querySelector(`.${CLASS_CLOSE_BTN}`);
|
63 |
}
|
64 |
|
65 |
-
/**
|
66 |
-
* Turn a string into a node
|
67 |
-
* @param {String} htmlString to convert
|
68 |
-
* @return {Node} Converted node element
|
69 |
-
*/
|
70 |
-
static createFromString(htmlString) {
|
71 |
-
const div = document.createElement('div');
|
72 |
-
div.innerHTML = htmlString.trim();
|
73 |
-
|
74 |
-
// Change this to div.childNodes to support multiple top-level nodes
|
75 |
-
return div.firstChild;
|
76 |
-
}
|
77 |
-
|
78 |
-
/**
|
79 |
-
* Gets the size for popover
|
80 |
-
* @returns {{height: number, width: number}}
|
81 |
-
*/
|
82 |
-
getSize() {
|
83 |
-
return {
|
84 |
-
height: Math.max(this.node.scrollHeight, this.node.offsetHeight),
|
85 |
-
width: Math.max(this.node.scrollWidth, this.node.offsetWidth),
|
86 |
-
};
|
87 |
-
}
|
88 |
-
|
89 |
hide() {
|
90 |
this.node.style.display = 'none';
|
91 |
}
|
|
|
9 |
ID_POPOVER,
|
10 |
POPOVER_HTML,
|
11 |
} from '../common/constants';
|
12 |
+
import { createNodeFromString } from '../common/utils';
|
13 |
|
14 |
/**
|
15 |
* Popover that is displayed on top of the highlighted element
|
|
|
49 |
makeNode() {
|
50 |
let popover = this.document.getElementById(ID_POPOVER);
|
51 |
if (!popover) {
|
52 |
+
popover = createNodeFromString(POPOVER_HTML);
|
53 |
document.body.appendChild(popover);
|
54 |
}
|
55 |
|
56 |
+
|
57 |
this.node = popover;
|
58 |
this.tipNode = popover.querySelector(`.${CLASS_POPOVER_TIP}`);
|
59 |
this.titleNode = popover.querySelector(`.${CLASS_POPOVER_TITLE}`);
|
|
|
64 |
this.closeBtnNode = popover.querySelector(`.${CLASS_CLOSE_BTN}`);
|
65 |
}
|
66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
hide() {
|
68 |
this.node.style.display = 'none';
|
69 |
}
|
src/core/stage.js
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { ID_STAGE, POPOVER_HTML, STAGE_HTML } from '../common/constants';
|
2 |
+
import { createNodeFromString } from '../common/utils';
|
3 |
+
import Element from './element';
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Stage behind the highlighted element to give it a little
|
7 |
+
* highlight from rest of the page
|
8 |
+
*/
|
9 |
+
export default class Stage extends Element {
|
10 |
+
/**
|
11 |
+
* @param {Object} options
|
12 |
+
* @param {Window} window
|
13 |
+
* @param {Document} document
|
14 |
+
*/
|
15 |
+
constructor(options, window, document) {
|
16 |
+
super();
|
17 |
+
|
18 |
+
this.options = options;
|
19 |
+
this.window = window;
|
20 |
+
this.document = document;
|
21 |
+
|
22 |
+
this.makeNode();
|
23 |
+
this.hide();
|
24 |
+
}
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Prepares the DOM element if not already there
|
28 |
+
*/
|
29 |
+
makeNode() {
|
30 |
+
let stage = this.document.getElementById(ID_STAGE);
|
31 |
+
if (!stage) {
|
32 |
+
stage = createNodeFromString(STAGE_HTML);
|
33 |
+
document.body.appendChild(stage);
|
34 |
+
}
|
35 |
+
|
36 |
+
this.node = stage;
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Simply hides the stage
|
41 |
+
*/
|
42 |
+
hide() {
|
43 |
+
this.node.style.display = 'none';
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Makes it visible and sets the default properties
|
48 |
+
*/
|
49 |
+
reset() {
|
50 |
+
this.node.style.display = 'block';
|
51 |
+
this.node.style.left = '0';
|
52 |
+
this.node.style.top = '0';
|
53 |
+
this.node.style.bottom = '';
|
54 |
+
this.node.style.right = '';
|
55 |
+
}
|
56 |
+
|
57 |
+
show(position) {
|
58 |
+
this.reset();
|
59 |
+
|
60 |
+
// Make it two times the padding because, half will be given on left and half on right
|
61 |
+
const requiredPadding = this.options.padding * 2;
|
62 |
+
|
63 |
+
const width = (position.right - position.left) + (requiredPadding);
|
64 |
+
const height = (position.bottom - position.top) + (requiredPadding);
|
65 |
+
|
66 |
+
// Show the stage
|
67 |
+
this.node.style.display = 'block';
|
68 |
+
this.node.style.position = 'absolute';
|
69 |
+
this.node.style.width = `${width}px`;
|
70 |
+
this.node.style.height = `${height}px`;
|
71 |
+
this.node.style.top = `${position.top - (requiredPadding / 2)}px`;
|
72 |
+
this.node.style.left = `${position.left - (requiredPadding / 2)}px`;
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
src/index.js
CHANGED
@@ -14,6 +14,7 @@ import {
|
|
14 |
OVERLAY_PADDING,
|
15 |
RIGHT_KEY_CODE,
|
16 |
} from './common/constants';
|
|
|
17 |
|
18 |
/**
|
19 |
* Plugin class that drives the plugin
|
@@ -38,13 +39,13 @@ export default class Driver {
|
|
38 |
|
39 |
this.document = document;
|
40 |
this.window = window;
|
41 |
-
|
42 |
this.isActivated = false;
|
43 |
-
this.overlay = new Overlay(this.options, this.window, this.document);
|
44 |
-
|
45 |
this.steps = []; // steps to be presented if any
|
46 |
this.currentStep = 0; // index for the currently highlighted step
|
47 |
|
|
|
|
|
|
|
48 |
this.onResize = this.onResize.bind(this);
|
49 |
this.onKeyUp = this.onKeyUp.bind(this);
|
50 |
this.onClick = this.onClick.bind(this);
|
@@ -242,11 +243,16 @@ export default class Driver {
|
|
242 |
let querySelector = '';
|
243 |
let elementOptions = {};
|
244 |
|
|
|
245 |
if (typeof currentStep === 'string') {
|
246 |
querySelector = currentStep;
|
247 |
} else {
|
248 |
querySelector = currentStep.element;
|
249 |
-
elementOptions = Object.assign(
|
|
|
|
|
|
|
|
|
250 |
}
|
251 |
|
252 |
const domElement = this.document.querySelector(querySelector);
|
@@ -260,7 +266,8 @@ export default class Driver {
|
|
260 |
const popoverOptions = Object.assign(
|
261 |
{},
|
262 |
this.options,
|
263 |
-
elementOptions.popover,
|
|
|
264 |
totalCount: allSteps.length,
|
265 |
currentIndex: index,
|
266 |
isFirst: index === 0,
|
|
|
14 |
OVERLAY_PADDING,
|
15 |
RIGHT_KEY_CODE,
|
16 |
} from './common/constants';
|
17 |
+
import Stage from './core/stage';
|
18 |
|
19 |
/**
|
20 |
* Plugin class that drives the plugin
|
|
|
39 |
|
40 |
this.document = document;
|
41 |
this.window = window;
|
|
|
42 |
this.isActivated = false;
|
|
|
|
|
43 |
this.steps = []; // steps to be presented if any
|
44 |
this.currentStep = 0; // index for the currently highlighted step
|
45 |
|
46 |
+
const stage = new Stage(this.options, window, document);
|
47 |
+
this.overlay = new Overlay(this.options, stage, window, document);
|
48 |
+
|
49 |
this.onResize = this.onResize.bind(this);
|
50 |
this.onKeyUp = this.onKeyUp.bind(this);
|
51 |
this.onClick = this.onClick.bind(this);
|
|
|
243 |
let querySelector = '';
|
244 |
let elementOptions = {};
|
245 |
|
246 |
+
// If it is just a query selector string
|
247 |
if (typeof currentStep === 'string') {
|
248 |
querySelector = currentStep;
|
249 |
} else {
|
250 |
querySelector = currentStep.element;
|
251 |
+
elementOptions = Object.assign(
|
252 |
+
{},
|
253 |
+
this.options,
|
254 |
+
currentStep,
|
255 |
+
);
|
256 |
}
|
257 |
|
258 |
const domElement = this.document.querySelector(querySelector);
|
|
|
266 |
const popoverOptions = Object.assign(
|
267 |
{},
|
268 |
this.options,
|
269 |
+
elementOptions.popover,
|
270 |
+
{
|
271 |
totalCount: allSteps.length,
|
272 |
currentIndex: index,
|
273 |
isFirst: index === 0,
|