-
-
Notifications
You must be signed in to change notification settings - Fork 51
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
!node-insert - Script not running on page load for Safari and sometimes Chrome #18
Comments
Have you tried bootstrapping your code using the |
https://cdpn.io/petermonte/debug/Vwwqgjv/LDAmdnPpbExr I've updated the script to make Sentinel only run once ...
const _components = [];
function registerComponent(_name, _selector, _callback) {
_components.push({
name: _name,
selector: _selector,
callback: _callback
});
return true;
}
document.addEventListener('sentinel-load', function () {
sentinel.on('!node-inserted', function (el) {
var i = 0;
const lth = _components.length;
for (i; i < lth; i++) {
const component = _components[i];
if (el.matches(component.selector)) {
component.callback(el);
}
}
});
});
... |
The There's a lot of extra code in the example. Can you isolate the bug with a simpler script? For example, does this work when you run it locally on Safari? <!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
@keyframes changeColor {
0% {
color: blue;
transform: translateX(-10px);
}
100% {
color: black;
transform: translateX(0);
}
}
.example-cls {
animation-duration: 1s;
animation-name: changeColor, node-inserted;
transform: translateX(0);
}
</style>
<script src="https://cdn.rawgit.com/muicss/sentineljs/0.0.5/dist/sentinel.min.js"></script>
<script>
sentinel.on('!node-inserted', function (el) {
el.innerHTML = "Sentinel is always watching";
});
</script>
</head>
<body>
<!-- element to be parsed by sentinel -->
<div class="example-cls"><div>
</body>
</html> What is it that you want to do differently? |
Here is you're code in a simple way isolate from any other script.
Imagine a UI Kit that offers (per example):
Let say that all 3 features exist isolated or combined like so: How would you implement such UI Kit given that you need to trigger all existing elements on DOM at page load and any new added to the DOM via script? |
When I click on the codepen link I see a "This debug view expired" message. From the description of what you're trying to do it sounds like you might be running into a race condition between the page load event and the <html>
<head>
<script src="/path/to/sentinel.js"></script>
<script>
sentinel.on('custom-element', function(el) {
el.innerHTML = "Sentinel is always watching";
});
</script>
</head>
<body>
<custom-element></custom-element>
</body>
</html> Alternatively, if you want to bootstrap your code after the <html>
<head>
<script src="/path/to/sentinel.js"></script>
</head>
<body>
<custom-element></custom-element>
<script>
function modifyElement(el) {
el.innerHTML = "This element has been modified";
}
document.addEventListener('DOMContentLoaded', function(ev) {
// process previously defined DOM elements
document.querySelectorAll('custom-element').forEach(modifyElement);
// initialize sentinel
sentinel.on('custom-element', modifyElement);
});
</script>
</body>
</html> |
let me put things in a simple way by using your example. Need to slightly change it because you only target one element base on the css animation name. I'm targeting multiple elements, based on multiple kinds of selectors. Environment:
This is the markup: <div class="example-cls" data-attr="abc" title="Title For Tooltip">ON DOM</div>
<!--
I expect a call on Sentinel based on a div tagname
I expect a call on Sentinel based on an attribute named title
I expect a call on Sentinel based on an attribute called data-attr
I expect a call on Sentinel based on a classname example-css
--> This is the CSS: @keyframes change-color {
0% {
color: blue;
transform: translateX(-10px);
}
100% {
color: black;
transform: translateX(0);
}
}
div, /* I expect a call on Sentinel based on a tagname */
[title], /* I expect a call on Sentinel based on an attribute named title */
[data-attr], /* I expect a call on Sentinel based on an attribute called data-attr */
.example-cls /* I expect a call on Sentinel based on a classname example-css */
{
animation-duration: 1s;
animation-name: change-color, node-inserted;
transform: translateX(0);
} This is the JS: function modifyElement(el) {
// I increment the innerHTML so that I can count how many times an element is caught by Sentinel
el.innerHTML += " Sentinel ";
}
window.addEventListener('DOMContentLoaded', function (ev) {
document.querySelectorAll('[data-attr], .example-cls, [title]').forEach(modifyElement);
sentinel.on('!node-inserted', modifyElement);
});
// Added a click to generate markup on the fly
document.addEventListener('click', function () {
const div = document.createElement('div'); // I expect a call on Sentinel based on a tagname Div
div.textContent = 'ADDED ';
div.className = 'example-cls'; // I expect a call on Sentinel based on classname example-cls
div.dataset.attr = 'abc'; // I expect a call on Sentinel based on attibute data-attr
div.title = 'hello'; // I expect a call on Sentinel based on attibute title
document.body.append(div);
}); This is what I get (Safari, Firefox, Chrome): This is what I expected: This is the code editor: https://codepen.io/petermonte/pen/XWWKRNv |
First, with regards to "ON DOM Sentinel" I think the difference in behavior between the browsers is related to a race condition between function modifyElement(el) {
(if (!el._upgraded) el.innerHTML != " Sentinel ";
el._upgraded = true;
}
window.addEventListener("DOMContentLoaded", function(ev) {
document.querySelectorAll('[data-attr], .example-cls, [title]').forEach(\
modifyElement);
sentinel.on('!node-inserted', modifyElement);
}); This will result in consistent "ON DOM Sentinel" behavior across browsers. Second, with regards to "ADDED Sentinel Sentinel Sentinel" it sounds like what you're expecting is for the browser to trigger |
Thanks man. I was almost going crazy trying to figure out what was happening. My purpose with this thread was to understand how sensible Sentinel is with how "each browser deals differently with events for script execution and page load".
On another topic but related to this thread I realised that Sentinel when used with the
sentinel.on('.my-target', function(){}, true);
// Last boolean parameter stands for using the generic animation name [node-inserted] to catch any element on DOM
// So if a specific selector has already an animation name declared an additional one will be added: my-animation, node-inserted This means that we could use the following logic: // Both these events can occur or not on a same element
sentinel.on('.my-target', function(){
// My code specifically for any new element added with the classname .my-target
}, true);
sentinel.on('[title]', function(){
// My code specifically for any new element added that has a title attribute to use has a tooltip
}, true); In the meantime this is my workaround (Click anywhere to add new elements to DOM): Edit: Forgot to include the css. @keyframes my-animation {
0% {
color: blue;
}
100% {
color: black;
}
}
[title],
[data-attr],
.tabs {
animation-duration: 1s;
animation-name: my-animation, node-inserted;
} // Interface to record every single constructor that can be called on an element based on its selector
const components = [];
function registerComponent(_name, _selector, _callback) {
// Register our component
components.push({
name: _name,
selector: _selector,
callback: _callback
});
return true;
}
function initElement(el) {
// Run the element through our components and find matches
components.forEach(component => el.matches(component.selector) ? component.callback(el) : null);
return true;
}
// Interface to manage elements on DOM and when added to DOM
let sentinelRanAtDomContentLoaded = false;
sentinel.on('!node-inserted', el => {
if (!sentinelRanAtDomContentLoaded){
sentinelRanAtDomContentLoaded = true;
}
initElement(el);
});
document.addEventListener('DOMContentLoaded', e => {
if (!sentinelRanAtDomContentLoaded){
components.forEach(function(component){
document.querySelectorAll(component.selector).forEach(function(el){
component.callback(el);
});
});
sentinelRanAtDomContentLoaded = true;
}
}, true);
/**
* Usage. Every single selector has its own context
*/
registerComponent(
'tabs',
'.tabs',
function tabs(el) {
// RUN EVERYTHING NEEDED FOR THE COMPONENT
return el;
}
);
registerComponent(
'title-attr',
'[title]',
function attrTitle(el) {
// RUN EVERYTHING NEEDED FOR THE COMPONENT
return el;
}
);
registerComponent(
'data-attr',
'[data-attr]',
function dataAttr(el) {
// RUN EVERYTHING NEEDED FOR THE COMPONENT
return el;
}
); |
No problem. Happy to hear that helped.
Can you describe this in more detail? What do you mean by script execution time? The time when the browser parses and executes the "sentinel.js" script?
It sounds like what you want is SentinelJS to execute all three callbacks in this example: <script>
sentinel.on('div', function callback1() {});
sentinel.on('.example-cls', function callback2() {});
sentinel.on('[example-attr]', function callback3() {});
</script>
<div class="example-cls" example-attr="value"></div> Is that correct? |
Why can't you use the
The example snippet wasn't intended to work, I posed it as a theoretical example to see if that is what you are asking for. |
Ah! sorry, my bad. Yes, that is the idea. To have as many calls I want on a same element. |
Yes, in fact my text practically describes the event So to sum things up and for the sake of simplicity two issues are raised here on my comments: 1 - Bug: Safari - Version 14.0.2 (16610.3.7.1.9) on MacOS Big Sur 11.1 Sentinel seems to sometimes not parse elements that are at DOM on page load. Using 2 - Feature: Run separate callbacks with different selectors on a same element. |
Sentinel isn't designed to detect elements at
This would require calling |
You're right when it comes to the event https://cdpn.io/petermonte/debug/LYPKKQQ/yokZEpWRVwyA <div class="node_inserted">!node-inserted</div>
<div class="class_name">class name</div> .node_inserted {
animation-name: node-inserted;
animation-duration: 0.001s;
} sentinel.on('!node-inserted', function(el) {
el.innerHTML += ' <b>Sentinel node-inserted watch!</b>';
});
sentinel.on('.class_name', function(el) {
el.innerHTML += ' <b>Sentinel class_name watch!</b>';
}); sentinel.mov
Thought so. Possible solution might be a simple wrapper for those who need such functionality. If no element is being targeted for more than a simple selector/callback then definitely there is no need to change anything on Sentinel. Conclusion: Can't thank you enough for your support! |
I tried clicking on the codepen link but it says the "Debug view is expired". In your previous code example, I think you were adding a Sentinel listener after you defined the DOM elements. However, if you want Sentinel to detect the <!doctype html>
<html>
<head>
<script src="//cdn.rawgit.com/muicss/sentineljs/0.0.5/dist/sentinel.min.js"></script>
<style>
@keyframes changeColor {
0% {color: red;}
100% {color: black;}
}
.example-cls {
animation-duration: 1s;
animation-name: changeColor, node-inserted;
}
</style>
<script>
sentinel.on('!node-inserted', function(el) {
el.innerHTML = "Sentinel is always watching";
});
</script>
</head>
<body>
<div class="example-cls"></div>
</body>
</html> I tested this code on Safari 14.0.3/Big Sur 11.2 repeatedly and didn't see Sentinel miss any recording.movI have some other thoughts to share on the |
Tests:
If you make script run at execution time you will see that Safari ignores all markup on DOM at hard refresh.
If you make script run only on Window Load event Safari ignores all markup on DOM at execution time.
If you make script run only on Document readystatechange event Safari ignores all markup on DOM on hard refresh.
If you make script run only on Window DOMContentLoaded event all 3 browsers ignore markup on DOM at execution time.
Code:
Editor mode - https://codepen.io/petermonte/pen/Vwwqgjv?editors=0010
Debug mode - https://cdpn.io/petermonte/debug/Vwwqgjv/PNrvYXGWZBPM
Specs:
Screen recordings:
https://user-images.githubusercontent.com/4997381/106580084-652e3380-6539-11eb-8137-9ffea143c4ec.mov
https://user-images.githubusercontent.com/4997381/106580430-d0780580-6539-11eb-8b80-d9ce14444d18.mov
This is a request by @amorey in #8 (comment)
The text was updated successfully, but these errors were encountered: