Forum customization
-
Hey hey thanks Luetage! Looks great! I love the way the top menu hides on scroll
-
A little low-contrast for my taste, but I like the hiding the of the menu (similar to what the forum otherwise does only if initial page load happened in a window below 992px wide, and the window is viewed at 768px wide or greater.)
A CAUTION TO OTHERS:
The script in the extension .crx luetage posted is fine (and luetage has been a helpful Vivaldi Community member for a couple of years already, so I didn't expect anything malicious), but just as a general practice, people should check the files of non-Chrome-Web-Store extensions before installing them. One should check not just ".js" files but any file listed in the manifest.json line
"js": [ "FILNAME1", "FILENAME2"... ]
(Even extensions in the Chrome Web Store should be installed with some caution. Google apparently does some (automated?) analysis of extensions, but sometimes a bad one can slip through.)
Also, one cannot always rely on other people vouching for a particular file link, as files can be changed on the server. (Unless it's hosted at a place with version control like github.com, so people can vouch for a particular version.)
-
Yeah, that's a good practice, I'm using crx viewer myself since back from the new Opera days. Although I'm too lazy to check everything out for extensions from the store before installing them, can't be bothered.
-
Adding a time stamp to the bottom of edited posts:
There already is a little pencil icon after the post date of any post that has been modified, and if you hover it will give an approximate last-edit time, but if you want a more exact timestamp at the bottom of modified posts, we can take advantage of a hidden META tag that posts have. The raw data is a timestamp like "2017-06-08T16:55:58.648Z", so the following CSSS uses ::before and ::after psuedo elements and hidden overflows to isolate the date and time to make it more readable. If you want it at the top of the post, take out the "position:absolute; bottom:0;".
[component='topic'] [component='post'] meta[itemprop="dateModified"][content^="2"] { display: block; position:absolute; bottom:0; font-family:monospace; opacity:0.5; } [component='topic'] [component='post'] meta[itemprop="dateModified"][content^="2"]::before { display: inline-block; overflow:hidden; white-space:nowrap; width:31ch; content: 'Last Modified (UTC): ' attr(content); } [component='topic'] [component='post'] meta[itemprop="dateModified"][content^="2"]::after { display: inline-block; overflow:hidden; white-space:nowrap; width:8ch; text-indent:-11ch; margin-left:1ch; content: attr(content); }
Note: The time stamp shown may not be updated right after you edit a post yourself; you may have to refresh the page.
-
These are the javascript mods I'm using right now. The first one is for hiding the topmenu on scroll, the second one fixes the link (on profile) to the bookmarks page (currently named "favourites" and dysfunctional). I was surprised how useful bookmarks are once you have easy access to them.
var scp = 0; window.addEventListener('scroll', function(){ if (scp > window.scrollY) { document.getElementById("header-menu").style.top = "0px"; } else if (window.scrollY <= 51) { document.getElementById("header-menu").style.top = "0px"; } else if (window.scrollY > 51) { document.getElementById("header-menu").style.top = "-51px"; } scp = window.scrollY; }); document.addEventListener('click', bookmarked); function bookmarked(e) { var favourites = document.querySelector(".dropdown-menu.dropdown-menu-right li:nth-of-type(12) a"); favourites.innerHTML = "Bookmarked"; favourites.href = "/user/USERNAME/bookmarks"; };
-
@luetage said in Forum customization:
the second one fixes the link (on profile) to the bookmarks page (currently named "watched" and dysfunctional). I was surprised how useful bookmarks are once you have easy access to them.
@luetage I think you mean the dysfunctional one named "favorites", which is the one your code replaces. (The "Watched" one works.)
Huh, I hadn't even noticed the intended bookmark functionality for a long time. Good idea making the function get called on click, since that way the link is ready every time the user drops down the menu, even if they navigated to the profile page via AJAX smooth navigation.
For others:
Note that where luetage wrote USERNAME, you need to replace that with yours, but the username must be lowercased, and any periods in the username will need to replaces those with dashes. if you don't want to hardcode in the username, I've edited luetage's code slightly to fetche it from the page:
document.addEventListener('click', bookmarked); function bookmarked(e) { var favourites = document.querySelector(".dropdown-menu.dropdown-menu-right li:nth-of-type(12) a"); var username = document.querySelector('#user-control-list [component="header/username"]').innerHTML.toLowerCase().replace(/\./g, '-');; favourites.innerHTML = "Bookmarked"; favourites.href = "/user/" + username + "/bookmarks"; };
Click a post's bottom-right menu button, and click "Bookmark ".
Reach the Bookmarks page from your profile page's right-hand menu, using either the code that luetage posted (replacing USERNAME with your own username in all-lowercase and with any periods replaced with dashes) or my slightly edited version of it above. Or you can set a browser bookmark to it athttps://forum.vivaldi.net/user/[your lowercased and dashed username]/bookmarks
-
Yeah, it's replacing "favourites" not "watched" obviously, I fixed that in my post now, thanks.
And nice, good idea fetching the username, I didn't think about that, will use it in the extension. The AJAX navigation is giving me big headaches by the way, I wanted to do some other mods but it's sometimes simply too painful working around it. I tried to listen for a hashchange initially, but I didn't get it to work reliably.
-
@luetage said in Forum customization:
The AJAX navigation is giving me big headaches by the way, I wanted to do some other mods but it's sometimes simply too painful working around it. I tried to listen for a hashchange initially, but I didn't get it to work reliably.
Hmm, one possibility is you could define your own onpushstate function and set some delayed code to hopefully execute after the AJAX, something like
(function(history){ var pushState = history.pushState; history.pushState = function(state) { if (typeof history.onpushstate == "function") { history.onpushstate({state: state}); } return pushState.apply(history, arguments); } })(window.history); window.onpopstate = history.onpushstate = function(e) { alert('test (this alert box will pause the thread, just to showing that AJAX stuff is not loaded yet'); setTimeout(function(){ /* stuff to do after a delay for the AJAX stuff to be loaded */ }, 1000); };
(modified from https://stackoverflow.com/a/4585031/8067821 )
See also here and here for variations on registrering the pushState.
-
I see what this is trying to do, but I can't get it to work after all it seems. The problem is the code only triggers on going back or forth in history, it doesn't do anything when just the AJAX navigation is being used. Maybe I'm using it wrong though.
-
I made another javascript mod for the forum extension. Recently someone found out that every member can set a signature by visiting the hidden node.bb settings (https://forum.vivaldi.net/user/username/edit). User signatures can be informative and helpful, but they do also waste a lot of vertical space, and, if the member is a regular poster, you might unwillingly read the sig multiple times a day, and I wanted to do something about it.
window.onload = sig; document.addEventListener('click', sig); function sig() { setTimeout(sig, 500); var signatures = document.querySelectorAll(".post-signature"); var siblings = document.querySelectorAll(".post-signature + .pull-right"); var prevent = document.querySelector(".post-signature + .pull-right button"); for (var i=0; i < signatures.length; i++) { if (prevent == null) { signatures[i].style = "display: none"; var button = document.createElement('button'); button.innerHTML = 'Signature'; siblings[i].insertBefore(button, siblings[i].firstChild); } } var showsig = document.querySelectorAll(".post-signature + .pull-right button"); for (i=0; i < showsig.length; i++) { showsig[i].addEventListener('click', function(i) { signatures[i].style = "display: block"; showsig[i].style = "color: #fd3563; text-decoration: none; cursor: default"; }.bind(this, i)); } };
/* additional css for the button */ .post-signature + .pull-right button { background-color: transparent; color: #006bda; text-decoration: underline; border: none; outline: none; margin-right: 5px; } .post-signature + .pull-right button:hover { text-decoration: none; }
The mod finds and hides all existing signatures on a forum page, and replaces each with a button. When clicked, the button will display the signature of the according post. This way no vertical space is being wasted, you still get to know who runs a signature, and if curious, you can display it.
picture
-
A little tweak to show the user id when hovering a username in forums, just for fun (it's also informative sometimes ^^ )
.clearfix.post-header small.pull-left strong a:hover::after { content: " [UID:"attr(data-UID)"]"; font-size: smaller; }
-
@luetage said in Forum customization:
I see what this is trying to do, but I can't get it to work after all it seems. The problem is the code only triggers on going back or forth in history, it doesn't do anything when just the AJAX navigation is being used. Maybe I'm using it wrong though.
Ah, I have "Paginate topics and posts instead of using infinite scroll" turned on in my settings, so I didn't think of the replaceState situation. If the infinite scroll XHR is what you're referring to, that could similarly be treated with:
(function(history){ var replaceState = history.replaceState; history.replaceState = function(state) { if (typeof history.onreplacestate == "function") { history.onreplacestate({state: state}); } return replaceState.apply(history, arguments); } })(window.history); history.onreplacestate = function(e) { /* do stuff without delay */ setTimeout(function(){ /* stuff to do after a delay, if needed */ }, 500); };
-
@Isildur If you look at my mod above I already have it solved. Even history back and forth works with the code I'm using. I couldn't tell you why but it does
-
I'm thinking about making a general extension for Vivaldi forums. Completely modular, with different themes and all mods from this thread optional from a settings page. Anyone wanna help with this? Does this idea even make sense?
-
-
@sjudenim Looks really cool, just the dropdown menu seems to need a little help, the icons are barely visible.
Also I reported a profile alignment problem yesterday, the avatar isn't centered and the profile cover is partially hidden when visiting other user's profiles. You can fix it with this:
/* Profile alignment fix */ .account .cover .avatar-wrapper { margin-left: -68px !important; } .account .cover { margin-top: 50px; }
-
It's been updated
-
@luetage That's not a bad idea.
What sort of help did you mean? My extension-creating knowledge so far is just limited to the simple kind that applies JS and CSS in hard-coded files as described in the thread's first post. I don't yet have any experience with making extension option pages, but the documentation looks like it's fairly reasonable stuff -- you make a page with checkboxes or whatever and have some calls to load/save it using chrome.storage.sync.get and chrome.storage.sync.set. (see also https://developer.chrome.com/extensions/storage )
-
@Isildur I haven't started yet, so I don't know. But the general plan is to create an options page accessible from the existing menu, or the profile page, and then just make checkboxes for the setup and provide detailed explanations what each item does.
I imagine the hard part will be to make it all compatible, so you don't have combinations of a theme and mods which don't fit (style), have features which cancel each other out, or are repetitive.
-
If you make an extension options page, I guess you could (in addition to presumably making it accessible either via clicking the extension's button or a dropdown from the button), make it accessible via a link from the forum's #user-control-list UL, by injecting a
<li> <a id="launch-extension-options" href="#">Extension settings</a></li>
, and then have an onclick listener in the content script call "chrome.runtime.openOptionsPage()". I think it would need to be a bit indirect, though;chrome.runtime.openOptionsPage()
isn't mentioned in this this limited list of things that are allowed from that script context, so I think you might have to send a message through chrome.runtime.sendMessage() and have an event listener in the extension's background page callchrome.runtime.openOptionsPage()
.As for conflicts, I figure people could try out which ones work well together, and uncheck some of the checkboxes if they don't.