Browse Source

Update PropertyStack

up-style-manager
Artur Arseniev 5 years ago
parent
commit
8e3e600bd0
  1. 8
      src/style_manager/model/Property.js
  2. 2
      src/style_manager/model/PropertyComposite.js
  3. 365
      src/style_manager/model/PropertyStack.js

8
src/style_manager/model/Property.js

@ -1,6 +1,6 @@
import { Model } from 'common'; import { Model } from 'common';
import { isUndefined, isString, result, keys } from 'underscore'; import { isUndefined, isString, result, keys } from 'underscore';
import { capitalize } from 'utils/mixins'; import { capitalize, camelCase } from 'utils/mixins';
/** /**
* @typedef Property * @typedef Property
@ -130,6 +130,8 @@ export default class Property extends Model {
/** /**
* Get the CSS style object of the property. * Get the CSS style object of the property.
* @param {Object} [opts={}] Options
* @param {Boolean} [opts.camelCase] Return property name in camelCase.
* @return {Object} * @return {Object}
* @example * @example
* // In case the property is `color` with a value of `red`. * // In case the property is `color` with a value of `red`.
@ -137,7 +139,9 @@ export default class Property extends Model {
* // { color: 'red' }; * // { color: 'red' };
*/ */
getStyle(opts = {}) { getStyle(opts = {}) {
return { [this.getName()]: this.__getFullValue(opts) }; const name = this.getName();
const key = opts.camelCase ? camelCase(name) : name;
return { [key]: this.__getFullValue(opts) };
} }
/** /**

2
src/style_manager/model/PropertyComposite.js

@ -142,6 +142,8 @@ export default class PropertyComposite extends Property {
/** /**
* Get style object from current properties * Get style object from current properties
* @param {Object} [opts={}] Options
* @param {Boolean} [opts.camelCase] Return property names in camelCase.
* @returns {Object} Style object * @returns {Object} Style object
* @private * @private
*/ */

365
src/style_manager/model/PropertyStack.js

@ -7,33 +7,208 @@ import { camelCase } from 'utils/mixins';
const VALUES_REG = /,(?![^\(]*\))/; const VALUES_REG = /,(?![^\(]*\))/;
const PARTS_REG = /\s(?![^(]*\))/; const PARTS_REG = /\s(?![^(]*\))/;
/**
* @typedef PropertyStack
* @property {String|RegExp} [layerSeparator=', '] The separator used to split layer values.
* @property {String} [layerJoin=', '] Value used to join layer values.
* @property {Function} [layerLabel] Custom logic for creating the layer value.
*/
export default class PropertyStack extends PropertyComposite { export default class PropertyStack extends PropertyComposite {
defaults() { defaults() {
return { return {
...PropertyComposite.getDefaults(), ...PropertyComposite.getDefaults(),
// Array of layers (which contain properties)
layers: [], layers: [],
// The separator used to split layer values
layerSeparator: ', ', layerSeparator: ', ',
// The separator used to join layer values
layerJoin: '', layerJoin: '',
// Prepend new layers in the list
prepend: 0, prepend: 0,
// Layer preview
preview: 0, preview: 0,
// Custom layer label function
layerLabel: null, layerLabel: null,
// Current selected layer
selectedLayer: null, selectedLayer: null,
}; };
} }
/**
* Get all available layers.
* @returns {Collection<[Layer]>}
*/
getLayers() {
return this.get('layers');
}
/**
* Get layer by index.
* @param {Number} [index=0] Layer index position.
* @returns {[Layer]|null}
* @example
* // Get the first layer
* const layerFirst = property.getLayer(0);
* // Get the last layer
* const layers = this.getLayers();
* const layerLast = property.getLayer(layers.length - 1);
*/
getLayer(index = 0) {
return this.getLayers().at(index) || null;
}
/**
* Get selected layer.
* @returns {[Layer] | null}
*/
getSelectedLayer() {
const layer = this.get('selectedLayer');
return layer && layer.getIndex() >= 0 ? layer : null;
}
/**
* Select layer.
* Without a selected layer any update made on inner properties has no effect.
* @param {[Layer]} layer Layer to select
* @example
* const layer = property.getLayer(0);
* property.selectLayer(layer);
*/
selectLayer(layer) {
return this.set('selectedLayer', layer, { __select: true });
}
/**
* Select layer by index.
* @param {Number} index Index of the layer to select.
* @example
* property.selectLayerAt(1);
*/
selectLayerAt(index = 0) {
const layer = this.getLayer(index);
return layer && this.selectLayer(layer);
}
/**
* Add new layer to the stack.
* @param {Object} [props={}] Custom property values to use in a new layer.
* @param {Object} [opts={}] Options
* @param {Number} [opts.at] Position index (by default the layer will be appended at the end).
* @returns {[Layer]} Added layer.
* @example
* // Add new layer at the beginning of the stack with custom values
* property.addLayer({ 'sub-prop1': 'value1', 'sub-prop2': 'value2' }, { at: 0 });
*/
addLayer(props = {}, opts = {}) {
const values = {};
this.getProperties().forEach(prop => {
const name = prop.getName();
const value = props[name];
values[name] = isUndefined(value) ? prop.getDefaultValue() : value;
});
const layer = this.get('layers').push({ values }, opts);
return layer;
}
/**
* Remove layer.
* @param {[Layer]} layer Layer to remove.
* @returns {[Layer]} Removed layer
* @example
* const layer = property.getLayer(0);
* property.removeLayer(layer);
*/
removeLayer(layer) {
return this.get('layers').remove(layer);
}
/**
* Remove layer by index.
* @param {Number} index Index of the layer to remove
* @returns {[Layer]|null} Removed layer
* @example
* property.removeLayerAt(0);
*/
removeLayerAt(index = 0) {
const layer = this.getLayer(index);
return layer ? this.removeLayer(layer) : null;
}
/**
* Get layer label.
* @param {[Layer]} layer
* @returns {String}
* @example
* const layer = this.getLayer(1);
* const label = this.getLayerLabel(layer);
*/
getLayerLabel(layer) {
let result = '';
if (layer) {
const layerLabel = this.get('layerLabel');
const values = layer.getValues();
const index = layer.getIndex();
if (layerLabel) {
result = layerLabel(layer, { index, values, property: this });
} else {
const parts = [];
this.getProperties().map(prop => {
parts.push(values[prop.getId()]);
});
result = parts.filter(Boolean).join(' ');
}
}
return result;
}
/**
* Get style object from the layer.
* @param {[Layer]} layer
* @param {Object} [opts={}] Options
* @param {Boolean} [opts.camelCase] Return property names in camelCase.
* @returns {Object} Style object
*/
getStyleFromLayer(layer, opts = {}) {
const join = this.__getJoin();
const joinLayers = this.__getJoinLayers();
const toStyle = this.get('toStyle');
const name = this.getName();
const values = layer.getValues();
let style;
if (toStyle) {
style = toStyle(values, { join, joinLayers, name, layer, property: this });
} else {
const result = this.getProperties().map(prop => {
const name = prop.getName();
const val = values[name];
const value = isUndefined(val) ? prop.getDefaultValue() : val;
return { name, value };
});
style = this.isDetached()
? result.reduce((acc, item) => {
acc[item.name] = item.value;
return acc;
}, {})
: {
[this.getName()]: result.map(r => r.value).join(join),
};
}
return opts.camelCase
? Object.keys(style).reduce((res, key) => {
res[camelCase(key)] = style[key];
return res;
}, {})
: style;
}
/**
* Get layer separator.
* @return {RegExp}
*/
getLayerSeparator() {
const sep = this.get('layerSeparator');
return isString(sep) ? new RegExp(`${sep}(?![^\\(]*\\))`) : sep;
}
initialize(props = {}, opts = {}) { initialize(props = {}, opts = {}) {
PropertyComposite.callParentInit(PropertyComposite, this, props, opts); PropertyComposite.callParentInit(PropertyComposite, this, props, opts);
const layers = this.get('layers'); const layers = this.get('layers');
@ -166,150 +341,16 @@ export default class PropertyStack extends PropertyComposite {
return isArray(result) ? result : [result]; return isArray(result) ? result : [result];
} }
/**
* Add new layer to the stack
* @param {Object} [props={}] Layer props
* @param {Object} [opts={}] Options
* @returns {[Layer]}
*/
addLayer(props = {}, opts = {}) {
const values = {};
this.getProperties().forEach(prop => {
const name = prop.getName();
const value = props[name];
values[name] = isUndefined(value) ? prop.getDefaultValue() : value;
});
const layer = this.get('layers').push({ values }, opts);
return layer;
}
/**
* Remove layer
* @param {[Layer]} layer
* @returns {[Layer]} Removed layer
*/
removeLayer(layer) {
return this.get('layers').remove(layer);
}
/**
* Remove layer at index
* @param {Number} index Index of the layer to remove
* @returns {[Layer] | null} Removed layer
*/
removeLayerAt(index = 0) {
const layer = this.getLayer(index);
return layer ? this.removeLayer(layer) : null;
}
/**
* Select layer
* @param {[Layer]} layer
*/
selectLayer(layer) {
return this.set('selectedLayer', layer, { __select: true });
}
/**
* Select layer at index
* @param {Number} index Index of the layer to select
*/
selectLayerAt(index = 0) {
const layer = this.getLayer(index);
return layer && this.selectLayer(layer);
}
/**
* Get layer label
* @param {[Layer]} layer
* @returns {String}
*/
getLayerLabel(layer) {
let result = '';
if (layer) {
const layerLabel = this.get('layerLabel');
const values = layer.getValues();
const index = layer.getIndex();
if (layerLabel) {
result = layerLabel(layer, { index, values, property: this });
} else {
const parts = [];
this.getProperties().map(prop => {
parts.push(values[prop.getId()]);
});
result = parts.filter(Boolean).join(' ');
}
}
return result;
}
/**
* Get selected layer
* @returns {[Layer] | null}
*/
getSelectedLayer() {
const layer = this.get('selectedLayer');
return layer && layer.getIndex() >= 0 ? layer : null;
}
getStyle(opts) { getStyle(opts) {
return this.getStyleFromLayers(opts); return this.getStyleFromLayers(opts);
} }
/** getStyleFromLayers(opts) {
* Get style object from layer
* @param {[Layer]} layer
* @returns {Object} Style object
*/
getStyleFromLayer(layer, opts = {}) {
const join = this.__getJoin();
const joinLayers = this.__getJoinLayers();
const toStyle = this.get('toStyle');
const name = this.getName();
const values = layer.getValues();
let style;
if (toStyle) {
style = toStyle(values, { join, joinLayers, name, layer, property: this });
} else {
const result = this.getProperties().map(prop => {
const name = prop.getName();
const val = values[name];
const value = isUndefined(val) ? prop.getDefaultValue() : val;
return { name, value };
});
style = this.isDetached()
? result.reduce((acc, item) => {
acc[item.name] = item.value;
return acc;
}, {})
: {
[this.getName()]: result.map(r => r.value).join(join),
};
}
return opts.camelCase
? Object.keys(style).reduce((res, key) => {
res[camelCase(key)] = style[key];
return res;
}, {})
: style;
}
/**
* Get style object from current layers
* @returns {Object} Style object
*/
getStyleFromLayers() {
let result = {}; let result = {};
const name = this.getName(); const name = this.getName();
const layers = this.getLayers(); const layers = this.getLayers();
const props = this.getProperties(); const props = this.getProperties();
const styles = layers.map(l => this.getStyleFromLayer(l)); const styles = layers.map(l => this.getStyleFromLayer(l, opts));
styles.forEach(style => { styles.forEach(style => {
keys(style).map(key => { keys(style).map(key => {
if (!result[key]) result[key] = []; if (!result[key]) result[key] = [];
@ -352,27 +393,6 @@ export default class PropertyStack extends PropertyComposite {
return style[this.getName()]; return style[this.getName()];
} }
/**
* Get layer sperator
* @return {RegExp}
*/
getLayerSeparator() {
const sep = this.get('layerSeparator');
return isString(sep) ? new RegExp(`${sep}(?![^\\(]*\\))`) : sep;
}
getLayers() {
return this.get('layers');
}
getLayer(index = 0) {
return this.getLayers().at(index) || null;
}
getCurrentLayer() {
return this.getLayers().filter(layer => layer.get('active'))[0];
}
getFullValue() { getFullValue() {
return this.get('detached') ? '' : this.get('layers').getFullValue(); return this.get('detached') ? '' : this.get('layers').getFullValue();
} }
@ -421,10 +441,15 @@ export default class PropertyStack extends PropertyComposite {
return PropertyBase.prototype.clear.call(this); return PropertyBase.prototype.clear.call(this);
} }
getCurrentLayer() {
return this.getLayers().filter(layer => layer.get('active'))[0];
}
/** /**
* This method allows to customize layers returned from the target * This method allows to customize layers returned from the target
* @param {Object} target * @param {Object} target
* @return {Array} Should return an array of layers * @return {Array} Should return an array of layers
* @private
* @example * @example
* // return example * // return example
* [ * [

Loading…
Cancel
Save