ember-text-resize
Version:
Easily resize texts to fit the container.
160 lines (135 loc) • 4.27 kB
JavaScript
import Ember from 'ember';
import layout from '../templates/components/text-resize';
const { get, getProperties, set, $, run:{next, scheduleOnce}, isPresent, typeOf, assert, RSVP:{Promise}, copy } = Ember;
export default Ember.Component.extend({
layout,
/*
Element settings
*/
tagName: 'div',
classNames: ['text-resize-container'],
classNameBindings: ['_visible:visible'],
/*
Public properties
*/
text: undefined,
fontSize: undefined,
minFontSize: undefined,
maxFontSize: undefined,
step: -2,
alwaysVisible: false,
/*
Private properties
*/
_fontSize: undefined,
_visible: false,
_activeDidRender: true,
/*
Private methods
*/
/**
* Active the solution
*/
_active() {
set(this, '_activeDidRender', false);
set(this, '_fontSize', copy(get(this, 'fontSize')));
this._validateParams();
scheduleOnce('afterRender', () => {
this._resizeText().then(() => {
scheduleOnce('afterRender', () => set(this, '_activeDidRender', true));
});
});
},
/**
* Validate the params received
*/
_validateParams() {
let {fontSize, minFontSize, maxFontSize} = getProperties(this, ['fontSize', 'minFontSize', 'maxFontSize']),
step = get(this, 'step'),
alwaysVisible = get(this, 'alwaysVisible'),
validNumber = (n) => n && parseFloat(n) && !isNaN(parseFloat(n)) || false,
validFontSize = isPresent(fontSize) ? validNumber(fontSize) : true,
validMinFontSize = isPresent(minFontSize) ? validNumber(minFontSize) : true,
validMaxFontSize = isPresent(maxFontSize) ? validNumber(maxFontSize) : true,
validStep = validNumber(step),
validAlwaysVisible = typeOf(alwaysVisible) === 'boolean';
assert(`Invalid 'fontSize'. It must be a number.`, validFontSize);
assert(`Invalid 'minFontSize'. It must be a number.`, validMinFontSize);
assert(`Invalid 'maxFontSize'. It must be a number.`, validMaxFontSize);
assert(`Invalid 'step'. It must be a number.`, validStep);
assert(`Invalid 'alwaysVisible'. It must be boolean.`, validAlwaysVisible);
},
/**
* Resize the text size
*/
_resizeText() {
return new Promise((resolve, reject) => {
let $element = $(`#${this.elementId}`),
$parent = $element.parent(),
fontSize = parseFloat(get(this, '_fontSize') || 0) || parseFloat($element.css('font-size')),
{minFontSize, maxFontSize} = getProperties(this, ['minFontSize', 'maxFontSize']),
step = parseFloat(get(this, 'step')),
alwaysVisible = get(this, 'alwaysVisible');
if ($element.width() <= 0) {
resolve();
return;
}
const finish = () => {
set(this, '_visible', true);
resolve();
};
const maximize = () => {
if ($element.width() < $parent.width()) {
if (maxFontSize && fontSize === maxFontSize) {
finish();
return;
}
fontSize += step;
if (maxFontSize && fontSize > maxFontSize) {
fontSize = maxFontSize;
}
resize();
} else {
step *= -1;
minimize();
}
};
const minimize = () => {
if ($element.width() > $parent.width()) {
if (minFontSize && fontSize === minFontSize) {
finish();
return;
}
fontSize += step;
if (minFontSize && fontSize < minFontSize) {
fontSize = minFontSize;
}
resize();
} else {
finish();
}
};
const resize = () => {
let valid = fontSize > 0
, action = step > 0 ? maximize : minimize;
set(this, '_fontSize', fontSize);
if (valid) {
next(() => action());
}
};
set(this, '_visible', alwaysVisible);
resize();
});
},
/*
Life cycle
*/
didReceiveAttrs() {
this._super(...arguments);
this._active();
},
didRender() {
this._super(...arguments);
get(this, '_activeDidRender') && this._active();
},
});