You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
179 lines
4.8 KiB
179 lines
4.8 KiB
'use strict';
|
|
|
|
var isString = require('./helpers').isString;
|
|
var isArray = require('./helpers').isArray;
|
|
var isUndefined = require('./helpers').isUndefined;
|
|
var isNull = require('./helpers').isNull;
|
|
|
|
/**
|
|
* Creates an instance of StyleContextStack used for style inheritance and style overrides
|
|
*
|
|
* @constructor
|
|
* @this {StyleContextStack}
|
|
* @param {Object} named styles dictionary
|
|
* @param {Object} optional default style definition
|
|
*/
|
|
function StyleContextStack(styleDictionary, defaultStyle) {
|
|
this.defaultStyle = defaultStyle || {};
|
|
this.styleDictionary = styleDictionary;
|
|
this.styleOverrides = [];
|
|
}
|
|
|
|
/**
|
|
* Creates cloned version of current stack
|
|
* @return {StyleContextStack} current stack snapshot
|
|
*/
|
|
StyleContextStack.prototype.clone = function () {
|
|
var stack = new StyleContextStack(this.styleDictionary, this.defaultStyle);
|
|
|
|
this.styleOverrides.forEach(function (item) {
|
|
stack.styleOverrides.push(item);
|
|
});
|
|
|
|
return stack;
|
|
};
|
|
|
|
/**
|
|
* Pushes style-name or style-overrides-object onto the stack for future evaluation
|
|
*
|
|
* @param {String|Object} styleNameOrOverride style-name (referring to styleDictionary) or
|
|
* a new dictionary defining overriding properties
|
|
*/
|
|
StyleContextStack.prototype.push = function (styleNameOrOverride) {
|
|
this.styleOverrides.push(styleNameOrOverride);
|
|
};
|
|
|
|
/**
|
|
* Removes last style-name or style-overrides-object from the stack
|
|
*
|
|
* @param {Number} howMany - optional number of elements to be popped (if not specified,
|
|
* one element will be removed from the stack)
|
|
*/
|
|
StyleContextStack.prototype.pop = function (howMany) {
|
|
howMany = howMany || 1;
|
|
|
|
while (howMany-- > 0) {
|
|
this.styleOverrides.pop();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Creates a set of named styles or/and a style-overrides-object based on the item,
|
|
* pushes those elements onto the stack for future evaluation and returns the number
|
|
* of elements pushed, so they can be easily poped then.
|
|
*
|
|
* @param {Object} item - an object with optional style property and/or style overrides
|
|
* @return the number of items pushed onto the stack
|
|
*/
|
|
StyleContextStack.prototype.autopush = function (item) {
|
|
if (isString(item)) {
|
|
return 0;
|
|
}
|
|
|
|
var styleNames = [];
|
|
|
|
if (item.style) {
|
|
if (isArray(item.style)) {
|
|
styleNames = item.style;
|
|
} else {
|
|
styleNames = [item.style];
|
|
}
|
|
}
|
|
|
|
for (var i = 0, l = styleNames.length; i < l; i++) {
|
|
this.push(styleNames[i]);
|
|
}
|
|
|
|
var styleProperties = [
|
|
'font',
|
|
'fontSize',
|
|
'fontFeatures',
|
|
'bold',
|
|
'italics',
|
|
'alignment',
|
|
'color',
|
|
'columnGap',
|
|
'fillColor',
|
|
'fillOpacity',
|
|
'decoration',
|
|
'decorationStyle',
|
|
'decorationColor',
|
|
'background',
|
|
'lineHeight',
|
|
'characterSpacing',
|
|
'noWrap',
|
|
'markerColor',
|
|
'leadingIndent',
|
|
'sup',
|
|
'sub'
|
|
//'tableCellPadding'
|
|
// 'cellBorder',
|
|
// 'headerCellBorder',
|
|
// 'oddRowCellBorder',
|
|
// 'evenRowCellBorder',
|
|
// 'tableBorder'
|
|
];
|
|
var styleOverrideObject = {};
|
|
var pushStyleOverrideObject = false;
|
|
|
|
styleProperties.forEach(function (key) {
|
|
if (!isUndefined(item[key]) && !isNull(item[key])) {
|
|
styleOverrideObject[key] = item[key];
|
|
pushStyleOverrideObject = true;
|
|
}
|
|
});
|
|
|
|
if (pushStyleOverrideObject) {
|
|
this.push(styleOverrideObject);
|
|
}
|
|
|
|
return styleNames.length + (pushStyleOverrideObject ? 1 : 0);
|
|
};
|
|
|
|
/**
|
|
* Automatically pushes elements onto the stack, using autopush based on item,
|
|
* executes callback and then pops elements back. Returns value returned by callback
|
|
*
|
|
* @param {Object} item - an object with optional style property and/or style overrides
|
|
* @param {Function} function to be called between autopush and pop
|
|
* @return {Object} value returned by callback
|
|
*/
|
|
StyleContextStack.prototype.auto = function (item, callback) {
|
|
var pushedItems = this.autopush(item);
|
|
var result = callback();
|
|
|
|
if (pushedItems > 0) {
|
|
this.pop(pushedItems);
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Evaluates stack and returns value of a named property
|
|
*
|
|
* @param {String} property - property name
|
|
* @return property value or null if not found
|
|
*/
|
|
StyleContextStack.prototype.getProperty = function (property) {
|
|
if (this.styleOverrides) {
|
|
for (var i = this.styleOverrides.length - 1; i >= 0; i--) {
|
|
var item = this.styleOverrides[i];
|
|
|
|
if (isString(item)) {
|
|
// named-style-override
|
|
var style = this.styleDictionary[item];
|
|
if (style && !isUndefined(style[property]) && !isNull(style[property])) {
|
|
return style[property];
|
|
}
|
|
} else if (!isUndefined(item[property]) && !isNull(item[property])) {
|
|
// style-overrides-object
|
|
return item[property];
|
|
}
|
|
}
|
|
}
|
|
|
|
return this.defaultStyle && this.defaultStyle[property];
|
|
};
|
|
|
|
module.exports = StyleContextStack;
|