Skip to content

Instantly share code, notes, and snippets.

@huafu
Created October 23, 2014 04:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save huafu/7de66f0b6ee4d1788af7 to your computer and use it in GitHub Desktop.
Save huafu/7de66f0b6ee4d1788af7 to your computer and use it in GitHub Desktop.
Add a `styleBindings` property to views which can be used like `attributeBindings`. Support units as well.
import Ember from 'ember';
/**
* @mixin WithStyleMixin
*/
var WithStyleMixin = Ember.Mixin.create({
concatenatedProperties: ['styleBindings'],
attributeBindings: ['style'],
/**
* Define each style binding as you'd do with `attributeBindings` with one added feature: the units
* If no unit is defined, the value of the property is used as the style if it is not null or undefined
* If a unit is defined it is appended to the style value only if the value is recognized as a number
* and if this number is not 0.
* To define the unit, append it to the style binding around brackets.
*
* @example
* ```javascript
* styleBindings: [
* // use the `display` property as the `display` style value:
* 'display',
*
* // use the `width` property as the `width` style value using `px` as the unit:
* 'width[px]',
*
* // use the `myHeightProperty` as the `height` style value using `%` as the unit:
* 'myHeightProperty:height[%]'
* ]
* ```
*
* @property styleBindings
* @type Array<String>
*/
styleBindings: Ember.required(),
/**
* @property styleBindingsMap
* @type Object<Object>
*/
styleBindingsMap: function () {
var res = {}, match, cssProp, emberProp, unit,
bindings = this.get('styleBindings');
for (var i = 0; i < bindings.length; i++) {
if ((match = bindings[i].match(/^(([^:]+):)?([a-z0-9_\.-]+)(\[([a-z%]+)\])?$/i))) {
cssProp = match[3];
emberProp = match[2] || cssProp;
unit = match[5];
res[cssProp] = { property: emberProp, unit: unit };
}
}
return res;
}.property('styleBindings.@each').readOnly(),
/**
* @property style
* @type String
*/
style: function () {
var map = this.get('styleBindingsMap');
var props = [], cssVal, unit;
for (var cssProp in map) {
cssVal = this.get(map[cssProp].property);
if (cssVal !== undefined && cssVal !== null) {
unit = map[cssProp].unit;
cssVal = '' + cssVal;
unit = unit && cssVal !== '0' && /^[0-9\.]+$/.test(cssVal) ? unit : '';
props.push(cssProp + ': ' + cssVal + unit);
}
}
return props.join('; ');
}.property().readOnly(),
/**
* Schedule the notification of the change of the style property
* @method _notifyStyleChange
* @private
*/
_notifyStyleChange: function () {
Ember.run.once(this, 'notifyPropertyChange', 'style');
},
/**
* Start listening for any style related property change
* @method _initWithStyleMixin
* @private
*/
_initWithStyleMixin: function () {
var map = this.get('styleBindingsMap');
for (var k in map) {
this.addObserver(map[k].property, this, '_notifyStyleChange');
}
}.observes('styleBindings.@each').on('init'),
/**
* Stop listening for any style related property change
* @method _destroyWithStyleMixin
* @private
*/
_destroyWithStyleMixin: function () {
var map = this.get('styleBindingsMap');
for (var k in map) {
this.removeObserver(map[k].property, this, '_notifyStyleChange');
}
}.observesBefore('styleBindings.@each').on('destroy')
});
export default WithStyleMixin;
@huafu
Copy link
Author

huafu commented Oct 23, 2014

Example use-case:

export default Ember.View.extend(WithStyleMixin, {
  styleBindings: ['width[px]', 'color', 'fontSize:font-size[em]'],
  width: 10,
  color: 'red',
  fontSize: '3pt' // will not use 'em' unless it is a number and !== 0
});

@huafu
Copy link
Author

huafu commented Oct 23, 2014

FYI I packaged that in an ember addon: https://github.com/huafu/with-style-mixin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment