Helping Avoid Overly-wide Code Blocks in Posts

Straight to the point… Use

<small>
image
/*.. your code ... */
image
</small>

Without <small>


/*\
title: $:/core/modules/widgets/eventcatcher.js
type: application/javascript
module-type: widget

Event handler widget

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

var Widget = require("$:/core/modules/widgets/widget.js").widget;

var EventWidget = function(parseTreeNode,options) {
	this.initialise(parseTreeNode,options);
};

/*
Inherit from the base widget class
*/
EventWidget.prototype = new Widget();

/*
Render this widget into the DOM
*/
EventWidget.prototype.render = function(parent,nextSibling) {
	var self = this;
	// Remember parent
	this.parentDomNode = parent;
	// Compute attributes and execute state
	this.computeAttributes();
	this.execute();
	// Create element
	var tag = this.parseTreeNode.isBlock ? "div" : "span";
	if(this.elementTag && $tw.config.htmlUnsafeElements.indexOf(this.elementTag) === -1) {
		tag = this.elementTag;
	}	
	var domNode = this.document.createElement(tag);
	this.domNode = domNode;
	// Assign classes
	this.assignDomNodeClasses();	
	// Add our event handler
	$tw.utils.each(this.types,function(type) {
		domNode.addEventListener(type,function(event) {
			var selector = self.getAttribute("selector"),
				actions = self.getAttribute("actions-"+type),
				selectedNode = event.target,
				selectedNodeRect,
				catcherNodeRect,
				variables = {};
			if(selector) {
				// Search ancestors for a node that matches the selector
				while(!selectedNode.matches(selector) && selectedNode !== domNode) {
					selectedNode = selectedNode.parentNode;
				}
				// If we found one, copy the attributes as variables, otherwise exit
				if(selectedNode.matches(selector)) {
					$tw.utils.each(selectedNode.attributes,function(attribute) {
						variables["dom-" + attribute.name] = attribute.value.toString();
					});
					//Add a variable with a popup coordinate string for the selected node
					variables["tv-popup-coords"] = "(" + selectedNode.offsetLeft + "," + selectedNode.offsetTop +"," + selectedNode.offsetWidth + "," + selectedNode.offsetHeight + ")";
					
					//Add variables for offset of selected node
					variables["tv-selectednode-posx"] = selectedNode.offsetLeft.toString();
					variables["tv-selectednode-posy"] = selectedNode.offsetTop.toString();
					variables["tv-selectednode-width"] = selectedNode.offsetWidth.toString();
					variables["tv-selectednode-height"] = selectedNode.offsetHeight.toString();

					//Add variables for event X and Y position relative to selected node
					selectedNodeRect = selectedNode.getBoundingClientRect();				
					variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
					variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString();

					//Add variables for event X and Y position relative to event catcher node
					catcherNodeRect = self.domNode.getBoundingClientRect();
					variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString();
					variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString();
				} else {
					return false;
				}
			}
			// Execute our actions with the variables
			if(actions) {
				// Add a variable for the modifier key
				variables.modifier = $tw.keyboardManager.getEventModifierKeyDescriptor(event);
				// Add a variable for the mouse button
				if("button" in event) {
					if(event.button === 0) {
						variables["event-mousebutton"] = "left";
					} else if(event.button === 1) {
						variables["event-mousebutton"] = "middle";
					} else if(event.button === 2) {
						variables["event-mousebutton"] = "right";
					}
				}
				variables["event-type"] = event.type.toString();
				if(typeof event.detail === "object" && !!event.detail) {
					$tw.utils.each(event.detail,function(detailValue,detail) {
						variables["event-detail-" + detail] = detailValue.toString();
					});
				} else if(!!event.detail) {
					variables["event-detail"] = event.detail.toString();
				}
				self.invokeActionString(actions,self,event,variables);
				event.preventDefault();
				event.stopPropagation();
				return true;
			}
			return false;
		},false);
	});
	// Insert element
	parent.insertBefore(domNode,nextSibling);
	this.renderChildren(domNode,null);
	this.domNodes.push(domNode);
};

/*
Compute the internal state of the widget
*/
EventWidget.prototype.execute = function() {
	var self = this;
	// Get attributes that require a refresh on change
	this.types = this.getAttribute("events","").split(" ");
	this.elementTag = this.getAttribute("tag");
	// Make child widgets
	this.makeChildWidgets();
};

EventWidget.prototype.assignDomNodeClasses = function() {
	var classes = this.getAttribute("class","").split(" ");
	classes.push("tc-eventcatcher");
	this.domNode.className = classes.join(" ");	
};

/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
EventWidget.prototype.refresh = function(changedTiddlers) {
	var changedAttributes = this.computeAttributes();
	if(changedAttributes["events"] || changedAttributes["tag"]) {
		this.refreshSelf();
		return true;
	} else if(changedAttributes["class"]) {
		this.assignDomNodeClasses();
	}
	return this.refreshChildren(changedTiddlers);
};

exports.eventcatcher = EventWidget;

})();

With <small>

/*\
title: $:/core/modules/widgets/eventcatcher.js
type: application/javascript
module-type: widget

Event handler widget

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

var Widget = require("$:/core/modules/widgets/widget.js").widget;

var EventWidget = function(parseTreeNode,options) {
	this.initialise(parseTreeNode,options);
};

/*
Inherit from the base widget class
*/
EventWidget.prototype = new Widget();

/*
Render this widget into the DOM
*/
EventWidget.prototype.render = function(parent,nextSibling) {
	var self = this;
	// Remember parent
	this.parentDomNode = parent;
	// Compute attributes and execute state
	this.computeAttributes();
	this.execute();
	// Create element
	var tag = this.parseTreeNode.isBlock ? "div" : "span";
	if(this.elementTag && $tw.config.htmlUnsafeElements.indexOf(this.elementTag) === -1) {
		tag = this.elementTag;
	}	
	var domNode = this.document.createElement(tag);
	this.domNode = domNode;
	// Assign classes
	this.assignDomNodeClasses();	
	// Add our event handler
	$tw.utils.each(this.types,function(type) {
		domNode.addEventListener(type,function(event) {
			var selector = self.getAttribute("selector"),
				actions = self.getAttribute("actions-"+type),
				selectedNode = event.target,
				selectedNodeRect,
				catcherNodeRect,
				variables = {};
			if(selector) {
				// Search ancestors for a node that matches the selector
				while(!selectedNode.matches(selector) && selectedNode !== domNode) {
					selectedNode = selectedNode.parentNode;
				}
				// If we found one, copy the attributes as variables, otherwise exit
				if(selectedNode.matches(selector)) {
					$tw.utils.each(selectedNode.attributes,function(attribute) {
						variables["dom-" + attribute.name] = attribute.value.toString();
					});
					//Add a variable with a popup coordinate string for the selected node
					variables["tv-popup-coords"] = "(" + selectedNode.offsetLeft + "," + selectedNode.offsetTop +"," + selectedNode.offsetWidth + "," + selectedNode.offsetHeight + ")";
					
					//Add variables for offset of selected node
					variables["tv-selectednode-posx"] = selectedNode.offsetLeft.toString();
					variables["tv-selectednode-posy"] = selectedNode.offsetTop.toString();
					variables["tv-selectednode-width"] = selectedNode.offsetWidth.toString();
					variables["tv-selectednode-height"] = selectedNode.offsetHeight.toString();

					//Add variables for event X and Y position relative to selected node
					selectedNodeRect = selectedNode.getBoundingClientRect();				
					variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString();
					variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString();

					//Add variables for event X and Y position relative to event catcher node
					catcherNodeRect = self.domNode.getBoundingClientRect();
					variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString();
					variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString();
				} else {
					return false;
				}
			}
			// Execute our actions with the variables
			if(actions) {
				// Add a variable for the modifier key
				variables.modifier = $tw.keyboardManager.getEventModifierKeyDescriptor(event);
				// Add a variable for the mouse button
				if("button" in event) {
					if(event.button === 0) {
						variables["event-mousebutton"] = "left";
					} else if(event.button === 1) {
						variables["event-mousebutton"] = "middle";
					} else if(event.button === 2) {
						variables["event-mousebutton"] = "right";
					}
				}
				variables["event-type"] = event.type.toString();
				if(typeof event.detail === "object" && !!event.detail) {
					$tw.utils.each(event.detail,function(detailValue,detail) {
						variables["event-detail-" + detail] = detailValue.toString();
					});
				} else if(!!event.detail) {
					variables["event-detail"] = event.detail.toString();
				}
				self.invokeActionString(actions,self,event,variables);
				event.preventDefault();
				event.stopPropagation();
				return true;
			}
			return false;
		},false);
	});
	// Insert element
	parent.insertBefore(domNode,nextSibling);
	this.renderChildren(domNode,null);
	this.domNodes.push(domNode);
};

/*
Compute the internal state of the widget
*/
EventWidget.prototype.execute = function() {
	var self = this;
	// Get attributes that require a refresh on change
	this.types = this.getAttribute("events","").split(" ");
	this.elementTag = this.getAttribute("tag");
	// Make child widgets
	this.makeChildWidgets();
};

EventWidget.prototype.assignDomNodeClasses = function() {
	var classes = this.getAttribute("class","").split(" ");
	classes.push("tc-eventcatcher");
	this.domNode.className = classes.join(" ");	
};

/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
EventWidget.prototype.refresh = function(changedTiddlers) {
	var changedAttributes = this.computeAttributes();
	if(changedAttributes["events"] || changedAttributes["tag"]) {
		this.refreshSelf();
		return true;
	} else if(changedAttributes["class"]) {
		this.assignDomNodeClasses();
	}
	return this.refreshChildren(changedTiddlers);
};

exports.eventcatcher = EventWidget;

})();

2 Likes

The suggestion to use <small> really sucks for those of us with aging eyeballs.

Well, having half of the screen used-up by obscenely large left and right margins sucks just as much, so these eyeballs are stuck between a rock and a hard place.

Take my gripe with a huge grain of salt, because I’m probably the only bottom-dweller still depending on the old discussion group, try as I might to get used to this one.

Hey @Charlie_Veniot – I had answered elsewhere that if you or someone else in the community wants to research CSS / Discourse theming, we can include a theme that changes the margins and can be selected by users. Just like @pmario already added the simpler theme.

I don’t really know CSS so can’t be helpful with the design.

@CodaCoder there is probably a “wrap” property in CSS that can soft-wrap lines rather than just making it smaller, but I don’t know enough CSS.

Anyone else got the CSS chops for this?

A quick search showed me this Make "Pre" Text Wrap | CSS-Tricks – maybe something @pmario can add to the default theme as a snippet to experiment with?

yes, something like whitespace:pre-wrap?

IMO, code should never be wrapped. The best solution would be a button which, when clicked, launches the code in a popup window (I have that somewhere in a tampermonkey script).

I’m one of those with aging eyes. But scrolling right on a pitifully narrow box is worse, IMO.

Cognitively, I’m really not up to the frustrations of that challenge.

I do make a point of visiting a few times per day, hoping that at some point I’ll warm up to this new forum.

But I’m the guy who prefers to use a manual can opener because the sound of an electric can opener is irritating.

Over-stimulation by sensory and/or cognitive overload. Good thing it isn’t catchy.

.

Yeah, that’s kind of why I brought up a couple of times that the left and white margins are way too big.

But that’s on my 27 inch display.

Getting rid of those margins would give more width to view code, but I don’t think it would be helpful for folk using mobile devices, and discourse seems like a mobile-first product.

Maybe it would be good for code blocks to have a “open in new window” kind of feature. Along with no margin, a phone could be flipped sideways to better view source code.

Something like that.

Seems I misremembered… it wasn’t a tampermonkey script, per se, it’s a script I wrote with intentions to add it to tampermonkey.

If someone wants to slide it into the code blocks here, be my guest:

WITHDRAWN - it used to work... seems I have a bug

Drop that in the devtools console. Change the last line to any post number you want from the given page.

Is window.open() blocked here, @boris ?

Answering it myself - yes it is. It works fine on another discourse implementation.

If someone researches Discourse themes that is where it could be added correctly.

@Charlie_Veniot – As for <small> and aging eyeballs, if you have a wide monitor (as it sounds like you also do), if you use your browser’s zoom function it will use the extra space at the sides of your screen to make the code a more easily readable size without reducing the amount you can see.

Yeah, I know. Zoom in/out is but a CTRL +/- away.

Makes the code bigger in a good way, but makes everything else bigger in a bad way. Like being screamed at.

Cognitive bleurk.

Thanks for the suggestion, but there is no fixing “this” (as I point to my cranium), and one could waste an unhealthy amount of time/effort trying to either make things fit me and/or make me fit things. (Square peg, meet round hole.)

No worries, I’ll figure something out.

There’s nothing incorrect about using the console – at least, not for POCs.

Here’s what it should look like, using it to popup a copy of its own source (how’s that for dogfooding?)

Just to repeat… this was executed on another discourse site, in the console, to dump a copy of the code as posted in the thread there. If window.open wasn’t hijacked (probably to null) on this site, this code would work.

The next step would be to site a button next to the “copy” button on the code blocks here and run a hosted copy of this code.