Doing it wrong userscripts - Show raw
-
Let's add some stuff to Discourse! And, if possible, stuff that is deemed as Doing it Wrong™
Users need no stinkin' info! Info is a barrier to reading.
So, time to add some: specifically topic ID, post ID (not reply number, although it's easy to modify it to that), and, as a bonus, clicking it shows you the raw form of the post so you can bask in the glory of Markdown, HTML and BB code, all in one post:
Script:
// ==UserScript== // @name TDWTH - Show raw button // @namespace TDWTF // @description Shows raw form of the post in a new tab // @include http://what.thedailywtf.com/t/* // @version 1 // @grant none // ==/UserScript== Ember.View.reopen({ didInsertElement: function () { this._super(); Ember.run.scheduleOnce('afterRender', this, this.insertRawButton); }, insertRawButton: function () { } }); Discourse.View.reopen({ insertRawButton: function () { // This thing triggers for any render, so we check if a post has been rendered if (this.post) { // Get post ID var postID = this.post.post_number; // Get topic ID var topicID = this.post.topic_id; // Find action area for the post var actionArea = $('button[data-post-number="' + postID + '"][data-action="share"]') .parent('.actions'); // This triggers for every render, so we check for existence of the button if (actionArea.children('.tdwtf-view-raw') .length == 0) { // Add the button! actionArea.prepend('<button title="view raw post" class="tdwtf-view-raw" onclick="window.open(\'http://what.thedailywtf.com/raw/' + topicID + '/' + postID + '\', \'_blank\');"><i class="fa fa-code"></i>#' + topicID + ':' + postID + '</button>'); } } } });
Suggestions, bug reports, fixes and shit can go below. Github repo is possible if a need arises. Or just stick it up there yourself, I don't care. Released under WTFPL.
-
YMMV
- New post toolbar (quote, bold, italic as a minimum) to mobile view reply box.
- Right gutter on zoom > 100% (thanks @pjh)
- fa-spin?
- Reply to images directly to the left of the timestamp in both mobile and desktop views (max 20x20 px?)
- If reply box is open, on desktop -> escape to close reply window, on mobile back (phone hardware button or emulated hardware button) hides the reply, a second tap navigates back. (if reply window == hidden, navigate back)
- If notification window is open, on desktop -> escape to close the notification window, on mobile back (phone hardware button or emulated hardware button) hides the notification window, a second tap navigates back (if notification window == hidden, navigate back)
- Make "quote" act exactly like
something
-
Some of these are CSS changes and that's implementable by @PJH from admin panel AFAIK, so that's nice.
I wasn't aware some of those things were missing in mobile view. Again, I guess most of it is just a matter of few CSS overrides. I'd be happy to help with it though, so if I figure it out I guess I can make a userstyle which could be copied into the "official" CSS almost verbatim.
Also, that quote seems to render differently in mobile, good job! I don't know what you mean by it though, and if it's doable clientside, whatever it is.
-
Quote Quote
"Quote""Quote"
[ Quote] quote
quote
quote
and that's just before embedded quotes.
-
Ah, I see. I guess the best way would be a CSS hack on the <aside> element so it's transparent if added to site's CSS.
Might poke around that later tonight, seems simple enough.
Also, my user stats thing aligns it wrong in mobile view, though I don't know how much of a problem that is anyway, since you can't really use userscripts on mobile AFAIK.
-
- Right gutter on zoom > 100% (thanks @pjh)
- Right gutter on zoom < 100% as well please.
I wasn't aware some of those things were missing in mobile view. Again, I guess most of it is just a matter of few CSS overrides. I'd be happy to help with it though, so if I figure it out I guess I can make a userstyle which could be copied into the "official" CSS almost verbatim.
There is a separate stylesheet available for mobile. The interface I have:
Specifically the Stylesheet (desktop only) and Mobile Stylesheet (mobile only) are the CSS ones.
-
Ok, you are going to laugh... No, actually, you are going to cry, because this is so fucking simple and no one tested it!
It would seem that setting
.topic-body { padding-right: 0; } /* Now to restore the padding */ .ember-view-gutter { padding-left: 11px; }
Does it. Overrode it inline though, going to apply it as a user style and click around stuff in different browsers, but it seems to not break anything and fixes zoom on Firefox at least.
-
I'm going to try the Preview function of that admin area since I think I have a handle on how it (the customisation) works now..
(For the interested, apparently only one of the CSS customisations listed down the left hand size there can be applied at any one time.)
-
but it seems to not break anything and fixes zoom on Firefox at least.
Confirming same on Chrome where it was previously broken. I've submitted your CSS to meta, and added it to the site CSS (not mobile obviously) until it gets fixed. Or we're told why it's broken....
-
- Make "quote" act exactly like
something
.cooked blockquote { padding-top: 0; }
Seems to do it fairly well. Nested... well, kinda? No idea what to do with them anyway tbh, they look weird either way.
I know I'm taking on simple shit, but each time I expect something hard I do it in 3 lines of CSS... What gives Discurse devs?
-
I know I'm taking on simple shit, but each time I expect something hard I do it in 3 lines of CSS... What gives Discurse devs?
Do it in jquery/javascript instead of CSS.
Report back in.
-
Do it in jquery/javascript instead of CSS.
I could make a userscript that injects an <aside> around every <blockquote> that doesn't already have it before the post renders.
Or, you can do it in CSS.
Oh, wait, this is not SO, this is just a troll. Damn it!
-
Also, I know we went off-topic here (oh, the humanity!), but I genuinely expected almost nothing here and at least some interest in the user info userscript :P
-
Oh. This isn't the fix discourse thread?
-
When I'm at home, and if I feel like mucking around with it, I'll poke around with it (and the other one) and see what I can come up with.
-
Oh. This isn't the fix discourse thread?
There's an entire Discourse install dedicated to that and they still haven't managed it. I kinda doubt this thread will do anything much, no matter what we talk about.
When I'm at home, and if I feel like mucking around with it, I'll poke around with it (and the other one) and see what I can come up with.
If you could figure out how to override shit in
Discourse.PostView
instead ofDiscourse.View
it would most likely help with performance on both. But, so far, it hasn't panned out for me.
-
Decided to have some fun with this one.
// ==UserScript== // @name TDWTH - Show raw button // @namespace TDWTF // @description Shows raw form of the post in a new tab // @include http://what.thedailywtf.com/t/* // @version 1 // @grant none // ==/UserScript== function getRawPost(e) { if (!window.cookedPostStash) window.cookedPostStash = new Array(); topicId = e.data.topicId; postId = e.data.postId; var actionArea = $('button[data-post-number=\"' + postId + '\"][data-action=\"share\"]').parent('.actions'); var callingButton = actionArea.children('.tdwtf-view-raw')[0]; var postArea = actionArea.parents('div.contents').children('.cooked')[0]; if (callingButton.className == 'tdwtf-view-raw') { callingButton.className = 'tdwtf-view-raw dummy'; cookedPostStash[postId] = postArea.innerHTML; $.get('/raw/' + topicId + '/' + postId, function(content){ $(postArea).text(content); postArea.innerHTML = '<pre>' + postArea.innerHTML + '</pre>' });} else { callingButton.className = 'tdwtf-view-raw'; postArea.innerHTML = cookedPostStash[postId]; } } Ember.View.reopen({ didInsertElement: function () { this._super(); Ember.run.scheduleOnce('afterRender', this, this.insertRawButton); }, insertRawButton: function () { } }); Discourse.View.reopen({ insertRawButton: function () { // This thing triggers for any render, so we check if a post has been rendered if (this.post) { // Get post ID var postID = this.post.post_number; // Get topic ID var topicID = this.post.topic_id; // Find action area for the post var actionArea = $('button[data-post-number="' + postID + '"][data-action="share"]') .parent('.actions'); var postArea = actionArea.parents('div.contents').children('.cooked')[0]; // This triggers for every render, so we check for existence of the button if (actionArea.children('.tdwtf-view-raw') .length == 0) { // Add the button! actionArea.prepend('<button title="view raw post" class="tdwtf-view-raw"><i class="fa fa-code"></i>#' + topicID + ':' + postID + '</button>').children('.tdwtf-view-raw').on("click", { topicId: topicID, postId: postID }, getRawPost); } } } });
Full of really ugly TDWTF-worthy hacks, sure, but works. Try to break it, if you can.
-
Brillant!
-
This post is deleted!
-
I have now switched to this script for regular use. Scrollbars are a bit annoying but there's not much that can be done there. Less annoying than a new tab for sure.
Actually... now that I think about it...
-
Scrollbars are a bit annoying but there's not much that can be done there.
You can drop the
<pre>
tags. They work for me in Chrome.Also, the script fails to load on first page load / refresh, because reasons.
-
Works for me on first load. Weird. Aaaanyway:
// ==UserScript== // @name TDWTH - Show raw button // @namespace TDWTF // @description Shows raw form of the post in a new tab // @include http://what.thedailywtf.com/t/* // @version 1 // @grant none // ==/UserScript== // WARNING! Stupidity ahead! function transformHtml(htmlString) { return htmlString .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, """) .replace(/'/g, "'") .replace(/\n/g, "<br>"); } function getRawPost(e) { if (!window.cookedPostStash) window.cookedPostStash = new Array(); topicId = e.data.topicId; postId = e.data.postId; var actionArea = $('button[data-post-number=\"' + postId + '\"][data-action=\"share\"]').parent('.actions'); var callingButton = actionArea.children('.tdwtf-view-raw')[0]; var postArea = actionArea.parents('div.contents').children('.cooked')[0]; if (callingButton.className == 'tdwtf-view-raw') { callingButton.className = 'tdwtf-view-raw dummy'; cookedPostStash[postId] = postArea.innerHTML; $.get('/raw/' + topicId + '/' + postId, function(content){ $(postArea).html(transformHtml(content)); postArea.innerHTML = '<div style="font-family: monospace;">' + postArea.innerHTML + '</div>' });} else { callingButton.className = 'tdwtf-view-raw'; postArea.innerHTML = cookedPostStash[postId]; } } Ember.View.reopen({ didInsertElement: function () { this._super(); Ember.run.scheduleOnce('afterRender', this, this.insertRawButton); }, insertRawButton: function () { } }); Discourse.View.reopen({ insertRawButton: function () { // This thing triggers for any render, so we check if a post has been rendered if (this.post) { // Get post ID var postID = this.post.post_number; // Get topic ID var topicID = this.post.topic_id; // Find action area for the post var actionArea = $('button[data-post-number="' + postID + '"][data-action="share"]') .parent('.actions'); var postArea = actionArea.parents('div.contents').children('.cooked')[0]; // This triggers for every render, so we check for existence of the button if (actionArea.children('.tdwtf-view-raw') .length == 0) { // Add the button! actionArea.prepend('<button title="view raw post" class="tdwtf-view-raw"><i class="fa fa-code"></i>#' + topicID + ':' + postID + '</button>').children('.tdwtf-view-raw').on("click", { topicId: topicID, postId: postID }, getRawPost); } } } });
This is sooo XSS-able, isn't it?
-
Question -------- Can you make the raw view use the **syntax highlighter** from the post [preview](http://example.com)?
Oh look it has no styles associated with it. Hmm...
-
Oh look it has no styles associated with it. Hmm...
There was something in PostView named attemptHighliting or something. Maybe.
-
$(postArea).html(transformHtml(content));
Do you explicitly want something unescaped? Setting
.text()
should work equally well.
-
Gaaah! It was fucking up newlines and I went with the WTF-yest solution, of course. I replaced shit anyway, I should've just...
// ==UserScript== // @name TDWTH - Show raw button // @namespace TDWTF // @description Shows raw form of the post in a new tab // @include http://what.thedailywtf.com/t/* // @version 1 // @grant none // ==/UserScript== function getRawPost(e) { if (!window.cookedPostStash) window.cookedPostStash = new Array(); topicId = e.data.topicId; postId = e.data.postId; var actionArea = $('button[data-post-number=\"' + postId + '\"][data-action=\"share\"]').parent('.actions'); var callingButton = actionArea.children('.tdwtf-view-raw')[0]; var postArea = actionArea.parents('div.contents').children('.cooked')[0]; if (callingButton.className == 'tdwtf-view-raw') { callingButton.className = 'tdwtf-view-raw dummy'; cookedPostStash[postId] = postArea.innerHTML; $.get('/raw/' + topicId + '/' + postId, function(content){ $(postArea).text(content); postArea.innerHTML = '<div style="font-family: monospace;">' + postArea.innerHTML.replace(/\n/g, '<br>') + '</div>' });} else { callingButton.className = 'tdwtf-view-raw'; postArea.innerHTML = cookedPostStash[postId]; } } Ember.View.reopen({ didInsertElement: function () { this._super(); Ember.run.scheduleOnce('afterRender', this, this.insertRawButton); }, insertRawButton: function () { } }); Discourse.View.reopen({ insertRawButton: function () { // This thing triggers for any render, so we check if a post has been rendered if (this.post) { // Get post ID var postID = this.post.post_number; // Get topic ID var topicID = this.post.topic_id; // Find action area for the post var actionArea = $('button[data-post-number="' + postID + '"][data-action="share"]') .parent('.actions'); var postArea = actionArea.parents('div.contents').children('.cooked')[0]; // This triggers for every render, so we check for existence of the button if (actionArea.children('.tdwtf-view-raw') .length == 0) { // Add the button! actionArea.prepend('<button title="view raw post" class="tdwtf-view-raw"><i class="fa fa-code"></i>#' + topicID + ':' + postID + '</button>').children('.tdwtf-view-raw').on("click", { topicId: topicID, postId: postID }, getRawPost); } } } });
There we go.
-
Also, found a bug. View refreshes break the toggle on the button.
-
Can you make the raw view use the syntax highlighter from the post preview?
Replace the
$get
call with:$.get('/raw/' + topicId + '/' + postId, function(content){ $(postArea).text(content); postArea.innerHTML = '<pre><code>' + postArea.innerHTML + '</code></pre>'; $(postArea).children().each(function(i, block) {hljs.highlightBlock(block);}); });
If that's what you mean (and you really need to). It seems to break more than it fixes.
Also, found a bug. View refreshes break the toggle on the button.
Yeah, I've seen it break once or twice. Not really sure how to work around it.
-
Why are you constructing a new jQuery over and over?
-
Why are you constructing a new jQuery over and over?
Because I'm kinda lazy. And it's open source, so fix it yourself.
seriously though, if that's the only WTF you see there, that's weak
-
I can't see more WTFs personally because I'm too damned tired atm.
And it's not simply open source, it's Do What The Fuck You Want To Public License. While it does fall under OS I feel it's important to additionally emphasise that.
-
Confirming same on Chrome where it was previously broken. I've submitted your CSS to meta, and added it to the site CSS (not mobile obviously) until it gets fixed. Or we're told why it's broken....
Right gutter still appears to be broken in Private Messages - the envelope icon is in the wrong place.
-
Okay. Got rid of some of the WTF-y solutions (not all though). Button toggle can now survive page updates. If a post you're viewing as raw gets edited you get returned to the regular view though. Should be simple-ish fix but I have to get back to real work now.
// ==UserScript== // @name TDWTH - Show raw button // @namespace TDWTF // @description Shows raw form of the post in a new tab // @include http://what.thedailywtf.com/t/* // @version 1 // @grant none // ==/UserScript== function getRawPost(e) { var topicID = e.data.topicID; var postID = e.data.postID; var callingButton = $(e.target); // Fuck your inconsistency Discourse! Why don't post numbers match??? Now I have to do this shit... var postArea = $('button[data-post-number="' + postID + '"][data-action="share"]') .closest('.contents'); callingButton.toggleClass('active'); if (callingButton.hasClass('active')) { //Prettify callingButton.css({backgroundColor: '#08C', color: '#FFF'}); if (postArea.children('.tdwtf-raw-area') .length == 0 || postArea.children('.tdwtf-raw-area') .html() == '') { $.get('/raw/' + topicID + '/' + postID) .done(function (content) { if (postArea.children('.tdwtf-raw-area') .length == 0) { postArea.children('.cooked') .after('<div style="font-family: monospace; padding-top: 15px;" class="tdwtf-raw-area"></div>'); postArea.children('.cooked') .hide(); } postArea.children('.tdwtf-raw-area') .text(content); postArea.children('.tdwtf-raw-area') .html(postArea.children('.tdwtf-raw-area') .text() .replace(/\n/g, '<br>')); }); } else { postArea.children('.cooked') .hide(); postArea.children('.tdwtf-raw-area') .show(); } } else { //Unprettify :( callingButton.css({backgroundColor: 'transparent', color: '#A7A7A7'}); postArea.children('.cooked') .show(); postArea.children('.tdwtf-raw-area') .hide(); } } Ember.View.reopen({ didInsertElement: function () { this._super(); Ember.run.scheduleOnce('afterRender', this, this.insertRawButton); }, insertRawButton: function () { } }); Discourse.View.reopen({ insertRawButton: function () { // This thing triggers for any render, so we check if a post has been rendered if (this.post) { // Get post ID var postID = this.post.post_number; // Get topic ID var topicID = this.post.topic_id; // Find action area for the post var actionArea = $('button[data-post-number="' + postID + '"][data-action="share"]') .parent('.actions'); var postArea = actionArea.parents('div.contents') .children('.cooked') [0]; // This triggers for every render, so we check for existence of the button if (actionArea.children('.tdwtf-view-raw') .length == 0) { // Add the button! actionArea.prepend('<button title="view raw post" class="tdwtf-view-raw" data-post-id="' + postID + '"><i class="fa fa-code"></i>#' + topicID + ':' + postID + '</button>') .children('.tdwtf-view-raw') .on('click', { topicID: topicID, postID: postID }, getRawPost); } } } });
-
Can't repro. Or my memory of where it should be is wrong?
-
Hmm, this line:
postArea.children('.tdwtf-raw-area') .html(postArea.children('.tdwtf-raw-area') .text() .replace(/\n/g, '<br>'));
seems to break
<img>
escaping. For some reason.Otherwise, yeah, that's way better.
EDIT: yeah, well, you're putting all markup in
.html()
property, which probably unescapes it or something. Can't you style<pre>
, or perhaps<textarea>
for word-wrapping somehow? It works in Chrome on Windows without scrollbars, and it preserves linebreaks...
-
Hmmm...
.html
may be doing something to it. I'll try to revert to the old version later and see if it's broken there too. In worst case scenario, manually replacing<
and>
with<
and>
as an extra step (after filtering through.text
) should do it.Also, I'll set up a repo for the scripts later today. I have another one all planned out too :)
-
What browser do you use, anyway? I still think you should look at styling the
<pre>
element withwhite-space: pre-wrap;
or other things mentioned in the SO answers I linked. There's definitely no need to manually replace.Also, I'll set up a repo for the scripts later today. I have another one all planned out too
I'm kind of lacking creativity. Maybe I'll make a pagination script...
Filed under: hope jeff doesn't hear it
-
tell jeff tell jeff tell jeff
-
What browser do you use, anyway? I still think you should look at styling the <pre> element with white-space: pre-wrap; or other things mentioned in the SO answers I linked. There's definitely no need to manually replace.
I tried it and it still refused to wrap around in Firefox. I agree that it's a better solution, but I either did something wrong or Firefox is being an ass.
I'm kind of lacking creativity. Maybe I'll make a pagination script...
I kinda want to do that too, yeah. I'm learning how DC works by doing this so I can give it a go and hopefully have some idea of what I'm doing.
But hey, I don't hold a copyright on doing shit
withto Discourse.
-
tell jeff tell jeff tell jeff
I was thinking of spamming it over on meta when we make a decent collection of them on Github :P
-
Fuck yes. Team TDWTF, coming again to save the motherfucking day yeah.
-
+1. That thread.
-
Hm, Firefox seems broken in general to me. Doing
$.get('/raw/705/1', function(r){console.log(r);});
returns the main page instead of the raw page.
What in the name of...
-
Are you logged in?
/raw/
only works if you're logged in.I know. Bad ideas thread / Sidebar. Take your pick.
-
-
Yeeah, that makes sense. Anyway:
// ==UserScript== // @name TDWTH - Show raw button // @namespace TDWTF // @description Shows raw form of the post // @include http://what.thedailywtf.com/t/* // @include *what.thedailywtf.com/t/* // @version 1 // @grant none // ==/UserScript== function getRawPost(e) { var topicID = e.data.topicID; var postID = e.data.postID; var callingButton = $(e.target); // Fuck your inconsistency Discourse! Why don't post numbers match??? Now I have to do this shit... var postArea = $('button[data-post-number="' + postID + '"][data-action="share"]') .closest('.contents'); callingButton.toggleClass('active'); if (callingButton.hasClass('active')) { //Prettify callingButton.css({backgroundColor: '#08C', color: '#FFF'}); if (postArea.children('.tdwtf-raw-area') .length == 0 || postArea.children('.tdwtf-raw-area') .html() == '') { $.get('/raw/' + topicID + '/' + postID) .done(function (content) { if (postArea.children('.tdwtf-raw-area') .length == 0) { postArea.children('.cooked') .after('<pre class="tdwtf-raw-area"></pre>'); postArea.children('.cooked') .hide(); } postArea.children('.tdwtf-raw-area').css("white-space", "pre-wrap") .text(content); //postArea.children('.tdwtf-raw-area') .html(postArea.children('.tdwtf-raw-area') .text() .replace(/\n/g, '<br>')); }); } else { postArea.children('.cooked') .hide(); postArea.children('.tdwtf-raw-area') .show(); } } else { //Unprettify :( callingButton.css({backgroundColor: 'transparent', color: '#A7A7A7'}); postArea.children('.cooked') .show(); postArea.children('.tdwtf-raw-area') .hide(); } } Ember.View.reopen({ didInsertElement: function () { this._super(); Ember.run.scheduleOnce('afterRender', this, this.insertRawButton); }, insertRawButton: function () { } }); Discourse.View.reopen({ insertRawButton: function () { // This thing triggers for any render, so we check if a post has been rendered if (this.post) { // Get post ID var postID = this.post.post_number; // Get topic ID var topicID = this.post.topic_id; // Find action area for the post var actionArea = $('button[data-post-number="' + postID + '"][data-action="share"]') .parent('.actions'); var postArea = actionArea.parents('div.contents') .children('.cooked') [0]; // This triggers for every render, so we check for existence of the button if (actionArea.children('.tdwtf-view-raw') .length == 0) { // Add the button! actionArea.prepend('<button title="view raw post" class="tdwtf-view-raw" data-post-id="' + postID + '"><i class="fa fa-code"></i>#' + topicID + ':' + postID + '</button>') .children('.tdwtf-view-raw') .on('click', { topicID: topicID, postID: postID }, getRawPost); } } } });
seems to work nicely in both FF and Chrome. Aside from Chrome still failing to show the button after refresh, only on navigation inside Disco-curse.
-
seems to work nicely in both FF and Chrome
Fucking hell! I think I know what it was now. I was adding style information inline and that probably failed for some stupid reason.
Aside from Chrome still failing to show the button after refresh, only on navigation inside Disco-curse.
That might a problem with the Ember override. Will check it out tonight.
-
Can't repro. Or my memory of where it should be is wrong?
Proper patch fixing underlying problems, rather than sticking plaster put over the top of the symptoms, was issued this morning and is now on here. And I suspect in-place when you took your screendump.
-
Lies. CDCK doesn't know how to do anything other than stick plasters over the top of terribad design.
-
No complaints here. Less hacks, more (hopefully) proper fixes.
Do you get patch notes in the admin panel? I'd like to see the commit, wonder what they did.