kamrify commited on
Commit
27c03db
·
1 Parent(s): 095d0ef

Dependency injection and move bringInView to element

Browse files
assets/scripts/src/element.js CHANGED
@@ -5,12 +5,16 @@ export default class Element {
5
  * DOM element object
6
  * @param node
7
  * @param options
 
 
 
8
  */
9
- constructor(node, options) {
10
  this.node = node;
11
  this.document = document;
12
  this.window = window;
13
  this.options = options;
 
14
  this.popover = this.getPopover();
15
  }
16
 
@@ -62,10 +66,10 @@ export default class Element {
62
  }
63
 
64
  const elementRect = this.getCalculatedPosition();
65
- const absoluteElementTop = elementRect.top + window.pageYOffset;
66
- const middle = absoluteElementTop - (window.innerHeight / 2);
67
 
68
- window.scrollTo(0, middle);
69
  }
70
 
71
  /**
@@ -106,6 +110,18 @@ export default class Element {
106
 
107
  onHighlighted() {
108
  this.showPopover();
 
 
 
 
 
 
 
 
 
 
 
 
109
  }
110
 
111
  showPopover() {
 
5
  * DOM element object
6
  * @param node
7
  * @param options
8
+ * @param overlay
9
+ * @param window
10
+ * @param document
11
  */
12
+ constructor(node, options, overlay, window, document) {
13
  this.node = node;
14
  this.document = document;
15
  this.window = window;
16
  this.options = options;
17
+ this.overlay = overlay;
18
  this.popover = this.getPopover();
19
  }
20
 
 
66
  }
67
 
68
  const elementRect = this.getCalculatedPosition();
69
+ const absoluteElementTop = elementRect.top + this.window.pageYOffset;
70
+ const middle = absoluteElementTop - (this.window.innerHeight / 2);
71
 
72
+ this.window.scrollTo(0, middle);
73
  }
74
 
75
  /**
 
110
 
111
  onHighlighted() {
112
  this.showPopover();
113
+
114
+ const highlightedElement = this;
115
+ const lastHighlightedElement = this.overlay.getLastHighlightedElement();
116
+
117
+ const highlightedNode = this.node;
118
+ const lastHighlightedNode = lastHighlightedElement && lastHighlightedElement.node;
119
+
120
+ // If this element is not already highlighted (because this call could
121
+ // be from the resize or scroll) and is not in view
122
+ if (highlightedNode !== lastHighlightedNode && !highlightedElement.isInView()) {
123
+ highlightedElement.bringInView();
124
+ }
125
  }
126
 
127
  showPopover() {
assets/scripts/src/overlay.js CHANGED
@@ -9,12 +9,14 @@ export default class Overlay {
9
  * @param opacity number
10
  * @param padding number
11
  * @param animate bool
 
 
12
  */
13
  constructor({
14
  opacity = 0.75,
15
  padding = 10,
16
  animate = true,
17
- }) {
18
  this.opacity = opacity; // Fixed opacity for the layover
19
  this.padding = padding; // Padding around the highlighted item
20
  this.animate = animate; // Should animate between the transitions
@@ -24,6 +26,7 @@ export default class Overlay {
24
  this.highlightedPosition = new Position({}); // position at which layover is patched currently
25
  this.redrawAnimation = null; // used to cancel the redraw animation
26
  this.highlightedElement = null; // currently highlighted dom element (instance of Element)
 
27
 
28
  this.draw = this.draw.bind(this); // To pass the context of class, as it is to be used in redraw animation callback
29
 
@@ -58,6 +61,7 @@ export default class Overlay {
58
  */
59
  highlight(element, animate = true) {
60
  if (!element || !element.node) {
 
61
  return;
62
  }
63
 
@@ -75,6 +79,7 @@ export default class Overlay {
75
  return;
76
  }
77
 
 
78
  this.highlightedElement = element;
79
  this.positionToHighlight = position;
80
 
@@ -95,6 +100,14 @@ export default class Overlay {
95
  return this.highlightedElement;
96
  }
97
 
 
 
 
 
 
 
 
 
98
  /**
99
  * Removes the overlay and cancel any listeners
100
  */
@@ -102,6 +115,7 @@ export default class Overlay {
102
  this.positionToHighlight = new Position();
103
  this.highlightedElement.onDeselected();
104
  this.highlightedElement = null;
 
105
 
106
  this.draw();
107
  }
@@ -138,8 +152,8 @@ export default class Overlay {
138
 
139
  // Cut the chunk of overlay that is over the highlighted item
140
  this.removeCloak({
141
- posX: this.highlightedPosition.left - window.scrollX - this.padding,
142
- posY: this.highlightedPosition.top - window.scrollY - this.padding,
143
  width: (this.highlightedPosition.right - this.highlightedPosition.left) + (this.padding * 2),
144
  height: (this.highlightedPosition.bottom - this.highlightedPosition.top) + (this.padding * 2),
145
  });
@@ -164,7 +178,7 @@ export default class Overlay {
164
  if (canHighlight || this.overlayAlpha > 0) {
165
  // Add the overlay if not already there
166
  if (!this.overlay.parentNode) {
167
- document.body.appendChild(this.overlay);
168
  }
169
 
170
  // Stage a new animation frame only if the position has not been reached
 
9
  * @param opacity number
10
  * @param padding number
11
  * @param animate bool
12
+ * @param window
13
+ * @param document
14
  */
15
  constructor({
16
  opacity = 0.75,
17
  padding = 10,
18
  animate = true,
19
+ }, window, document) {
20
  this.opacity = opacity; // Fixed opacity for the layover
21
  this.padding = padding; // Padding around the highlighted item
22
  this.animate = animate; // Should animate between the transitions
 
26
  this.highlightedPosition = new Position({}); // position at which layover is patched currently
27
  this.redrawAnimation = null; // used to cancel the redraw animation
28
  this.highlightedElement = null; // currently highlighted dom element (instance of Element)
29
+ this.lastHighlightedElement = null; // element that was highlighted before current one
30
 
31
  this.draw = this.draw.bind(this); // To pass the context of class, as it is to be used in redraw animation callback
32
 
 
61
  */
62
  highlight(element, animate = true) {
63
  if (!element || !element.node) {
64
+ console.warn('Invalid element to highlight. Must be an instance of `Element`');
65
  return;
66
  }
67
 
 
79
  return;
80
  }
81
 
82
+ this.lastHighlightedElement = this.highlightedElement;
83
  this.highlightedElement = element;
84
  this.positionToHighlight = position;
85
 
 
100
  return this.highlightedElement;
101
  }
102
 
103
+ /**
104
+ * Gets the element that was highlighted before current element
105
+ * @returns {null|*}
106
+ */
107
+ getLastHighlightedElement() {
108
+ return this.lastHighlightedElement;
109
+ }
110
+
111
  /**
112
  * Removes the overlay and cancel any listeners
113
  */
 
115
  this.positionToHighlight = new Position();
116
  this.highlightedElement.onDeselected();
117
  this.highlightedElement = null;
118
+ this.lastHighlightedElement = null;
119
 
120
  this.draw();
121
  }
 
152
 
153
  // Cut the chunk of overlay that is over the highlighted item
154
  this.removeCloak({
155
+ posX: this.highlightedPosition.left - this.window.scrollX - this.padding,
156
+ posY: this.highlightedPosition.top - this.window.scrollY - this.padding,
157
  width: (this.highlightedPosition.right - this.highlightedPosition.left) + (this.padding * 2),
158
  height: (this.highlightedPosition.bottom - this.highlightedPosition.top) + (this.padding * 2),
159
  });
 
178
  if (canHighlight || this.overlayAlpha > 0) {
179
  // Add the overlay if not already there
180
  if (!this.overlay.parentNode) {
181
+ this.document.body.appendChild(this.overlay);
182
  }
183
 
184
  // Stage a new animation frame only if the position has not been reached
assets/scripts/src/sholo.js CHANGED
@@ -16,11 +16,11 @@ export default class Sholo {
16
  opacity: 0.75,
17
  }, options);
18
 
19
- this.overlay = new Overlay(options);
20
-
21
  this.document = document;
22
  this.window = window;
23
 
 
 
24
  this.steps = []; // steps to be presented if any
25
  this.currentStep = 0; // index for the currently highlighted step
26
 
@@ -57,7 +57,7 @@ export default class Sholo {
57
  }
58
 
59
  const highlightedElement = this.overlay.getHighlightedElement();
60
- const popover = document.getElementById('sholo-popover-item');
61
 
62
  const clickedHighlightedElement = highlightedElement.node.contains(e.target);
63
  const clickedPopover = popover && popover.contains(e.target);
@@ -82,13 +82,6 @@ export default class Sholo {
82
  } else if (prevClicked) {
83
  this.movePrevious();
84
  }
85
-
86
- // @todo - move to onHighlighted hook and add the check if not visible then do this
87
- if (this.overlay.highlightedElement) {
88
- window.setTimeout(() => {
89
- this.overlay.highlightedElement.bringInView();
90
- }, 800);
91
- }
92
  }
93
 
94
  /**
@@ -167,12 +160,19 @@ export default class Sholo {
167
  this.steps = [];
168
 
169
  steps.forEach((step, index) => {
170
- if (!step.element) {
171
- throw new Error(`Element (query selector or a dom element) missing in step ${index}`);
172
  }
173
 
174
- const domElement = Sholo.findDomElement(step.element);
175
- const element = new Element(domElement, Object.assign({}, this.options, step));
 
 
 
 
 
 
 
176
 
177
  this.steps.push(element);
178
  });
@@ -189,24 +189,17 @@ export default class Sholo {
189
 
190
  /**
191
  * Highlights the given selector
192
- * @param selector
 
193
  */
194
  highlight(selector) {
195
- const domElement = Sholo.findDomElement(selector);
196
-
197
- const element = new Element(domElement, this.options);
198
- this.overlay.highlight(element);
199
- }
200
-
201
- static findDomElement(selector) {
202
- if (typeof selector === 'string') {
203
- return document.querySelector(selector);
204
- }
205
-
206
- if (typeof selector === 'object') {
207
- return selector;
208
  }
209
 
210
- throw new Error('Element can only be string or the dom element');
 
211
  }
212
  }
 
16
  opacity: 0.75,
17
  }, options);
18
 
 
 
19
  this.document = document;
20
  this.window = window;
21
 
22
+ this.overlay = new Overlay(options, window, document);
23
+
24
  this.steps = []; // steps to be presented if any
25
  this.currentStep = 0; // index for the currently highlighted step
26
 
 
57
  }
58
 
59
  const highlightedElement = this.overlay.getHighlightedElement();
60
+ const popover = this.document.getElementById('sholo-popover-item');
61
 
62
  const clickedHighlightedElement = highlightedElement.node.contains(e.target);
63
  const clickedPopover = popover && popover.contains(e.target);
 
82
  } else if (prevClicked) {
83
  this.movePrevious();
84
  }
 
 
 
 
 
 
 
85
  }
86
 
87
  /**
 
160
  this.steps = [];
161
 
162
  steps.forEach((step, index) => {
163
+ if (!step.element || typeof step.element !== 'string') {
164
+ throw new Error(`Element (query selector string) missing in step ${index}`);
165
  }
166
 
167
+ const elementOptions = Object.assign({}, this.options, step);
168
+
169
+ const domElement = this.document.querySelector(step.element);
170
+ if (!domElement) {
171
+ console.warn(`Element to highlight ${step.element} not found`);
172
+ return;
173
+ }
174
+
175
+ const element = new Element(domElement, elementOptions, this.overlay, this.window, this.document);
176
 
177
  this.steps.push(element);
178
  });
 
189
 
190
  /**
191
  * Highlights the given selector
192
+ * @param selector string query selector
193
+ * @todo make it accept json or query selector
194
  */
195
  highlight(selector) {
196
+ const domElement = this.document.querySelector(selector);
197
+ if (!domElement) {
198
+ console.warn(`Element to highlight ${selector} not found`);
199
+ return;
 
 
 
 
 
 
 
 
 
200
  }
201
 
202
+ const element = new Element(domElement, this.options, this.overlay, this.window, this.document);
203
+ this.overlay.highlight(element);
204
  }
205
  }