-
Notifications
You must be signed in to change notification settings - Fork 9.3k
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
Stickyjs improvements #7139
Stickyjs improvements #7139
Conversation
Hi @vovayatsyuk, Thanks for second loop with this improvement. We will go ahead and accept it. |
@vovayatsyuk could you please resolve conflicts so that we can proceed with PR acceptance? |
Done. |
@vovayatsyuk thank you for resolving the merge conflicts |
lib/web/mage/sticky.js
Outdated
@@ -41,8 +44,34 @@ define([ | |||
|
|||
if (!isStatic && this.element.is(':visible')) { | |||
offset = $(document).scrollTop() - this.parentOffset; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need this line of code? Variable offset will be redefined in any case in line 49 or 51.
Could you please review this logic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I'm missing the point, but it's not redefined at those lines, it just modified with the possible spacingTop
parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, can you comment on this? I don't understand how you'd like to modify the source.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good. Thank you
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some readability issues and at least one bug, but mostly this is great!
lib/web/mage/sticky.js
Outdated
@@ -41,8 +44,34 @@ define([ | |||
|
|||
if (!isStatic && this.element.is(':visible')) { | |||
offset = $(document).scrollTop() - this.parentOffset; | |||
|
|||
if (typeof this.options.spacingTop === 'function') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should check to see whether spacingTop
is a Number, or whether it returns a Number.
var spacingTop = this.options.spacingTop || 0;
if (typeof this.options.spacingTop === 'function') {
spacingTop = this.options.spacingTop();
}
spacingTop = Number(spacingTop);
if (isNaN(spacingTop)) {
throw new Error('sticky: spacingTop must be a Number');
}
offset += this.options.spacingTop;
See below for more notes.
lib/web/mage/sticky.js
Outdated
offsetTop = this.options.offsetTop(); | ||
} else { | ||
offsetTop = this.options.offsetTop; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pattern happens twice, and there may be further configurable numbers, so it probably should be separated into a private function.
At the top of this file:
function optionToNumber(self, option) {
var value = self.options[option] || 0;
if (typeof value === 'function') {
value = self.options[option]();
}
var converted = Number(value);
if (isNaN(converted)) {
throw Error('sticky: Could not convert supplied option "' + option + '" to Number from "' + value + '"');
}
return converted;
}
And then here, you can just have:
var offsetTop = optionToNumber(this, 'offsetTop');
if (offset < offsetTop) {
offset = 0;
}
And above, you can just have:
offset += optionToNumber(this, 'spacingTop');
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice optimization, but is it ok to send this
? Maybe it's better to place the function inside the widget to get rid of this
parameter? I know the function is not needed there, but I'm not sure what is better: "send this" or create a function inside the widget?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's okay to send this
from an object method to a locally declared function. It's a way to do real privacy in JavaScript. I see it in lots of codebases! But the way that you implemented it, as an underscore-prefixed method, is also just fine.
lib/web/mage/sticky.js
Outdated
offsetTop = this.options.offsetTop; | ||
} | ||
|
||
if (offset < this.options.offsetTop) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is a bug; this.options.offsetTop
may still be a function. You might have means if (offset < offsetTop)
. The refactor I suggest in my above comments should fix it, though.
lib/web/mage/sticky.js
Outdated
|
||
if (offset && | ||
this.options.offsetTop && | ||
!this.element.hasClass(this.options.stickyClass)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain the desired logic here? It's hard to tell from the code what !this.element.hasClass(this.options.stickyClass)
means for the business logic. Does it mean "the element is currently displayed as sticky" or "the element is NOT currently displayed as sticky"? For more readability, you could assign it to a variable stuck
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic inside of this if
should work for the non-sticked element, when offsetTop
is used. (It makes smooth return of the items with offsetTop
parameter, when scrolling up)
In other words, I check if an element should be stuck (offset > 0), offsetTop
is used and an element is not yet stuck.
@vovayatsyuk Hi. I can`t apply your improvement. |
You should redeploy static content: Quick solution:
|
I do it same.
I Also try apply your commit like a patch for my project and nothing changing. |
Sorry, it's a bit off topic to talk about magento deployment here. If you'd like to see how the patch is working, you can open deployed file and apply the changes manually. If you use English locale and luma theme, you'll find the file right here: If that will not work for you, I really don't know how to help you, sorry. p.s. did you flush browser cache? |
lib/web/mage/sticky.js
Outdated
stickyClass: '_sticky' | ||
}, | ||
|
||
_optionToNumber(option) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not correct function declaration. Move it out of widget in to module private scope or declare this like method of widget. Also, i have a question, why are you check on type of function offsetTop
and spacingTop
when it's declared below as Number?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, thank you @omiroshnichenko, I missed that. ES6 object shorthand is not currently allowed in Magento JavaScript. This should change to:
_optionToNumber: function(option) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, validate it with static test locallygrunt static --file=lib/web/mage/sticky.js
or rerun travis build.
lib/web/mage/sticky.js
Outdated
|
||
var converted = Number(value); | ||
if (isNaN(converted)) { | ||
throw Error( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have practice to throwing errors in magento js.
lib/web/mage/sticky.js
Outdated
@@ -11,7 +11,26 @@ define([ | |||
|
|||
$.widget('mage.sticky', { | |||
options: { | |||
container: '' | |||
container: '', | |||
spacingTop: 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have been provide new settings properties that by default is Number, no reason to check it on another types. User can't change this property, only developer, when developer will be configuring sticky widget he can look at type of parameter. Also, offsetTop
it's native property of HTMLElement would be nice to change it to another, e.g. blockOffsetTop
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still thinking about a new name for it 😫
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would you say to rename it to stickAfter
or triggerOffset
or stickOffset
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've picked a stickAfter
. It seems that it better and self-explanatory name.
lib/web/mage/sticky.js
Outdated
var stuck = this.element.hasClass(this.options.stickyClass); | ||
if (offset && this.options.offsetTop && !stuck) { | ||
var offsetTop = this._optionToNumber('offsetTop'); | ||
if (offset < offsetTop) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check can be include in upper if
statement via AND(&&) operator.
Hi @vovayatsyuk |
- Removed option type validation - Renamed into getOptionValue as it can be used for any option types
…nt's offsetTop property
Sorry for the delay. I think I'm done. |
_getOptionValue: function (option) { | ||
var value = this.options[option] || 0; | ||
|
||
if (typeof value === 'function') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why you check value on function type? In what case it can be function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be useful to set a function for stickAfter
parameter that will calculate sticky element height when you wish to stick element after it goes out of the viewport and the element could change its height dynamically (shopping cart for example)
You can use different spacing top value for different screen size/orientation also.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, but can you leave docblock with description. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
_sticky
class for "stuck" elementstickAfter
pixels.Screenshots
Default Settings
With spacingTop = 25
With spacingTop = 25 and stickAfter = 60