Browse Source

Update style sectors on target change

up-style-manager
Artur Arseniev 5 years ago
parent
commit
d0f6a7c366
  1. 21
      docs/modules/Style-manager.md
  2. 123
      src/style_manager/index.js
  3. 15
      src/style_manager/view/SectorsView.js

21
docs/modules/Style-manager.md

@ -434,8 +434,25 @@ For a more advanced usage you can rely on the [Style Manager API] to perform dif
sm.removeSector('sector-id'); sm.removeSector('sector-id');
``` ```
* Change target * Managing the selected target,
* Get current selected target ```js
// Select the first button in the current page
const btnCmp = editor.Pages.getSelected().getMainComponent().findType('button')[0];
btnCmp && sm.select(btnCmp);
// Add new property to the sector
sm.addProperty('sector-id', {
type: 'number',
property: 'min-width',
});
// Remove sector
sm.removeSector('sector-id');
```
## Customization ## Customization

123
src/style_manager/index.js

@ -16,6 +16,7 @@
* ``` * ```
* ## Available Events * ## Available Events
* * `style:sector:add` - Sector added. The [Sector] is passed as an argument to the callback. * * `style:sector:add` - Sector added. The [Sector] is passed as an argument to the callback.
* * `style:target` - Target selection changed. The target (or `null` in case the target is deselected) is passed as an argument to the callback.
* *
* ## Methods * ## Methods
* * [getConfig](#getconfig) * * [getConfig](#getconfig)
@ -27,7 +28,9 @@
* * [getProperty](#getproperty) * * [getProperty](#getproperty)
* * [getProperties](#getproperties) * * [getProperties](#getproperties)
* * [removeProperty](#removeproperty) * * [removeProperty](#removeproperty)
* * [getModelToStyle](#getmodeltostyle) * * [select](#select)
* * [getSelected](#getselected)
* * [getLastSelected](#getlastselected)
* * [addType](#addtype) * * [addType](#addtype)
* * [getType](#gettype) * * [getType](#gettype)
* * [getTypes](#gettypes) * * [getTypes](#gettypes)
@ -55,6 +58,7 @@ export const evAll = 'style';
export const evPfx = `${evAll}:`; export const evPfx = `${evAll}:`;
export const evPropUp = `${evPfx}property:update`; export const evPropUp = `${evPfx}property:update`;
export const evLayerSelect = `${evPfx}layer:select`; export const evLayerSelect = `${evPfx}layer:select`;
export const evTarget = `${evPfx}target`;
export const evCustom = `${evPfx}custom`; export const evCustom = `${evPfx}custom`;
const propDef = value => value || value === 0; const propDef = value => value || value === 0;
@ -72,6 +76,7 @@ export default () => {
all: evAll, all: evAll,
propertyUpdate: evPropUp, propertyUpdate: evPropUp,
layerSelect: evLayerSelect, layerSelect: evLayerSelect,
target: evTarget,
custom: evCustom, custom: evCustom,
}, },
@ -98,23 +103,27 @@ export default () => {
this.builtIn = new PropertyFactory(); this.builtIn = new PropertyFactory();
properties = new Properties(); properties = new Properties();
sectors = new Sectors([], c); sectors = new Sectors([], c);
this.model = new Model({ targets: [] }); const model = new Model({ targets: [] });
this.model = model;
// Triggers for the selection refresh and properties // Triggers for the selection refresh and properties
const ev = 'component:toggled component:update:classes change:state change:device frame:resized selector:type'; const ev = 'component:toggled component:update:classes change:state change:device frame:resized selector:type';
const upAll = debounce(() => this.__upSel()); const upAll = debounce(() => this.__upSel());
this.model.listenTo(em, ev, upAll); model.listenTo(em, ev, upAll);
// Triggers only for properties (avoid selection refresh) // Triggers only for properties (avoid selection refresh)
const upProps = debounce(() => { const upProps = debounce(() => {
this.__upProps(); this.__upProps();
this.__trgCustom(); this.__trgCustom();
}); });
this.model.listenTo(em, 'styleable:change', upProps); model.listenTo(em, 'styleable:change', upProps);
// Triggers only custom event // Triggers only custom event
const trgCustom = debounce(() => this.__trgCustom()); const trgCustom = debounce(() => this.__trgCustom());
this.model.listenTo(em, evLayerSelect, trgCustom); model.listenTo(em, evLayerSelect, trgCustom);
// Other listeners
model.on('change:lastTarget', () => em.trigger(evTarget, this.getLastSelected()));
return this; return this;
}, },
@ -281,6 +290,58 @@ export default () => {
return props ? props.remove(this.getProperty(sectorId, id)) : null; return props ? props.remove(this.getProperty(sectorId, id)) : null;
}, },
/**
* Select new target.
* The target could be a Component, CSSRule, or a CSS selector string.
* @param {[Component]|[CSSRule]|String} target
* @returns {Array<[Component]|[CSSRule]>} Array containing selected Components or CSSRules
*/
select(target, opts = {}) {
const { em } = this;
const trgs = isArray(target) ? target : [target];
const { stylable } = opts;
const cssc = em.get('CssComposer');
let targets = [];
trgs.filter(Boolean).forEach(target => {
let model = target;
if (isString(target)) {
const rule = cssc.getRule(target) || cssc.setRule(target);
!isUndefined(stylable) && rule.set({ stylable });
model = rule;
}
targets.push(model);
});
targets = targets.map(t => this.getModelToStyle(t));
const lastTarget = targets.slice().reverse()[0];
const lastTargetParents = this.getParentRules(lastTarget, em.getState());
this.model.set({ targets, lastTarget, lastTargetParents });
// lastTarget && this.setTarget(lastTarget); // TODO to refactor
this.__upProps(opts);
return targets;
},
/**
* Get the array of selected targets.
* @returns {Array<[Component]|[CSSRule]>}
*/
getSelected() {
return this.model.get('targets');
},
/**
* Get the last selected target.
* By default, the Style Manager shows styles of the last selected target.
* @returns {[Component]|[CSSRule]|null}
*/
getLastSelected() {
return this.model.get('lastTarget') || null;
},
/** /**
* Get what to style inside Style Manager. If you select the component * Get what to style inside Style Manager. If you select the component
* without classes the entity is the Component itself and all changes will * without classes the entity is the Component itself and all changes will
@ -288,6 +349,7 @@ export default () => {
* one or more classes, the function will return the corresponding CSS Rule * one or more classes, the function will return the corresponding CSS Rule
* @param {Model} model * @param {Model} model
* @return {Model} * @return {Model}
* @private
*/ */
getModelToStyle(model, options = {}) { getModelToStyle(model, options = {}) {
const { em } = this; const { em } = this;
@ -352,10 +414,10 @@ export default () => {
// Componente related rule // Componente related rule
if (cmp) { if (cmp) {
cmpRules = cssC.getRules(`#${cmp.getId()}`); cmpRules = cssC.getRules(`#${cmp.getId()}`);
otherRules = cssC.getRules(sel.getSelectors().getFullName(optsSel)); otherRules = sel ? cssC.getRules(sel.getSelectors().getFullName(optsSel)) : [];
rules = otherRules.concat(cmpRules); rules = otherRules.concat(cmpRules);
} else { } else {
cmpRules = cssC.getRules(`#${sel.getId()}`); cmpRules = sel ? cssC.getRules(`#${sel.getId()}`) : [];
otherRules = cssC.getRules(target.getSelectors().getFullName(optsSel)); otherRules = cssC.getRules(target.getSelectors().getFullName(optsSel));
rules = cmpRules.concat(otherRules); rules = cmpRules.concat(otherRules);
} }
@ -454,7 +516,7 @@ export default () => {
}, },
setTarget(target, opts) { setTarget(target, opts) {
return SectView.setTarget(target, opts); return SectView?.setTarget(target, opts);
}, },
getTargets() { getTargets() {
@ -462,53 +524,10 @@ export default () => {
return (propTarget && propTarget.targets) || []; return (propTarget && propTarget.targets) || [];
}, },
/**
* Select different target for the Style Manager.
* It could be a Component, CSSRule, or a string of any CSS selector
* @param {[Component]|[CSSRule]|String} target
* @return {Array<[Component]|[CSSRule]>} Array containing selected Components or CSSRules
* @private
*/
select(target, opts = {}) {
const { em } = this;
const trgs = isArray(target) ? target : [target];
const { stylable } = opts;
const cssc = em.get('CssComposer');
let targets = [];
trgs.filter(Boolean).forEach(target => {
let model = target;
if (isString(target)) {
const rule = cssc.getRule(target) || cssc.setRule(target);
!isUndefined(stylable) && rule.set({ stylable });
model = rule;
}
targets.push(model);
});
targets = targets.map(t => this.getModelToStyle(t));
const lastTarget = targets.slice().reverse()[0];
const lastTargetParents = this.getParentRules(lastTarget, em.getState());
this.model.set({ targets, lastTarget, lastTargetParents });
this.__upProps(opts);
return targets;
},
addStyleTargets(style, opts) { addStyleTargets(style, opts) {
this.getSelected().map(t => t.addStyle(style, opts)); this.getSelected().map(t => t.addStyle(style, opts));
}, },
getSelected() {
return this.model.get('targets');
},
getLastSelected() {
return this.model.get('lastTarget') || null;
},
getSelectedParents() { getSelectedParents() {
return this.model.get('lastTargetParents') || []; return this.model.get('lastTargetParents') || [];
}, },
@ -529,7 +548,9 @@ export default () => {
el, el,
collection: sectors, collection: sectors,
target: em, target: em,
em,
config, config,
module: this,
}); });
return SectView.render().el; return SectView.render().el;
}, },

15
src/style_manager/view/SectorsView.js

@ -13,6 +13,9 @@ export default Backbone.View.extend({
this.ppfx = config.pStylePrefix || ''; this.ppfx = config.pStylePrefix || '';
this.target = o.target || {}; this.target = o.target || {};
this.config = config; this.config = config;
const { module, em } = o;
this.module = module;
this.em = em;
// The target that will emit events for properties // The target that will emit events for properties
const target = {}; const target = {};
@ -24,11 +27,9 @@ export default Backbone.View.extend({
body.removeChild(dummy); body.removeChild(dummy);
this.propTarget = target; this.propTarget = target;
const coll = this.collection; const coll = this.collection;
const events =
'component:toggled component:update:classes change:state change:device frame:resized';
this.listenTo(coll, 'add', this.addTo); this.listenTo(coll, 'add', this.addTo);
this.listenTo(coll, 'reset', this.render); this.listenTo(coll, 'reset', this.render);
this.listenTo(this.target, events, this.targetUpdated); this.listenTo(em, module.events.target, this.targetUpdated);
}, },
remove() { remove() {
@ -137,9 +138,7 @@ export default Backbone.View.extend({
const rules = em.get('CssComposer').getAll(); const rules = em.get('CssComposer').getAll();
if (targetIsClass) { if (targetIsClass) {
rule = rules.filter( rule = rules.filter(rule => rule.get('selectors').getFullString() === target)[0];
rule => rule.get('selectors').getFullString() === target
)[0];
} }
if (!rule) { if (!rule) {
@ -180,7 +179,7 @@ export default Backbone.View.extend({
properties: model.get('properties'), properties: model.get('properties'),
target, target,
propTarget, propTarget,
config config,
}).render().el; }).render().el;
appendAtIndex(appendTo, rendered, opts.at); appendAtIndex(appendTo, rendered, opts.at);
@ -197,5 +196,5 @@ export default Backbone.View.extend({
$el.append(frag); $el.append(frag);
$el.addClass(`${pfx}sectors ${ppfx}one-bg ${ppfx}two-color`); $el.addClass(`${pfx}sectors ${ppfx}one-bg ${ppfx}two-color`);
return this; return this;
} },
}); });

Loading…
Cancel
Save