Multi-line Text Ellipsis

CSS can only add ellipsis to a single line of text. Here’s how to do it in Javascript using lodash:

// Update wrapping text to limit the number of lines.
var maxLines = 2;
var textEls = document.getElementsByClassName('text-els-class');
var textMaxH = Math.ceil(textEls[0].getBoundingClientRect().height) * maxLines;

_.forEach(textEls, function(el) {

    el.style.whiteSpace = 'normal';

    var elH = el.getBoundingClientRect().height;
    var isOverflow = elH > textMaxH;
    var text = el.innerHTML;

    // Remove the last word until the height is within bounds.
    while (elH > textMaxH) {

        text = (text
            .split(' ')
            .slice(0,-1)
            .join(' ')
        );
        el.innerHTML = text;
        elH = el.getBoundingClientRect().height;
    }

    if (isOverflow) {
        title.innerHTML += ' ...';
        title.style.maxHeight = titleMaxH + 'px';
    }
});

Seven Tenets

  • Strive to act with compassion and empathy toward all creatures in accordance with reason.
  • The struggle for justice is an ongoing and necessary pursuit that should prevail over laws and institutions.
  • One’s body is inviolable, subject to one’s own will alone.
  • The freedoms of others should be respected, including the freedom to offend. To willfully and unjustly encroach upon the freedoms of another is to forgo your own.
  • Beliefs should conform to our best scientific understanding of the world. We should take care never to distort scientific facts to fit our beliefs.
  • People are fallible. If we make a mistake, we should do our best to rectify it and resolve any harm that may have been caused.
  • Every tenet is a guiding principle designed to inspire nobility in action and thought. The spirit of compassion, wisdom, and justice should always prevail over the written or spoken word.

Redol Landing I

Dropping in, it looks abstract. But now that it’s closer, I can tell it’s Gweorlian; probably shoaniperag. Going lower down until it gets clearer. The shapes of the crop fields and forest lines become jagged with the texture of the life inside them. Down further until it’s almost like walking on the ground. There are burn marks in the shoaniper field from a landing party. There’s the shiny spot on the horizon near the treeline.

Dropping in, it looks abstract. But now that it’s closer, I can tell it’s Gweorlian; probably shoanipag. Going lower, it gets clearer. The shapes of the crop fields and forest lines become jagged with the texture of the life inside them. Down further until it’s almost like walking on the ground. There are burn marks in the shoaniper field from a landing party. There’s the shiny spot on the horizon near the treeline. When I get closer, I know it’s the Gretchen class landing ship that I can never identify. Who makes a ship so shiny? Obviously not a tactical vessel. The shoaniper is short; looks like it was harvested recently. No aerli, which is unusual for harvest. But there are some small mamli near the treeline. Probably checking the absurd mirror ship to scavenge. Rolling across the field at triple. Once I’m past the ship, the harvest field is monotonous; I’m not taking precautions, just cutting triple. Up ahead at the edge of the field is the long low building. White. No windows. Simple geometry with flat walls and squared angles. It’s long like one of the history bunkers. It stretches from the treeline across the field: the length of three Gretchens, easy. There is a door. I’m going toward the door again. It’s like a relic door with a doorknob. I put my hand on the knob and it turns easily.

“Oh shit.” The blood lights flood and I open my eyes. I’m back in the wake at the psyen lab again. And there he is, as usual. Peering at me with his oversize officer scrubs and his curious face. He’s looking different today though. He looks… alarmed? Maybe because I cursed. He already reviewed this sleep several times; I’m not sure what has changed. The sleep hasn’t changed for weeks. “Excuse me, Medicius Senior. The wake was abrupt today.”

“It’s OK, Kirik. That was good. Thank you.”

“OK, are we done or do you need more?”

“No, we’re done for today. You can go back to quarters. Just remember to keep the the monitor on for your sleep.”

I see his cosci through the window in the monitor room suddenly look up at me. Then the Medicius puts on his best stern face and locks eyes with me. “Kirik, it’s crucial that the monitor stays on for your sleep.” Short pause as his cosci turns back to the monitors, “I need you to tell me you understand.”

“Yes Medicius Senior, I understand.” How this guy is a Medicius Senior is what I do not understand. He’s at least ten seasons younger than me.

Prep Cook Human

I was slicing the hard-boiled eggs for the salad bar at the pantry station when Gabriela stopped crumbling the cheese and turned to me. She told me she wanted me to hear the new song she wrote last night. I stopped slicing the eggs. I opened my mouth as if to speak but in that instant realized I had no words, only anticipation. She smiled as though she understood. Then she started to sing.

I can tell you how
This world made your father blind

And you can tell me how
Your father made
Your mother lose her mind

Entelechy

  • the realization of potential.
  • the supposed vital principle that guides the development and functioning of an organism or other system or organization.
  • the soul.

Destroying a Javascript API

Problem:

  • A third party JS API doesn’t have a destroy method.
  • The JS API can only be instantiated once per page view.
  • Writing a single page app by its nature requires a dynamic DOM
  • Dynamic DOM will require the JS API to be spun up and destroyed on multiple elements during the life cycle of the page view

What to do?

Answer: Destroy it yourself. By highjacking the events as they are created, you can gather a collection of all events that the JS API has created during instantiation. When it’s time to destroy the JS API, reference your collection of events to remove them from the window:


var _apiE 		= []; // Array of JS API Events.
var _scriptTag 	= null; 

var _methods: {

	initJsApi: function() {
		// Hook the native event listener to capture JS API events.
		// Preserve the original native method.
		var ogAddEventListener = window.addEventListener;

		// Override the native method.
		window.addEventListener = function() {

			// Capture JS API events.
			_apiE.push({
				type: 			arguments[0],
				listener: 		arguments[1],
				useCapture: 	arguments[2]
			});

			// Call the original native method after capturing the event 
			// so JS API and the browser do their business as usual.
			ogAddEventListener.apply(this, arguments);
		};

		// Add the <script> tag to the DOM dynamically to load the JS API.
		// jQuery will inject ?_0000 cache buster to script tag src attribute value.
		// Some sites will not allow the JS API to be requested with the querystring present.
		// Use native element to work around this.
		_scriptTag = document.createElement('script');
		_scriptTag.setAttribute('src', 		'https://js-api-cdn.com/js/third-party-api.min.js');
		_scriptTag.setAttribute('type', 	'text/javascript');
		_scriptTag.setAttribute('id', 		'js-api-script');
		$('html').append(_scriptTag);

		// Wait for the JS API to instantiate after the <script> has been attached to the DOM.
		var intvl = setInterval(function() {

			if (window.jsApi) { // The actual name of the API object would go here.

				clearInterval(intvl);

				// Instantiate the JS API.
				window.jsApi.init({ options });

				// Reset the native event listener to the original method so we stop capturing events.
				window.addEventListener = ogAddEventListener;
			}
		}, 5);
	},

	destroyJsApi: function() {

		// Remove the <script> tag and instance of the JS API.
		$('#js-api-script').remove();
		delete window.jsApi;

		// Remove the events that the JS API added.
		$.each(_apiE, function(i, e) {

			window.removeEventListener(e.type, e.listener, e.useCapture);
		});
	}
};

Danger: other events that are registered while waiting for the JS API to instantiate will also get removed.