Browse Source

Refactor StyleManager model properties

pull/487/head
Artur Arseniev 8 years ago
parent
commit
7839ac7985
  1. 2
      dist/css/grapes.min.css
  2. 21
      src/domain_abstract/ui/Input.js
  3. 19
      src/domain_abstract/ui/InputColor.js
  4. 11
      src/domain_abstract/ui/InputNumber.js
  5. 2
      src/style_manager/index.js
  6. 2
      src/style_manager/model/Layers.js
  7. 23
      src/style_manager/model/Property.js
  8. 17
      src/style_manager/model/PropertyInteger.js
  9. 2
      src/style_manager/model/Sectors.js
  10. 2
      src/style_manager/view/PropertyCompositeView.js
  11. 8
      src/style_manager/view/PropertyIntegerView.js
  12. 37
      src/style_manager/view/PropertyView.js
  13. 48
      src/styles/scss/_gjs_inputs.scss
  14. 55
      test/specs/style_manager/model/Models.js
  15. 9
      test/specs/style_manager/view/PropertyIntegerView.js

2
dist/css/grapes.min.css

File diff suppressed because one or more lines are too long

21
src/domain_abstract/ui/Input.js

@ -8,16 +8,24 @@ module.exports = Backbone.View.extend({
template() { template() {
return `<span class="${this.holderClass}"></span>`; return `<span class="${this.holderClass()}"></span>`;
},
inputClass() {
return `${this.ppfx}field`;
},
holderClass() {
return `${this.ppfx}input-holder`;
}, },
initialize(opts = {}) { initialize(opts = {}) {
const ppfx = opts.ppfx || ''; const ppfx = opts.ppfx || '';
this.opts = opts;
this.ppfx = ppfx; this.ppfx = ppfx;
this.target = opts.target || {}; this.target = opts.target || {};
this.inputClass = `${ppfx}field`;
this.holderClass = `${ppfx}input-holder`;
this.listenTo(this.model, 'change:value', this.handleModelChange); this.listenTo(this.model, 'change:value', this.handleModelChange);
}, },
@ -67,8 +75,7 @@ module.exports = Backbone.View.extend({
getInputEl() { getInputEl() {
if (!this.inputEl) { if (!this.inputEl) {
const plh = this.model.get('defaults'); const plh = this.model.get('defaults');
const cls = this.inputCls; this.inputEl = $(`<input type="text" placeholder="${plh}">`);
this.inputEl = $(`<input type="text" class="${cls}" placeholder="${plh}">`);
} }
return this.inputEl.get(0); return this.inputEl.get(0);
@ -77,9 +84,9 @@ module.exports = Backbone.View.extend({
render() { render() {
const el = this.$el; const el = this.$el;
el.addClass(this.inputClass); el.addClass(this.inputClass());
el.html(this.template()); el.html(this.template());
el.find(`.${this.holderClass}`).append(this.getInputEl()); el.find(`.${this.holderClass()}`).append(this.getInputEl());
return this; return this;
} }

19
src/domain_abstract/ui/InputColor.js

@ -7,21 +7,22 @@ module.exports = Input.extend({
template() { template() {
const ppfx = this.ppfx; const ppfx = this.ppfx;
return ` return `
<div class="${ppfx}input-holder"></div> <div class="${this.holderClass()}"></div>
<div class="${ppfx}field-colorp"> <div class="${ppfx}field-colorp">
<div class="${ppfx}field-colorp-c"> <div class="${ppfx}field-colorp-c" data-colorp-c>
<div class="${ppfx}checker-bg"></div> <div class="${ppfx}checker-bg"></div>
</div> </div>
</div> </div>
`; `;
}, },
initialize() { inputClass() {
Input.prototype.initialize.apply(this, arguments);
const ppfx = this.ppfx; const ppfx = this.ppfx;
this.colorCls = `${ppfx}field-color-picker`; return `${ppfx}field ${ppfx}field-color`;
this.inputClass = `${ppfx}field ${ppfx}field-color`; },
this.colorHolderClass = `${ppfx}field-colorp-c`;
holderClass() {
return `${this.ppfx}input-holder`;
}, },
/** /**
@ -53,7 +54,7 @@ module.exports = Input.extend({
const self = this; const self = this;
var model = this.model; var model = this.model;
var colorEl = $(`<div class="${this.colorCls}"></div>`); var colorEl = $(`<div class="${this.ppfx}field-color-picker"></div>`);
var cpStyle = colorEl.get(0).style; var cpStyle = colorEl.get(0).style;
var elToAppend = this.target && this.target.config ? this.target.config.el : ''; var elToAppend = this.target && this.target.config ? this.target.config.el : '';
const getColor = color => { const getColor = color => {
@ -63,7 +64,7 @@ module.exports = Input.extend({
let changed = 0; let changed = 0;
let previousСolor; let previousСolor;
this.$el.find(`.${this.colorHolderClass}`).append(colorEl); this.$el.find(`[data-colorp-c]`).append(colorEl);
colorEl.spectrum({ colorEl.spectrum({
appendTo: elToAppend || 'body', appendTo: elToAppend || 'body',

11
src/domain_abstract/ui/InputNumber.js

@ -27,15 +27,16 @@ module.exports = Input.extend({
`; `;
}, },
inputClass() {
const ppfx = this.ppfx;
return this.opts.contClass || `${ppfx}field ${ppfx}field-integer`;
},
initialize(opts = {}) { initialize(opts = {}) {
Input.prototype.initialize.apply(this, arguments); Input.prototype.initialize.apply(this, arguments);
bindAll(this, 'moveIncrement', 'upIncrement'); bindAll(this, 'moveIncrement', 'upIncrement');
const ppfx = this.ppfx;
this.doc = document; this.doc = document;
this.inputCls = `${ppfx}field-number`;
this.unitCls = `${ppfx}input-unit`;
this.inputClass = opts.contClass || `${ppfx}field ${ppfx}field-integer`;;
this.listenTo(this.model, 'change:unit', this.handleModelChange); this.listenTo(this.model, 'change:unit', this.handleModelChange);
}, },
@ -123,7 +124,7 @@ module.exports = Input.extend({
}); });
const temp = document.createElement('div'); const temp = document.createElement('div');
temp.innerHTML = `<select class="${this.unitCls}">${options.join('')}</select>`; temp.innerHTML = `<select class="${this.ppfx}input-unit">${options.join('')}</select>`;
this.unitEl = temp.firstChild; this.unitEl = temp.firstChild;
} }
} }

2
src/style_manager/index.js

@ -97,7 +97,7 @@ module.exports = () => {
c.stylePrefix = ppfx + c.stylePrefix; c.stylePrefix = ppfx + c.stylePrefix;
properties = new Properties(); properties = new Properties();
sectors = new Sectors(c.sectors); sectors = new Sectors(c.sectors, c);
SectView = new SectorsView({ SectView = new SectorsView({
collection: sectors, collection: sectors,
target: c.em, target: c.em,

2
src/style_manager/model/Layers.js

@ -64,7 +64,7 @@ module.exports = Backbone.Collection.extend({
const style = styleObj[propModel.get('property')]; const style = styleObj[propModel.get('property')];
const values = style ? style.split(', ') : []; const values = style ? style.split(', ') : [];
values.forEach((value, i) => { values.forEach((value, i) => {
value = propModel.parseValue(value.trim()); value = propModel.parseValue(value.trim()).value;
const layer = layers[i]; const layer = layers[i];
const propertyObj = Object.assign({}, propModel.attributes, {value}); const propertyObj = Object.assign({}, propModel.attributes, {value});

23
src/style_manager/model/Property.js

@ -35,29 +35,37 @@ module.exports = require('backbone').Model.extend({
* @param {Object} [opts={}] Options * @param {Object} [opts={}] Options
*/ */
setValue(value, complete = 1, opts = {}) { setValue(value, complete = 1, opts = {}) {
this.set('value', value, { ...opts, avoidStore: 1}); const parsed = this.parseValue(value);
this.set(parsed, { ...opts, avoidStore: 1});
// It's important to set an empty value, otherwise the // It's important to set an empty value, otherwise the
// UndoManager won't see the change // UndoManager won't see the change
if (complete) { if (complete) {
this.set('value', '', opts); this.set('value', '', opts);
this.set('value', value, opts); this.set(parsed, opts);
} }
}, },
/** /**
* Parse a raw value, generally fetched from the target, for this property * Parse a raw value, generally fetched from the target, for this property
* @param {string} value * @param {string} value Raw value string
* @return {string} * @return {Object}
* @example
* // example with an Input type
* prop.parseValue('translateX(10deg)');
* // -> { value: 10, unit: 'deg', functionName: 'translateX' }
*
*/ */
parseValue(value) { parseValue(value) {
const result = { value };
if (!this.get('functionName')) { if (!this.get('functionName')) {
return value; return result;
} }
const args = []; const args = [];
let valueStr = value + ''; let valueStr = `${value}`;
let start = valueStr.indexOf('(') + 1; let start = valueStr.indexOf('(') + 1;
let end = valueStr.lastIndexOf(')'); let end = valueStr.lastIndexOf(')');
args.push(start); args.push(start);
@ -67,7 +75,8 @@ module.exports = require('backbone').Model.extend({
args.push(end); args.push(end);
} }
return String.prototype.substring.apply(valueStr, args); result.value = String.prototype.substring.apply(valueStr, args);
return result;
}, },

17
src/style_manager/model/PropertyInteger.js

@ -1,8 +1,9 @@
const Property = require('./Property'); const Property = require('./Property');
const InputNumber = require('domain_abstract/ui/InputNumber');
module.exports = Property.extend({ module.exports = Property.extend({
defaults: Object.assign({}, Property.prototype.defaults, { defaults: { ...Property.prototype.defaults,
// Array of units, eg. ['px', '%'] // Array of units, eg. ['px', '%']
units: [], units: [],
@ -17,17 +18,29 @@ module.exports = Property.extend({
// Maximum value // Maximum value
max: '', max: '',
}), },
init() { init() {
const unit = this.get('unit'); const unit = this.get('unit');
const units = this.get('units'); const units = this.get('units');
this.input = new InputNumber({ model: this });
if (units.length && !unit) { if (units.length && !unit) {
this.set('unit', units[0]); this.set('unit', units[0]);
} }
}, },
parseValue(val) {
const parsed = Property.prototype.parseValue.apply(this, arguments);
const { value, unit } = this.input.validateInputValue(parsed.value, {deepCheck: 1});
parsed.value = value;
parsed.unit = unit;
return parsed;
},
getFullValue() { getFullValue() {
let value = this.get('value') + this.get('unit'); let value = this.get('value') + this.get('unit');
return Property.prototype.getFullValue.apply(this, [value]); return Property.prototype.getFullValue.apply(this, [value]);

2
src/style_manager/model/Sectors.js

@ -1,5 +1,5 @@
const Sector = require('./Sector'); const Sector = require('./Sector');
module.exports = require('backbone').Collection.extend({ module.exports = require('backbone').Collection.extend({
model: Sector, model: Sector
}); });

2
src/style_manager/view/PropertyCompositeView.js

@ -107,7 +107,7 @@ module.exports = PropertyView.extend({
} }
if (view) { if (view) {
value = view.model.parseValue(value); value = view.model.parseValue(value).value;
} }
return value; return value;

8
src/style_manager/view/PropertyIntegerView.js

@ -21,11 +21,9 @@ module.exports = require('./PropertyView').extend({
const ppfx = this.ppfx; const ppfx = this.ppfx;
if (!this.input) { if (!this.input) {
const inputNumber = new InputNumber({ const input = this.model.input;
model: this.model, input.ppfx = ppfx;
ppfx: this.ppfx input.render();
});
const input = inputNumber.render();
const fields = this.el.querySelector(`.${ppfx}fields`); const fields = this.el.querySelector(`.${ppfx}fields`);
fields.appendChild(input.el); fields.appendChild(input.el);
this.$input = input.inputEl; this.$input = input.inputEl;

37
src/style_manager/view/PropertyView.js

@ -56,6 +56,7 @@ module.exports = Backbone.View.extend({
const pfx = this.pfx; const pfx = this.pfx;
this.inputHolderId = '#' + pfx + 'input-holder'; this.inputHolderId = '#' + pfx + 'input-holder';
this.sector = model.collection && model.collection.sector; this.sector = model.collection && model.collection.sector;
model.view = this;
if (!model.get('value')) { if (!model.get('value')) {
model.set('value', model.getDefaultValue()); model.set('value', model.getDefaultValue());
@ -199,8 +200,7 @@ module.exports = Backbone.View.extend({
status = ''; status = '';
} }
model.set('value', value, {silent: 1}); model.setValue(value, 0, { fromTarget: 1 });
this.setValue(value, {targetUpdate: 1});
model.set('status', status); model.set('status', status);
if (em) { if (em) {
@ -249,11 +249,6 @@ module.exports = Backbone.View.extend({
result = target.getStyle()[model.get('property')]; result = target.getStyle()[model.get('property')];
// TODO when stack type asks the sub-property (in valueOnIndex method)
// to provide its target value and its detached, I should avoid parsing
// (at least is wrong applying 'functionName' cleaning)
result = model.parseValue(result);
if (!result && !opts.ignoreDefault) { if (!result && !opts.ignoreDefault) {
result = model.getDefaultValue(); result = model.getDefaultValue();
} }
@ -305,9 +300,9 @@ module.exports = Backbone.View.extend({
const target = this.getTarget(); const target = this.getTarget();
const onChange = this.onChange; const onChange = this.onChange;
// I don't need to update the input if the change comes from it // Avoid element update if the change comes from it
if (!opt.fromInput) { if (!opt.fromInput) {
this.setRawValue(value); this.setValue(value);
} }
// Check if component is allowed to be styled // Check if component is allowed to be styled
@ -315,10 +310,13 @@ module.exports = Backbone.View.extend({
return; return;
} }
if (onChange) { // Avoid target update if the changes comes from it
onChange(target, this, opt); if (!opt.fromTarget) {
} else { if (onChange) {
this.updateTargetStyle(value, null, opt); onChange(target, this, opt);
} else {
this.updateTargetStyle(value, null, opt);
}
} }
if (em) { if (em) {
@ -401,19 +399,20 @@ module.exports = Backbone.View.extend({
this.setValue(this.model.parseValue(value)); this.setValue(this.model.parseValue(value));
}, },
/** /**
* Set the value to property input * Update the element input.
* @param {String} value * Usually the value is a result of `model.getFullValue()`
* @param {Boolean} force * @param {String} value The value from the model
* @private
* */ * */
setValue(value, opts = {}) { setValue(value) {
const model = this.model; const model = this.model;
let val = value || model.get('value') || model.getDefaultValue(); let val = value || model.getDefaultValue();
const input = this.getInputEl(); const input = this.getInputEl();
input && (input.value = val); input && (input.value = val);
}, },
getInputEl() { getInputEl() {
if (!this.input) { if (!this.input) {
this.input = this.el.querySelector('input'); this.input = this.el.querySelector('input');

48
src/styles/scss/_gjs_inputs.scss

@ -49,9 +49,34 @@
} }
&field { &field {
input,
select,
textarea {
@include appearance(none);
color: inherit;
border: none;
background-color: transparent;
box-sizing: border-box;
width: 100%;
position: relative;
padding: $inputPadding;
z-index: 1;
&:focus {
outline: none;
}
}
&-range { &-range {
flex: 9 1 auto; flex: 9 1 auto;
} }
&-integer {
input {
padding-right: 30px;
}
}
} }
} }
@ -72,25 +97,6 @@
position: relative; position: relative;
color: $inputFontColor; color: $inputFontColor;
input,
select,
textarea {
@include appearance(none);
color: inherit;
border: none;
background-color: transparent;
box-sizing: border-box;
width: 100%;
position: relative;
padding: $inputPadding;
z-index: 1;
&:focus {
outline: none;
}
}
textarea { textarea {
resize: vertical; resize: vertical;
} }
@ -122,10 +128,6 @@
cursor: pointer; cursor: pointer;
} }
.#{$app-prefix}field-number {
padding-right: 30px;
}
&-arrows { &-arrows {
position: absolute; position: absolute;
cursor: ns-resize; cursor: ns-resize;

55
test/specs/style_manager/model/Models.js

@ -1,6 +1,7 @@
const Sector = require('style_manager/model/Sector'); const Sector = require('style_manager/model/Sector');
const Sectors = require('style_manager/model/Sectors'); const Sectors = require('style_manager/model/Sectors');
const Property = require('style_manager/model/Property'); const Property = require('style_manager/model/Property');
const PropertyInteger = require('style_manager/model/PropertyInteger');
const Properties = require('style_manager/model/Properties'); const Properties = require('style_manager/model/Properties');
const Layer = require('style_manager/model/Layer'); const Layer = require('style_manager/model/Layer');
const Layers = require('style_manager/model/Layers'); const Layers = require('style_manager/model/Layers');
@ -125,7 +126,6 @@ module.exports = {
}); });
describe('Property', () => { describe('Property', () => {
var obj; var obj;
beforeEach(() => { beforeEach(() => {
@ -140,6 +140,59 @@ module.exports = {
expect(obj.has('property')).toEqual(true); expect(obj.has('property')).toEqual(true);
}); });
it('parseValue', () => {
const result = { value: 'testValue' };
expect(obj.parseValue('testValue')).toEqual(result);
});
it('parseValue with function but without functionName', () => {
const result = { value: 'fn(testValue)' };
expect(obj.parseValue('fn(testValue)')).toEqual(result);
});
it('parseValue with function and functionName', () => {
obj = new Property({ functionName: 'fn' });
const result = { value: 'testValue' };
expect(obj.parseValue('fn(testValue)')).toEqual(result);
expect(obj.parseValue('fn(testValue')).toEqual(result);
});
});
describe('PropertyInteger', () => {
var obj;
beforeEach(() => {
obj = new PropertyInteger({units: ['px', 'deg']});
});
afterEach(() => {
obj = null;
});
it('parseValue with units', () => {
const result = { value: 20, unit: 'px' };
expect(obj.parseValue('20px')).toEqual(result);
});
it('parse input value with function', () => {
obj = new PropertyInteger({units: ['px', 'deg'], functionName: 'test'});
const result = { value: 55, unit: 'deg' };
expect(obj.parseValue('test(55deg)')).toEqual(result);
});
it('parse input value with min', () => {
obj = new PropertyInteger({units: ['px'], min: 10});
const result = { value: 10, unit: 'px' };
expect(obj.parseValue('1px')).toEqual(result);
expect(obj.parseValue('15px')).toEqual({ value: 15, unit: 'px' });
});
it('parse input value with max', () => {
obj = new PropertyInteger({units: ['px'], max: 100});
const result = { value: 100, unit: 'px' };
expect(obj.parseValue('200px')).toEqual(result);
expect(obj.parseValue('95px')).toEqual({ value: 95, unit: 'px' });
});
}); });
describe('Properties', () => { describe('Properties', () => {

9
test/specs/style_manager/view/PropertyIntegerView.js

@ -1,11 +1,12 @@
const PropertyIntegerView = require('style_manager/view/PropertyIntegerView'); const PropertyIntegerView = require('style_manager/view/PropertyIntegerView');
const Property = require('style_manager/model/Property'); const Property = require('style_manager/model/Property');
const PropertyInteger = require('style_manager/model/PropertyInteger');
const Component = require('dom_components/model/Component'); const Component = require('dom_components/model/Component');
module.exports = { module.exports = {
run() { run() {
describe('PropertyIntegerView', () => { describe.only('PropertyIntegerView', () => {
var component; var component;
var fixtures; var fixtures;
@ -26,8 +27,7 @@ module.exports = {
beforeEach(() => { beforeEach(() => {
target = new Component(); target = new Component();
component = new Component(); component = new Component();
model = new Property({ model = new PropertyInteger({
type: 'integer',
units, units,
property: propName property: propName
}); });
@ -161,8 +161,7 @@ module.exports = {
beforeEach(() => { beforeEach(() => {
component = new Component(); component = new Component();
model = new Property({ model = new PropertyInteger({
type: 'integer',
units, units,
property: propName, property: propName,
defaults: intValue, defaults: intValue,

Loading…
Cancel
Save