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.
 
 

354 lines
9.9 KiB

/**
* This file is part of the jps-like-websites lib
* URL: https://git.labos.goip.de/chris/jpc-like-websites
* @copyright by its creator Christian Martin
*/
/**
* A chained class that sets most of the stylings of an element
* Attributes:
* _modifications: {Object}
*/
class Modifier {
/**
* @type {Map<string,string>} _modifications
*/
_modifications;
/**
* @type {Array<string>}
*/
_removeMods;
/**
* @type {Shape}
*/
_shape;
/**
* @type {Sides} paddingValues
*/
_paddingValues;
constructor() {
this._modifications = new Object();
this._removeMods = [];
}
/**
* Sets the modifications for widht and height to 100%.
* @returns {Modifier} this modifier object
*/
fillMaxSize(widthFraction = 1, heightFraction = 1) {
return this.fillMaxWidth(widthFraction)
.fillMaxHeight(heightFraction);
}
/**
* Sets the modification for width to the given fraction of 1 (default 1 := 100%).
* @param {number} fraction
* @returns {Modifier} this modifier object
*/
fillMaxWidth(fraction = 1) {
this._modifications["width"] = (100 * fraction) + "%";
this._modifications["max-width"] = (100 * fraction) + "%";
return this;
}
/**
* Sets the modification for height to the given fraction of 1 (default 1 := 100%).
* @param {number} fraction
* @returns {Modifier} this modifier object
*/
fillMaxHeight(fraction = 1) {
this._modifications["height"] = (100 * fraction) + "%";
this._modifications["max-height"] = (100 * fraction) + "%";
return this;
}
/**
*
* @param {string} keyWord weither 'height' or 'width' that will be adjusted and looked for
* @param {Sides} parentalPadding
*/
_updateDimensionsBy(parentalPadding) {
function updateDirection(keyWord, modifications, parentalAdjustment) {
let refKeys = Object.keys(modifications)
.filter(k => k.includes(keyWord));
if (refKeys.length > 0) {
for (let i = 0; i < refKeys.length; i++) {
let key = refKeys[i];
let value = modifications[key];
if (key.includes("calc")) {
console.log(
`Modifier._updateByParent... ${keyWord
} - unexpected value '${value
}' for '${key
}', skipping...`
);
} else {
let newValue = `calc(${value} - ${parentalAdjustment});`;
modifications[key] = newValue.trim();
}
}
}
return modifications;
}
if (parentalPadding) {
let pval = parentalPadding.getValues();
if (pval["horizontal"] > 0) {
this._modifications = updateDirection("width", this._modifications, pval["horizontal"]+parentalPadding._unit);
}
if (pval["vertical"] > 0) {
this._modifications = updateDirection("height", this._modifications, pval["vertical"]+parentalPadding._unit);
}
}
return this;
}
/**
* Sets modifications according to the dimensions object.
* @param {Dimensions} dimensions
* @returns {Modifier} this modifier object
*/
dimensions(dimensions) {
dimensions.toModifications()
.forEach(kvpair => {
this._modifications[kvpair.key] = kvpair.value;
})
return this;
}
/**
* Sets the padding on all sides according to the given padding object.
* Currently the padding will always be set
* to the most recent padding/padding.
* @param {Sides} siding
* @returns {Modifier} this modifier object
*/
padding(siding) {
this._paddingValues = siding;
let keyToAdd = "";
if (siding instanceof PaddingChain) {
/* TODO what is this supposed to do */
} else if (siding instanceof Sides) {
keyToAdd = "padding-"
}
siding.toModifications()
.forEach(kvpair => {
this._modifications[keyToAdd + kvpair.key] = kvpair.value;
})
return this;
}
/**
* Sets the margin on all sides according to the given siding object.
* Currently the margin will always be set
* to the most recent margin/siding.
* @param {Sides} siding
* @returns {Modifier} this modifier object
*/
margin(siding) {
let keyToAdd = "";
if (siding instanceof Sides) {
keyToAdd = "margin-"
}
siding.toModifications()
.forEach(kvpair => {
this._modifications[keyToAdd + kvpair.key] = kvpair.value;
});
return this;
}
/**
* Sets the background-color as a rgb color.
* @param {Color} color
* @returns {Modifier} this modifier object
*/
background(color) {
this._modifications["background-color"] = color.cssRGBString();
return this;
}
/**
* Sets the color as a rgb color.
* @param {Color} color
* @returns {Modifier} this modifier object
*/
color(color) {
this._modifications["color"] = color.cssRGBString();
return this;
}
/**
* Adds the modifications of the given Modifier to current Modifier.
* This is especailly used in the cases of extending existing/pre defined
* Components.
* CAUTION matching existing modifications will be overwritten.
* @param modifier The "new" Modifier
* @returns {Modifier} The "old/current" Modifier,
* extended with the modifications of the given Modifier.
*/
join(modifier, modifications = {}) {
var keys = Object.keys(modifier.ensureModifier()._modifications);
for (let i = 0; i < keys.length; i++) {
/* if (!this._modifications.hasOwnProperty(keys[i])) */
this._modifications[keys[i]] = modifier.ensureModifier()._modifications[keys[i]];
}
let removeMods = modifier.ensureModifier()._removeMods;
if (removeMods.length > 0) {
for (let i = 0; i < removeMods.length; i++) {
delete this._modifications[removeMods[i]];
}
}
return this;
}
/**
*
* @param {string} key a css style rule
* @param {string} value the corresponding value to the css style rule
* @returns {Modifier} this modifier object
*/
setStyleRule(key, value) {
this._modifications[key] = value;
return this;
}
/**
*
* @param {string} key
* @returns {Modifier} this modifier object
*/
removeStyleRule(key) {
this._removeMods.push(key);
if (Object.keys(this._modifications).includes(key)) {
delete this._modifications[key];
}
return this;
}
/**
* Sets a border line (with given linestyle) to all sides.
* If lineStyle is an array, the containing LineStyles,
* are applied in the order: [top, right, bottom, left].
* If the border has a shape defined,
* this shape will override earlier shape definitions.
* Otherwise existing shape definitions will be applied.
* @param {Border} border the style of the border line
* @returns {Modifier} this modifier object
*/
border(border) {
if (border._shape) {
this.clip(border._shape);
} else if (this._shape) {
border._shape = this._shape;
}
border.toModifications()
.forEach(e => this._modifications[e.key] = e.value);
return this;
}
/**
*
* @param {Shape} shape
* @returns {Modifier}
*/
clip(shape) {
this._shape = shape;
this._modifications["border-radius"] = shape.getOrderedValues().join(' ');
return this;
}
/**
*
* @param {number} size of width and height in pixels
* @returns {DimensionsChain}
*/
linkDimensions(size = -1) {
if (size === -1) {
return new DimensionsChain(this);
} else {
return new DimensionsChain(this).all(size).ensureModifier()
}
}
/**
*
* @param {number} amount the padding for all four sides
* @returns {PaddingChain}
*/
linkPadding(amount = -1) {
if (amount === -1) {
return new PaddingChain(this);
} else {
return new PaddingChain(this).all(amount);
}
}
/**
*
* @param {number} cornerRadius will create a rounded rectangle with the given cornerRadius
* @returns {ShapeChain}
*/
linkClip(cornerRadius = -1) {
if (cornerRadius === -1) {
return new ShapeChain(this);
} else {
return new ShapeChain(this).all(cornerRadius);
}
}
/**
*
* @param {number} borderWidth sets the width of all four border sides
* @returns {BorderChain}
*/
linkBorder(borderWidth = -1) {
if (borderWidth === -1) {
return new BorderChain(this);
} else {
return new BorderChain(this).width(borderWidth);
}
}
/**
*
* @returns {Modifier}
*/
ensureModifier() {
return this;
}
}
class ChainableModifier extends Modifier {
_component;
constructor(component) {
super();
this._component = component;
}
/**
*
* @returns {Component}
*/
toComponent() {
return this._component.modifier(this);
}
/**
*
* @param {Component|Array<Component>} innerComponent
* @returns {Component} the parent Component
*/
childContext(innerComponent) {
return this._component
.modifier(this)
.childContext(innerComponent);
}
}