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 Selectors from '../../selector_manager/model/Selectors';
import { getMediaLength } from '../../code_manager/model/CssGenerator'; import { getMediaLength } from '../../code_manager/model/CssGenerator';
import { isEmptyObj, hasWin } from '../../utils/mixins'; 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 : {}; const { CSS } = hasWin() ? window : {};
/** /**
@ -23,7 +86,11 @@ const { CSS } = hasWin() ? window : {};
* [State]: state.html * [State]: state.html
* [Component]: component.html * [Component]: component.html
*/ */
export default class CssRule extends StyleableModel { export default class CssRule extends StyleableModel<CssRuleProperties> {
config: CssRuleProperties;
em?: EditorModel;
opt: any;
defaults() { defaults() {
return { return {
selectors: [], selectors: [],
@ -36,38 +103,39 @@ export default class CssRule extends StyleableModel {
singleAtRule: false, singleAtRule: false,
important: false, important: false,
group: '', group: '',
// If true, won't be stored in JSON or showed in CSS
shallow: false, shallow: false,
_undo: true, _undo: true,
}; };
} }
initialize(c, opt = {}) { constructor(props: CssRuleProperties, opt: any = {}) {
this.config = c || {}; super(props);
this.config = props || {};
this.opt = opt; this.opt = opt;
this.em = opt.em; this.em = opt.em;
this.ensureSelectors(); this.ensureSelectors(null, null, {});
this.on('change', this.__onChange); this.on('change', this.__onChange);
} }
__onChange(m, opts) { __onChange(m: CssRule, opts: any) {
const { em } = this; const { em } = this;
const changed = this.changedAttributes(); const changed = this.changedAttributes();
!isEmptyObj(changed) && em && em.changesUp(opts); changed && !isEmptyObj(changed) && em?.changesUp(opts);
} }
clone() { clone(): CssRule {
const opts = { ...this.opt }; const opts = { ...this.opt };
const attr = { ...this.attributes }; 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); return new this.constructor(attr, opts);
} }
ensureSelectors(m, c, opts) { ensureSelectors(m: any, c: any, opts: any) {
const { em } = this; const { em } = this;
const sm = em && em.get('SelectorManager'); const sm = em?.get('SelectorManager');
const toListen = [this, 'change:selectors', this.ensureSelectors]; const toListen = [this, 'change:selectors', this.ensureSelectors];
let sels = this.getSelectors(); let sels = this.getSelectors() as any;
this.stopListening(...toListen); this.stopListening(...toListen);
if (sels.models) { if (sels.models) {
@ -82,6 +150,7 @@ export default class CssRule extends StyleableModel {
} }
this.set('selectors', sels, opts); this.set('selectors', sels, opts);
// @ts-ignore
this.listenTo(...toListen); this.listenTo(...toListen);
} }
@ -114,13 +183,14 @@ export default class CssRule extends StyleableModel {
* cssRule.selectorsToString(); // ".class1:hover" * cssRule.selectorsToString(); // ".class1:hover"
* cssRule.selectorsToString({ skipState: true }); // ".class1" * cssRule.selectorsToString({ skipState: true }); // ".class1"
*/ */
selectorsToString(opts = {}) { selectorsToString(opts: AnyObject = {}) {
const result = []; const result = [];
const state = this.get('state'); const state = this.get('state');
const addSelector = this.get('selectorsAdd'); const addSelector = this.get('selectorsAdd');
const selOpts = { 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 selectors = this.get('selectors').getFullString(0, selOpts);
const stateStr = state && !opts.skipState ? `:${state}` : ''; const stateStr = state && !opts.skipState ? `:${state}` : '';
selectors && result.push(`${selectors}${stateStr}`); selectors && result.push(`${selectors}${stateStr}`);
@ -139,7 +209,7 @@ export default class CssRule extends StyleableModel {
* }); * });
* cssRule.getDeclaration() // ".class1{color:red;}" * cssRule.getDeclaration() // ".class1{color:red;}"
*/ */
getDeclaration(opts = {}) { getDeclaration(opts: AnyObject = {}) {
let result = ''; let result = '';
const { important } = this.attributes; const { important } = this.attributes;
const selectors = this.selectorsToString(opts); const selectors = this.selectorsToString(opts);
@ -164,11 +234,11 @@ export default class CssRule extends StyleableModel {
const { em } = this; const { em } = this;
const { atRuleType, mediaText } = this.attributes; const { atRuleType, mediaText } = this.attributes;
const devices = em?.get('DeviceManager').getDevices() || []; 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) { if (atRuleType !== 'media' || !mediaText) {
return deviceDefault || null; 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() { getState() {
const { em } = this; const { em } = this;
const stateValue = this.get('state'); const stateValue = this.get('state');
const states = em.get('SelectorManager').getStates() || []; const states = em?.get('SelectorManager').getStates() || [];
return states.filter(s => s.getName() === stateValue)[0] || null; return states.filter((s: any) => s.getName() === stateValue)[0] || null;
} }
/** /**
@ -193,7 +263,7 @@ export default class CssRule extends StyleableModel {
* console.log(cmp?.toHTML()); * console.log(cmp?.toHTML());
*/ */
getComponent() { getComponent() {
const sel = this.getSelectors(); const sel = this.getSelectors() as any;
const sngl = sel.length == 1 && sel.at(0); const sngl = sel.length == 1 && sel.at(0);
const cmpId = sngl && sngl.isId() && sngl.get('name'); const cmpId = sngl && sngl.isId() && sngl.get('name');
return (cmpId && this.em?.get('DomComponents').getById(cmpId)) || null; 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;}}" * cssRule.toCSS() // "@media (min-width: 500px){.class1{color:red;}}"
*/ */
toCSS(opts = {}) { toCSS(opts: AnyObject = {}) {
let result = ''; let result = '';
const atRule = this.getAtRule(); const atRule = this.getAtRule();
const block = this.getDeclaration(opts); const block = this.getDeclaration(opts);
@ -225,10 +295,10 @@ export default class CssRule extends StyleableModel {
return result; return result;
} }
toJSON(...args) { toJSON(...args: any) {
const obj = Model.prototype.toJSON.apply(this, args); const obj = Model.prototype.toJSON.apply(this, args);
if (this.em.getConfig().avoidDefaults) { if (this.em?.getConfig().avoidDefaults) {
const defaults = this.defaults(); const defaults = this.defaults();
forEach(defaults, (value, key) => { forEach(defaults, (value, key) => {
@ -256,7 +326,7 @@ export default class CssRule extends StyleableModel {
* @returns {Boolean} * @returns {Boolean}
* @private * @private
*/ */
compare(selectors, state, width, ruleProps = {}) { compare(selectors: any, state: string, width: string, ruleProps: Partial<CssRuleProperties> = {}) {
const st = state || ''; const st = state || '';
const wd = width || ''; const wd = width || '';
const selAdd = ruleProps.selectorsAdd || ''; const selAdd = ruleProps.selectorsAdd || '';
@ -266,8 +336,8 @@ export default class CssRule extends StyleableModel {
// Fix atRuleType in case is not specified with width // Fix atRuleType in case is not specified with width
if (wd && !atRule) atRule = 'media'; if (wd && !atRule) atRule = 'media';
const a1 = sel.map(model => model.getFullName()); const a1: string[] = sel.map((model: any) => model.getFullName());
const a2 = this.get('selectors').map(model => model.getFullName()); const a2: string[] = this.get('selectors')?.map(model => model.getFullName())!;
// Check selectors // Check selectors
const a1S = a1.slice().sort(); 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 { shallowDiff } from '../../utils/mixins';
import ParserHtml from '../../parser/model/ParserHtml'; import ParserHtml from '../../parser/model/ParserHtml';
import { Model } from '../../common'; import { Model } from '../../common';
import { ObjectHash } from 'backbone';
type AnyObject = Record<string, any>;
const parserHtml = ParserHtml(); 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 * Forward style string to `parseStyle` to be parse to an object
* @param {string} str * @param {string} str
* @returns * @returns
*/ */
parseStyle(str) { parseStyle(str: string) {
return parserHtml.parseStyle(str); return parserHtml.parseStyle(str);
} }
@ -21,7 +24,7 @@ export default class StyleableModel extends Model {
* @param {Object} prop * @param {Object} prop
* @return {Object} * @return {Object}
*/ */
extendStyle(prop) { extendStyle(prop: AnyObject): AnyObject {
return { ...this.getStyle(), ...prop }; return { ...this.getStyle(), ...prop };
} }
@ -29,9 +32,9 @@ export default class StyleableModel extends Model {
* Get style object * Get style object
* @return {Object} * @return {Object}
*/ */
getStyle(prop) { getStyle(prop?: string | AnyObject) {
const style = this.get('style') || {}; const style = this.get('style') || {};
const result = { ...style }; const result: AnyObject = { ...style };
return prop && isString(prop) ? result[prop] : result; return prop && isString(prop) ? result[prop] : result;
} }
@ -41,7 +44,7 @@ export default class StyleableModel extends Model {
* @param {Object} opts * @param {Object} opts
* @return {Object} Applied properties * @return {Object} Applied properties
*/ */
setStyle(prop = {}, opts = {}) { setStyle(prop: string | AnyObject = {}, opts: AnyObject = {}) {
if (isString(prop)) { if (isString(prop)) {
prop = this.parseStyle(prop); prop = this.parseStyle(prop);
} }
@ -60,7 +63,8 @@ export default class StyleableModel extends Model {
// Delete the property used for partial updates // Delete the property used for partial updates
delete diff.__p; delete diff.__p;
keys(diff).forEach(pr => { keys(diff).forEach(pr => {
const em = this.em; // @ts-ignore
const { em } = this;
if (opts.noEvent) return; if (opts.noEvent) return;
this.trigger(`change:style:${pr}`); this.trigger(`change:style:${pr}`);
if (em) { if (em) {
@ -80,7 +84,7 @@ export default class StyleableModel extends Model {
* this.addStyle({color: 'red'}); * this.addStyle({color: 'red'});
* this.addStyle('color', 'blue'); * this.addStyle('color', 'blue');
*/ */
addStyle(prop, value = '', opts = {}) { addStyle(prop: string | AnyObject, value = '', opts = {}) {
if (typeof prop == 'string') { if (typeof prop == 'string') {
prop = { prop = {
prop: value, prop: value,
@ -97,7 +101,7 @@ export default class StyleableModel extends Model {
* Remove style property * Remove style property
* @param {string} prop * @param {string} prop
*/ */
removeStyle(prop) { removeStyle(prop: string) {
let style = this.getStyle(); let style = this.getStyle();
delete style[prop]; delete style[prop];
this.setStyle(style); this.setStyle(style);
@ -108,7 +112,7 @@ export default class StyleableModel extends Model {
* @param {Object} [opts={}] Options * @param {Object} [opts={}] Options
* @return {String} * @return {String}
*/ */
styleToString(opts = {}) { styleToString(opts: AnyObject = {}) {
const result = []; const result = [];
const style = this.getStyle(opts); const style = this.getStyle(opts);
@ -127,11 +131,13 @@ export default class StyleableModel extends Model {
return this.get('selectors') || this.get('classes'); return this.get('selectors') || this.get('classes');
} }
getSelectorsString(opts) { getSelectorsString(opts?: AnyObject) {
// @ts-ignore
return this.selectorsToString ? this.selectorsToString(opts) : this.getSelectors().getFullString(); return this.selectorsToString ? this.selectorsToString(opts) : this.getSelectors().getFullString();
} }
_validate(attr, opts) { // @ts-ignore
return true; // _validate(attr, opts) {
} // return true;
// }
} }
Loading…
Cancel
Save