The Return of the view raw button
-
@FrostCat said:
@RaceProUK Also, we really need the equivalent of the View Raw button back.
my DOM manioulation skills fail me, this will add a button, fetch the raw and display it in an annoying alert.
one cookie to anyone who wants to make it do the whole toggle between showing the raw and the cooked on subsequent clicks, and also for making it look better.
// ==UserScript== // @name View Raw Button // @match https://what.thedailywtf.com/* // @grant none // ==/UserScript== 'use strict'; $(window).on('action:ajaxify.contentLoaded', function(){ $('.post-tools:not(a.viewRaw)').prepend('<a class="viewRaw" href="#" class="no-select">View Raw</a>'); }); $('.post-tools:not(a.viewRaw)').prepend('<a class="viewRaw" href="#" class="no-select">View Raw</a>'); $(document).on('click', 'a.viewRaw', null, function(){ var post = $(this).closest('li[component=post]'); var pid = post.data('pid'); socket.emit('posts.getRawPost', pid, function(err,rawContent){ if (err){ alert(err); } alert(rawContent); }); }); // Your code here...
-
@accalia said:
one cookie to anyone who wants to make it do the whole toggle
Sigh. But then I'd have to learn more JS.
-
@FrostCat fiiiiiine......
if it's frostcat he can have the whole dozen cookies.
i was going to share them with the orphans.... but if you need them more....
-
You're like, one line between appending the content to the dom and toggling it back, methinks....
-
@Tsaukpaetra have at it my friend then.
i fiddels with it for ten minutes or so before deciding to give it to y'all to solve instead.
-
@accalia said:
have at it my friend then.
Awe darn, challenge received just before I go to excercises... Hmm choices...
-
If it helps, here's @Onyx47's code for the Discourse button.
-
I got bored and poked at this a bit.
There's probably a prettier way to handle the raw formatting than just wrapping it in
<pre>
tags and calling it good, or duplicating the other buttons styles to format the link, but I'm not feeling like working it out right now.Undefined behavior will result if the post is updated while you're viewing raw. There's probably an event (on that magic
socket
black box thing I'm being too lazy to Google?) I could listen to for updates, but I'm not feeling it right now.// ==UserScript== // @name View Raw Button // @match https://what.thedailywtf.com/* // @grant none // ==/UserScript== 'use strict'; var viewRawButton = '<a class="view-raw no-select" href="#">View Raw</a>'; $('<style>a.view-raw { background-color: #337ab7; color: white; padding: 10px; margin-right: 3px; }</style>').appendTo('head'); $(window).on('action:ajaxify.contentLoaded', function(){ $('.post-tools:not(a.view-raw)').prepend(viewRawButton); $('a.view-raw').off('click', showRaw); $('a.view-raw').on('click', showRaw); }); $('.post-tools:not(a.view-raw)').prepend(viewRawButton); $('a.view-raw').off('click', showRaw); $('a.view-raw').on('click', showRaw); function showRaw() { var button = $(this); var post = button.closest('li[component=post]'); var pid = post.data('pid'); socket.emit('posts.getRawPost', pid, function(err, rawContent) { if (err) { if (console && console.error) { console.error(err); } else { alert(err); } } var contentElement = post.find('div.content'); var oldContentHtml = contentElement.html(); var oldHeight = contentElement.height(); var encodedRaw = $('<div/>').text(rawContent).html(); // String concatination is the best way to build any DOM element contentElement.html('<pre>' + encodedRaw + '</pre>'); // prevent some ugly height popping if (contentElement.height() < oldHeight) { contentElement.height(oldHeight); } button.off('click', showRaw); button.on('click', showContent); function showContent() { contentElement.html(oldContentHtml); button.off('click', showContent); button.on('click', showRaw); } }); }
Edited to fix a couple bugs.
-
@AngleOSaxon
socket
is just the socket.io websocket that the forum uses to communicate with the server. i hijacked it for getting the post raw. ;-)
-
@AngleOSaxon said:
just wrapping it in
<pre>
tagsLong lines of text don't wrap. Other than that, it works really well.
-
@NedFodder Bootstrap has decently styled
<code>
tags IIRC, but I don't know how they handle wrapping in that.
-
@Onyx I just tried
<code>
and I have somewhat the opposite problem. Text wraps just fine, but all newlines are stripped out.
-
@NedFodder In that case, I guess a
<pre>
with a custom class will be the easiest?
-
@NedFodder said:
newlines are stripped out
-
@Onyx That's beyond my skills.
Also, when new posts stream in, they don't get the view raw button.
-
@hungrier HTML ignores
\n
s and\r
s. That's why there's a<br>
tag.<pre>
element is special in that regard: it will render the plaintext representation of what ever you give it.
-
@Onyx Yes, that works beautifully. So I can apply the style to all
pre
thingys, what I don't know how to do is that custom class stuffs. Do you mean something like<pre class="raw-post-content">
?
-
@NedFodder That's what I was thinking, yes. Maybe also add a border or something, but that's territory...
And you change the CSS from
pre { ...
topre.raw-post-content { ...
, of course ;)
-
@NedFodder said:
Also, when new posts stream in, they don't get the view raw button.
must be missing an event then.....
-
@Onyx I thought
<code>
might be special in a similar way. However I did find while fiddling thatwhite-space: pre-wrap;
looks pretty good for line-wrapped, preformatted code.
-
@accalia said:
must be missing an event then.....
I changed it from
ajaxify.contentLoaded
toposts.loading
and it seems to work.Next problem, @Onyx : The
pre
stuff is wrapping the text, but it does it in the middle of words instead of on whitespace.
-
-
@NedFodder said:
Next problem, @Onyx : The pre stuff is wrapping the text, but it does it in the middle of words instead of on whitespace.
Darn, didn't expect that... Maybe fiddle with
word-wrap
CSS property? I honestly don't know off the top of my head, and still at work now so no time to play with it much.
-
I think
pre-line
instead ofpre-wrap
does what you want.
-
@AngleOSaxon That didn't change anything for me, but
word-break: normal;
worked.
-
@FrostCat Just put the container for the raw in the same LI in the same position as the content class, and swap visibilities. You can load the raw on demand.
-
Actually,
posts.loaded
did work. A little too well. It prepends the button every time a new post (or batch of posts) streams in. I got up to 4 buttons at one point...
-
@NedFodder OK, I solved that problem by removing all the buttons and adding them back on
posts.loaded
(with a combination ofgetElementsByClassName("view-raw")
andremoveChild
). There's gotta be a better way...
-
@NedFodder Check if they exist before adding them?
-
@RaceProUK I couldn't figure out how to do that. On a related note, I don't know anything about JS, DOM, CSS, etc...
-
Did you try
<pre><code>
? That's pretty standard for multi-line code blocks.
-
Okay, Imma go dive into the docs, see if I can suss out the plugin architecture and make a proper Thing™.
-
Ok, so, update, NodeBB's docs on building plugins are... not great but it all looks reasonable enough, shouldn't be much of a problem.
However!
It seems that plugins have to be npm packages... Meaning I now have to learn npm in order to even start hacking away. Yay.
... can we go back to userscripts?
-
@Onyx If you can get the JS working, the other sockdevs have published stuff to NPM before and can probably show you how
-
@Yamikuronue The problem is that it seems that it has to be a node module for it to even get loaded by NodeBB. The docs would seem to suggest there's another way but it's not described anywhere.
-
@Yamikuronue said:
If you can get the JS working, the other sockdevs have published stuff to NPM before and can probably show you how
Or @ben_lubar will have it deployed while you are still shitting around with your pants around your ankles.
-
The
$('a.view-raw').on('click', showRaw);
stuff should all be removed and replaced with$(document).on('click', '.view-raw', showRaw);
(just once, don't need it in the event handler). (Edit: dammit, that worked for a while and now it doesn't work after a refresh. Greasemonkey is pissing me off!)@Onyx @boomzilla Here's the plugin code to add a button to every post:
-
@Onyx said:
The problem is that it seems that it has to be a node module for it to even get loaded by NodeBB. The docs would seem to suggest there's another way but it's not described anywhere.
As near as I can tell, being a node module isn't required, but looking like one is. Seems like you can imitate the expected format well enough and drop a folder into
node_modules
to have NodeBB pick it up without publishing it (see below).I uploaded a bare-bones plugin that adds the View Raw button to Github here, if you want to take that as a starting point. It's not published as an npm package (not even sure the
packages.json
has enough data to be valid for npm), but you ought to be able togit clone
it down into yournode_modules
folder and restart your instance of NodeBB to have it picked up.Seemed to work okay while I was playing with it on my test instance, but you know what they say about programmers testing their own code.
I haven't checked the code, but NodeBB appears to search the
nodebb/node_modules/
directory for any folders prefixed withnodebb-plugin
, and checks those to see if they have the right definition files (package.json
andplugin.json
) to be plugins.It's important to note that, despite what the docs imply about NodeBB only using
plugin.json
, both files are required, and metadata is pulled from both.The package name, description, and version number will all be pulled from the
package.json
file (which needs to look like an npm package file), while the support URL and nodebb-relevant configuration will be pulled fromplugin.json
.If
package.json
doesn't exist, NodeBB will not deign to notice your plugin. If name or version number aren't set, it will crash.
-
@NedFodder said:
Actually,
posts.loaded
did work. A little too well. It prepends the button every time a new post (or batch of posts) streams in. I got up to 4 buttons at one point...Try using
'.post-tools a:first-child[component="post/reply"]'
to select Reply buttons if they're the first child. Once you add the raw button, the Reply button isn't the first child so you won't get more than one raw button.edit: okay, this really isn't a good method because it assumes that things inside
.post-tools
won't ever change. Better would be to use @accalia's modified jQuery code,$('.post-tools:not(:has(a.viewRaw))')
, or filter it with Javascript as I did in the code I posted further down this topic.
-
@anotherusername personally i go for
$('.post-tools:not(a.viewRaw)')
as that selects the post tools sections that don't have a view raw button (assuminga.viewRaw
matches the view raw button) so that it's no longer order dependent
-
@AngleOSaxon said:
As near as I can tell, being a node module isn't required, but looking like one is.
In Node, the map is the territory: if you export anything to module.exports, you're a module. NPM publication is never really required, it just has to be someplace NPM can get at it if you want it to be able to be installed. NPM can install from Github, from a git URL, from a number of places.
-
Status update: Ok, figured out how to package the raw with the post so we don't have to pull it on each click. Hopefully it's not much of an overhead. Unfortunately, the button adding thing @NedFodder linked to doesn't really work. I'll try poking around the templates, see if something got renamed.
-
@Yamikuronue said:
if you
export anything to module.exportsare a .js file, you're a module.@Yamikuronue said:
NPM publication is never really required, it just has to be someplace NPM can get at it if you want it to be able to be installed.
you also need a
package.json
to be installed via NPMyes, that is overloading the term a bit to call individual files modules as well as what you install via NPM....
basically a module is anything that you can
require()
and NPM installs packages that happen to be treated as modules byrequire()
i wish they had come up with better terminology.
-
@accalia said:
basically a module is anything that you can require()
I beg to differ, unless you consider a flat JSON file a "module"
-
@accalia said:
@anotherusername personally i go for
$('.post-tools:not(a.viewRaw)')
as that selects the post tools sections that don't have a view raw button (assuminga.viewRaw
matches the view raw button) so that it's no longer order dependentDid you try it?
$('.post-tools:not(a.viewRaw)')
is still selecting.post-tools
witha.viewRaw
child elements...That seems correct, anyway. The
.not
pseudo-class applies to the node you're trying to select. You're selecting the.post-tools
node, which doesn't matcha.viewRaw
, so it matches.post-tools:not(a.viewRaw)
. It doesn't matter if it contains a node that matchesa.viewRaw
; that's not the node being selected so it doesn't affect the rule at allTo actually make it order-independent, you wouldn't be able to do it in pure CSS... you'd need to select
.post-tools
and then use Javascript to filter out any that containa.viewRaw
descendant nodes.
-
Anyone have the source to that userscript?
post-tools
is the stuff in the dotburger menu, no?
-
@anotherusername said:
$('.post-tools:not(a.viewRaw)')
huh... okay then.....
$('.post-tools:not(:has(a.viewRaw))')
that works.
-
-
-
@Yamikuronue said:
In Node, the map is the territory: if you export anything to module.exports, you're a module.
I know I'm hairsplitting here, but in my head I wasn't considering it a node module because I'm not adding anything to
module.exports
, and I'm not adding it to the install location'spackages.json
(which is what I originally worried NodeBB was checking).@anotherusername said:
To actually make it order-independent, you wouldn't be able to do it in pure CSS... you'd need to select .post-tools and then use Javascript to filter out any that contain a.viewRaw descendant nodes.
You can't do it in pure CSS, but you can use JQuery's selectors to do something like
'.post-tools:not(:has(a.view-raw))'
. I don't want to think about the complexity of that, but it will filter out any.post-tools
that already containa.view-raw
.Edit: by @accalia.
Although does it count as a if I checked it in last night?