js: Implement DynamicText class.

This implements the DynamicText class for resizing of text to fit the
parent node.
This commit is contained in:
Brock Whittaker 2017-04-04 17:10:04 -07:00 committed by Tim Abbott
parent 0ce04556bf
commit 6e7305f784
3 changed files with 99 additions and 0 deletions

View File

@ -16,6 +16,7 @@
"marked": false, "marked": false,
"moment": false, "moment": false,
"i18n": false, "i18n": false,
"DynamicText": false,
"bridge": false, "bridge": false,
"page_params": false, "page_params": false,
"status_classes": false, "status_classes": false,

97
static/js/dynamic_text.js Normal file
View File

@ -0,0 +1,97 @@
// This is a public instance of the `DynamicText` class.
// The `DynamicText` object serves to resize text that is set through its
// public methods so that the text won't ever overrun the parent container.
var DynamicText = (function () {
// the initialization of the `DynamicText` instance.
var DynamicText = function ($parent) {
if (typeof jQuery !== "undefined" && $parent instanceof jQuery) {
// we grab the first element in a jQuery list to run DynamicText on.
this.parent = $parent[0];
} else if ($parent instanceof Node) {
// this is a node rather than a list, so we just take the element given
// to run DynamicText on.
this.parent = $parent;
}
this.node = document.createElement("span");
this.node.style.whiteSpace = "nowrap";
this.prev_content = this.parent.innerHTML;
this.parent.innerHTML = "";
this.parent.appendChild(this.node);
this.update();
};
// an object for private functions that are inaccessible to the outside
// world.
var internal_funcs = {
insertText: function (type, text, node, parent) {
if (type === DynamicText.prototype.TYPE.TEXT) {
node.innerText = text;
} else if (type === DynamicText.prototype.TYPE.HTML) {
node.innerHTML = text;
} else {
blueslip.error("The method '" + type + "' is not a valid " +
" DynamicText input method.");
}
// reset the font-size to inherit the parent's size; 1em.
node.style.fontSize = "1em";
var width = {
node: node.offsetWidth,
parent: parent.clientWidth,
};
// if the width is larger than the parent, resize by the ratio of
// the parent's width to the node's width.
if (width.node > width.parent) {
node.style.fontSize = (width.parent / width.node) + "em";
} else {
node.style.fontSize = "1em";
}
},
};
DynamicText.prototype = {
// insertion enum types.
TYPE: {
TEXT: 1,
HTML: 2,
},
// re-set the content inside the span element and process for width.
// the structure goes like:
// FROM: <parent>content</parent>
// TO: <parent>
// <span style="font-size: {{ value }}">content</span>
// </parent>
update: function () {
// call `text` by default since if HTML is needed (unsafe), it can be
// done manually.
this.text(this.prev_content);
},
// this takes about 0.005ms for items that don't need resizing and 0.08ms
// for items that do need resizing.
text: function (text) {
internal_funcs.insertText(this.TYPE.TEXT, text, this.node, this.parent);
},
// this function takes approx 0.4ms/iteration.
// the speed is mostly limited to the slowness of the innerHTML function.
html: function (html) {
internal_funcs.insertText(this.TYPE.HTML, html, this.node, this.parent);
},
};
// keep these arguments updated with `DynamicText` class constructor.
return function ($node) {
return new DynamicText($node);
};
}());
if (typeof module !== 'undefined') {
module.exports = DynamicText;
}

View File

@ -854,6 +854,7 @@ JS_SPECS = {
'js/feature_flags.js', 'js/feature_flags.js',
'js/loading.js', 'js/loading.js',
'js/util.js', 'js/util.js',
'js/dynamic_text.js',
'js/rtl.js', 'js/rtl.js',
'js/dict.js', 'js/dict.js',
'js/components.js', 'js/components.js',