status

Functions that create a "status bar" to display messages and ask for user input

View the Project on GitHub dwachss/status

status

Promise functions to create a “status bar” to display messages and to ask for user input.

Adds two functions to Promise: Promise.alert and Promise.prompt, and adds one function to Promise.prototype: Promise.prototype.alert. The latter is a non-enumerable property, so it won’t mess up for...in loops on actual objects.

Optionally uses my dwachss/historystack.

A previous version that was a set of plugins for jQuery is still available as version 1.0. This release is completely different.

Promise.prompt

Asks for user input, just like window.prompt(message, defaultValue), but asynchronously, so it returns a Promise that is resolved with the user input, or rejected if the user canceled.

Usage

Promise.prompt(message = '', container = globalThis, defaultValue = '').then (response => do something).catch (cancelError => do something else);

If container is a DOM element, then the following is prepended to the element:

<label><strong>message</strong><input /></label>

with keydown handlers, such that Enter resolves the Promise with the value of the input element, Escape rejects the Promise.

If historystack is included, it creates a History that keeps track of past entries in container, and the ArrowUp and ArrowDown go back and forward, respectively, through that history.

After an Enter or Escape the created elements are removed.

If element is not a DOM element (i.e. Promise.prompt('Enter data:')) then it simply uses container.prompt(), which is a modal dialog. If container does not have a prompt method, the Promise will reject with a TypeError.

Localization

The error message for canceling is Promise.prompt.cancelMessage = "User Cancelled" and can be changed for localization.

Promise.alert

Displays a message and returns a Promise that is resolved with the message or rejected with an error.

Usage

Promise.alert(message, container = globalThis); 

The method turns message into a Promise with Promise.resolve(message). If that promise resolves to an instance of Error, it rejects with that error. If it rejects, an error message is displayed with that error. If it resolves, it displays the message. The Promise is returned for further thening.

If container is a DOM element, then <span role=alert >message or error</span> is prepended to it. The span is given a class of success or failure depending on whether the Promise resolved or rejected (for appropriate CSS). Then the class hidden is added to the span. The assumption is that span[role=alert] has a CSS transition attached it, and span[role=alert].hidden evokes that transition. The span has an ontransitionend handler that removes it. For example:

	span[role=alert] {
		transition: opacity 4s 2s;
	}
	span[role=alert].hidden {
		opacity: 0;
	}
	span[role=alert].success {
		color: green;
	}
	span[role=alert].failure {
		color: red;
	}

will remove the element after 6 seconds. If there is no transition, then the user has to take responsibility for removing the message.

If container is not a DOM element, then uses container.log or container.error appropriately, if those exist, or container.alert to display the message. Since alert doesn’t distinguish between errors and messages, a ⚠️ is prepended to the message.

Either way, a rejected Promise is handled with catch, so the final promise returned will be resolved with a value of undefined.

Examples

Promise.alert('Finished').then(doOtherWork);

Promise.alert(new Error('Failed')).then(doOtherWork);

Promise.alert(
	fetch(url).then(response =>{
		if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
		return response.text();
	}),
	resultElement;
);

Customization

If you want to change the class names used, they are stored as

Promise.alert.classes = {
	success: 'success',
	failure: 'failure',
	hidden: 'hidden'
};

Promise.prototype.alert

Convenience function that sends a pre-existing Promise to Promise.alert. So the above examples become:

Promise.resolve('Finished').alert().then(doOtherWork);

Promise.reject(new Error('Failed')).alert().then(doOtherWork);

fetch(url).then(response =>{
	if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
	return response.text();
}).alert(resultElement);

Implemented as

Object.defineProperty( Promise.prototype, 'alert', {
	value: function (container) { return Promise.alert(this, container) }
});

I thought long and hard about this, since modifying the prototype of a built-in object is considered harmful and will get you fired from Google. But with Object.defineProperty the only downside is a collision with this name with another library or a future standard. Consider this a warning that if whatwg decides to implement Promise.prototype.alert, then things will break.