@qooxdoo/framework
Version:
The JS Framework for Coders
516 lines (440 loc) • 13.3 kB
JavaScript
/* ************************************************************************
qooxdoo - the new era of web development
http://qooxdoo.org
Copyright:
2006 STZ-IDA, Germany, http://www.stz-ida.de
2004-2009 1&1 Internet AG, Germany, http://www.1und1.de
License:
MIT: https://opensource.org/licenses/MIT
See the LICENSE file in the project's top-level directory for details.
Authors:
* Fabian Jakobs (fjakobs)
************************************************************************ */
/**
* Themeable Cell renderer.
*
* This cell renderer can be styled by an appearance theme.
*/
qx.Class.define("qx.ui.virtual.cell.Cell", {
extend: qx.ui.virtual.cell.Abstract,
construct() {
super();
this.__stylesheet = qx.ui.virtual.cell.CellStylesheet.getInstance();
this.__userStyles = {};
this.__themeStyles = {};
this.__userPaddings = {};
this.__themePaddings = {};
this.__states = {};
this.__themeValues = {};
this.initAppearance();
this.__initializeThemableProperties();
},
/*
*****************************************************************************
PROPERTIES
*****************************************************************************
*/
properties: {
/**
* The appearance ID. This ID is used to identify the appearance theme
* entry to use for this cell.
*/
appearance: {
check: "String",
init: "cell",
apply: "_applyAppearance"
},
/** The cell's background color */
backgroundColor: {
nullable: true,
check: "Color",
apply: "_applyBackgroundColor",
themeable: true
},
/** The cell's text color */
textColor: {
nullable: true,
check: "Color",
apply: "_applyTextColor",
themeable: true
},
/** The text alignment of the cell's content */
textAlign: {
check: ["left", "center", "right", "justify"],
nullable: true,
themeable: true,
apply: "_applyTextAlign"
},
/**
* The cell's font. The value is either a font name defined in the font
* theme or an instance of {@link qx.bom.Font}.
*/
font: {
nullable: true,
apply: "_applyFont",
check: "Font",
themeable: true
},
/*
---------------------------------------------------------------------------
PADDING
---------------------------------------------------------------------------
*/
/** Padding of the widget (top) */
paddingTop: {
check: "Integer",
init: 0,
apply: "_applyPadding",
themeable: true
},
/** Padding of the widget (right) */
paddingRight: {
check: "Integer",
nullable: true,
apply: "_applyPadding",
themeable: true
},
/** Padding of the widget (bottom) */
paddingBottom: {
check: "Integer",
nullable: true,
apply: "_applyPadding",
themeable: true
},
/** Padding of the widget (left) */
paddingLeft: {
check: "Integer",
nullable: true,
apply: "_applyPadding",
themeable: true
},
/**
* The 'padding' property is a shorthand property for setting 'paddingTop',
* 'paddingRight', 'paddingBottom' and 'paddingLeft' at the same time.
*
* If four values are specified they apply to top, right, bottom and left
* respectively. If there is only one value, it applies to all sides, if
* there are two or three, the missing values are taken from the opposite
* side.
*/
padding: {
group: ["paddingTop", "paddingRight", "paddingBottom", "paddingLeft"],
mode: "shorthand",
themeable: true
}
},
/*
*****************************************************************************
MEMBERS
*****************************************************************************
*/
members: {
/** @type {Array} List of all non CSS themable properties */
__themableProperties: null,
/** @type {String} Unique key over the current set of states */
__statesKey: null,
__states: null,
__themeValues: null,
__themeStyles: null,
__userStyles: null,
__userPaddings: null,
__themePaddings: null,
__isThemed: false,
__stylesheet: null,
/**
* Collect all themable properties, which are not CSS properties
*/
__initializeThemableProperties() {
var PropertyUtil = qx.util.PropertyUtil;
var cssProperties = qx.lang.Object.fromArray(this._getCssProperties());
this.__themableProperties = [];
var clazz = this.constructor;
while (clazz) {
var properties = PropertyUtil.getProperties(clazz);
for (var prop in properties) {
if (!cssProperties[prop]) {
this.__themableProperties.push(prop);
}
}
clazz = clazz.superclass;
}
},
/**
* Get a list of all properties, which should be applied as CSS styles.
*
* @return {Array} List of property names
*/
_getCssProperties() {
return [
"backgroundColor",
"textColor",
"font",
"textAlign",
"paddingTop",
"paddingRight",
"paddingBottom",
"paddingLeft"
];
},
// property apply
_applyAppearance(value, old) {
if (old) {
this.__themeStyles = {};
}
},
/**
* Compute the value of the given property
*
* @param propertyName {String} Name of the property
* @return {var} The Property value
*/
_getValue(propertyName) {
if (this.__isThemed) {
return qx.util.PropertyUtil.getThemeValue(this, propertyName);
} else {
return qx.util.PropertyUtil.getUserValue(this, propertyName);
}
},
/**
* Store a properties computed style string either in the user or in the
* theme values. User values will be applied as inline styles, while theme
* values are stored in a stylesheet.
*
* @param propertyName {String} The property name
* @param styles {String} String with computed CSS styles
*/
_storeStyle(propertyName, styles) {
var store;
if (this.__isThemed) {
store = this.__themeStyles;
} else {
store = this.__userStyles;
}
if (styles === null) {
delete store[propertyName];
} else {
store[propertyName] = styles;
}
},
// property apply
_applyBackgroundColor(value, old, name) {
var value = this._getValue(name);
if (!value) {
this._storeStyle(name, null);
} else {
this._storeStyle(
name,
"background-color:" +
qx.theme.manager.Color.getInstance().resolve(value)
);
}
},
// property apply
_applyTextColor(value, old, name) {
var value = this._getValue(name);
if (!value) {
this._storeStyle(name, null);
} else {
this._storeStyle(
name,
"color:" + qx.theme.manager.Color.getInstance().resolve(value)
);
}
},
// property apply
_applyTextAlign(value, old, name) {
var value = this._getValue(name);
if (!value) {
this._storeStyle(name, null);
} else {
this._storeStyle(name, "text-align:" + value);
}
},
// property apply
_applyFont(value, old, name) {
var value = this._getValue(name);
if (!value) {
this._storeStyle(name, null);
} else {
var font = qx.theme.manager.Font.getInstance().resolve(value);
this._storeStyle(name, qx.bom.element.Style.compile(font.getStyles()));
}
},
// property apply
_applyPadding(value, old, name) {
var value = this._getValue(name);
if (this.__isThemed) {
var paddingStore = this.__themePaddings;
} else {
paddingStore = this.__userPaddings;
}
if (value === null) {
delete paddingStore[name];
} else {
paddingStore[name] = value;
}
if (value === null) {
this._storeStyle(name, null);
} else {
var cssKey = qx.bom.Style.getCssName(name);
this._storeStyle(name, cssKey + ":" + value + "px");
}
},
/*
---------------------------------------------------------------------------
IMPLEMENT CELL API
---------------------------------------------------------------------------
*/
// overridden
getCellProperties(value, states) {
this.__setStates(states);
return {
classes: this.getCssClasses(value, states),
style: this.getStyles(value, states),
attributes: this.getAttributes(value, states),
content: this.getContent(value, states),
insets: this.getInsets(value, states)
};
},
// overridden
getAttributes(value, states) {
return "";
},
// overridden
getContent(value, states) {
return value;
},
// overridden
getCssClasses(value, states) {
var cssClass = this.__stylesheet.getCssClass(this.__statesKey) || "";
return "qx-cell " + cssClass;
},
/**
* Set the cell states and set the correct CSS class for the given state
* combination
*
* @param states {Object} A map containing the cell's state names as map keys.
*/
__setStates(states) {
// Avoid errors if no states are set
if (!states) {
states = {};
}
var appearance = this.getAppearance();
var statesKey = appearance + "-" + Object.keys(states).sort().join(" ");
if (this.__statesKey == statesKey) {
return;
}
this.__statesKey = statesKey;
var themeStyles = this.__states[this.__statesKey];
if (!themeStyles) {
this.__clearThemedPropertyValues();
this.__updateThemeableProperties(states);
this.__computeCssClassForStates(states);
this.__cacheThemedValues();
this.__states[this.__statesKey] = 1;
}
this.__applyThemeValues();
},
/**
* Remove the themed value from all CSS properties
*/
__clearThemedPropertyValues() {
var PropertyUtil = qx.util.PropertyUtil;
var themableProperties = this._getCssProperties();
for (var i = 0; i < themableProperties.length; i++) {
PropertyUtil.deleteThemeValue(this, themableProperties[i]);
}
},
/**
* Set the new themed value for all CSS properties given the set of states
*
* @param states {Object} A map containing the cell's state names as map keys.
*/
__updateThemeableProperties(states) {
this.__themeStyles = {};
this.__isThemed = true;
var appearance = this.getAppearance();
var PropertyUtil = qx.util.PropertyUtil;
var styles = qx.theme.manager.Appearance.getInstance().styleFrom(
appearance,
states
);
for (var prop in styles) {
if (styles[prop] !== undefined) {
PropertyUtil.setThemed(this, prop, styles[prop]);
}
}
this.__isThemed = false;
},
/**
* Compute a CSS class for the current values of all CSS properties
*/
__computeCssClassForStates() {
var styleString = Object.values(this.__themeStyles).join(";");
this.__stylesheet.computeClassForStyles(this.__statesKey, styleString);
},
/**
* Cache the themed values for the current state combination
*/
__cacheThemedValues() {
var properties = this.__themableProperties;
var PropertyUtil = qx.util.PropertyUtil;
var themeValues = {};
for (var i = 0; i < properties.length; i++) {
var key = properties[i];
var value = PropertyUtil.getThemeValue(this, key);
if (value !== undefined) {
themeValues[key] = value;
}
}
this.__themeValues[this.__statesKey] = themeValues;
},
/**
* Apply the themed values to the properties
*/
__applyThemeValues() {
var PropertyUtil = qx.util.PropertyUtil;
var themeValues = this.__themeValues[this.__statesKey] || {};
for (var key in themeValues) {
PropertyUtil.setThemed(this, key, themeValues[key]);
}
},
// overridden
getStyles(value, states) {
return Object.values(this.__userStyles).join(";");
},
// overridden
getInsets(value, states) {
var user = this.__userPaddings;
var theme = this.__themePaddings;
var top =
(user.paddingTop !== undefined ? user.paddingTop : theme.paddingTop) ||
0;
var right =
(user.paddingRight !== undefined
? user.paddingRight
: theme.paddingRight) || 0;
var bottom =
(user.paddingBottom !== undefined
? user.paddingBottom
: theme.paddingBottom) || 0;
var left =
(user.paddingLeft !== undefined
? user.paddingLeft
: theme.paddingLeft) || 0;
return [left + right, top + bottom];
}
},
destruct() {
this.__stylesheet =
this.__userStyles =
this.__themeStyles =
this.__userPaddings =
this.__themePaddings =
this.__states =
this.__themeValues =
this.__themableProperties =
null;
}
});