Browse Source

Move CssRule to TS

pull/4695/head
Artur Arseniev 4 years ago
parent
commit
8f4f3e3e73
  1. 122
      src/css_composer/model/CssRule.ts
  2. 36
      src/domain_abstract/model/StyleableModel.ts

122
src/css_composer/model/CssRule.js → src/css_composer/model/CssRule.ts

@ -4,7 +4,70 @@ import StyleableModel from '../../domain_abstract/model/StyleableModel';
import Selectors from '../../selector_manager/model/Selectors';
import { getMediaLength } from '../../code_manager/model/CssGenerator';
import { isEmptyObj, hasWin } from '../../utils/mixins';
import Selector from '../../selector_manager/model/Selector';
import EditorModel from '../../editor/model/Editor';
/** @private */
export interface CssRuleProperties {
/**
* Array of selectors
*/
selectors: Selector[];
/**
* Object containing style definitions
* @default {}
*/
style?: Record<string, any>;
/**
* Additional string css selectors
* @default ''
*/
selectorsAdd?: string;
/**
* Type of at-rule, eg. `media`, 'font-face'
* @default ''
*/
atRuleType?: string;
/**
* At-rule value, eg. `(max-width: 1000px)`
* @default ''
*/
mediaText?: string;
/**
* This property is used only on at-rules, like 'page' or 'font-face', where the block containes only style declarations.
* @default false
*/
singleAtRule?: boolean;
/**
* State of the rule, eg: `hover`, `focused`
* @default ''
*/
state?: string;
/**
* If true, sets `!important` on all properties. You can also pass an array to specify properties on which to use important.
* @default false
*/
important?: boolean | string[];
/**
* Indicates if the rule is stylable from the editor.
* @default true
*/
stylable?: boolean | string[];
/**
* Group for rules.
* @default ''
*/
group?: string;
/**
* If true, the rule won't be stored in JSON or showed in CSS export.
* @default false
*/
shallow?: boolean;
}
type AnyObject = Record<string, any>;
// @ts-ignore
const { CSS } = hasWin() ? window : {};
/**
@ -23,7 +86,11 @@ const { CSS } = hasWin() ? window : {};
* [State]: state.html
* [Component]: component.html
*/
export default class CssRule extends StyleableModel {
export default class CssRule extends StyleableModel<CssRuleProperties> {
config: CssRuleProperties;
em?: EditorModel;
opt: any;
defaults() {
return {
selectors: [],
@ -36,38 +103,39 @@ export default class CssRule extends StyleableModel {
singleAtRule: false,
important: false,
group: '',
// If true, won't be stored in JSON or showed in CSS
shallow: false,
_undo: true,
};
}
initialize(c, opt = {}) {
this.config = c || {};
constructor(props: CssRuleProperties, opt: any = {}) {
super(props);
this.config = props || {};
this.opt = opt;
this.em = opt.em;
this.ensureSelectors();
this.ensureSelectors(null, null, {});
this.on('change', this.__onChange);
}
__onChange(m, opts) {
__onChange(m: CssRule, opts: any) {
const { em } = this;
const changed = this.changedAttributes();
!isEmptyObj(changed) && em && em.changesUp(opts);
changed && !isEmptyObj(changed) && em?.changesUp(opts);
}
clone() {
clone(): CssRule {
const opts = { ...this.opt };
const attr = { ...this.attributes };
attr.selectors = this.get('selectors').map(s => s.clone());
attr.selectors = this.get('selectors')!.map(s => s.clone()) as Selector[];
// @ts-ignore
return new this.constructor(attr, opts);
}
ensureSelectors(m, c, opts) {
ensureSelectors(m: any, c: any, opts: any) {
const { em } = this;
const sm = em && em.get('SelectorManager');
const sm = em?.get('SelectorManager');
const toListen = [this, 'change:selectors', this.ensureSelectors];
let sels = this.getSelectors();
let sels = this.getSelectors() as any;
this.stopListening(...toListen);
if (sels.models) {
@ -82,6 +150,7 @@ export default class CssRule extends StyleableModel {
}
this.set('selectors', sels, opts);
// @ts-ignore
this.listenTo(...toListen);
}
@ -114,13 +183,14 @@ export default class CssRule extends StyleableModel {
* cssRule.selectorsToString(); // ".class1:hover"
* cssRule.selectorsToString({ skipState: true }); // ".class1"
*/
selectorsToString(opts = {}) {
selectorsToString(opts: AnyObject = {}) {
const result = [];
const state = this.get('state');
const addSelector = this.get('selectorsAdd');
const selOpts = {
escape: str => (CSS && CSS.escape ? CSS.escape(str) : str),
escape: (str: string) => (CSS && CSS.escape ? CSS.escape(str) : str),
};
// @ts-ignore
const selectors = this.get('selectors').getFullString(0, selOpts);
const stateStr = state && !opts.skipState ? `:${state}` : '';
selectors && result.push(`${selectors}${stateStr}`);
@ -139,7 +209,7 @@ export default class CssRule extends StyleableModel {
* });
* cssRule.getDeclaration() // ".class1{color:red;}"
*/
getDeclaration(opts = {}) {
getDeclaration(opts: AnyObject = {}) {
let result = '';
const { important } = this.attributes;
const selectors = this.selectorsToString(opts);
@ -164,11 +234,11 @@ export default class CssRule extends StyleableModel {
const { em } = this;
const { atRuleType, mediaText } = this.attributes;
const devices = em?.get('DeviceManager').getDevices() || [];
const deviceDefault = devices.filter(d => d.getWidthMedia() === '')[0];
const deviceDefault = devices.filter((d: any) => d.getWidthMedia() === '')[0];
if (atRuleType !== 'media' || !mediaText) {
return deviceDefault || null;
}
return devices.filter(d => d.getWidthMedia() === getMediaLength(mediaText))[0] || null;
return devices.filter((d: any) => d.getWidthMedia() === getMediaLength(mediaText))[0] || null;
}
/**
@ -181,8 +251,8 @@ export default class CssRule extends StyleableModel {
getState() {
const { em } = this;
const stateValue = this.get('state');
const states = em.get('SelectorManager').getStates() || [];
return states.filter(s => s.getName() === stateValue)[0] || null;
const states = em?.get('SelectorManager').getStates() || [];
return states.filter((s: any) => s.getName() === stateValue)[0] || null;
}
/**
@ -193,7 +263,7 @@ export default class CssRule extends StyleableModel {
* console.log(cmp?.toHTML());
*/
getComponent() {
const sel = this.getSelectors();
const sel = this.getSelectors() as any;
const sngl = sel.length == 1 && sel.at(0);
const cmpId = sngl && sngl.isId() && sngl.get('name');
return (cmpId && this.em?.get('DomComponents').getById(cmpId)) || null;
@ -210,7 +280,7 @@ export default class CssRule extends StyleableModel {
* });
* cssRule.toCSS() // "@media (min-width: 500px){.class1{color:red;}}"
*/
toCSS(opts = {}) {
toCSS(opts: AnyObject = {}) {
let result = '';
const atRule = this.getAtRule();
const block = this.getDeclaration(opts);
@ -225,10 +295,10 @@ export default class CssRule extends StyleableModel {
return result;
}
toJSON(...args) {
toJSON(...args: any) {
const obj = Model.prototype.toJSON.apply(this, args);
if (this.em.getConfig().avoidDefaults) {
if (this.em?.getConfig().avoidDefaults) {
const defaults = this.defaults();
forEach(defaults, (value, key) => {
@ -256,7 +326,7 @@ export default class CssRule extends StyleableModel {
* @returns {Boolean}
* @private
*/
compare(selectors, state, width, ruleProps = {}) {
compare(selectors: any, state: string, width: string, ruleProps: Partial<CssRuleProperties> = {}) {
const st = state || '';
const wd = width || '';
const selAdd = ruleProps.selectorsAdd || '';
@ -266,8 +336,8 @@ export default class CssRule extends StyleableModel {
// Fix atRuleType in case is not specified with width
if (wd && !atRule) atRule = 'media';
const a1 = sel.map(model => model.getFullName());
const a2 = this.get('selectors').map(model => model.getFullName());
const a1: string[] = sel.map((model: any) => model.getFullName());
const a2: string[] = this.get('selectors')?.map(model => model.getFullName())!;
// Check selectors
const a1S = a1.slice().sort();

36
src/domain_abstract/model/StyleableModel.js → src/domain_abstract/model/StyleableModel.ts

@ -1,17 +1,20 @@
import { isString, isArray, keys, isUndefined } from 'underscore';
import { isString, isArray, keys } from 'underscore';
import { shallowDiff } from '../../utils/mixins';
import ParserHtml from '../../parser/model/ParserHtml';
import { Model } from '../../common';
import { ObjectHash } from 'backbone';
type AnyObject = Record<string, any>;
const parserHtml = ParserHtml();
export default class StyleableModel extends Model {
export default class StyleableModel<T extends ObjectHash = any> extends Model<T> {
/**
* Forward style string to `parseStyle` to be parse to an object
* @param {string} str
* @returns
*/
parseStyle(str) {
parseStyle(str: string) {
return parserHtml.parseStyle(str);
}
@ -21,7 +24,7 @@ export default class StyleableModel extends Model {
* @param {Object} prop
* @return {Object}
*/
extendStyle(prop) {
extendStyle(prop: AnyObject): AnyObject {
return { ...this.getStyle(), ...prop };
}
@ -29,9 +32,9 @@ export default class StyleableModel extends Model {
* Get style object
* @return {Object}
*/
getStyle(prop) {
getStyle(prop?: string | AnyObject) {
const style = this.get('style') || {};
const result = { ...style };
const result: AnyObject = { ...style };
return prop && isString(prop) ? result[prop] : result;
}
@ -41,7 +44,7 @@ export default class StyleableModel extends Model {
* @param {Object} opts
* @return {Object} Applied properties
*/
setStyle(prop = {}, opts = {}) {
setStyle(prop: string | AnyObject = {}, opts: AnyObject = {}) {
if (isString(prop)) {
prop = this.parseStyle(prop);
}
@ -60,7 +63,8 @@ export default class StyleableModel extends Model {
// Delete the property used for partial updates
delete diff.__p;
keys(diff).forEach(pr => {
const em = this.em;
// @ts-ignore
const { em } = this;
if (opts.noEvent) return;
this.trigger(`change:style:${pr}`);
if (em) {
@ -80,7 +84,7 @@ export default class StyleableModel extends Model {
* this.addStyle({color: 'red'});
* this.addStyle('color', 'blue');
*/
addStyle(prop, value = '', opts = {}) {
addStyle(prop: string | AnyObject, value = '', opts = {}) {
if (typeof prop == 'string') {
prop = {
prop: value,
@ -97,7 +101,7 @@ export default class StyleableModel extends Model {
* Remove style property
* @param {string} prop
*/
removeStyle(prop) {
removeStyle(prop: string) {
let style = this.getStyle();
delete style[prop];
this.setStyle(style);
@ -108,7 +112,7 @@ export default class StyleableModel extends Model {
* @param {Object} [opts={}] Options
* @return {String}
*/
styleToString(opts = {}) {
styleToString(opts: AnyObject = {}) {
const result = [];
const style = this.getStyle(opts);
@ -127,11 +131,13 @@ export default class StyleableModel extends Model {
return this.get('selectors') || this.get('classes');
}
getSelectorsString(opts) {
getSelectorsString(opts?: AnyObject) {
// @ts-ignore
return this.selectorsToString ? this.selectorsToString(opts) : this.getSelectors().getFullString();
}
_validate(attr, opts) {
return true;
}
// @ts-ignore
// _validate(attr, opts) {
// return true;
// }
}
Loading…
Cancel
Save