Kami
Forum Cat
Posts: 40,033
Mini-Profile Theme: Kami's Mini-Profile
#f35f71
156500
0
Offline
Jul 24, 2021 11:48:29 GMT -8
Kami
40,033
July 2010
kamiyakaoru
Kami's Mini-Profile
|
Post by Kami on Oct 14, 2018 1:43:34 GMT -8
preface: i'm putting this together on the fly so please be js/jquery 101 friendly when answering! forum url: theavatarrp.comi'm trying to target the new text inside the participated dialogue with jquery. at the moment, $[participated_threads_link] is in my dropdown menu. i'm currently using the below script to a) replace the new in the span with the class .new-icon that appears next to the participated button with a fontawesome icon, and b) to append the same fontawesome icon to an empty span with the class of .newthread__notif to that end i'm using the following script: <script> jQuery(function($) { if ($(".new-icon").length) { $(".new-icon").html("<i class='fas fa-star-exclamation'></i>"); $(".newthread__notif").append(" <i class='fas fa-star-exclamation'></i>"); ;} }); </script>
I had hoped that targeting the .new-icon class would replace the icons as a whole unless overridden in the layout templates. It seemed to work, initially, but when I actually clicked on the Participated link in the menu, the dialogue shows just the text new next to the thread titles (screenshot below) I then tried adding $("#recent-threads .new-icon").html("<i class='fas fa-star-exclamation'></i>"); but to no avail. Is there any way to have the new text in the dialogue also be replaced with the fontawesome icon? Thanks!
|
|
inherit
2671
0
May 14, 2013 14:40:03 GMT -8
Peter
🐺
10,615
February 2002
peter3
|
Post by Peter on Oct 15, 2018 0:57:36 GMT -8
So the issue you have is that the dialog content is dynamic. The first time you click on it, it performs an AJAX request, then populates the dialog with the data that is returned. You can see that when inspecting the element and looking at the click event. You can see that an AJAX request is performed if the recent threads dialog doesn't exist. So this is a one time request per page. Basically you are looking for elements that doesn't exist until the user has clicked on the "Participated" button. So the ready event is useless here. So what can you do? There are a few ways to monitor the DOM for changes, one of those being Mutation Observers. Basically we can watch the DOM for changes, and we get a list of nodes that were added or removed. In this case we are only interested in finding the node that contains the recent threads container. This is simple to do, check the example code below. let observer = new MutationObserver(mutations => { mutations.forEach(mutation => {
if(mutation.addedNodes.length > 0){ for(let i = 0; i < mutation.addedNodes.length; ++ i){ let the_node = mutation.addedNodes[i]; let $recent = $(the_node).find("#recent-threads"); if($recent.length == 1){ $recent.find(".new-icon").each((index, elem) => { console.log(elem); });
break; } } }
}); });
observer.observe($("body").get(0), {
attributes: false, childList: true, characterData: false
});
All we do is observe the body for any nodes added or removed. Once we find the one we are interested in, then we can manipulate the span that is used for the new icon. While Mutation Observers are much more performant that the previous Mutation Events, it's probably not a good idea to watch a big node list like the body. There are some changes you will want to consider if you go down this route. - Don't start observing until the DOM is ready (In your case. So use the ready event).
- Don't observe nodes that could contain big node lists (body in this case is considered a big node list).
- Don't loop through all the mutation nodes if all you are looking for is an element with an id (example code is bad, but the loop is there for you to test).
In regards #3. You will see in my example code above that I am actually looping through all the mutation nodes. This would be bad in your case, since you only care if a specific element with an id exists. So you could bypass the loop and just check for it instead. I included the loop so you can log out the nodes to the console to see how it works.
So what about another solution? Another one we could do is monitor the AJAX request. We could set up a prefilter to basically watch for requests made to the participated threads URL. The benefit of this one, is the code is much simpler to understand than the Mutation Observer above. $.ajaxPrefilter(function(opts, orig_opts){
if(orig_opts.url == proboards.route("participated_threads")){ let orig_success = orig_opts.success;
opts.success = data => { orig_success(data); let $new_icons = $("#recent-threads").find(".new-icon"); $new_icons.each((index, elem) => { console.log(elem); }); }; } });
As you can see, easier to understand, and much smaller. The downside of this one compared to the mutation observer, is that ProBoards controls more of the underlying code which could break your filter. Chances of them changing anything now is extremely small, but it's something to consider if you are releasing a plugin or theme. One day it will work, the next day a small change like the URL for the AJAX request could break it. I personally would go with the filter in this case. But anyway, there are 2 options from a list that I feel would be better solutions in your case.
|
|
Kami
Forum Cat
Posts: 40,033
Mini-Profile Theme: Kami's Mini-Profile
#f35f71
156500
0
Offline
Jul 24, 2021 11:48:29 GMT -8
Kami
40,033
July 2010
kamiyakaoru
Kami's Mini-Profile
|
Post by Kami on Oct 15, 2018 6:41:05 GMT -8
Wow, thanks for such a detailed and easy to understand breakdown! I’ll definitely test this out later today when I have some free time.
Thanks Peter!
|
|
inherit
2671
0
May 14, 2013 14:40:03 GMT -8
Peter
🐺
10,615
February 2002
peter3
|
Post by Peter on Oct 16, 2018 2:19:12 GMT -8
No probs. I didn't go too in depth with the explanations, especially the prefilter, so post back if you have any questions. The Mutation Observers isn't something you will see very often here. I think only me and Chris use them. So I was kinda debating if I should even post about them. But you know, it's nice to have options
|
|
Kami
Forum Cat
Posts: 40,033
Mini-Profile Theme: Kami's Mini-Profile
#f35f71
156500
0
Offline
Jul 24, 2021 11:48:29 GMT -8
Kami
40,033
July 2010
kamiyakaoru
Kami's Mini-Profile
|
Post by Kami on Oct 17, 2018 15:07:08 GMT -8
So after some fiddling around I actually managed to do this with CSS, but thank you anyway for the help!
|
|
inherit
2671
0
May 14, 2013 14:40:03 GMT -8
Peter
🐺
10,615
February 2002
peter3
|
Post by Peter on Oct 18, 2018 6:17:13 GMT -8
Maybe share your CSS solution for others that stumble across this, even if it's a basic explanation for them.
|
|
Kami
Forum Cat
Posts: 40,033
Mini-Profile Theme: Kami's Mini-Profile
#f35f71
156500
0
Offline
Jul 24, 2021 11:48:29 GMT -8
Kami
40,033
July 2010
kamiyakaoru
Kami's Mini-Profile
|
Post by Kami on Oct 18, 2018 10:41:06 GMT -8
Good idea Peter ! I added the following to my CSS: #recent-threads .new-icon a { width:0px; color: transparent; } #recent-threads .new-icon::before { content: "\f2f3"; font-style: normal; font-weight: 900; font-family: "Font Awesome 5 Pro"; font-variant: normal; text-rendering: auto; color: @gold_light;/*show when child of*/ } Some notes: the "Font Awesome Pro" font is a pay-for font, but you should be able to use this with the Font Awesome Free font as well. \f2f3 is the HTML entity for this particular text icon, and it will not work without Font Awesome added to your forum. @gold _light; is a colour variable determined earlier in my CSS, but you can replace this with your standard hexadecimal colour.
|
|